Skip to content

Commit 5653eea

Browse files
feat(highcharts): implement cat-strip (#2769)
## Implementation: `cat-strip` - highcharts Implements the **highcharts** version of `cat-strip`. **File:** `plots/cat-strip/implementations/highcharts.py` --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20601060796)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent bed9d24 commit 5653eea

2 files changed

Lines changed: 187 additions & 0 deletions

File tree

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
""" pyplots.ai
2+
cat-strip: Categorical Strip Plot
3+
Library: highcharts unknown | Python 3.13.11
4+
Quality: 91/100 | Created: 2025-12-30
5+
"""
6+
7+
import tempfile
8+
import time
9+
import urllib.request
10+
from pathlib import Path
11+
12+
import numpy as np
13+
from highcharts_core.chart import Chart
14+
from highcharts_core.options import HighchartsOptions
15+
from highcharts_core.options.series.scatter import ScatterSeries
16+
from selenium import webdriver
17+
from selenium.webdriver.chrome.options import Options
18+
19+
20+
# Data - Plant growth measurements across different fertilizer types
21+
np.random.seed(42)
22+
categories = ["Control", "Fertilizer A", "Fertilizer B", "Fertilizer C"]
23+
n_per_category = 25
24+
25+
data_by_category = {}
26+
# Control: lower growth, moderate spread
27+
data_by_category["Control"] = np.random.normal(loc=15, scale=3, size=n_per_category)
28+
# Fertilizer A: moderate growth, tight spread
29+
data_by_category["Fertilizer A"] = np.random.normal(loc=22, scale=2, size=n_per_category)
30+
# Fertilizer B: high growth, wider spread with some outliers
31+
data_by_category["Fertilizer B"] = np.concatenate(
32+
[
33+
np.random.normal(loc=28, scale=4, size=n_per_category - 3),
34+
np.array([38, 40, 12]), # outliers
35+
]
36+
)
37+
# Fertilizer C: moderate-high growth, bimodal distribution
38+
data_by_category["Fertilizer C"] = np.concatenate(
39+
[
40+
np.random.normal(loc=20, scale=2, size=n_per_category // 2),
41+
np.random.normal(loc=30, scale=2, size=n_per_category - n_per_category // 2),
42+
]
43+
)
44+
45+
# Colors for each category
46+
colors = ["#306998", "#FFD43B", "#9467BD", "#17BECF"]
47+
48+
# Create chart
49+
chart = Chart(container="container")
50+
chart.options = HighchartsOptions()
51+
52+
# Chart configuration
53+
chart.options.chart = {
54+
"type": "scatter",
55+
"width": 4800,
56+
"height": 2700,
57+
"backgroundColor": "#ffffff",
58+
"marginBottom": 250,
59+
"spacingBottom": 50,
60+
}
61+
62+
# Title
63+
chart.options.title = {
64+
"text": "cat-strip · highcharts · pyplots.ai",
65+
"style": {"fontSize": "48px", "fontWeight": "bold"},
66+
}
67+
68+
# X-axis (categories)
69+
chart.options.x_axis = {
70+
"categories": categories,
71+
"title": {"text": "Treatment Group", "style": {"fontSize": "36px"}},
72+
"labels": {"style": {"fontSize": "28px"}},
73+
"gridLineWidth": 1,
74+
"gridLineColor": "rgba(0, 0, 0, 0.1)",
75+
}
76+
77+
# Y-axis (values)
78+
chart.options.y_axis = {
79+
"title": {"text": "Plant Height (cm)", "style": {"fontSize": "36px"}},
80+
"labels": {"style": {"fontSize": "28px"}},
81+
"gridLineWidth": 1,
82+
"gridLineColor": "rgba(0, 0, 0, 0.1)",
83+
}
84+
85+
# Legend - position at top right for better visibility
86+
chart.options.legend = {
87+
"enabled": True,
88+
"itemStyle": {"fontSize": "32px"},
89+
"symbolHeight": 20,
90+
"symbolWidth": 20,
91+
"symbolRadius": 10,
92+
"layout": "vertical",
93+
"align": "right",
94+
"verticalAlign": "top",
95+
"x": -50,
96+
"y": 80,
97+
"borderWidth": 1,
98+
"borderColor": "#cccccc",
99+
"backgroundColor": "#ffffff",
100+
"padding": 15,
101+
}
102+
103+
# Plot options
104+
chart.options.plot_options = {
105+
"scatter": {
106+
"marker": {"radius": 14, "symbol": "circle"},
107+
"jitter": {"x": 0.2, "y": 0}, # Highcharts built-in jitter
108+
}
109+
}
110+
111+
# Add series for each category
112+
for i, (cat, values) in enumerate(data_by_category.items()):
113+
series = ScatterSeries()
114+
# For jitter to work with categories, we use category index as x
115+
series.data = [[i, float(v)] for v in values]
116+
series.name = cat
117+
series.color = colors[i]
118+
series.marker = {"fillColor": colors[i], "lineWidth": 2, "lineColor": "#ffffff"}
119+
chart.add_series(series)
120+
121+
# Download Highcharts JS
122+
highcharts_url = "https://code.highcharts.com/highcharts.js"
123+
with urllib.request.urlopen(highcharts_url, timeout=30) as response:
124+
highcharts_js = response.read().decode("utf-8")
125+
126+
# Generate HTML with inline scripts
127+
html_str = chart.to_js_literal()
128+
html_content = f"""<!DOCTYPE html>
129+
<html>
130+
<head>
131+
<meta charset="utf-8">
132+
<script>{highcharts_js}</script>
133+
</head>
134+
<body style="margin:0;">
135+
<div id="container" style="width: 4800px; height: 2700px;"></div>
136+
<script>{html_str}</script>
137+
</body>
138+
</html>"""
139+
140+
# Write temp HTML and take screenshot
141+
with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False, encoding="utf-8") as f:
142+
f.write(html_content)
143+
temp_path = f.name
144+
145+
chrome_options = Options()
146+
chrome_options.add_argument("--headless")
147+
chrome_options.add_argument("--no-sandbox")
148+
chrome_options.add_argument("--disable-dev-shm-usage")
149+
chrome_options.add_argument("--disable-gpu")
150+
chrome_options.add_argument("--window-size=4800,2700")
151+
152+
driver = webdriver.Chrome(options=chrome_options)
153+
driver.get(f"file://{temp_path}")
154+
time.sleep(5)
155+
driver.save_screenshot("plot.png")
156+
driver.quit()
157+
158+
Path(temp_path).unlink()
159+
160+
# Save HTML for interactive version
161+
with open("plot.html", "w", encoding="utf-8") as f:
162+
f.write(html_content)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
library: highcharts
2+
specification_id: cat-strip
3+
created: '2025-12-30T16:31:47Z'
4+
updated: '2025-12-30T16:44:06Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20601060796
7+
issue: 0
8+
python_version: 3.13.11
9+
library_version: unknown
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/cat-strip/highcharts/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/cat-strip/highcharts/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/cat-strip/highcharts/plot.html
13+
quality_score: 91
14+
review:
15+
strengths:
16+
- Excellent use of Highcharts built-in jitter feature for proper strip plot behavior
17+
- 'Thoughtful data design showing different distribution characteristics: tight
18+
vs wide spread, outliers, bimodal patterns'
19+
- Colorblind-safe palette following library guidelines
20+
- Clean rendering with appropriate font sizes for high-resolution output
21+
- White marker borders add visual clarity and separation between overlapping points
22+
weaknesses:
23+
- Legend position in top-right corner encroaches on the data visualization area
24+
- Points lack alpha/transparency which would help visualize density in overlapping
25+
areas

0 commit comments

Comments
 (0)