@@ -101,31 +101,49 @@ def init_notebook_mode(
101101 )
102102
103103
104+ def _format_column (x ):
105+ if x .dtype .kind == "O" :
106+ return x .astype (str )
107+
108+ if x .dtype .kind == "f" :
109+ x = np .array (fmt .format_array (x .values , None ))
110+ try :
111+ return x .astype (float )
112+ except ValueError :
113+ pass
114+
115+ return x
116+
117+
104118def _formatted_values (df ):
105- """Return the table content as a list of lists for DataTables"""
106- formatted_df = df .copy ()
119+ """Format the values in the table and return the data, row by row, as requested by DataTables"""
107120 # We iterate over columns using an index rather than the column name
108121 # to avoid an issue in case of duplicated column names #89
109- for j , col in enumerate (formatted_df ):
110- x = formatted_df .iloc [:, j ]
111- if x .dtype .kind in ["b" , "i" , "s" ]:
112- continue
113-
114- if x .dtype .kind == "O" :
115- formatted_df .iloc [:, j ] = formatted_df .iloc [:, j ].astype (str )
116- continue
117-
118- formatted_df .iloc [:, j ] = np .array (fmt .format_array (x .values , None ))
119- if x .dtype .kind == "f" :
120- try :
121- formatted_df .iloc [:, j ] = formatted_df .iloc [:, j ].astype (float )
122- except ValueError :
123- pass
122+ return list (
123+ zip (
124+ * (
125+ _format_column (df .iloc [:, j ]).tolist ()
126+ for j , col in enumerate (df .columns )
127+ )
128+ )
129+ )
124130
125- rows = formatted_df .values .tolist ()
126131
127- # Replace pd.NA with None
128- return [[cell if cell is not pd .NA else None for cell in row ] for row in rows ]
132+ class TableValuesEncoder (json .JSONEncoder ):
133+ def default (self , obj ):
134+ if obj is pd .NA :
135+ return None
136+ if isinstance (obj , np .bool_ ):
137+ return bool (obj )
138+ if isinstance (obj , np .integer ):
139+ return int (obj )
140+ if isinstance (obj , np .floating ):
141+ return float (obj )
142+ if isinstance (obj , pd .Timedelta ):
143+ return str (obj )
144+ if isinstance (obj , pd .Timestamp ):
145+ return str (obj )
146+ return json .JSONEncoder .default (self , obj )
129147
130148
131149def _table_header (
@@ -352,7 +370,7 @@ def to_html_datatable(df=None, tableId=None, connected=True, **kwargs):
352370
353371 # Export the table data to JSON and include this in the HTML
354372 data = _formatted_values (df .reset_index () if showIndex else df )
355- dt_data = json .dumps (data )
373+ dt_data = json .dumps (data , cls = TableValuesEncoder )
356374 output = replace_value (output , "const data = [];" , f"const data = { dt_data } ;" )
357375
358376 return output
0 commit comments