Skip to content

Commit ad0b297

Browse files
committed
extend utils for tables
1 parent 106c288 commit ad0b297

File tree

1 file changed

+102
-14
lines changed

1 file changed

+102
-14
lines changed

doc/utils/style_tables.py

Lines changed: 102 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import numpy as np
22
import pandas as pd
33
from 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(
7880
def 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

Comments
 (0)