Skip to content

Commit 933f9ad

Browse files
feat(plotly): implement bar-3d (#2885)
## Implementation: `bar-3d` - plotly Implements the **plotly** version of `bar-3d`. **File:** `plots/bar-3d/implementations/plotly.py` **Parent Issue:** #2857 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20608477432)* --------- 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 4839262 commit 933f9ad

2 files changed

Lines changed: 178 additions & 0 deletions

File tree

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
""" pyplots.ai
2+
bar-3d: 3D Bar Chart
3+
Library: plotly 6.5.0 | Python 3.13.11
4+
Quality: 91/100 | Created: 2025-12-30
5+
"""
6+
7+
import numpy as np
8+
import plotly.graph_objects as go
9+
10+
11+
# Data - Quarterly sales by product category (5 products x 4 quarters)
12+
np.random.seed(42)
13+
14+
products = ["Electronics", "Clothing", "Food", "Home", "Sports"]
15+
quarters = ["Q1", "Q2", "Q3", "Q4"]
16+
17+
# Create sales data with realistic patterns (values in thousands)
18+
base_sales = np.array([120, 85, 95, 70, 55])
19+
seasonal_factors = np.array([0.8, 1.0, 0.9, 1.3]) # Q4 holiday boost
20+
sales_matrix = np.outer(base_sales, seasonal_factors) + np.random.randn(5, 4) * 10
21+
sales_matrix = np.maximum(sales_matrix, 10) # Ensure positive values
22+
23+
# Create 3D bar coordinates
24+
x_coords = []
25+
y_coords = []
26+
z_coords = []
27+
colors = []
28+
29+
# Python-inspired colorscale
30+
colorscale = ["#306998", "#4A8BB2", "#6AADCC", "#FFD43B", "#FFE873"]
31+
32+
for i, _product in enumerate(products):
33+
for j, _quarter in enumerate(quarters):
34+
x_coords.append(i)
35+
y_coords.append(j)
36+
z_coords.append(sales_matrix[i, j])
37+
colors.append(colorscale[i])
38+
39+
# Create 3D bars using Mesh3d for each bar
40+
fig = go.Figure()
41+
42+
bar_width = 0.35
43+
bar_depth = 0.35
44+
45+
for i in range(len(x_coords)):
46+
x, y, z = x_coords[i], y_coords[i], z_coords[i]
47+
48+
# Define the 8 vertices of each bar
49+
vertices_x = [
50+
x - bar_width,
51+
x + bar_width,
52+
x + bar_width,
53+
x - bar_width,
54+
x - bar_width,
55+
x + bar_width,
56+
x + bar_width,
57+
x - bar_width,
58+
]
59+
vertices_y = [
60+
y - bar_depth,
61+
y - bar_depth,
62+
y + bar_depth,
63+
y + bar_depth,
64+
y - bar_depth,
65+
y - bar_depth,
66+
y + bar_depth,
67+
y + bar_depth,
68+
]
69+
vertices_z = [0, 0, 0, 0, z, z, z, z]
70+
71+
# Define faces using triangular indices
72+
faces_i = [0, 0, 4, 4, 0, 0, 1, 1, 0, 0, 3, 3]
73+
faces_j = [1, 2, 5, 6, 1, 4, 2, 5, 3, 4, 2, 6]
74+
faces_k = [2, 3, 6, 7, 4, 5, 5, 6, 4, 7, 6, 7]
75+
76+
fig.add_trace(
77+
go.Mesh3d(
78+
x=vertices_x,
79+
y=vertices_y,
80+
z=vertices_z,
81+
i=faces_i,
82+
j=faces_j,
83+
k=faces_k,
84+
color=colors[i],
85+
opacity=0.9,
86+
flatshading=True,
87+
showlegend=False,
88+
hovertemplate=f"{products[x_coords[i]]}<br>{quarters[y_coords[i]]}<br>Sales: ${z:.0f}K<extra></extra>",
89+
)
90+
)
91+
92+
# Add legend traces for products
93+
for i, product in enumerate(products):
94+
fig.add_trace(
95+
go.Scatter3d(
96+
x=[None],
97+
y=[None],
98+
z=[None],
99+
mode="markers",
100+
marker=dict(size=16, color=colorscale[i]),
101+
name=product,
102+
showlegend=True,
103+
)
104+
)
105+
106+
# Update layout
107+
fig.update_layout(
108+
title=dict(
109+
text="bar-3d \u00b7 plotly \u00b7 pyplots.ai", font=dict(size=32, color="#333333"), x=0.5, xanchor="center"
110+
),
111+
scene=dict(
112+
xaxis=dict(
113+
title=dict(text="Product Category", font=dict(size=20)),
114+
ticktext=products,
115+
tickvals=list(range(len(products))),
116+
tickfont=dict(size=14),
117+
gridcolor="rgba(0,0,0,0.1)",
118+
showbackground=True,
119+
backgroundcolor="rgba(240,240,240,0.9)",
120+
),
121+
yaxis=dict(
122+
title=dict(text="Quarter", font=dict(size=20)),
123+
ticktext=quarters,
124+
tickvals=list(range(len(quarters))),
125+
tickfont=dict(size=14),
126+
gridcolor="rgba(0,0,0,0.1)",
127+
showbackground=True,
128+
backgroundcolor="rgba(240,240,240,0.9)",
129+
),
130+
zaxis=dict(
131+
title=dict(text="Sales ($K)", font=dict(size=20)),
132+
tickfont=dict(size=14),
133+
gridcolor="rgba(0,0,0,0.1)",
134+
showbackground=True,
135+
backgroundcolor="rgba(240,240,240,0.9)",
136+
),
137+
camera=dict(eye=dict(x=1.8, y=1.8, z=1.2)),
138+
aspectmode="manual",
139+
aspectratio=dict(x=1.2, y=1, z=0.8),
140+
),
141+
legend=dict(
142+
font=dict(size=16), x=0.92, y=0.9, bgcolor="rgba(255,255,255,0.9)", bordercolor="rgba(0,0,0,0.2)", borderwidth=1
143+
),
144+
margin=dict(l=20, r=20, t=80, b=20),
145+
paper_bgcolor="white",
146+
width=1600,
147+
height=900,
148+
)
149+
150+
# Save as PNG and HTML
151+
fig.write_image("plot.png", width=1600, height=900, scale=3)
152+
fig.write_html("plot.html", include_plotlyjs="cdn")

plots/bar-3d/metadata/plotly.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
library: plotly
2+
specification_id: bar-3d
3+
created: '2025-12-30T23:55:43Z'
4+
updated: '2025-12-31T00:02:01Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20608477432
7+
issue: 2857
8+
python_version: 3.13.11
9+
library_version: 6.5.0
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/bar-3d/plotly/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/bar-3d/plotly/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/bar-3d/plotly/plot.html
13+
quality_score: 91
14+
review:
15+
strengths:
16+
- Excellent implementation of 3D bars using Mesh3d with proper vertex and face definitions
17+
- Good color scheme following Python-inspired palette that is colorblind-safe
18+
- Interactive hover templates with detailed information (product, quarter, sales
19+
value)
20+
- Dual output format (PNG + HTML) leveraging Plotly interactive capabilities
21+
- Realistic business scenario with seasonal sales patterns (Q4 holiday boost)
22+
- Semi-transparent bars (opacity=0.9) help with depth perception
23+
weaknesses:
24+
- Legend marker style (circular) does not match the bar chart style
25+
- Some minor occlusion of back rows inherent to 3D visualization could be mitigated
26+
with more transparency

0 commit comments

Comments
 (0)