Skip to content

Commit bbc686b

Browse files
feat(pygal): implement errorbar-asymmetric (#2811)
## Implementation: `errorbar-asymmetric` - pygal Implements the **pygal** version of `errorbar-asymmetric`. **File:** `plots/errorbar-asymmetric/implementations/pygal.py` --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20602451830)* --------- 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 0d89080 commit bbc686b

2 files changed

Lines changed: 125 additions & 0 deletions

File tree

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
""" pyplots.ai
2+
errorbar-asymmetric: Asymmetric Error Bars Plot
3+
Library: pygal 3.1.0 | Python 3.13.11
4+
Quality: 88/100 | Created: 2025-12-30
5+
"""
6+
7+
import pygal
8+
from pygal.style import Style
9+
10+
11+
# Data - Material strength testing (MPa) with asymmetric confidence intervals
12+
materials = ["Steel", "Aluminum", "Titanium", "Copper", "Brass", "Bronze"]
13+
# Central values (median strength)
14+
y_values = [250, 150, 450, 200, 180, 220]
15+
# Asymmetric errors - showing realistic variation in error distribution
16+
# Some materials have larger lower errors (conservative bounds), others have larger upper errors
17+
error_lower = [35, 12, 20, 25, 8, 18] # 10th percentile distance from median
18+
error_upper = [20, 28, 50, 15, 22, 30] # 90th percentile distance from median
19+
# Now Steel and Copper have larger lower than upper (conservative), others have larger upper
20+
21+
# Cap width for horizontal lines at error bar ends (in x-axis units)
22+
# Wider caps for clear visibility as proper horizontal lines (approx 1/3 of spacing between bars)
23+
cap_width = 0.35
24+
25+
# Custom style for 4800x2700 canvas with larger fonts
26+
custom_style = Style(
27+
background="white",
28+
plot_background="white",
29+
foreground="#333333",
30+
foreground_strong="#333333",
31+
foreground_subtle="#666666",
32+
colors=("#306998", "#306998", "#306998", "#306998", "#306998", "#306998", "#306998"),
33+
title_font_size=84,
34+
label_font_size=52,
35+
major_label_font_size=48,
36+
legend_font_size=52,
37+
value_font_size=42,
38+
stroke_width=7,
39+
opacity=1.0,
40+
transition="0s",
41+
)
42+
43+
# Create XY chart for error bar visualization
44+
chart = pygal.XY(
45+
width=4800,
46+
height=2700,
47+
style=custom_style,
48+
title="errorbar-asymmetric · pygal · pyplots.ai",
49+
x_title="Material",
50+
y_title="Tensile Strength (MPa)",
51+
show_legend=True,
52+
legend_at_bottom=False,
53+
legend_box_size=28,
54+
show_y_guides=True,
55+
show_x_guides=False,
56+
print_values=False,
57+
margin=120,
58+
stroke=True,
59+
dots_size=8,
60+
range=(80, 550),
61+
xrange=(0, 7),
62+
x_labels=["", "Steel", "Aluminum", "Titanium", "Copper", "Brass", "Bronze"],
63+
x_labels_major_every=1,
64+
show_minor_x_labels=False,
65+
)
66+
67+
# Add each error bar with proper caps (horizontal lines at ends)
68+
for i in range(len(materials)):
69+
x_pos = i + 1
70+
y_center = y_values[i]
71+
y_low = y_center - error_lower[i]
72+
y_high = y_center + error_upper[i]
73+
74+
# Vertical error bar segment
75+
bar_data = [(x_pos, y_low), (x_pos, y_high)]
76+
77+
# Bottom cap (horizontal line)
78+
bottom_cap = [(x_pos - cap_width, y_low), (x_pos + cap_width, y_low)]
79+
80+
# Top cap (horizontal line)
81+
top_cap = [(x_pos - cap_width, y_high), (x_pos + cap_width, y_high)]
82+
83+
# Only first bar gets legend entry
84+
if i == 0:
85+
chart.add("10th-90th Percentile Range", bar_data, stroke=True, show_dots=False, stroke_style={"width": 7})
86+
else:
87+
chart.add(None, bar_data, stroke=True, show_dots=False, stroke_style={"width": 7})
88+
89+
# Add caps as visible horizontal lines (thicker stroke for clarity as proper T-caps)
90+
chart.add(None, bottom_cap, stroke=True, show_dots=False, stroke_style={"width": 12})
91+
chart.add(None, top_cap, stroke=True, show_dots=False, stroke_style={"width": 12})
92+
93+
# Add central points as main series (on top of error bars)
94+
central_data = [(i + 1, y_values[i]) for i in range(len(materials))]
95+
chart.add("Median Strength", central_data, stroke=False, dots_size=24)
96+
97+
# Render to files
98+
chart.render_to_file("plot.html")
99+
chart.render_to_png("plot.png")
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
library: pygal
2+
specification_id: errorbar-asymmetric
3+
created: '2025-12-30T17:48:43Z'
4+
updated: '2025-12-30T18:17:17Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20602451830
7+
issue: 0
8+
python_version: 3.13.11
9+
library_version: 3.1.0
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/errorbar-asymmetric/pygal/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/errorbar-asymmetric/pygal/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/errorbar-asymmetric/pygal/plot.html
13+
quality_score: 88
14+
review:
15+
strengths:
16+
- Clear visualization of asymmetric error bars using pygal XY chart creatively
17+
- Well-labeled axes with units (MPa for strength, Material for x-axis)
18+
- Realistic engineering context (material tensile strength testing)
19+
- Good demonstration of asymmetric errors with varied patterns across materials
20+
- Clean code structure following KISS principles
21+
- Proper title format and legend explaining what the percentile ranges represent
22+
weaknesses:
23+
- Legend symbols do not perfectly match the plot elements (squares in legend vs
24+
lines/dots in plot)
25+
- Layout has some unused whitespace on the sides
26+
- Error bar caps could be more visually prominent

0 commit comments

Comments
 (0)