Skip to content

Commit 20d9d76

Browse files
feat(plotly): implement subplot-mosaic (#3025)
## Implementation: `subplot-mosaic` - plotly Implements the **plotly** version of `subplot-mosaic`. **File:** `plots/subplot-mosaic/implementations/plotly.py` **Parent Issue:** #3002 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20617508328)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 54f9beb commit 20d9d76

2 files changed

Lines changed: 212 additions & 0 deletions

File tree

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
""" pyplots.ai
2+
subplot-mosaic: Mosaic Subplot Layout with Varying Sizes
3+
Library: plotly 6.5.0 | Python 3.13.11
4+
Quality: 91/100 | Created: 2025-12-31
5+
"""
6+
7+
import numpy as np
8+
import pandas as pd
9+
import plotly.graph_objects as go
10+
from plotly.subplots import make_subplots
11+
12+
13+
# Data
14+
np.random.seed(42)
15+
16+
# Time series data for the wide overview chart (A - spans top row)
17+
dates = pd.date_range("2024-01-01", periods=120, freq="D")
18+
revenue = 50000 + np.cumsum(np.random.randn(120) * 1000) + np.arange(120) * 200
19+
revenue = np.maximum(revenue, 30000)
20+
21+
# Monthly breakdown for bar chart (B - top right)
22+
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
23+
monthly_sales = [42000, 48000, 51000, 46000, 58000, 62000]
24+
25+
# Scatter data for distribution view (C - middle left)
26+
product_x = np.random.randn(80) * 15 + 50
27+
product_y = product_x * 0.7 + np.random.randn(80) * 10 + 20
28+
29+
# Category comparison (D - middle right)
30+
categories = ["Electronics", "Clothing", "Food", "Books", "Sports"]
31+
cat_values = [35, 28, 22, 15, 18]
32+
33+
# Metric panel data (E, F, G - bottom row)
34+
metric_1_history = np.random.rand(30) * 20 + 80
35+
metric_2_history = np.random.rand(30) * 15 + 60
36+
metric_3_history = np.random.rand(30) * 25 + 45
37+
38+
# Create mosaic layout: "AAB;CCD;EFG"
39+
# Row 1: A spans 2 cols, B takes 1 col
40+
# Row 2: C spans 2 cols, D takes 1 col
41+
# Row 3: E, F, G each take 1 col
42+
43+
fig = make_subplots(
44+
rows=3,
45+
cols=3,
46+
specs=[[{"colspan": 2}, None, {}], [{"colspan": 2}, None, {}], [{}, {}, {}]],
47+
row_heights=[0.4, 0.35, 0.25],
48+
column_widths=[0.33, 0.33, 0.34],
49+
subplot_titles=[
50+
"Revenue Trend (Overview)",
51+
"Monthly Sales",
52+
"Product Performance",
53+
"Category Distribution",
54+
"Efficiency",
55+
"Quality Score",
56+
"Response Time",
57+
],
58+
vertical_spacing=0.1,
59+
horizontal_spacing=0.08,
60+
)
61+
62+
# A: Revenue trend line (top spanning)
63+
fig.add_trace(
64+
go.Scatter(
65+
x=dates,
66+
y=revenue,
67+
mode="lines",
68+
line={"color": "#306998", "width": 3},
69+
fill="tozeroy",
70+
fillcolor="rgba(48, 105, 152, 0.2)",
71+
name="Revenue",
72+
),
73+
row=1,
74+
col=1,
75+
)
76+
77+
# B: Monthly sales bar (top right)
78+
fig.add_trace(go.Bar(x=months, y=monthly_sales, marker_color="#FFD43B", name="Monthly"), row=1, col=3)
79+
80+
# C: Product scatter (middle spanning)
81+
fig.add_trace(
82+
go.Scatter(
83+
x=product_x, y=product_y, mode="markers", marker={"size": 12, "color": "#306998", "opacity": 0.7}, name="Products"
84+
),
85+
row=2,
86+
col=1,
87+
)
88+
89+
# D: Category horizontal bar (middle right)
90+
fig.add_trace(
91+
go.Bar(
92+
y=categories,
93+
x=cat_values,
94+
orientation="h",
95+
marker_color=["#306998", "#FFD43B", "#4B8BBE", "#646464", "#8B4513"],
96+
name="Categories",
97+
),
98+
row=2,
99+
col=3,
100+
)
101+
102+
# E: Efficiency metric (bottom left)
103+
fig.add_trace(
104+
go.Scatter(
105+
x=list(range(30)),
106+
y=metric_1_history,
107+
mode="lines",
108+
line={"color": "#306998", "width": 2},
109+
fill="tozeroy",
110+
fillcolor="rgba(48, 105, 152, 0.3)",
111+
name="Efficiency",
112+
),
113+
row=3,
114+
col=1,
115+
)
116+
117+
# F: Quality score metric (bottom middle)
118+
fig.add_trace(
119+
go.Scatter(
120+
x=list(range(30)),
121+
y=metric_2_history,
122+
mode="lines",
123+
line={"color": "#FFD43B", "width": 2},
124+
fill="tozeroy",
125+
fillcolor="rgba(255, 212, 59, 0.3)",
126+
name="Quality",
127+
),
128+
row=3,
129+
col=2,
130+
)
131+
132+
# G: Response time metric (bottom right)
133+
fig.add_trace(
134+
go.Scatter(
135+
x=list(range(30)),
136+
y=metric_3_history,
137+
mode="lines",
138+
line={"color": "#4B8BBE", "width": 2},
139+
fill="tozeroy",
140+
fillcolor="rgba(75, 139, 190, 0.3)",
141+
name="Response",
142+
),
143+
row=3,
144+
col=3,
145+
)
146+
147+
# Update layout for large canvas
148+
fig.update_layout(
149+
title={"text": "subplot-mosaic · plotly · pyplots.ai", "font": {"size": 32}, "x": 0.5, "xanchor": "center"},
150+
template="plotly_white",
151+
showlegend=False,
152+
margin={"l": 80, "r": 60, "t": 120, "b": 60},
153+
)
154+
155+
# Update all axes for visibility
156+
fig.update_xaxes(tickfont={"size": 14}, title_font={"size": 16})
157+
fig.update_yaxes(tickfont={"size": 14}, title_font={"size": 16})
158+
159+
# Specific axis labels
160+
fig.update_xaxes(title_text="Date", row=1, col=1)
161+
fig.update_yaxes(title_text="Revenue ($)", row=1, col=1)
162+
fig.update_xaxes(title_text="Month", row=1, col=3)
163+
fig.update_yaxes(title_text="Sales ($)", row=1, col=3)
164+
fig.update_xaxes(title_text="Feature X", row=2, col=1)
165+
fig.update_yaxes(title_text="Feature Y", row=2, col=1)
166+
fig.update_xaxes(title_text="Units Sold", row=2, col=3)
167+
fig.update_xaxes(title_text="Days", row=3, col=1)
168+
fig.update_yaxes(title_text="%", row=3, col=1)
169+
fig.update_xaxes(title_text="Days", row=3, col=2)
170+
fig.update_yaxes(title_text="Score", row=3, col=2)
171+
fig.update_xaxes(title_text="Days", row=3, col=3)
172+
fig.update_yaxes(title_text="ms", row=3, col=3)
173+
174+
# Update subplot titles font size
175+
fig.update_annotations(font_size=18)
176+
177+
# Save as PNG
178+
fig.write_image("plot.png", width=1600, height=900, scale=3)
179+
180+
# Save as HTML for interactivity
181+
fig.write_html("plot.html", include_plotlyjs=True, full_html=True)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
library: plotly
2+
specification_id: subplot-mosaic
3+
created: '2025-12-31T10:56:09Z'
4+
updated: '2025-12-31T11:07:41Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20617508328
7+
issue: 3002
8+
python_version: 3.13.11
9+
library_version: 6.5.0
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/subplot-mosaic/plotly/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/subplot-mosaic/plotly/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/subplot-mosaic/plotly/plot.html
13+
quality_score: 91
14+
review:
15+
strengths:
16+
- Excellent mosaic layout implementation using Plotly make_subplots with colspan
17+
specifications to achieve the AAB/CCD/EFG pattern
18+
- Well-designed business dashboard scenario with coherent data narrative
19+
- Clean code structure following KISS principles with clear comments explaining
20+
the layout pattern
21+
- Good visual hierarchy with larger panels for primary data and smaller panels for
22+
supporting metrics
23+
- Proper use of Plotly white template and consistent color scheme
24+
- Correctly implements both PNG and HTML outputs for static and interactive viewing
25+
weaknesses:
26+
- Scatter plot markers in Product Performance panel are slightly small (size=12)
27+
for 80 data points at this canvas size
28+
- Missing demonstration of empty cell/gap feature using placeholder mentioned in
29+
spec
30+
- Bottom row metric panels feel slightly cramped; row_heights could be adjusted
31+
for better balance

0 commit comments

Comments
 (0)