From c9b1032be7f5b7f7e380696390849b30e943a326 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 16 Dec 2025 05:52:17 +0000 Subject: [PATCH 1/3] feat(plotly): implement bullet-basic --- plots/bullet-basic/implementations/plotly.py | 112 +++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 plots/bullet-basic/implementations/plotly.py diff --git a/plots/bullet-basic/implementations/plotly.py b/plots/bullet-basic/implementations/plotly.py new file mode 100644 index 0000000000..ade5f3a020 --- /dev/null +++ b/plots/bullet-basic/implementations/plotly.py @@ -0,0 +1,112 @@ +""" +bullet-basic: Basic Bullet Chart +Library: plotly +""" + +import plotly.graph_objects as go +from plotly.subplots import make_subplots + + +# Data - Multiple KPIs with different performance levels +metrics = [ + {"label": "Revenue ($K)", "actual": 275, "target": 250, "ranges": [150, 200, 300]}, + {"label": "Profit ($K)", "actual": 85, "target": 100, "ranges": [50, 75, 125]}, + {"label": "Customers", "actual": 320, "target": 400, "ranges": [200, 350, 500]}, + {"label": "Satisfaction", "actual": 4.2, "target": 4.5, "ranges": [3.0, 4.0, 5.0]}, +] + +# Grayscale colors for qualitative ranges (poor -> satisfactory -> good) +range_colors = ["#D9D9D9", "#BFBFBF", "#A6A6A6"] + +# Create subplots - one row per metric for proper scaling +fig = make_subplots( + rows=len(metrics), cols=1, shared_xaxes=False, vertical_spacing=0.12, subplot_titles=[m["label"] for m in metrics] +) + +# Create each bullet chart in its own subplot +for i, m in enumerate(metrics): + row = i + 1 + + # Add qualitative range bands (background, plotted in reverse order) + for j, r in enumerate(reversed(m["ranges"])): + fig.add_trace( + go.Bar( + x=[r], + y=[""], + orientation="h", + marker=dict(color=range_colors[len(m["ranges"]) - 1 - j]), + width=0.6, + showlegend=False, + hoverinfo="skip", + ), + row=row, + col=1, + ) + + # Add actual value bar (primary measure) + fig.add_trace( + go.Bar( + x=[m["actual"]], + y=[""], + orientation="h", + marker=dict(color="#306998"), + width=0.25, + showlegend=False, + name=m["label"], + hovertemplate=f"{m['label']}: {m['actual']}", + ), + row=row, + col=1, + ) + + # Add target marker line + fig.add_shape( + type="line", + x0=m["target"], + x1=m["target"], + y0=-0.4, + y1=0.4, + line=dict(color="#1A1A1A", width=5), + row=row, + col=1, + ) + + # Add actual value annotation + max_range = m["ranges"][-1] + fig.add_annotation( + x=max_range * 1.02, + y=0, + text=f"{m['actual']}", + showarrow=False, + font=dict(size=20, color="#306998"), + xanchor="left", + row=row, + col=1, + ) + + # Update x-axis range for each subplot + fig.update_xaxes( + range=[0, max_range * 1.15], tickfont=dict(size=16), showgrid=True, gridcolor="rgba(0,0,0,0.1)", row=row, col=1 + ) + + fig.update_yaxes(showticklabels=False, row=row, col=1) + +# Layout +fig.update_layout( + title=dict(text="bullet-basic · plotly · pyplots.ai", font=dict(size=32), x=0.5, xanchor="center"), + barmode="overlay", + template="plotly_white", + margin=dict(l=80, r=100, t=120, b=60), + showlegend=False, + height=900, + width=1600, +) + +# Update subplot titles font size +for annotation in fig["layout"]["annotations"]: + if "text" in annotation and annotation["text"] in [m["label"] for m in metrics]: + annotation["font"] = dict(size=22) + +# Save +fig.write_image("plot.png", width=1600, height=900, scale=3) +fig.write_html("plot.html", include_plotlyjs="cdn") From dacddc5128ac3422b844d1530754d0b67b501587 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 16 Dec 2025 05:52:31 +0000 Subject: [PATCH 2/3] chore(plotly): add metadata for bullet-basic --- plots/bullet-basic/metadata/plotly.yaml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 plots/bullet-basic/metadata/plotly.yaml diff --git a/plots/bullet-basic/metadata/plotly.yaml b/plots/bullet-basic/metadata/plotly.yaml new file mode 100644 index 0000000000..36551710ff --- /dev/null +++ b/plots/bullet-basic/metadata/plotly.yaml @@ -0,0 +1,23 @@ +# Per-library metadata for plotly implementation of bullet-basic +# Auto-generated by impl-generate.yml + +library: plotly +specification_id: bullet-basic + +# Preview URLs (filled by workflow) +preview_url: https://storage.googleapis.com/pyplots-images/plots/bullet-basic/plotly/plot.png +preview_thumb: https://storage.googleapis.com/pyplots-images/plots/bullet-basic/plotly/plot_thumb.png +preview_html: https://storage.googleapis.com/pyplots-images/plots/bullet-basic/plotly/plot.html + +current: + version: 0 + generated_at: 2025-12-16T05:52:30Z + generated_by: claude-opus-4-5-20251101 + workflow_run: 20257947593 + issue: 999 + quality_score: null + # Version info (filled by workflow) + python_version: "3.13.11" + library_version: "unknown" + +history: [] From 76c9583dcfc2f9fccfbed396ff190f524e3629b1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 16 Dec 2025 05:54:39 +0000 Subject: [PATCH 3/3] chore(plotly): set quality score 93 for bullet-basic --- plots/bullet-basic/metadata/plotly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plots/bullet-basic/metadata/plotly.yaml b/plots/bullet-basic/metadata/plotly.yaml index 36551710ff..1a0e861c24 100644 --- a/plots/bullet-basic/metadata/plotly.yaml +++ b/plots/bullet-basic/metadata/plotly.yaml @@ -15,7 +15,7 @@ current: generated_by: claude-opus-4-5-20251101 workflow_run: 20257947593 issue: 999 - quality_score: null + quality_score: 93 # Version info (filled by workflow) python_version: "3.13.11" library_version: "unknown"