Skip to content

Commit efb8c6b

Browse files
claudeedmundmiller
authored andcommitted
refactor: extract highlight logic into helper function
Improvements: - Extract _determine_highlighted_intersections() helper function for better testability and code organization - Use Literal types for type safety (only "least" and "greatest" allowed) - Reduce main function complexity from ~330 lines to ~300 lines - Make highlight determination logic more reusable and maintainable No functional changes - all tests pass.
1 parent 9a5d0e1 commit efb8c6b

1 file changed

Lines changed: 50 additions & 36 deletions

File tree

altair_upset/upset.py

Lines changed: 50 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import List, Optional, Union
1+
from typing import List, Literal, Optional, Union
22

33
import altair as alt
44
import pandas as pd
@@ -9,6 +9,51 @@
99
from .transforms import create_base_chart
1010

1111

12+
def _determine_highlighted_intersections(
13+
data: pd.DataFrame,
14+
highlight: Union[Literal["least", "greatest"], int, List[int]],
15+
) -> List[float]:
16+
"""Determine which intersection IDs to highlight based on the highlight parameter.
17+
18+
Parameters
19+
----------
20+
data : pd.DataFrame
21+
The preprocessed data with intersection_id and count columns
22+
highlight : "least", "greatest", int, or list of int
23+
The highlighting criteria
24+
25+
Returns
26+
-------
27+
list of float
28+
List of intersection_ids to highlight
29+
"""
30+
# Get unique intersections with their counts
31+
intersections = (
32+
data.groupby("intersection_id")["count"]
33+
.first()
34+
.reset_index()
35+
.sort_index()
36+
)
37+
38+
if isinstance(highlight, str):
39+
if highlight == "least":
40+
min_idx = intersections["count"].idxmin()
41+
return [intersections.loc[min_idx, "intersection_id"]]
42+
else: # highlight == "greatest"
43+
max_idx = intersections["count"].idxmax()
44+
return [intersections.loc[max_idx, "intersection_id"]]
45+
elif isinstance(highlight, int):
46+
if highlight < len(intersections):
47+
return [intersections.iloc[highlight]["intersection_id"]]
48+
return []
49+
else: # isinstance(highlight, list)
50+
return [
51+
intersections.iloc[i]["intersection_id"]
52+
for i in highlight
53+
if i < len(intersections)
54+
]
55+
56+
1257
class UpSetChart:
1358
"""A wrapper class for UpSet plots."""
1459

@@ -84,7 +129,7 @@ def UpSetAltair(
84129
"#BDC6CA",
85130
],
86131
highlight_color: str = "#EA4667",
87-
highlight: Optional[Union[str, int, List[int]]] = None,
132+
highlight: Optional[Union[Literal["least", "greatest"], int, List[int]]] = None,
88133
glyph_size: int = 100, # Reduced from 200
89134
set_label_bg_size: int = 500, # Reduced from 1000
90135
line_connection_size: int = 1, # Reduced from 2
@@ -230,38 +275,6 @@ def UpSetAltair(
230275
data, sets, abbre, sort_order
231276
)
232277

233-
# Determine which intersections to highlight
234-
highlighted_intersection_ids = []
235-
if highlight is not None:
236-
# Get unique intersections with their counts
237-
intersections = (
238-
data.groupby("intersection_id")
239-
.agg({"count": "first"})
240-
.reset_index()
241-
.sort_index()
242-
)
243-
244-
if isinstance(highlight, str):
245-
if highlight == "least":
246-
# Find intersection with smallest count
247-
min_idx = intersections["count"].idxmin()
248-
highlighted_intersection_ids = [intersections.loc[min_idx, "intersection_id"]]
249-
elif highlight == "greatest":
250-
# Find intersection with largest count
251-
max_idx = intersections["count"].idxmax()
252-
highlighted_intersection_ids = [intersections.loc[max_idx, "intersection_id"]]
253-
elif isinstance(highlight, int):
254-
# Highlight specific index
255-
if highlight < len(intersections):
256-
highlighted_intersection_ids = [intersections.iloc[highlight]["intersection_id"]]
257-
elif isinstance(highlight, list):
258-
# Highlight multiple indices
259-
highlighted_intersection_ids = [
260-
intersections.iloc[i]["intersection_id"]
261-
for i in highlight
262-
if i < len(intersections)
263-
]
264-
265278
# Setup selections for interactivity
266279
legend_selection = alt.selection_point(fields=["set"], bind="legend")
267280

@@ -270,10 +283,11 @@ def UpSetAltair(
270283
# Default hover behavior
271284
color_selection = alt.selection_point(fields=["intersection_id"], on="mouseover")
272285
else:
273-
# Fixed highlight based on specified criteria
286+
# Determine which intersections to highlight and create fixed selection
287+
highlighted_ids = _determine_highlighted_intersections(data, highlight)
274288
color_selection = alt.selection_point(
275289
fields=["intersection_id"],
276-
value=[{"intersection_id": id_} for id_ in highlighted_intersection_ids]
290+
value=[{"intersection_id": id_} for id_ in highlighted_ids]
277291
)
278292

279293
# Calculate dimensions

0 commit comments

Comments
 (0)