Skip to content

Commit c09c42a

Browse files
feat(plotnine): implement subplot-grid-custom (#2900)
## Implementation: `subplot-grid-custom` - plotnine Implements the **plotnine** version of `subplot-grid-custom`. **File:** `plots/subplot-grid-custom/implementations/plotnine.py` **Parent Issue:** #2856 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20608471415)* --------- 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 59b274e commit c09c42a

2 files changed

Lines changed: 159 additions & 0 deletions

File tree

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
""" pyplots.ai
2+
subplot-grid-custom: Custom Subplot Grid Layout
3+
Library: plotnine 0.15.2 | Python 3.13.11
4+
Quality: 91/100 | Created: 2025-12-30
5+
"""
6+
7+
import numpy as np
8+
import pandas as pd
9+
from plotnine import (
10+
aes,
11+
element_line,
12+
element_rect,
13+
element_text,
14+
geom_bar,
15+
geom_histogram,
16+
geom_line,
17+
geom_point,
18+
ggplot,
19+
labs,
20+
scale_fill_manual,
21+
stat_smooth,
22+
theme,
23+
theme_minimal,
24+
)
25+
26+
27+
# Data - Investment Portfolio Dashboard
28+
np.random.seed(42)
29+
30+
# Main time series: Daily portfolio value over 60 days
31+
n_days = 60
32+
dates = pd.date_range("2024-01-01", periods=n_days, freq="D")
33+
portfolio_value = 100000 + np.cumsum(np.random.randn(n_days) * 500 + 50)
34+
df_portfolio = pd.DataFrame({"day": range(n_days), "value": portfolio_value, "date": dates})
35+
36+
# Volume/Activity data - Trading volume per day
37+
volume = np.abs(np.random.randn(n_days) * 1000 + 3000)
38+
df_volume = pd.DataFrame({"day": range(n_days), "volume": volume})
39+
40+
# Asset allocation (pie chart equivalent - bar chart for plotnine)
41+
assets = ["Stocks", "Bonds", "Real Estate", "Cash"]
42+
allocations = [55, 25, 12, 8]
43+
df_allocation = pd.DataFrame(
44+
{"asset": pd.Categorical(assets, categories=assets, ordered=True), "allocation": allocations}
45+
)
46+
47+
# Daily returns distribution
48+
returns = np.diff(portfolio_value) / portfolio_value[:-1] * 100
49+
df_returns = pd.DataFrame({"returns": returns})
50+
51+
# Colors
52+
colors = ["#306998", "#FFD43B", "#4A8BBF", "#E07A5F"]
53+
54+
# Shared theme - sized for 4800x2700 canvas
55+
base_theme = theme_minimal() + theme(
56+
plot_title=element_text(size=18, face="bold", ha="center", margin={"b": 8}),
57+
axis_title=element_text(size=16),
58+
axis_text=element_text(size=13),
59+
legend_text=element_text(size=13),
60+
legend_title=element_text(size=14, face="bold"),
61+
panel_grid_major=element_line(color="#cccccc", alpha=0.3),
62+
panel_grid_minor=element_line(color="#eeeeee", alpha=0.2),
63+
panel_background=element_rect(fill="white"),
64+
plot_margin=0.01,
65+
)
66+
67+
# Small theme for right-side panels (more compact titles)
68+
small_theme = base_theme + theme(
69+
plot_title=element_text(size=16, face="bold", margin={"b": 5, "t": 5}),
70+
axis_title=element_text(size=14),
71+
axis_text=element_text(size=11),
72+
)
73+
74+
# Main Plot (spans full left side): Portfolio Value Over Time
75+
p_main = (
76+
ggplot(df_portfolio, aes(x="day", y="value"))
77+
+ geom_line(size=1.8, color="#306998")
78+
+ geom_point(size=2.5, color="#306998", alpha=0.6)
79+
+ stat_smooth(method="lm", se=True, color="#FFD43B", fill="#FFD43B", alpha=0.2, size=1.2)
80+
+ labs(title="Portfolio Value Trend", x="Trading Day", y="Portfolio Value ($)")
81+
+ base_theme
82+
+ theme(plot_title=element_text(size=22, margin={"b": 10, "t": 40}))
83+
)
84+
85+
# Top Right: Asset Allocation (horizontal bar chart)
86+
p_allocation = (
87+
ggplot(df_allocation, aes(x="asset", y="allocation", fill="asset"))
88+
+ geom_bar(stat="identity", width=0.7, show_legend=False)
89+
+ scale_fill_manual(values=colors)
90+
+ labs(title="Asset Allocation", x="", y="Allocation (%)")
91+
+ small_theme
92+
+ theme(axis_text_x=element_text(size=11, angle=0))
93+
)
94+
95+
# Middle Right: Trading Volume
96+
p_volume = (
97+
ggplot(df_volume, aes(x="day", y="volume"))
98+
+ geom_bar(stat="identity", fill="#306998", alpha=0.7, width=0.8)
99+
+ labs(title="Daily Trading Volume", x="Trading Day", y="Volume (Units)")
100+
+ small_theme
101+
)
102+
103+
# Bottom Right: Returns Distribution
104+
p_returns = (
105+
ggplot(df_returns, aes(x="returns"))
106+
+ geom_histogram(bins=15, fill="#FFD43B", color="#306998", alpha=0.8, size=0.5)
107+
+ labs(title="Returns Distribution", x="Daily Return (%)", y="Frequency")
108+
+ small_theme
109+
)
110+
111+
# Create custom grid layout using plotnine composition operators
112+
# Layout: Main plot (full height left) | 3 stacked smaller plots (right column)
113+
# This creates a dashboard with main visualization and supporting detail panels
114+
right_column = p_allocation / p_volume / p_returns
115+
custom_grid = p_main | right_column
116+
117+
# Draw and customize the figure
118+
fig = custom_grid.draw()
119+
120+
# Set figure size for 4800x2700 px at 300 DPI
121+
fig.set_size_inches(16, 9)
122+
123+
# Adjust subplot spacing for clean layout with main title
124+
fig.subplots_adjust(top=0.88, bottom=0.08, left=0.06, right=0.98, hspace=0.35, wspace=0.18)
125+
126+
# Add main title positioned above all subplot titles
127+
fig.suptitle("subplot-grid-custom · plotnine · pyplots.ai", fontsize=28, fontweight="bold", y=0.98)
128+
129+
# Save
130+
fig.savefig("plot.png", dpi=300, bbox_inches="tight", facecolor="white")
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
library: plotnine
2+
specification_id: subplot-grid-custom
3+
created: '2025-12-30T23:58:25Z'
4+
updated: '2025-12-31T00:02:32Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20608471415
7+
issue: 2856
8+
python_version: 3.13.11
9+
library_version: 0.15.2
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/subplot-grid-custom/plotnine/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/subplot-grid-custom/plotnine/plot_thumb.png
12+
preview_html: null
13+
quality_score: 91
14+
review:
15+
strengths:
16+
- Excellent dashboard layout demonstrating custom grid with non-uniform cell sizes
17+
using plotnine composition operators
18+
- Clear visual hierarchy with main plot given appropriate prominence
19+
- Real-world investment portfolio scenario is highly relevant to the spec executive
20+
dashboard application
21+
- Clean code structure following KISS principles with shared theme definitions
22+
- Good use of stat_smooth for trend line with confidence band in main plot
23+
- Colorblind-safe color palette with good contrast
24+
weaknesses:
25+
- Text sizes on right-panel subplots are slightly smaller than optimal for the canvas
26+
size
27+
- The grid layout uses | and / operators which create a 2-column layout, but does
28+
not demonstrate explicit colspan/rowspan parameters mentioned in spec notes
29+
- Library features score could be higher with additional ggplot2 grammar features

0 commit comments

Comments
 (0)