Skip to content

Commit c997ae0

Browse files
feat(highcharts): implement raincloud-basic (#1939)
## Implementation: `raincloud-basic` - highcharts Implements the **highcharts** version of `raincloud-basic`. **File:** `plots/raincloud-basic/implementations/highcharts.py` --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20500987365)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 137cea1 commit c997ae0

2 files changed

Lines changed: 60 additions & 45 deletions

File tree

plots/raincloud-basic/implementations/highcharts.py

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
""" pyplots.ai
22
raincloud-basic: Basic Raincloud Plot
33
Library: highcharts unknown | Python 3.13.11
4-
Quality: 91/100 | Created: 2025-12-24
4+
Quality: 78/100 | Created: 2025-12-25
55
"""
66

77
import json
@@ -19,6 +19,8 @@
1919
np.random.seed(42)
2020
categories = ["Control", "Treatment A", "Treatment B", "Treatment C"]
2121
colors = ["#306998", "#FFD43B", "#9467BD", "#17BECF"]
22+
# Fill colors for box plots with good visibility (increased opacity)
23+
box_fill_colors = ["rgba(48,105,152,0.7)", "rgba(255,212,59,0.7)", "rgba(148,103,189,0.7)", "rgba(23,190,207,0.7)"]
2224

2325
# Generate realistic reaction time data with different distributions
2426
control = np.random.normal(450, 60, 80) # Normal distribution
@@ -52,14 +54,15 @@
5254
}
5355
)
5456

55-
# Create jittered scatter data (the "rain")
57+
# Create jittered scatter data (the "rain" - falls LEFT of the cloud for vertical orientation)
5658
scatter_data = []
5759
for i, data in enumerate(all_data):
5860
for val in data:
5961
jitter = np.random.uniform(-0.08, 0.08)
60-
scatter_data.append({"x": i + 0.25 + jitter, "y": float(val), "color": colors[i]})
62+
# Rain on LEFT side (negative offset from category center)
63+
scatter_data.append({"x": i - 0.25 + jitter, "y": float(val), "color": colors[i]})
6164

62-
# Box plot series data
65+
# Box plot series data with semi-transparent fill and dark borders
6366
box_series_data = []
6467
for i, box in enumerate(box_data):
6568
box_series_data.append(
@@ -69,12 +72,13 @@
6972
"median": box["median"],
7073
"q3": box["q3"],
7174
"high": box["high"],
72-
"color": colors[i],
73-
"fillColor": f"rgba({int(colors[i][1:3], 16)}, {int(colors[i][3:5], 16)}, {int(colors[i][5:7], 16)}, 0.6)",
75+
"color": "#1a1a1a", # Dark border for visibility
76+
"fillColor": box_fill_colors[i],
7477
}
7578
)
7679

7780
# Create polygon data for half-violin (the "cloud") - inline KDE
81+
# Cloud on RIGHT side for vertical orientation (rain falls from cloud, so cloud is RIGHT/TOP)
7882
violin_polygons = []
7983
for i, data in enumerate(all_data):
8084
# Inline KDE computation (Gaussian kernel)
@@ -90,13 +94,14 @@
9094
density = density / (n * bandwidth * np.sqrt(2 * np.pi))
9195
density = density / density.max() * 0.35
9296

