diff --git a/plots/violin-basic/implementations/matplotlib.py b/plots/violin-basic/implementations/matplotlib.py index c80b51f107..9ee8a3b378 100644 --- a/plots/violin-basic/implementations/matplotlib.py +++ b/plots/violin-basic/implementations/matplotlib.py @@ -1,62 +1,81 @@ """ pyplots.ai violin-basic: Basic Violin Plot -Library: matplotlib 3.10.8 | Python 3.13.11 -Quality: 92/100 | Created: 2025-12-23 +Library: matplotlib 3.10.8 | Python 3.14.3 +Quality: 92/100 | Updated: 2026-02-21 """ +import matplotlib.patheffects as pe import matplotlib.pyplot as plt import numpy as np -# Data - simulated test scores across different schools +# Data - simulated test scores (0-100) across different schools np.random.seed(42) -categories = ["School A", "School B", "School C", "School D"] +categories = ["Lincoln HS", "Roosevelt Acad.", "Jefferson HS", "Hamilton Prep"] data = [ - np.random.normal(75, 10, 150), # School A: centered around 75 - np.random.normal(82, 8, 150), # School B: higher scores, less spread - np.random.normal(68, 15, 150), # School C: lower average, more spread - np.random.normal(78, 12, 150), # School D: moderate + np.clip(np.random.normal(75, 10, 150), 0, 100), # Lincoln: normal, centered ~75 + np.clip(np.random.normal(85, 6, 150), 0, 100), # Roosevelt: high, tight cluster + np.clip(np.random.normal(62, 15, 150), 0, 100), # Jefferson: lower, wide spread + np.clip( + np.concatenate([np.random.normal(70, 5, 80), np.random.normal(88, 4, 70)]), 0, 100 + ), # Hamilton: bimodal (two subgroups) ] -# Create plot (4800x2700 px) +# Multi-series palette starting with Python Blue; warm accent for bimodal Hamilton +colors = ["#306998", "#5BA58B", "#7A6FB5", "#D4853F"] +edge_colors = ["#1E4060", "#3A7460", "#524A80", "#9A5F2A"] + +# Plot fig, ax = plt.subplots(figsize=(16, 9)) -# Create violin plot with quartile markers -parts = ax.violinplot(data, positions=range(len(categories)), showmeans=False, showmedians=True, showextrema=True) +parts = ax.violinplot( + data, + positions=range(len(categories)), + quantiles=[[0.25, 0.5, 0.75]] * len(categories), + showmeans=False, + showmedians=False, + showextrema=False, + bw_method=0.3, + widths=0.75, +) -# Style the violins with Python Blue -for pc in parts["bodies"]: - pc.set_facecolor("#306998") - pc.set_edgecolor("#1e4a6e") - pc.set_alpha(0.7) +# Style each violin body with a distinct color +for i, pc in enumerate(parts["bodies"]): + pc.set_facecolor(colors[i]) + pc.set_edgecolor(edge_colors[i]) + pc.set_alpha(0.8) pc.set_linewidth(2) -# Style the lines (median, min, max) -parts["cmedians"].set_color("#FFD43B") -parts["cmedians"].set_linewidth(3) -parts["cmins"].set_color("#1e4a6e") -parts["cmins"].set_linewidth(2) -parts["cmaxes"].set_color("#1e4a6e") -parts["cmaxes"].set_linewidth(2) -parts["cbars"].set_color("#1e4a6e") -parts["cbars"].set_linewidth(2) - -# Add quartile markers (Q1 and Q3) as box indicators -quartile1 = [np.percentile(d, 25) for d in data] -quartile3 = [np.percentile(d, 75) for d in data] - -# Draw thin boxes for interquartile range -for i, (q1, q3) in enumerate(zip(quartile1, quartile3, strict=True)): - ax.vlines(i, q1, q3, color="#1e4a6e", linewidth=6, zorder=3) - -# Labels and styling (scaled font sizes for 4800x2700) +# Quantile lines with path effects for legibility against colored bodies +q_colors = ["white", "#FFD43B", "white"] * len(categories) +q_widths = [2.5, 4, 2.5] * len(categories) +parts["cquantiles"].set_colors(q_colors) +parts["cquantiles"].set_linewidths(q_widths) +parts["cquantiles"].set_path_effects([pe.Stroke(linewidth=6, foreground="black", alpha=0.3), pe.Normal()]) + +# Labels and styling ax.set_xticks(range(len(categories))) ax.set_xticklabels(categories) ax.set_xlabel("School", fontsize=20) ax.set_ylabel("Test Score (points)", fontsize=20) -ax.set_title("violin-basic · matplotlib · pyplots.ai", fontsize=24) +ax.set_title("violin-basic \u00b7 matplotlib \u00b7 pyplots.ai", fontsize=24, fontweight="medium") ax.tick_params(axis="both", labelsize=16) -ax.grid(True, alpha=0.3, linestyle="--", axis="y") + +ax.spines["top"].set_visible(False) +ax.spines["right"].set_visible(False) +ax.yaxis.grid(True, alpha=0.2, linewidth=0.8) + +# Subtle annotation highlighting Hamilton Prep's bimodal distribution +ax.annotate( + "Two distinct\nperformance groups", + xy=(3, 75), + xytext=(3, 45), + fontsize=13, + color="#9A5F2A", + fontstyle="italic", + ha="center", + arrowprops={"arrowstyle": "->", "color": "#9A5F2A", "lw": 1.5}, +) plt.tight_layout() plt.savefig("plot.png", dpi=300, bbox_inches="tight") diff --git a/plots/violin-basic/metadata/matplotlib.yaml b/plots/violin-basic/metadata/matplotlib.yaml index bfd0c53e77..40f77dba45 100644 --- a/plots/violin-basic/metadata/matplotlib.yaml +++ b/plots/violin-basic/metadata/matplotlib.yaml @@ -1,11 +1,11 @@ library: matplotlib specification_id: violin-basic created: '2025-12-23T00:35:08Z' -updated: '2025-12-23T00:38:15Z' -generated_by: claude-opus-4-5-20251101 +updated: '2026-02-21T22:50:23Z' +generated_by: claude-opus-4-6 workflow_run: 20447775895 issue: 0 -python_version: 3.13.11 +python_version: 3.14.3 library_version: 3.10.8 preview_url: https://storage.googleapis.com/pyplots-images/plots/violin-basic/matplotlib/plot.png preview_thumb: https://storage.googleapis.com/pyplots-images/plots/violin-basic/matplotlib/plot_thumb.png @@ -14,151 +14,165 @@ quality_score: 92 impl_tags: dependencies: [] techniques: - - manual-ticks + - annotations + - manual-ticks patterns: - - data-generation + - data-generation + - iteration-over-groups dataprep: [] styling: - - grid-styling + - alpha-blending + - edge-highlighting + - grid-styling review: strengths: - - Excellent data scenario with test scores across schools - immediately comprehensible - - Clear visual hierarchy with yellow median lines contrasting well against blue - violins - - Proper quartile visualization with IQR bars inside violins - - Text sizes perfectly calibrated for 4800x2700 output - - Good variation in distributions showing different spread and center characteristics + - 'Excellent data design: four distinct distribution shapes (normal, tight, wide, + bimodal) showcase the full power of violin plots' + - Path effects on quantile lines ensure legibility against colored bodies — a thoughtful + detail + - Coordinated annotation with matching color and arrow guides the viewer to the + bimodal insight + - Custom palette with edge color hierarchy adds depth and professional polish + - Yellow median line is immediately distinguishable from white quartile lines weaknesses: - - Test score values exceeding 100 are unrealistic for typical percentage-based scoring - - Could use matplotlib built-in quartile visualization (showquartiles parameter) - instead of manual vlines - - Missing legend element (though not critical for this plot type) - image_description: The plot displays four violin plots comparing test score distributions - across four schools (School A, B, C, D). The violins are rendered in a muted blue - color (#306998) with slight transparency (alpha 0.7). Each violin shows the kernel - density estimation shape, with School C being the widest (indicating highest variance) - and School B being narrower (lower variance). Yellow horizontal lines mark the - median values inside each violin. Dark blue vertical bars indicate the interquartile - range (Q1 to Q3). Vertical lines extend to min/max values. The title "violin-basic - · matplotlib · pyplots.ai" appears at the top. X-axis is labeled "School" and - Y-axis is labeled "Test Score (points)". A subtle horizontal dashed grid is present. - The layout is well-balanced with good proportions. + - Blue-green color pair may be slightly ambiguous for deuteranopia + - Default matplotlib font family used throughout — a custom sans-serif font could + elevate the aesthetic further + image_description: 'The plot displays four violin shapes representing test score + distributions across four schools: Lincoln HS (steel blue, #306998), Roosevelt + Acad. (muted green, #5BA58B), Jefferson HS (soft purple, #7A6FB5), and Hamilton + Prep (warm orange, #D4853F). Each violin has darker edge colors matching its fill. + Inside each violin, white horizontal lines mark Q1 and Q3, while a brighter yellow + line marks the median. Path effects (dark stroke behind lines) make quartile markers + legible against the colored bodies. Lincoln HS shows a broad normal distribution + centered ~75; Roosevelt Acad. shows a tight cluster around ~85; Jefferson HS has + the widest spread centered ~63 reaching down to ~30; Hamilton Prep shows a distinctive + bimodal shape with two bulges (~70 and ~88). An italic annotation in brown reads + "Two distinct performance groups" with an arrow pointing into Hamilton''s violin. + Top and right spines are removed, a subtle y-axis grid (alpha=0.2) is visible, + and the title reads "violin-basic · matplotlib · pyplots.ai" in the correct format. + Axis labels are "School" (x) and "Test Score (points)" (y).' criteria_checklist: visual_quality: - score: 37 - max: 40 + score: 29 + max: 30 items: - id: VQ-01 name: Text Legibility - score: 10 - max: 10 + score: 8 + max: 8 passed: true - comment: Title at 24pt, labels at 20pt, ticks at 16pt - all perfectly readable + comment: 'All font sizes explicitly set: title 24pt, axis labels 20pt, ticks + 16pt, annotation 13pt' - id: VQ-02 name: No Overlap - score: 8 - max: 8 + score: 6 + max: 6 passed: true - comment: No overlapping text elements + comment: No overlapping text, well-spaced x-axis labels and annotation - id: VQ-03 name: Element Visibility - score: 8 - max: 8 + score: 6 + max: 6 passed: true - comment: Violin shapes clearly visible, appropriate alpha for density visualization + comment: Violins well-sized with alpha=0.8, quantile lines enhanced with path + effects - id: VQ-04 name: Color Accessibility - score: 4 - max: 5 + score: 3 + max: 4 passed: true - comment: Python blue is colorblind-safe, good contrast, but single color palette - is simple + comment: Good palette but blue-green pair may challenge deuteranopia - id: VQ-05 - name: Layout Balance - score: 5 - max: 5 + name: Layout & Canvas + score: 4 + max: 4 passed: true - comment: Excellent proportions, no cut-off, good whitespace + comment: tight_layout with balanced margins, 16:9 well-utilized - id: VQ-06 - name: Axis Labels + name: Axis Labels & Title score: 2 max: 2 passed: true - comment: '"Test Score (points)" and "School" are descriptive with units' - - id: VQ-07 - name: Grid & Legend - score: 0 - max: 2 + comment: Test Score (points) with units, School descriptive + design_excellence: + score: 16 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 6 + max: 8 passed: true - comment: Grid is subtle at alpha=0.3, but no legend present (not strictly - needed for this plot type) + comment: Custom palette with edge colors, path effects, yellow median emphasis, + coordinated annotation color + - id: DE-02 + name: Visual Refinement + score: 5 + max: 6 + passed: true + comment: Spines removed, subtle grid, path effects, edge highlighting; default + font is only rough edge + - id: DE-03 + name: Data Storytelling + score: 5 + max: 6 + passed: true + comment: Bimodal annotation guides viewer, four distinct distributions create + comparative narrative spec_compliance: - score: 25 - max: 25 + score: 15 + max: 15 items: - id: SC-01 name: Plot Type - score: 8 - max: 8 - passed: true - comment: Correct violin plot with kernel density estimation - - id: SC-02 - name: Data Mapping score: 5 max: 5 passed: true - comment: Categories on X, values on Y correctly assigned - - id: SC-03 + comment: Correct violin plot with KDE-based density shapes + - id: SC-02 name: Required Features - score: 5 - max: 5 + score: 4 + max: 4 passed: true - comment: Shows quartile markers (IQR bars), mirrored density on both sides, - median line (yellow) - - id: SC-04 - name: Data Range + comment: Quartile markers, mirrored density, median line all present + - id: SC-03 + name: Data Mapping score: 3 max: 3 passed: true - comment: All data visible, y-axis shows full range ~35-115 - - id: SC-05 - name: Legend Accuracy - score: 2 - max: 2 - passed: true - comment: No legend needed as categories are on x-axis - - id: SC-06 - name: Title Format - score: 2 - max: 2 + comment: X=categories, Y=test scores, all data visible + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 passed: true - comment: 'Correct format: "violin-basic · matplotlib · pyplots.ai"' + comment: Title format correct, legend not needed with x-axis labels data_quality: - score: 18 - max: 20 + score: 15 + max: 15 items: - id: DQ-01 name: Feature Coverage - score: 7 - max: 8 + score: 6 + max: 6 passed: true - comment: Shows different distribution shapes (narrow vs wide), different centers - (68-82), different spreads. Could show more extreme outliers or bimodal - distributions. + comment: Normal, tight, wide, and bimodal distributions showcase full violin + plot capability - id: DQ-02 name: Realistic Context - score: 7 - max: 7 + score: 5 + max: 5 passed: true - comment: Test scores across schools is a perfect, comprehensible real-world - scenario + comment: 'School test scores: real-world, neutral, comprehensible with named + schools' - id: DQ-03 name: Appropriate Scale score: 4 - max: 5 + max: 4 passed: true - comment: Test scores in 35-115 range are reasonable, though some exceed 100 - which is unusual for typical test scoring + comment: 0-100 scale with realistic means (62-85) and standard deviations + (4-15) code_quality: score: 10 max: 10 @@ -168,42 +182,46 @@ review: score: 3 max: 3 passed: true - comment: 'Simple linear flow: imports → data → plot → save' + comment: 'Linear flow: imports, data, plot, styling, annotation, save' - id: CQ-02 name: Reproducibility - score: 3 - max: 3 + score: 2 + max: 2 passed: true - comment: np.random.seed(42) ensures reproducibility + comment: np.random.seed(42) set at top - id: CQ-03 name: Clean Imports score: 2 max: 2 passed: true - comment: Only matplotlib.pyplot and numpy imported, both used + comment: 'All three imports used: patheffects, pyplot, numpy' - id: CQ-04 - name: No Deprecated API - score: 1 - max: 1 + name: Code Elegance + score: 2 + max: 2 passed: true - comment: Uses current matplotlib API + comment: Clean, appropriate complexity, no over-engineering - id: CQ-05 - name: Output Correct + name: Output & API score: 1 max: 1 passed: true - comment: Saves as plot.png with dpi=300 - library_features: - score: 2 - max: 5 + comment: Saves as plot.png, dpi=300, current API + library_mastery: + score: 7 + max: 10 items: - - id: LF-01 - name: Uses distinctive library features - score: 2 + - id: LM-01 + name: Idiomatic Usage + score: 4 max: 5 - passed: false - comment: Uses basic violinplot() but doesn't leverage matplotlib's more advanced - violin customization like bw_method for bandwidth, widths parameter, or - vert parameter. The manual IQR overlay is a good touch but could use matplotlib's - built-in showquartiles parameter. + passed: true + comment: Uses violinplot with quantiles parameter, parts dictionary for per-element + styling + - id: LM-02 + name: Distinctive Features + score: 3 + max: 5 + passed: true + comment: Path effects and direct LineCollection manipulation are matplotlib-specific verdict: APPROVED diff --git a/plots/violin-basic/specification.md b/plots/violin-basic/specification.md index 5924825f55..5719807b05 100644 --- a/plots/violin-basic/specification.md +++ b/plots/violin-basic/specification.md @@ -16,10 +16,10 @@ A violin plot combining a box plot with a kernel density estimation on each side - `category` (string) - group labels for comparison - `value` (numeric) - numerical values to plot - Size: 30-1000 points per category, 2-6 categories +- Example: Test scores (50-100) across 4 class groups with distinct distribution shapes ## Notes - Show quartile markers inside the violin - Use mirrored density on both sides - Include median line -- Consider split violins for comparing two conditions diff --git a/plots/violin-basic/specification.yaml b/plots/violin-basic/specification.yaml index 8b832adcdf..f3fc370655 100644 --- a/plots/violin-basic/specification.yaml +++ b/plots/violin-basic/specification.yaml @@ -6,7 +6,7 @@ title: Basic Violin Plot # Specification tracking created: 2025-12-14T09:45:06Z -updated: 2025-12-14T09:45:06Z +updated: 2026-02-21T12:00:00Z issue: 722 suggested: MarkusNeusinger @@ -16,6 +16,7 @@ tags: - violin data_type: - numeric + - continuous - categorical domain: - statistics @@ -24,3 +25,4 @@ tags: - basic - distribution - density + - comparison