Skip to content

Commit d8f07cf

Browse files
Merge branch 'main' into implementation/stem-basic/pygal
2 parents c11be8c + 7ad1f85 commit d8f07cf

8 files changed

Lines changed: 849 additions & 583 deletions

File tree

Lines changed: 80 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,108 @@
1-
""" pyplots.ai
1+
""" anyplot.ai
22
stem-basic: Basic Stem Plot
3-
Library: altair 6.0.0 | Python 3.13.11
4-
Quality: 92/100 | Created: 2025-12-23
3+
Library: altair 6.1.0 | Python 3.13.13
4+
Quality: 89/100 | Updated: 2026-04-30
55
"""
66

7+
import os
8+
79
import altair as alt
810
import numpy as np
911
import pandas as pd
1012

1113

12-
# Data - Discrete signal samples (simulating a damped oscillation)
14+
# Theme tokens
15+
THEME = os.getenv("ANYPLOT_THEME", "light")
16+
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
17+
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
18+
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
19+
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
20+
BRAND = "#009E73" # Okabe-Ito position 1
21+
22+
# Data — acoustic impulse response samples
1323
np.random.seed(42)
14-
x = np.arange(0, 30)
15-
y = np.exp(-x / 10) * np.cos(x * 0.8) + np.random.randn(30) * 0.05
24+
n_samples = 30
25+
sample_index = np.arange(n_samples)
26+
amplitude = np.exp(-sample_index / 8) * np.cos(sample_index * 0.9) + np.random.randn(n_samples) * 0.03
27+
28+
df = pd.DataFrame({"n": sample_index, "amplitude": amplitude, "baseline": 0.0})
29+
30+
# Decay envelope — highlights the exponential decay story
31+
n_env = np.linspace(0, n_samples - 1, 200)
32+
env_df = pd.DataFrame({"n": n_env, "upper": np.exp(-n_env / 8), "lower": -np.exp(-n_env / 8)})
1633

17-
df = pd.DataFrame({"x": x, "y": y, "y0": 0})
34+
# Shaded decay region (subtle background emphasis)
35+
envelope_area = (
36+
alt.Chart(env_df)
37+
.mark_area(color=BRAND, opacity=0.07)
38+
.encode(x=alt.X("n:Q"), y=alt.Y("upper:Q"), y2=alt.Y2("lower:Q"))
39+
)
40+
41+
# Dashed bounds of the decay envelope
42+
envelope_upper = (
43+
alt.Chart(env_df)
44+
.mark_line(color=INK_SOFT, strokeWidth=1.5, strokeDash=[5, 4], opacity=0.45)
45+
.encode(x=alt.X("n:Q"), y=alt.Y("upper:Q"))
46+
)
1847

19-
# Create stems (vertical lines from baseline y=0 to each data point)
48+
envelope_lower = (
49+
alt.Chart(env_df)
50+
.mark_line(color=INK_SOFT, strokeWidth=1.5, strokeDash=[5, 4], opacity=0.45)
51+
.encode(x=alt.X("n:Q"), y=alt.Y("lower:Q"))
52+
)
53+
54+
# Baseline rule at y=0
55+
baseline_rule = alt.Chart(pd.DataFrame({"y": [0]})).mark_rule(color=INK_SOFT, strokeWidth=1.5).encode(y=alt.Y("y:Q"))
56+
57+
# Stems: vertical rules from baseline to each data point
2058
stems = (
2159
alt.Chart(df)
22-
.mark_rule(color="#306998", strokeWidth=2.5, opacity=0.8)
60+
.mark_rule(color=BRAND, strokeWidth=2.5, opacity=0.85)
2361
.encode(
24-
x=alt.X("x:Q", title="Sample Index", axis=alt.Axis(labelFontSize=18, titleFontSize=22)),
25-
y=alt.Y("y0:Q"),
26-
y2=alt.Y2("y:Q"),
62+
x=alt.X("n:Q", title="Sample Index (n)", axis=alt.Axis(labelFontSize=18, titleFontSize=22)),
63+
y=alt.Y("baseline:Q"),
64+
y2=alt.Y2("amplitude:Q"),
2765
)
2866
)
2967

30-
# Create markers at the top of each stem
68+
# Markers at the tip of each stem
3169
markers = (
3270
alt.Chart(df)
33-
.mark_circle(color="#306998", size=300, stroke="white", strokeWidth=2)
71+
.mark_circle(color=BRAND, size=300, stroke=PAGE_BG, strokeWidth=2)
3472
.encode(
35-
x=alt.X("x:Q"),
36-
y=alt.Y("y:Q", title="Amplitude", axis=alt.Axis(labelFontSize=18, titleFontSize=22)),
37-
tooltip=[alt.Tooltip("x:Q", title="Sample"), alt.Tooltip("y:Q", title="Amplitude", format=".3f")],
73+
x=alt.X("n:Q"),
74+
y=alt.Y("amplitude:Q", title="Amplitude (a.u.)", axis=alt.Axis(labelFontSize=18, titleFontSize=22)),
75+
tooltip=[
76+
alt.Tooltip("n:Q", title="Sample (n)"),
77+
alt.Tooltip("amplitude:Q", title="Amplitude (a.u.)", format=".3f"),
78+
],
3879
)
3980
)
4081

41-
# Create baseline at y=0
42-
baseline = alt.Chart(pd.DataFrame({"y": [0]})).mark_rule(color="#333333", strokeWidth=2).encode(y=alt.Y("y:Q"))
43-
44-
# Combine stems, markers, and baseline
82+
# Compose and apply theme-adaptive chrome
4583
chart = (
46-
(baseline + stems + markers)
84+
(envelope_area + envelope_upper + envelope_lower + baseline_rule + stems + markers)
4785
.properties(
48-
width=1600, height=900, title=alt.Title("stem-basic · altair · pyplots.ai", fontSize=28, anchor="middle")
86+
width=1600,
87+
height=900,
88+
background=PAGE_BG,
89+
title=alt.Title("stem-basic · altair · anyplot.ai", fontSize=28, anchor="middle", color=INK),
90+
)
91+
.configure_view(fill=PAGE_BG, stroke=None)
92+
.configure_axis(
93+
domainColor=INK_SOFT,
94+
tickColor=INK_SOFT,
95+
gridColor=INK,
96+
gridOpacity=0.10,
97+
labelColor=INK_SOFT,
98+
titleColor=INK,
99+
labelFontSize=18,
100+
titleFontSize=22,
49101
)
50-
.configure_axis(labelFontSize=18, titleFontSize=22, grid=True, gridOpacity=0.3, gridDash=[4, 4])
51-
.configure_view(strokeWidth=0)
102+
.configure_axisX(grid=False)
103+
.configure_title(color=INK, fontSize=28)
52104
)
53105

54-
# Save as PNG (scale_factor=3 to get 4800x2700)
55-
chart.save("plot.png", scale_factor=3.0)
56-
57-
# Save as HTML for interactive version
58-
chart.save("plot.html")
106+
# Save
107+
chart.save(f"plot-{THEME}.png", scale_factor=3.0)
108+
chart.save(f"plot-{THEME}.html")
Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,35 @@
1-
""" pyplots.ai
1+
""" anyplot.ai
22
stem-basic: Basic Stem Plot
3-
Library: bokeh 3.8.1 | Python 3.13.11
4-
Quality: 91/100 | Created: 2025-12-23
3+
Library: bokeh 3.9.0 | Python 3.13.13
4+
Quality: 84/100 | Updated: 2026-04-30
55
"""
66