93-
# Create polygon points for filled half-violin (close the polygon)
97+
# Create polygon points for filled half-violin on RIGHT side (close the polygon)
9498
polygon_points = []
99+
# Right side: baseline at category, extend RIGHT (positive direction)
95100
for y, d in zip(y_range, density, strict=True):
96-
polygon_points.append([float(i - d - 0.05), float(y)])
101+
polygon_points.append([float(i + d + 0.05), float(y)])
97102
# Close polygon by going back along the baseline
98103
for y in reversed(y_range):
99-
polygon_points.append([float(i - 0.05), float(y)])
104+
polygon_points.append([float(i + 0.05), float(y)])
100105
# Close the polygon
101106
polygon_points.append(polygon_points[0])
102107
violin_polygons.append({"points": polygon_points, "color": colors[i]})
@@ -117,6 +122,7 @@
117122
enableMouseTracking: false,
118123
showInLegend: {show_legend},
119124
{linked}
125+
legendSymbol: 'areaMarker',
120126
marker: {{ enabled: false }}
121127
}}""")
122128

@@ -128,7 +134,7 @@
128134
backgroundColor: '#ffffff',
129135
marginBottom: 280,
130136
marginLeft: 220,
131-
marginRight: 350,
137+
marginRight: 200,
132138
spacingBottom: 80
133139
}},
134140
title: {{
@@ -158,33 +164,42 @@
158164
labels: {{
159165
style: {{ fontSize: '36px' }}
160166
}},
161-
gridLineWidth: 1,
162-
gridLineDashStyle: 'Dash',
163-
min: 200,
164-
max: 660
167+
gridLineWidth: 2,
168+
gridLineColor: 'rgba(0, 0, 0, 0.35)',
169+
gridLineDashStyle: 'Solid',
170+
tickInterval: 50,
171+
min: 250,
172+
max: 650
165173
}},
166174
legend: {{
167175
enabled: true,
168-
itemStyle: {{ fontSize: '32px' }},
176+
itemStyle: {{ fontSize: '36px' }},
169177
align: 'right',
170178
verticalAlign: 'top',
171179
layout: 'vertical',
172180
x: -50,
173-
y: 100
181+
y: 100,
182+
backgroundColor: 'rgba(255, 255, 255, 0.9)',
183+
borderWidth: 1,
184+
borderColor: '#cccccc',
185+
padding: 20
174186
}},
175187
plotOptions: {{
176188
boxplot: {{
177-
medianColor: '#1a1a1a',
178-
medianWidth: 6,
189+
medianColor: '#000000',
190+
medianWidth: 8,
191+
medianDashStyle: 'Solid',
192+
stemColor: '#1a1a1a',
179193
stemWidth: 4,
180-
whiskerWidth: 4,
181-
whiskerLength: '40%',
182-
lineWidth: 3,
183-
pointWidth: 60
194+
whiskerColor: '#1a1a1a',
195+
whiskerWidth: 5,
196+
whiskerLength: '50%',
197+
lineWidth: 4,
198+
pointWidth: 70
184199
}},
185200
scatter: {{
186201
marker: {{
187-
radius: 10,
202+
radius: 18,
188203
symbol: 'circle'
189204
}}
190205
}},
@@ -196,10 +211,13 @@
196211
series: [
197212
{",".join(polygon_series_js)},
198213
{{
199-
name: 'Box Plot',
214+
name: 'Box Plot (Q1-Q3)',
200215
type: 'boxplot',
201216
data: {json.dumps(box_series_data)},
202217
colorByPoint: true,
218+
showInLegend: true,
219+
legendSymbol: 'rectangle',
220+
color: '#1a1a1a',
203221
tooltip: {{
204222
headerFormat: '<b>{{point.key}}</b><br/>',
205223
pointFormat: 'Max: {{point.high:.0f}} ms<br/>Q3: {{point.q3:.0f}} ms<br/>Median: {{point.median:.0f}} ms<br/>Q1: {{point.q1:.0f}} ms<br/>Min: {{point.low:.0f}} ms'
@@ -210,11 +228,11 @@
210228
type: 'scatter',
211229
data: {json.dumps(scatter_data)},
212230
marker: {{
213-
radius: 8,
214-
lineWidth: 1,
215-
lineColor: 'rgba(0,0,0,0.3)'
231+
radius: 16,
232+
lineWidth: 2,
233+
lineColor: 'rgba(0,0,0,0.4)'
216234
}},
217-
opacity: 0.6,
235+
opacity: 0.65,
218236
tooltip: {{
219237
pointFormat: 'Value: {{point.y:.0f}} ms'
220238
}}
Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,26 @@
11
library: highcharts
22
specification_id: raincloud-basic
3-
created: '2025-12-24T22:25:07Z'
4-
updated: '2025-12-24T22:41:38Z'
3+
created: '2025-12-25T07:14:56Z'
4+
updated: '2025-12-25T07:35:23Z'
55
generated_by: claude-opus-4-5-20251101
6-
workflow_run: 20494684277
6+
workflow_run: 20500987365
77
issue: 0
88
python_version: 3.13.11
99
library_version: unknown
1010
preview_url: https://storage.googleapis.com/pyplots-images/plots/raincloud-basic/highcharts/plot.png
1111
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/raincloud-basic/highcharts/plot_thumb.png
1212
preview_html: https://storage.googleapis.com/pyplots-images/plots/raincloud-basic/highcharts/plot.html
13-
quality_score: 91
13+
quality_score: 78
1414
review:
1515
strengths:
16-
- Excellent implementation of all three raincloud components (cloud, rain, box plot)
17-
positioned correctly relative to each other
18-
- Creative use of Highcharts polygon series to create smooth half-violin density
19-
curves with inline KDE calculation
20-
- Bimodal distribution in Treatment B effectively demonstrates the visualization
21-
power to reveal hidden distribution characteristics
22-
- Colorblind-safe color palette with good visual distinction between groups
23-
- Proper whisker calculation using IQR method for box plots
16+
- Excellent implementation of the raincloud metaphor with cloud (half-violin) on
17+
right, boxplot centered, and rain (jittered points) on left
18+
- Good use of bimodal distribution for Treatment B demonstrating feature coverage
19+
- Colorblind-safe palette with good color contrast between categories
20+
- Clean KISS code structure with inline KDE computation
21+
- Proper use of Highcharts polygon series for density clouds
2422
weaknesses:
25-
- Legend placement in top-right creates slight layout imbalance; could be positioned
26-
closer to the plot area
27-
- Box plot fill colors use rgba calculation that could be simplified
28-
- Individual points marker size could be slightly larger for better visibility at
29-
this canvas scale
23+
- Box plot fill colors are too light/transparent making Q1-Q3 boxes difficult to
24+
distinguish from background
25+
- Legend shows wrong symbol for Box Plot - displays circle instead of rectangle
26+
- Grid lines are slightly too prominent (alpha 0.35) should be more subtle

0 commit comments

Comments
 (0)