Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 57 additions & 24 deletions plots/span-basic/implementations/python/bokeh.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
""" pyplots.ai
""" anyplot.ai
span-basic: Basic Span Plot (Highlighted Region)
Library: bokeh 3.8.1 | Python 3.13.11
Quality: 92/100 | Created: 2025-12-23
Library: bokeh 3.9.0 | Python 3.13.13
Quality: 89/100 | Updated: 2026-04-30
"""

import os

import numpy as np
from bokeh.io import export_png, output_file, save
from bokeh.models import BoxAnnotation, ColumnDataSource, Label
from bokeh.models import BoxAnnotation, ColumnDataSource, HoverTool, Label
from bokeh.plotting import figure


# Theme tokens
THEME = os.getenv("ANYPLOT_THEME", "light")
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
BRAND = "#009E73" # Okabe-Ito position 1 — always first series

# Data - Monthly revenue over 2 years with spans highlighting key periods
np.random.seed(42)
months = np.arange(1, 25)
Expand All @@ -24,56 +34,79 @@
p = figure(
width=4800,
height=2700,
title="span-basic · bokeh · pyplots.ai",
title="span-basic · bokeh · anyplot.ai",
x_axis_label="Month",
y_axis_label="Revenue (thousands $)",
)

# Add vertical span - highlight Q4 of Year 1 (months 10-12)
vertical_span = BoxAnnotation(
left=10, right=12, fill_alpha=0.25, fill_color="#306998", line_color="#306998", line_width=2, line_alpha=0.5
left=10, right=12, fill_alpha=0.25, fill_color="#0072B2", line_color="#0072B2", line_width=2, line_alpha=0.5
)
p.add_layout(vertical_span)

# Add horizontal span - highlight target revenue range (120-140)
horizontal_span = BoxAnnotation(
bottom=120, top=140, fill_alpha=0.2, fill_color="#FFD43B", line_color="#FFD43B", line_width=2, line_alpha=0.5
bottom=120, top=140, fill_alpha=0.2, fill_color="#E69F00", line_color="#E69F00", line_width=2, line_alpha=0.5
)
p.add_layout(horizontal_span)

# Plot line with markers
p.line(x="x", y="y", source=source, line_width=4, line_color="#306998", legend_label="Monthly Revenue")
p.scatter(x="x", y="y", source=source, size=16, fill_color="#306998", line_color="white", line_width=2)
# Plot line with markers (Okabe-Ito position 1)
p.line(x="x", y="y", source=source, line_width=4, line_color=BRAND, legend_label="Monthly Revenue")
p.scatter(x="x", y="y", source=source, size=20, fill_color=BRAND, line_color=PAGE_BG, line_width=2)

# HoverTool — showcases Bokeh's interactive HTML output
hover = HoverTool(tooltips=[("Month", "@x"), ("Revenue", "@y{0.1} K$")])
p.add_tools(hover)

# Add labels for spans
# Add labels for spans — positioned prominently at top of each span
vertical_label = Label(
x=10.2, y=102, text="Q4 Peak Season", text_font_size="24pt", text_color="#1a4d7c", text_font_style="bold"
x=10.2, y=143, text="Q4 Peak Season", text_font_size="28pt", text_color="#0072B2", text_font_style="bold"
)
p.add_layout(vertical_label)

horizontal_label = Label(
x=17, y=125, text="Target Range", text_font_size="28pt", text_color="#B8860B", text_font_style="bold"
x=17,
y=124,
text="Target Range",
text_font_size="28pt",
text_color="#B8720B" if THEME == "light" else "#E69F00",
text_font_style="bold",
)
p.add_layout(horizontal_label)

# Style text sizes for 4800x2700 px
# Apply theme-adaptive chrome
p.background_fill_color = PAGE_BG
p.border_fill_color = PAGE_BG
p.outline_line_color = None # remove box border; L-shaped spines via xaxis/yaxis lines only

p.title.text_color = INK
p.title.text_font_size = "48pt"
p.xaxis.axis_label_text_color = INK
p.yaxis.axis_label_text_color = INK
p.xaxis.axis_label_text_font_size = "36pt"
p.yaxis.axis_label_text_font_size = "36pt"
p.xaxis.major_label_text_color = INK_SOFT
p.yaxis.major_label_text_color = INK_SOFT
p.xaxis.major_label_text_font_size = "28pt"
p.yaxis.major_label_text_font_size = "28pt"
p.xaxis.axis_line_color = INK_SOFT
p.yaxis.axis_line_color = INK_SOFT
p.xaxis.major_tick_line_color = INK_SOFT
p.yaxis.major_tick_line_color = INK_SOFT

# Grid styling
p.grid.grid_line_alpha = 0.3
p.grid.grid_line_dash = "dashed"
p.xgrid.grid_line_color = None # y-only grid preferred for line charts
p.ygrid.grid_line_color = INK
p.ygrid.grid_line_alpha = 0.10

# Legend styling
# Legend — top-left for better visual balance
p.legend.label_text_font_size = "28pt"
p.legend.location = "bottom_right"
p.legend.background_fill_alpha = 0.7

# Save as PNG and HTML
export_png(p, filename="plot.png")
p.legend.location = "top_left"
p.legend.background_fill_color = ELEVATED_BG
p.legend.border_line_color = INK_SOFT
p.legend.label_text_color = INK_SOFT

output_file("plot.html")
# Save
export_png(p, filename=f"plot-{THEME}.png")
output_file(f"plot-{THEME}.html")
save(p)
Loading
Loading