7+
import os
8+
import sys
9+
10+
11+
sys.path = [p for p in sys.path if not p.endswith("/python")]
12+
713
import numpy as np
814
from bokeh.io import export_png, output_file, save
915
from bokeh.models import ColumnDataSource
1016
from bokeh.plotting import figure
1117

1218

19+
# Theme tokens
20+
THEME = os.getenv("ANYPLOT_THEME", "light")
21+
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
22+
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
23+
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
24+
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
25+
BRAND = "#009E73"
26+
1327
# Data - Discrete signal samples (damped oscillation)
1428
np.random.seed(42)
1529
n_points = 30
1630
x = np.arange(n_points)
1731
y = np.exp(-0.1 * x) * np.sin(0.5 * x) * 2 + np.random.randn(n_points) * 0.1
1832

19-
# Baseline for stems
2033
baseline = 0
2134

2235
# Create data sources
@@ -27,39 +40,48 @@
2740
p = figure(
2841
width=4800,
2942
height=2700,
30-
title="stem-basic · bokeh · pyplots.ai",
43+
title="stem-basic · bokeh · anyplot.ai",
3144
x_axis_label="Sample Index",
3245
y_axis_label="Amplitude",
3346
)
3447

3548
# Draw stems (vertical lines from baseline to data points)
36-
p.segment(x0="x0", y0="y0", x1="x1", y1="y1", source=stem_source, line_width=4, color="#306998", alpha=0.8)
49+
p.segment(x0="x0", y0="y0", x1="x1", y1="y1", source=stem_source, line_width=4, color=BRAND, alpha=0.85)
3750

