11import numpy as np
22import pandas as pd
33from pandas .io .formats .style import Styler
4+ from typing import Union , Optional , List , Any
5+ from itables import show
46
57
68# Define highlighting tiers as a list of dictionaries or tuples
@@ -78,9 +80,9 @@ def color_coverage_columns(
7880def create_styled_table (
7981 df : pd .DataFrame ,
8082 level : float ,
81- n_rep : int , # Or Union[int, str] if "N/A" is possible
83+ n_rep : Union [int , str ],
8284 caption_prefix : str = "Coverage" ,
83- coverage_cols : list [str ] = ["Coverage" ],
85+ coverage_cols : List [str ] = ["Coverage" ],
8486 float_precision : str = "{:.3f}" ,
8587) -> Styler :
8688 """
@@ -102,21 +104,18 @@ def create_styled_table(
102104 if not df .columns .tolist ()
103105 else [None ] * len (empty_df_cols )
104106 )
105- return (
106- pd .DataFrame (
107- (
108- dict (zip (empty_df_cols , [[v ] for v in message_val ]))
109- if not df .columns .tolist ()
110- else []
111- ),
112- columns = empty_df_cols ,
113- )
114- .style .hide (axis = "index" )
115- .set_caption ("No data to display." )
107+ df_to_style = pd .DataFrame (
108+ (
109+ dict (zip (empty_df_cols , [[v ] for v in message_val ]))
110+ if not df .columns .tolist ()
111+ else {} # Pass empty dict for empty DataFrame with columns
112+ ),
113+ columns = empty_df_cols ,
116114 )
115+ return df_to_style .style .hide (axis = "index" ).set_caption ("No data to display." )
117116
118117 # Prepare float formatting dictionary
119- float_cols = df .select_dtypes (include = ["float" ]).columns
118+ float_cols = df .select_dtypes (include = ["float" , "float64" , "float32" ]).columns
120119 format_dict = {col : float_precision for col in float_cols if col in df .columns }
121120
122121 # Create and set the caption text
@@ -141,3 +140,92 @@ def create_styled_table(
141140 )
142141
143142 return styled_df
143+
144+
145+ def generate_and_show_styled_table (
146+ main_df : pd .DataFrame ,
147+ filters : dict [str , Any ],
148+ display_cols : List [str ],
149+ n_rep : Union [int , str ],
150+ level_col : str = "level" ,
151+ rename_map : Optional [dict [str , str ]] = None ,
152+ caption_prefix : str = "Coverage" ,
153+ coverage_highlight_cols : List [str ] = ["Coverage" ],
154+ float_precision : str = "{:.3f}" ,
155+ ):
156+ """
157+ Filters a DataFrame based on a dictionary of conditions,
158+ creates a styled table, and displays it.
159+ """
160+ if main_df .empty :
161+ print ("Warning: Input DataFrame is empty." )
162+ # Optionally, show an empty table or a message
163+ empty_styled_df = (
164+ pd .DataFrame (columns = display_cols )
165+ .style .hide (axis = "index" )
166+ .set_caption ("No data available (input empty)." )
167+ )
168+ show (empty_styled_df , allow_html = True )
169+ return
170+
171+ # Build filter condition
172+ current_df = main_df
173+ filter_conditions = []
174+ filter_description_parts = []
175+
176+ for col , value in filters .items ():
177+ if col not in current_df .columns :
178+ print (
179+ f"Warning: Filter column '{ col } ' not found in DataFrame. Skipping this filter."
180+ )
181+ continue
182+ current_df = current_df [current_df [col ] == value ]
183+ filter_conditions .append (f"{ col } == { value } " )
184+ filter_description_parts .append (f"{ col } ='{ value } '" )
185+
186+ filter_description = " & " .join (filter_description_parts )
187+
188+ if current_df .empty :
189+ level_val = filters .get (level_col , "N/A" )
190+ level_percent_display = (
191+ f"{ level_val * 100 } %" if isinstance (level_val , (int , float )) else level_val
192+ )
193+ caption_msg = f"No data after filtering for { filter_description } at { level_percent_display } level."
194+ print (f"Warning: { caption_msg } " )
195+ empty_styled_df = (
196+ pd .DataFrame (columns = display_cols )
197+ .style .hide (axis = "index" )
198+ .set_caption (caption_msg )
199+ )
200+ show (empty_styled_df , allow_html = True )
201+ return
202+
203+ df_filtered = current_df [
204+ display_cols
205+ ].copy () # Select display columns after filtering
206+
207+ if rename_map :
208+ df_filtered .rename (columns = rename_map , inplace = True )
209+
210+ # Determine the level for styling from the filters, if present
211+ styling_level = filters .get (level_col )
212+ if styling_level is None or not isinstance (styling_level , (float , int )):
213+ print (
214+ f"Warning: '{ level_col } ' not found in filters or is not numeric. Cannot determine styling level for highlighting."
215+ )
216+ # Fallback or raise error, for now, we'll proceed without level-specific caption part if it's missing
217+ # Or you could try to infer it if there's only one unique level in the filtered data
218+ if level_col in df_filtered .columns and df_filtered [level_col ].nunique () == 1 :
219+ styling_level = df_filtered [level_col ].iloc [0 ]
220+ else : # Default to a common value or skip styling that depends on 'level'
221+ styling_level = 0.95 # Default, or handle error
222+
223+ styled_table = create_styled_table (
224+ df_filtered ,
225+ styling_level , # Use the level from filters for styling
226+ n_rep ,
227+ caption_prefix = caption_prefix ,
228+ coverage_cols = coverage_highlight_cols ,
229+ float_precision = float_precision ,
230+ )
231+ show (styled_table , allow_html = True )
0 commit comments