|
1 | | -""" pyplots.ai |
| 1 | +""" anyplot.ai |
2 | 2 | slope-basic: Basic Slope Chart (Slopegraph) |
3 | | -Library: plotly 6.5.0 | Python 3.13.11 |
4 | | -Quality: 91/100 | Created: 2025-12-23 |
| 3 | +Library: plotly 6.7.0 | Python 3.13.13 |
| 4 | +Quality: 88/100 | Updated: 2026-04-30 |
5 | 5 | """ |
6 | 6 |
|
| 7 | +import os |
| 8 | + |
7 | 9 | import plotly.graph_objects as go |
8 | 10 |
|
9 | 11 |
|
| 12 | +# Theme tokens |
| 13 | +THEME = os.getenv("ANYPLOT_THEME", "light") |
| 14 | +PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17" |
| 15 | +ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420" |
| 16 | +INK = "#1A1A17" if THEME == "light" else "#F0EFE8" |
| 17 | +INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0" |
| 18 | +INK_MUTED = "#6B6A63" if THEME == "light" else "#A8A79F" |
| 19 | +GRID = "rgba(26,26,23,0.10)" if THEME == "light" else "rgba(240,239,232,0.10)" |
| 20 | + |
| 21 | +# Okabe-Ito: increase = brand green, decrease = vermillion, flat = adaptive neutral |
| 22 | +COLOR_UP = "#009E73" |
| 23 | +COLOR_DOWN = "#D55E00" |
| 24 | +COLOR_FLAT = INK_MUTED |
| 25 | + |
10 | 26 | # Data - Product sales Q1 vs Q4 comparison (10 products showing various patterns) |
11 | 27 | products = [ |
12 | 28 | "Laptop Pro", |
|
21 | 37 | "Monitor Stand", |
22 | 38 | ] |
23 | 39 |
|
24 | | -# Sales figures in thousands ($K) |
25 | 40 | sales_q1 = [245, 180, 120, 195, 85, 110, 45, 30, 75, 55] |
26 | 41 | sales_q4 = [310, 220, 195, 160, 145, 130, 95, 85, 70, 40] |
27 | 42 |
|
28 | | -# Color coding by change direction |
29 | 43 | colors = [] |
30 | 44 | for q1, q4 in zip(sales_q1, sales_q4, strict=True): |
31 | 45 | if q4 > q1: |
32 | | - colors.append("#306998") # Python Blue for increase |
| 46 | + colors.append(COLOR_UP) |
33 | 47 | elif q4 < q1: |
34 | | - colors.append("#FFD43B") # Python Yellow for decrease |
| 48 | + colors.append(COLOR_DOWN) |
35 | 49 | else: |
36 | | - colors.append("#888888") # Gray for no change |
| 50 | + colors.append(COLOR_FLAT) |
37 | 51 |
|
38 | | -# Create figure |
| 52 | +# Plot |
39 | 53 | fig = go.Figure() |
40 | 54 |
|
41 | | -# Add slope lines for each product |
42 | 55 | for i, product in enumerate(products): |
43 | 56 | fig.add_trace( |
44 | 57 | go.Scatter( |
45 | 58 | x=[0, 1], |
46 | 59 | y=[sales_q1[i], sales_q4[i]], |
47 | 60 | mode="lines+markers", |
48 | 61 | line={"color": colors[i], "width": 3}, |
49 | | - marker={"size": 14}, |
| 62 | + marker={"size": 14, "color": colors[i]}, |
50 | 63 | name=product, |
51 | 64 | showlegend=False, |
52 | 65 | hovertemplate=f"{product}<br>Q1: ${sales_q1[i]}K<br>Q4: ${sales_q4[i]}K<extra></extra>", |
53 | 66 | ) |
54 | 67 | ) |
55 | 68 |
|
56 | | -# Add labels at start points (Q1) |
| 69 | +# Labels at Q1 (left side) |
57 | 70 | for i, product in enumerate(products): |
58 | 71 | fig.add_annotation( |
59 | 72 | x=-0.05, |
|
64 | 77 | font={"size": 16, "color": colors[i]}, |
65 | 78 | ) |
66 | 79 |
|
67 | | -# Add labels at end points (Q4) |
| 80 | +# Labels at Q4 (right side) |
68 | 81 | for i, product in enumerate(products): |
69 | 82 | fig.add_annotation( |
70 | 83 | x=1.05, |
|
75 | 88 | font={"size": 16, "color": colors[i]}, |
76 | 89 | ) |
77 | 90 |
|
78 | | -# Layout |
| 91 | +# Style |
79 | 92 | fig.update_layout( |
| 93 | + paper_bgcolor=PAGE_BG, |
| 94 | + plot_bgcolor=PAGE_BG, |
| 95 | + font={"color": INK}, |
80 | 96 | title={ |
81 | | - "text": "Product Sales Q1 vs Q4 · slope-basic · plotly · pyplots.ai", |
82 | | - "font": {"size": 28}, |
| 97 | + "text": "Product Sales Q1 vs Q4 · slope-basic · plotly · anyplot.ai", |
| 98 | + "font": {"size": 28, "color": INK}, |
83 | 99 | "x": 0.5, |
84 | 100 | "xanchor": "center", |
85 | 101 | }, |
86 | 102 | xaxis={ |
87 | 103 | "tickmode": "array", |
88 | 104 | "tickvals": [0, 1], |
89 | 105 | "ticktext": ["Q1 2024", "Q4 2024"], |
90 | | - "tickfont": {"size": 22}, |
91 | | - "range": [-0.4, 1.4], |
| 106 | + "tickfont": {"size": 22, "color": INK_SOFT}, |
| 107 | + "range": [-0.5, 1.5], |
92 | 108 | "showgrid": False, |
93 | 109 | "zeroline": False, |
| 110 | + "linecolor": INK_SOFT, |
94 | 111 | }, |
95 | 112 | yaxis={ |
96 | | - "title": {"text": "Sales ($K)", "font": {"size": 22}}, |
97 | | - "tickfont": {"size": 18}, |
| 113 | + "title": {"text": "Sales ($K)", "font": {"size": 22, "color": INK}}, |
| 114 | + "tickfont": {"size": 18, "color": INK_SOFT}, |
98 | 115 | "showgrid": True, |
99 | 116 | "gridwidth": 1, |
100 | | - "gridcolor": "rgba(0,0,0,0.1)", |
| 117 | + "gridcolor": GRID, |
101 | 118 | "zeroline": False, |
| 119 | + "linecolor": INK_SOFT, |
102 | 120 | }, |
103 | | - template="plotly_white", |
104 | | - margin={"l": 200, "r": 200, "t": 80, "b": 60}, |
| 121 | + margin={"l": 220, "r": 220, "t": 80, "b": 60}, |
105 | 122 | ) |
106 | 123 |
|
107 | | -# Save outputs |
108 | | -fig.write_image("plot.png", width=1600, height=900, scale=3) |
109 | | -fig.write_html("plot.html") |
| 124 | +# Save |
| 125 | +fig.write_image(f"plot-{THEME}.png", width=1600, height=900, scale=3) |
| 126 | +fig.write_html(f"plot-{THEME}.html", include_plotlyjs="cdn") |
0 commit comments