3851
# Draw markers at data points
39-
p.scatter(x="x", y="y", source=source, size=25, color="#306998", alpha=0.9)
52+
p.scatter(x="x", y="y", source=source, size=25, color=BRAND, alpha=1.0)
4053

4154
# Draw baseline
42-
p.line(
43-
x=[x.min() - 0.5, x.max() + 0.5],
44-
y=[baseline, baseline],
45-
line_width=3,
46-
line_dash="dashed",
47-
color="#999999",
48-
alpha=0.6,
49-
)
55+
p.line(x=[x.min() - 0.5, x.max() + 0.5], y=[baseline, baseline], line_width=3, color=INK_SOFT, alpha=0.6)
5056

51-
# Styling for 4800x2700
57+
# Sizing
5258
p.title.text_font_size = "36pt"
5359
p.xaxis.axis_label_text_font_size = "28pt"
5460
p.yaxis.axis_label_text_font_size = "28pt"
5561
p.xaxis.major_label_text_font_size = "22pt"
5662
p.yaxis.major_label_text_font_size = "22pt"
5763

58-
# Grid styling
59-
p.grid.grid_line_alpha = 0.3
60-
p.grid.grid_line_dash = "dashed"
64+
# Theme-adaptive chrome
65+
p.background_fill_color = PAGE_BG
66+
p.border_fill_color = PAGE_BG
67+
p.outline_line_color = INK_SOFT
68+
69+
p.title.text_color = INK
70+
p.xaxis.axis_label_text_color = INK
71+
p.yaxis.axis_label_text_color = INK
72+
p.xaxis.major_label_text_color = INK_SOFT
73+
p.yaxis.major_label_text_color = INK_SOFT
74+
p.xaxis.axis_line_color = INK_SOFT
75+
p.yaxis.axis_line_color = INK_SOFT
76+
p.xaxis.major_tick_line_color = INK_SOFT
77+
p.yaxis.major_tick_line_color = INK_SOFT
78+
79+
p.xgrid.grid_line_color = INK
80+
p.ygrid.grid_line_color = INK
81+
p.xgrid.grid_line_alpha = 0.10
82+
p.ygrid.grid_line_alpha = 0.10
6183

