Skip to content

Commit 5a24881

Browse files
feat(highcharts): implement box-basic
1 parent 8392814 commit 5a24881

1 file changed

Lines changed: 61 additions & 46 deletions

File tree

plots/highcharts/boxplot/box-basic/default.py

Lines changed: 61 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -33,79 +33,97 @@
3333
}
3434
)
3535

36-
# Compute boxplot statistics for each group
37-
groups = ["A", "B", "C", "D"]
38-
boxplot_data = []
39-
outliers_data = []
36+
# Calculate box plot statistics for each group
37+
groups = data["group"].unique()
38+
box_data = []
39+
outlier_data = []
4040

4141
for i, group in enumerate(groups):
4242
values = data[data["group"] == group]["value"].values
4343
q1 = np.percentile(values, 25)
4444
median = np.percentile(values, 50)
4545
q3 = np.percentile(values, 75)
4646
iqr = q3 - q1
47-
whisker_low = q1 - 1.5 * iqr
48-
whisker_high = q3 + 1.5 * iqr
47+
whisker_low = max(values.min(), q1 - 1.5 * iqr)
48+
whisker_high = min(values.max(), q3 + 1.5 * iqr)
4949

50-
# Actual whisker ends are the most extreme data within bounds
51-
low = values[values >= whisker_low].min()
52-
high = values[values <= whisker_high].max()
50+
# Find actual whisker values (closest data points within IQR range)
51+
lower_whisker = values[values >= q1 - 1.5 * iqr].min()
52+
upper_whisker = values[values <= q3 + 1.5 * iqr].max()
5353

54-
boxplot_data.append([low, q1, median, q3, high])
54+
box_data.append([lower_whisker, q1, median, q3, upper_whisker])
5555

56-
# Outliers
57-
outlier_values = values[(values < whisker_low) | (values > whisker_high)]
58-
for val in outlier_values:
59-
outliers_data.append([i, val])
56+
# Collect outliers
57+
outliers = values[(values < q1 - 1.5 * iqr) | (values > q3 + 1.5 * iqr)]
58+
for outlier in outliers:
59+
outlier_data.append([i, outlier])
6060

6161
# Create chart
6262
chart = Chart(container="container")
6363
chart.options = HighchartsOptions()
6464

65-
chart.options.chart = {"type": "boxplot", "width": 4800, "height": 2700, "backgroundColor": "#ffffff"}
65+
# Chart configuration
66+
chart.options.chart = {
67+
"type": "boxplot",
68+
"width": 4800,
69+
"height": 2700,
70+
"backgroundColor": "#ffffff",
71+
"style": {"fontFamily": "sans-serif"},
72+
}
6673

67-
chart.options.title = {"text": "Basic Box Plot", "style": {"fontSize": "48px"}}
74+
# Title
75+
chart.options.title = {"text": "Basic Box Plot", "style": {"fontSize": "60px", "fontWeight": "bold"}}
6876

77+
# X-axis
6978
chart.options.x_axis = {
70-
"categories": groups,
71-
"title": {"text": "Group", "style": {"fontSize": "40px"}},
72-
"labels": {"style": {"fontSize": "32px"}},
79+
"categories": list(groups),
80+
"title": {"text": "Group", "style": {"fontSize": "48px"}},
81+
"labels": {"style": {"fontSize": "40px"}},
7382
}
7483

84+
# Y-axis
7585
chart.options.y_axis = {
76-
"title": {"text": "Value", "style": {"fontSize": "40px"}},
77-
"labels": {"style": {"fontSize": "32px"}},
86+
"title": {"text": "Value", "style": {"fontSize": "48px"}},
87+
"labels": {"style": {"fontSize": "40px"}},
88+
"gridLineColor": "#e0e0e0",
89+
"gridLineWidth": 1,
7890
}
7991

80-
chart.options.legend = {"enabled": False}
92+
# Legend
93+
chart.options.legend = {"enabled": True, "itemStyle": {"fontSize": "40px"}}
94+
95+
# Colors from style guide
96+
colors = ["#306998", "#FFD43B", "#DC2626", "#059669", "#8B5CF6", "#F97316"]
8197

82-
# Boxplot series
83-
boxplot_series = BoxPlotSeries()
84-
boxplot_series.name = "Distribution"
85-
boxplot_series.data = boxplot_data
86-
boxplot_series.color = "#306998"
87-
boxplot_series.fillColor = "rgba(48, 105, 152, 0.4)"
88-
boxplot_series.lineWidth = 3
89-
boxplot_series.medianWidth = 4
90-
boxplot_series.medianColor = "#DC2626"
91-
boxplot_series.whiskerLength = "60%"
92-
boxplot_series.whiskerWidth = 3
98+
# Box plot series
99+
box_series = BoxPlotSeries()
100+
box_series.name = "Distribution"
101+
box_series.data = box_data
102+
box_series.color = colors[0]
103+
box_series.fillColor = "#306998"
104+
box_series.medianColor = "#ffffff"
105+
box_series.medianWidth = 4
106+
box_series.stemWidth = 3
107+
box_series.whiskerWidth = 3
108+
box_series.whiskerLength = "50%"
93109

94-
chart.add_series(boxplot_series)
110+
chart.add_series(box_series)
95111

96-
# Outliers as scatter series
97-
if outliers_data:
112+
# Outliers series (if any)
113+
if outlier_data:
98114
from highcharts_core.options.series.scatter import ScatterSeries
99115

100116
outlier_series = ScatterSeries()
101117
outlier_series.name = "Outliers"
102-
outlier_series.data = outliers_data
103-
outlier_series.color = "#DC2626"
104-
outlier_series.marker = {"radius": 6, "symbol": "circle"}
105-
118+
outlier_series.data = outlier_data
119+
outlier_series.color = colors[2]
120+
outlier_series.marker = {"symbol": "circle", "radius": 8, "fillColor": colors[2]}
106121
chart.add_series(outlier_series)
107122

108-
# Download Highcharts JS and highcharts-more.js (needed for boxplot)
123+
# Plot options
124+
chart.options.plot_options = {"boxplot": {"colorByPoint": True, "colors": colors[:4]}}
125+
126+
# Download Highcharts JS files (required for headless Chrome)
109127
highcharts_url = "https://code.highcharts.com/highcharts.js"
110128
with urllib.request.urlopen(highcharts_url, timeout=30) as response:
111129
highcharts_js = response.read().decode("utf-8")
@@ -139,15 +157,12 @@
139157
chrome_options.add_argument("--no-sandbox")
140158
chrome_options.add_argument("--disable-dev-shm-usage")
141159
chrome_options.add_argument("--disable-gpu")
142-
chrome_options.add_argument("--window-size=5000,3000")
160+
chrome_options.add_argument("--window-size=4800,2700")
143161

144162
driver = webdriver.Chrome(options=chrome_options)
145163
driver.get(f"file://{temp_path}")
146164
time.sleep(5)
147-
148-
# Screenshot the container element for exact dimensions
149-
container = driver.find_element("id", "container")
150-
container.screenshot("plot.png")
165+
driver.save_screenshot("plot.png")
151166
driver.quit()
152167

153168
Path(temp_path).unlink()

0 commit comments

Comments
 (0)