Skip to content

Commit f1f434f

Browse files
feat(pygal): implement bar-permutation-importance (#3034)
## Implementation: `bar-permutation-importance` - pygal Implements the **pygal** version of `bar-permutation-importance`. **File:** `plots/bar-permutation-importance/implementations/pygal.py` **Parent Issue:** #2998 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20617502897)* --------- 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 2b06e36 commit f1f434f

2 files changed

Lines changed: 157 additions & 0 deletions

File tree

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
""" pyplots.ai
2+
bar-permutation-importance: Permutation Feature Importance Plot
3+
Library: pygal 3.1.0 | Python 3.13.11
4+
Quality: 83/100 | Created: 2025-12-31
5+
"""
6+
7+
import numpy as np
8+
import pygal
9+
from pygal.style import Style
10+
11+
12+
# Data - Simulated permutation importance results (realistic ML feature importance)
13+
np.random.seed(42)
14+
15+
# Feature names representing typical ML model features (sorted by importance, ascending)
16+
features = [
17+
"Year Built",
18+
"Bathrooms",
19+
"Garage Size",
20+
"Lot Area",
21+
"Bedrooms",
22+
"Basement Area",
23+
"Total Rooms",
24+
"Living Area",
25+
"Neighborhood",
26+
"Overall Quality",
27+
]
28+
29+
# Mean importance values (mean decrease in R² score from permutation)
30+
# Sorted ascending for bottom-to-top display in horizontal bar
31+
importance_mean = np.array([0.002, 0.008, 0.015, 0.024, 0.032, 0.048, 0.067, 0.095, 0.128, 0.185])
32+
33+
# Standard deviation across 10 permutation repetitions
34+
importance_std = np.array([0.003, 0.005, 0.008, 0.011, 0.014, 0.018, 0.022, 0.028, 0.035, 0.042])
35+
36+
# Generate sequential color gradient (viridis-inspired) inline
37+
min_imp = importance_mean.min()
38+
max_imp = importance_mean.max()
39+
imp_range = max_imp - min_imp if max_imp != min_imp else 1.0
40+
41+
# Viridis color stops: purple (0) -> teal (0.5) -> yellow (1)
42+
viridis_stops = [(0.0, 68, 1, 84), (0.25, 58, 82, 139), (0.5, 32, 144, 140), (0.75, 94, 201, 97), (1.0, 253, 231, 36)]
43+
44+
45+
def get_viridis_color(t):
46+
"""Interpolate viridis color for normalized value t in [0, 1]."""
47+
for j in range(len(viridis_stops) - 1):
48+
t0, r0, g0, b0 = viridis_stops[j]
49+
t1, r1, g1, b1 = viridis_stops[j + 1]
50+
if t0 <= t <= t1:
51+
seg_t = (t - t0) / (t1 - t0)
52+
r = int(r0 + (r1 - r0) * seg_t)
53+
g = int(g0 + (g1 - g0) * seg_t)
54+
b = int(b0 + (b1 - b0) * seg_t)
55+
return f"#{r:02x}{g:02x}{b:02x}"
56+
return "#fde724"
57+
58+
59+
bar_colors = [get_viridis_color((imp - min_imp) / imp_range) for imp in importance_mean]
60+
61+
# Custom style with larger fonts for 4800x2700 canvas and subtle guides
62+
custom_style = Style(
63+
background="white",
64+
plot_background="white",
65+
foreground="#333333",
66+
foreground_strong="#333333",
67+
foreground_subtle="#999999",
68+
guide_stroke_color="#cccccc",
69+
major_guide_stroke_color="#cccccc",
70+
colors=tuple(bar_colors),
71+
title_font_size=84,
72+
label_font_size=48,
73+
major_label_font_size=48,
74+
legend_font_size=44,
75+
value_font_size=40,
76+
stroke_width=2,
77+
font_family="sans-serif",
78+
opacity=0.95,
79+
guide_stroke_dasharray="4,4",
80+
)
81+
82+
# Create horizontal stacked bar chart for error bar visualization
83+
# First stack: mean value (solid), Second stack: +std (semi-transparent for error bar effect)
84+
chart = pygal.HorizontalStackedBar(
85+
width=4800,
86+
height=2700,
87+
style=custom_style,
88+
title="bar-permutation-importance · pygal · pyplots.ai",
89+
x_title="Mean Decrease in R² Score",
90+
show_legend=True,
91+
legend_at_bottom=True,
92+
legend_at_bottom_columns=2,
93+
legend_box_size=36,
94+
print_values=True,
95+
print_values_position="top",
96+
show_y_guides=False,
97+
show_x_guides=True,
98+
truncate_label=-1,
99+
spacing=28,
100+
margin=80,
101+
margin_left=420,
102+
margin_bottom=200,
103+
range=(-0.02, importance_mean.max() + importance_std.max() + 0.02),
104+
zero=0,
105+
)
106+
107+
# Set feature labels on y-axis
108+
chart.x_labels = features
109+
110+
# Create data series: main bars (mean values) and error extensions (+std)
111+
mean_data = list(importance_mean)
112+
std_data = list(importance_std)
113+
114+
# Add mean importance bars with viridis colors
115+
chart.add(
116+
"Mean Importance",
117+
[{"value": v, "color": c} for v, c in zip(mean_data, bar_colors, strict=True)],
118+
formatter=lambda x: f"{x:.3f}" if x else "",
119+
)
120+
121+
# Add error bar extensions (std values) with semi-transparent styling
122+
error_color = "rgba(100, 100, 100, 0.35)"
123+
chart.add(
124+
"± Std Dev (Error Range)",
125+
[{"value": v, "color": error_color} for v in std_data],
126+
formatter=lambda x: f"±{x:.3f}" if x else "",
127+
)
128+
129+
# Save outputs
130+
chart.render_to_file("plot.html")
131+
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: bar-permutation-importance
3+
created: '2025-12-31T10:57:04Z'
4+
updated: '2025-12-31T11:36:32Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20617502897
7+
issue: 2998
8+
python_version: 3.13.11
9+
library_version: 3.1.0
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/bar-permutation-importance/pygal/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/bar-permutation-importance/pygal/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/bar-permutation-importance/pygal/plot.html
13+
quality_score: 83
14+
review:
15+
strengths:
16+
- Creative use of HorizontalStackedBar to simulate error bars by stacking std on
17+
mean values
18+
- Excellent viridis color gradient implementation for visual emphasis of importance
19+
hierarchy
20+
- Clean realistic housing prediction scenario with appropriate feature names
21+
- Properly sorted bars from highest to lowest importance
22+
weaknesses:
23+
- Legend appears cut off at bottom of the visible plot area
24+
- Contains a helper function (get_viridis_color) violating KISS structure requirement
25+
- Missing vertical reference line at x=0 as suggested in spec
26+
- X-axis label lacks units

0 commit comments

Comments
 (0)