66from .styling import (
77 TABLE_STYLING ,
88 COVERAGE_THRESHOLDS ,
9- get_coverage_tier_props ,
9+ get_coverage_tier_css_props ,
1010)
1111
1212
1313# Define highlighting tiers using centralized color configuration
1414HIGHLIGHT_TIERS = [
15- {"dist" : COVERAGE_THRESHOLDS ["poor" ], "props" : get_coverage_tier_props ("poor" )},
15+ {"dist" : COVERAGE_THRESHOLDS ["poor" ], "props" : get_coverage_tier_css_props ("poor" )},
1616 {
1717 "dist" : COVERAGE_THRESHOLDS ["medium" ],
18- "props" : get_coverage_tier_props ("medium" , "500" ),
18+ "props" : get_coverage_tier_css_props ("medium" , "500" ),
1919 },
20- {"dist" : COVERAGE_THRESHOLDS ["good" ], "props" : get_coverage_tier_props ("good" )},
20+ {"dist" : COVERAGE_THRESHOLDS ["good" ], "props" : get_coverage_tier_css_props ("good" )},
2121]
2222
2323
@@ -31,13 +31,34 @@ def _apply_highlight_range(
3131 s_numeric = pd .to_numeric (
3232 s_col , errors = "coerce"
3333 ) # Convert to numeric, non-convertibles become NaN
34+
3435 # Apply style ONLY if value is WITHIN the current dist from level
35- # This means for tiered styling, the order of applying styles in the calling function matters.
36- # If a value falls into multiple dist categories, the LAST applied style for that dist will win.
37- condition = ( s_numeric >= level - dist ) & ( s_numeric <= level + dist )
36+ # Use absolute difference to determine which tier applies
37+ abs_diff = np . abs ( s_numeric - level )
38+ condition = abs_diff <= dist
3839 return np .where (condition , props , "" )
3940
4041
42+ def _determine_coverage_tier (value : float , level : float ) -> str :
43+ """
44+ Determine which coverage tier a value belongs to based on distance from level.
45+ Returns the most specific (smallest distance) tier that applies.
46+ """
47+ if pd .isna (value ):
48+ return ""
49+
50+ abs_diff = abs (value - level )
51+
52+ # Check tiers from most specific to least specific
53+ sorted_tiers = sorted (HIGHLIGHT_TIERS , key = lambda x : x ["dist" ])
54+
55+ for tier in sorted_tiers :
56+ if abs_diff <= tier ["dist" ]:
57+ return tier ["props" ]
58+
59+ return ""
60+
61+
4162def _apply_base_table_styling (styler : Styler ) -> Styler :
4263 """
4364 Apply base styling to the table including headers, borders, and overall appearance.
@@ -114,7 +135,7 @@ def color_coverage_columns(
114135) -> Styler :
115136 """
116137 Applies tiered highlighting to specified coverage columns of a Styler object.
117- The order of application matters: more specific (narrower dist) rules are applied last to override .
138+ Uses non-overlapping logic to prevent CSS conflicts .
118139 """
119140 if not isinstance (styler , Styler ):
120141 raise TypeError ("Expected a pandas Styler object." )
@@ -132,24 +153,22 @@ def color_coverage_columns(
132153 # Apply base styling first
133154 current_styler = _apply_base_table_styling (styler )
134155
135- # Apply highlighting rules from the defined tiers
136- # The order in HIGHLIGHT_TIERS is important if props are meant to override.
137- # Pandas Styler.apply applies styles sequentially. If a cell matches multiple
138- # conditions from different .apply calls, the styles from later calls typically override
139- # or merge with earlier ones, depending on the CSS properties.
140- # For background-color, later calls will override.
141- for tier in HIGHLIGHT_TIERS :
142- current_styler = current_styler .apply (
143- _apply_highlight_range ,
144- level = level ,
145- dist = tier ["dist" ],
146- props = tier ["props" ],
147- subset = valid_coverage_cols ,
148- )
156+ # Apply single tier styling to prevent conflicts
157+ def apply_coverage_tier_to_cell (s_col ):
158+ """Apply only the most appropriate coverage tier for each cell."""
159+ return s_col .apply (lambda x : _determine_coverage_tier (x , level ))
160+
161+ current_styler = current_styler .apply (
162+ apply_coverage_tier_to_cell , subset = valid_coverage_cols
163+ )
149164
150165 # Apply additional styling to coverage columns for emphasis
151166 current_styler = current_styler .set_properties (
152- ** {"text-align" : "center" , "font-family" : "monospace" , "font-size" : "13px" },
167+ ** {
168+ "text-align" : "center" ,
169+ "font-family" : "monospace" ,
170+ "font-size" : "13px" ,
171+ },
153172 subset = valid_coverage_cols ,
154173 )
155174
0 commit comments