6284
# Save outputs
63-
export_png(p, filename="plot.png")
64-
output_file("plot.html")
85+
export_png(p, filename=f"plot-{THEME}.png")
86+
output_file(f"plot-{THEME}.html")
6587
save(p)
Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,94 @@
1-
""" pyplots.ai
1+
""" anyplot.ai
22
stem-basic: Basic Stem Plot
3-
Library: plotly 6.5.0 | Python 3.13.11
4-
Quality: 93/100 | Created: 2025-12-23
3+
Library: plotly 6.7.0 | Python 3.13.13
4+
Quality: 90/100 | Updated: 2026-04-30
55
"""
66

7+
import os
8+
79
import numpy as np
810
import plotly.graph_objects as go
911

1012

13+
# Theme tokens
14+
THEME = os.getenv("ANYPLOT_THEME", "light")
15+
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
16+
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
17+
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
18+
GRID = "rgba(26,26,23,0.20)" if THEME == "light" else "rgba(240,239,232,0.20)"
19+
BRAND = "#009E73" # Okabe-Ito position 1
20+
1121
# Data - Discrete signal samples (damped oscillation)
1222
np.random.seed(42)
1323
x = np.arange(0, 30)
1424
y = np.exp(-x / 10) * np.cos(x * 0.8) + np.random.randn(30) * 0.05
1525

16-
# Create figure
26+
# Plot
1727
fig = go.Figure()
1828

19-
# Add baseline at y=0
29+
# Baseline at y=0
2030
fig.add_trace(
2131
go.Scatter(
2232
x=[x.min() - 0.5, x.max() + 0.5],
2333
y=[0, 0],
2434
mode="lines",
25-
line={"color": "#333333", "width": 2},
35+
line={"color": INK_SOFT, "width": 2},
2636
showlegend=False,
2737
hoverinfo="skip",
2838
)
2939
)
3040

31-
# Add stems (vertical lines from baseline to data points)
41+
# Stems (vertical lines from baseline to data points)
3242
for xi, yi in zip(x, y, strict=True):
3343
fig.add_trace(
3444
go.Scatter(
35-
x=[xi, xi],
36-
y=[0, yi],
37-
mode="lines",
38-
line={"color": "#306998", "width": 2},
39-
showlegend=False,
40-
hoverinfo="skip",
45+
x=[xi, xi], y=[0, yi], mode="lines", line={"color": BRAND, "width": 2}, showlegend=False, hoverinfo="skip"
4146
)
4247
)
4348

44-
# Add markers at the top of each stem
49+
# Markers at the top of each stem
4550
fig.add_trace(
4651
go.Scatter(
4752
x=x,
4853
y=y,
4954
mode="markers",
50-
marker={"color": "#306998", "size": 16, "line": {"color": "white", "width": 2}},
55+
marker={"color": BRAND, "size": 16, "line": {"color": PAGE_BG, "width": 2}},
5156
showlegend=False,
5257
hovertemplate="Sample: %{x}<br>Amplitude: %{y:.3f}<extra></extra>",
5358
)
5459
)
5560

56-
# Update layout for 4800x2700 px
61+
# Style
5762
fig.update_layout(
58-
title={"text": "stem-basic · plotly · pyplots.ai", "font": {"size": 42}, "x": 0.5, "xanchor": "center"},
63+
paper_bgcolor=PAGE_BG,
64+
plot_bgcolor=PAGE_BG,
65+
font={"color": INK},
66+
title={
67+
"text": "stem-basic · plotly · anyplot.ai",
68+
"font": {"size": 42, "color": INK},
69+
"x": 0.5,
70+
"xanchor": "center",
71+
},
5972
xaxis={
60-
"title": {"text": "Sample Index", "font": {"size": 36}},
61-
"tickfont": {"size": 28},
62-
"gridcolor": "rgba(0,0,0,0.1)",
73+
"title": {"text": "Sample Index (n)", "font": {"size": 36, "color": INK}},
74+
"tickfont": {"size": 28, "color": INK_SOFT},
75+
"gridcolor": GRID,
6376
"gridwidth": 1,
6477
"zeroline": False,
78+
"linecolor": INK_SOFT,
6579
},
6680
yaxis={
67-
"title": {"text": "Amplitude", "font": {"size": 36}},
68-
"tickfont": {"size": 28},
69-
"gridcolor": "rgba(0,0,0,0.1)",
81+
"title": {"text": "Amplitude (a.u.)", "font": {"size": 36, "color": INK}},
82+
"tickfont": {"size": 28, "color": INK_SOFT},
83+
"gridcolor": GRID,
7084
"gridwidth": 1,
7185
"zeroline": False,
86+
"linecolor": INK_SOFT,
7287
},
73-
template="plotly_white",
7488
margin={"l": 120, "r": 60, "t": 130, "b": 110},
7589
showlegend=False,
7690
)
7791

78-
# Save as PNG (4800x2700 px)
79-
fig.write_image("plot.png", width=1600, height=900, scale=3)
80-
81-
# Save interactive HTML
82-
fig.write_html("plot.html")
92+
# Save
93+
fig.write_image(f"plot-{THEME}.png", width=1600, height=900, scale=3)
94+
fig.write_html(f"plot-{THEME}.html", include_plotlyjs="cdn")

0 commit comments

Comments
 (0)