@@ -50,15 +50,16 @@ def _try_parse_json_strings(dataframe: pd.DataFrame) -> pd.DataFrame:
5050
5151def _flatten_nested_data (
5252 dataframe : pd .DataFrame ,
53- ) -> tuple [pd .DataFrame , dict [str , list [int ]], list [str ]]:
53+ ) -> tuple [pd .DataFrame , dict [str , list [int ]], list [str ], set [ str ] ]:
5454 """Flatten nested STRUCT and ARRAY columns for display."""
5555 if dataframe .empty :
56- return dataframe .copy (), {}, []
56+ return dataframe .copy (), {}, [], set ()
5757
5858 result_df = _try_parse_json_strings (dataframe )
5959 initial_columns = list (result_df .columns )
6060
6161 array_row_groups : dict [str , list [int ]] = {}
62+ nested_originated_columns : set [str ] = set ()
6263
6364 # First, identify all STRUCT and ARRAY columns
6465 struct_columns : list [str ] = []
@@ -73,8 +74,10 @@ def _flatten_nested_data(
7374 pa_type = dtype .pyarrow_dtype
7475 if pa .types .is_struct (pa_type ):
7576 struct_columns .append (col_name )
77+ nested_originated_columns .add (col_name )
7678 elif pa .types .is_list (pa_type ):
7779 array_columns .append (col_name )
80+ nested_originated_columns .add (col_name )
7881 if hasattr (pa_type , "value_type" ) and (
7982 pa .types .is_struct (pa_type .value_type )
8083 ):
@@ -85,25 +88,36 @@ def _flatten_nested_data(
8588 clear_on_continuation_cols .append (col_name )
8689
8790 result_df , array_columns = _flatten_array_of_struct_columns (
88- result_df , array_of_struct_columns , array_columns
91+ result_df , array_of_struct_columns , array_columns , nested_originated_columns
8992 )
9093
9194 result_df , clear_on_continuation_cols = _flatten_struct_columns (
92- result_df , struct_columns , clear_on_continuation_cols
95+ result_df , struct_columns , clear_on_continuation_cols , nested_originated_columns
9396 )
9497
9598 # Now handle ARRAY columns (including the newly created ones from ARRAY of STRUCT)
9699 if not array_columns :
97- return result_df , array_row_groups , clear_on_continuation_cols
100+ return (
101+ result_df ,
102+ array_row_groups ,
103+ clear_on_continuation_cols ,
104+ nested_originated_columns ,
105+ )
98106
99107 result_df , array_row_groups = _explode_array_columns (result_df , array_columns )
100- return result_df , array_row_groups , clear_on_continuation_cols
108+ return (
109+ result_df ,
110+ array_row_groups ,
111+ clear_on_continuation_cols ,
112+ nested_originated_columns ,
113+ )
101114
102115
103116def _flatten_array_of_struct_columns (
104117 dataframe : pd .DataFrame ,
105118 array_of_struct_columns : list [str ],
106119 array_columns : list [str ],
120+ nested_originated_columns : set [str ],
107121) -> tuple [pd .DataFrame , list [str ]]:
108122 """Flatten ARRAY of STRUCT columns into separate array columns for each field."""
109123 result_df = dataframe .copy ()
@@ -116,6 +130,7 @@ def _flatten_array_of_struct_columns(
116130 for field_idx in range (struct_type .num_fields ):
117131 field = struct_type .field (field_idx )
118132 new_col_name = f"{ col_name } .{ field .name } "
133+ nested_originated_columns .add (new_col_name )
119134
120135 # Extract field values from each array element
121136 struct_field_values : list [list [Any ]] = []
@@ -224,6 +239,7 @@ def _flatten_struct_columns(
224239 dataframe : pd .DataFrame ,
225240 struct_columns : list [str ],
226241 clear_on_continuation_cols : list [str ],
242+ nested_originated_columns : set [str ],
227243) -> tuple [pd .DataFrame , list [str ]]:
228244 """Flatten regular STRUCT columns."""
229245 result_df = dataframe .copy ()
@@ -235,6 +251,7 @@ def _flatten_struct_columns(
235251 for field_idx in range (pa_type .num_fields ):
236252 field = pa_type .field (field_idx )
237253 new_col_name = f"{ col_name } .{ field .name } "
254+ nested_originated_columns .add (new_col_name )
238255 clear_on_continuation_cols .append (new_col_name )
239256
240257 regular_field_values : list [Any ] = []
@@ -252,6 +269,11 @@ def _flatten_struct_columns(
252269
253270def _is_dtype_numeric (dtype : Any ) -> bool :
254271 """Check if a dtype is numeric for alignment purposes."""
272+ # Arrays should always be left-aligned, even if they contain numeric elements
273+ if isinstance (dtype , pd .ArrowDtype ) and isinstance (
274+ dtype .pyarrow_dtype , pa .ListType
275+ ):
276+ return False
255277 return pandas .api .types .is_numeric_dtype (dtype )
256278
257279
@@ -266,6 +288,7 @@ def render_html(
266288 flattened_df ,
267289 array_row_groups ,
268290 clear_on_continuation ,
291+ nested_originated_columns ,
269292 ) = _flatten_nested_data (dataframe )
270293
271294 classes = "dataframe table table-striped table-hover"
@@ -312,7 +335,12 @@ def render_html(
312335 table_html_parts .append (" <td></td>\n " )
313336 continue
314337 dtype = flattened_df .dtypes .loc [col_name ] # type: ignore
315- align = "right" if _is_dtype_numeric (dtype ) else "left"
338+
339+ # Check if column originated from an array
340+ if col_name_str in nested_originated_columns :
341+ align = "left"
342+ else :
343+ align = "right" if _is_dtype_numeric (dtype ) else "left"
316344
317345 cell_content = ""
318346 if pandas .api .types .is_scalar (value ) and pd .isna (value ):
0 commit comments