Skip to content

Commit 2eef10e

Browse files
update(raincloud-basic): highcharts — fix orientation consistency
Fix cloud/rain orientation: cloud (half-violin) extends upward, rain (jittered points) falls downward. Updated spec to clarify absolute y-direction terms.
1 parent a1bd610 commit 2eef10e

3 files changed

Lines changed: 35 additions & 46 deletions

File tree

plots/raincloud-basic/implementations/highcharts.py

Lines changed: 27 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
""" pyplots.ai
1+
"""pyplots.ai
22
raincloud-basic: Basic Raincloud Plot
3-
Library: highcharts unknown | Python 3.13.11
4-
Quality: 91/100 | Created: 2025-12-25
3+
Library: highcharts 1.10.3 | Python 3.14
4+
Quality: /100 | Updated: 2026-02-14
55
"""
66

77
import tempfile
@@ -61,9 +61,13 @@
6161
chart.options = HighchartsOptions()
6262

6363
# Chart configuration - HORIZONTAL orientation
64+
# inverted=True swaps axes: x-axis (categories) on left, y-axis (values) on bottom
65+
# In inverted mode, x-axis increases DOWNWARD, so:
66+
# - negative x offset = UPWARD on screen (for clouds)
67+
# - positive x offset = DOWNWARD on screen (for rain)
6468
chart.options.chart = {
6569
"type": "boxplot",
66-
"inverted": True, # Swap axes for horizontal orientation
70+
"inverted": True,
6771
"width": 4800,
6872
"height": 2700,
6973
"backgroundColor": "#ffffff",
@@ -75,11 +79,11 @@
7579

7680
# Title
7781
chart.options.title = {
78-
"text": "raincloud-basic · highcharts · pyplots.ai",
82+
"text": "raincloud-basic \u00b7 highcharts \u00b7 pyplots.ai",
7983
"style": {"fontSize": "56px", "fontWeight": "bold"},
8084
}
8185

82-
# X-axis (categories - but shown on left due to inverted)
86+
# X-axis (categories - shown on left due to inverted)
8387
chart.options.x_axis = {
8488
"title": {"text": "Experimental Condition", "style": {"fontSize": "44px"}},
8589
"labels": {"style": {"fontSize": "36px"}},
@@ -93,14 +97,14 @@
9397
"title": {"text": "Reaction Time (ms)", "style": {"fontSize": "44px"}},
9498
"labels": {"style": {"fontSize": "36px"}},
9599
"gridLineWidth": 1,
96-
"gridLineColor": "rgba(0, 0, 0, 0.15)",
97-
"gridLineDashStyle": "Dash",
100+
"gridLineColor": "rgba(0, 0, 0, 0.08)",
101+
"gridLineDashStyle": "Dot",
98102
"tickInterval": 50,
99103
"min": 250,
100104
"max": 650,
101105
}
102106

103-
# Legend
107+
# Legend - consolidated to show only condition names
104108
chart.options.legend = {
105109
"enabled": True,
106110
"itemStyle": {"fontSize": "36px"},
@@ -135,8 +139,8 @@
135139
"polygon": {"fillOpacity": 0.6, "lineWidth": 2},
136140
}
137141

138-
# Create polygon data for half-violin (the "cloud") on TOP
139-
# With inverted=True, "positive" x offset becomes TOP visually
142+
# Create polygon data for half-violin (the "cloud") ABOVE category baseline
143+
# In inverted chart, x-axis goes downward, so NEGATIVE x offset = UPWARD on screen
140144
for i, data in enumerate(all_data):
141145
# Inline KDE computation (Gaussian kernel)
142146
data_arr = np.array(data)
@@ -151,19 +155,17 @@
151155
density = density / (n * bandwidth * np.sqrt(2 * np.pi))
152156
density = density / density.max() * 0.35
153157

154-
# Create polygon points for filled half-violin on TOP
158+
# Cloud extends UPWARD (negative x offset in inverted chart)
155159
polygon_points = []
156-
# With inverted chart: x=category position, y=value
157-
# Cloud extends in positive x direction from category center
158160
for y, d in zip(y_range, density, strict=True):
159-
polygon_points.append([float(i + d + 0.05), float(y)])
160-
# Close polygon by going back along the baseline
161+
polygon_points.append([float(i - d - 0.05), float(y)])
162+
# Close polygon along baseline
161163
for y in reversed(y_range):
162-
polygon_points.append([float(i + 0.05), float(y)])
164+
polygon_points.append([float(i - 0.05), float(y)])
163165

164166
series = PolygonSeries()
165167
series.data = polygon_points
166-
series.name = f"{categories[i]} (Cloud)"
168+
series.name = categories[i]
167169
series.color = colors[i]
168170
series.fill_color = colors[i]
169171
series.fill_opacity = 0.6
@@ -191,22 +193,25 @@
191193
box_series.name = "Box Plot"
192194
box_series.color = "#1a1a1a"
193195
box_series.color_by_point = True
196+
box_series.show_in_legend = False
194197
chart.add_series(box_series)
195198

196-
# Create jittered scatter data (the "rain") BELOW
199+
# Create jittered scatter data (the "rain") BELOW category baseline
200+
# In inverted chart, POSITIVE x offset = DOWNWARD on screen
197201
for i, data in enumerate(all_data):
198202
scatter_points = []
199203
for val in data:
200204
jitter = np.random.uniform(-0.08, 0.08)
201-
# Rain on negative side (BELOW with inverted chart)
202-
scatter_points.append([float(i - 0.25 + jitter), float(val)])
205+
# Rain falls downward (positive x offset in inverted chart)
206+
scatter_points.append([float(i + 0.25 + jitter), float(val)])
203207

204208
scatter_series = ScatterSeries()
205209
scatter_series.data = scatter_points
206-
scatter_series.name = f"{categories[i]} (Points)"
210+
scatter_series.name = categories[i]
207211
scatter_series.color = colors[i]
208212
scatter_series.opacity = 0.65
209213
scatter_series.marker = {"radius": 16, "lineWidth": 2, "lineColor": "rgba(0,0,0,0.4)", "fillColor": colors[i]}
214+
scatter_series.show_in_legend = False
210215
chart.add_series(scatter_series)
211216

212217
# Download Highcharts JS and required modules
@@ -238,22 +243,6 @@
238243
f.write(html_content)
239244
temp_path = f.name
240245

241-
# Save HTML for interactive viewing
242-
with open("plot.html", "w", encoding="utf-8") as f:
243-
standalone_html = f"""<!DOCTYPE html>
244-
<html>
245-
<head>
246-
<meta charset="utf-8">
247-
<script src="https://code.highcharts.com/highcharts.js"></script>
248-
<script src="https://code.highcharts.com/highcharts-more.js"></script>
249-
</head>
250-
<body style="margin:0;">
251-
<div id="container" style="width: 100%; height: 100vh;"></div>
252-
<script>{html_str}</script>
253-
</body>
254-
</html>"""
255-
f.write(standalone_html)
256-
257246
# Setup Chrome for screenshot
258247
chrome_options = Options()
259248
chrome_options.add_argument("--headless")

plots/raincloud-basic/metadata/highcharts.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
library: highcharts
22
specification_id: raincloud-basic
33
created: '2025-12-25T08:22:11Z'
4-
updated: '2025-12-25T08:31:38Z'
5-
generated_by: claude-opus-4-5-20251101
4+
updated: 2026-02-14T20:28:11+00:00
5+
generated_by: claude-opus-4-6
66
workflow_run: 20501867092
77
issue: 0
8-
python_version: 3.13.11
9-
library_version: unknown
8+
python_version: "3.14"
9+
library_version: "1.10.3"
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: null
1414
impl_tags:
1515
dependencies:
1616
- selenium

plots/raincloud-basic/specification.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ A raincloud plot combines three visualization elements—a half-violin (the "clo
2020

2121
## Notes
2222

23-
- **Required Orientation**: Use HORIZONTAL orientation with categories on y-axis and values on x-axis
24-
- **Critical Layout**: The "cloud" (half-violin/KDE) must be on TOP (positive y offset), boxplot in MIDDLE, and "rain" (jittered points) BELOW (negative y offset) - like rain falling from a cloud
23+
- **Required Orientation**: Use HORIZONTAL orientation with categories on y-axis and values on x-axis. "Above" and "below" always refer to the y-direction (screen up/down), not the x-direction
24+
- **Critical Layout**: For each category on the y-axis: the "cloud" (half-violin/KDE) must extend ABOVE the category baseline (upward on screen), the boxplot sits centered ON the category baseline, and "rain" (jittered points) must appear BELOW the category baseline (downward on screen) - like rain falling from a cloud
2525
- Clip the violin to show only half (the "cloud" portion), not a full violin
2626
- Use moderate jitter (0.05-0.1) to spread rain points without excessive overlap
2727
- Apply transparency (alpha 0.5-0.7) to jittered rain points for visibility
2828
- Include median and quartile markers in box plot
29-
- The visual metaphor must be clear: cloud above, rain falling below
29+
- The visual metaphor must be clear: cloud rises upward (positive y-direction), rain falls downward (negative y-direction) from each category line

0 commit comments

Comments
 (0)