Skip to content

Commit 481ea87

Browse files
feat(bokeh): implement area-basic
Add basic area chart implementation for bokeh library using varea glyph. Includes semi-transparent fill, line overlay, and proper grid styling.
1 parent 891065d commit 481ea87

2 files changed

Lines changed: 230 additions & 0 deletions

File tree

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
"""
2+
area-basic: Basic Area Chart
3+
Implementation for: bokeh
4+
Variant: default
5+
Python: 3.10+
6+
"""
7+
8+
from typing import TYPE_CHECKING, Optional
9+
10+
import pandas as pd
11+
from bokeh.models import ColumnDataSource
12+
from bokeh.plotting import figure
13+
14+
15+
if TYPE_CHECKING:
16+
from bokeh.plotting import Figure
17+
18+
19+
def create_plot(
20+
data: pd.DataFrame,
21+
x: str,
22+
y: str,
23+
fill_alpha: float = 0.5,
24+
line_color: Optional[str] = None,
25+
title: Optional[str] = None,
26+
x_label: Optional[str] = None,
27+
y_label: Optional[str] = None,
28+
width: int = 1600,
29+
height: int = 900,
30+
**kwargs,
31+
) -> "Figure":
32+
"""
33+
Create a basic filled area chart using bokeh.
34+
35+
A simple filled area chart showing a single data series over time or
36+
sequential x-values. The area between the data line and the baseline
37+
(zero) is filled with a semi-transparent color.
38+
39+
Args:
40+
data: Input DataFrame with x and y columns
41+
x: Column name for x-axis values
42+
y: Column name for y-axis values
43+
fill_alpha: Transparency of the filled area (default: 0.5)
44+
line_color: Color of the line and fill (default: bokeh blue)
45+
title: Chart title (optional)
46+
x_label: Label for x-axis (optional, defaults to column name)
47+
y_label: Label for y-axis (optional, defaults to column name)
48+
width: Figure width in pixels (default: 1600)
49+
height: Figure height in pixels (default: 900)
50+
**kwargs: Additional parameters passed to figure
51+
52+
Returns:
53+
Bokeh Figure object
54+
55+
Raises:
56+
ValueError: If data is empty or fill_alpha is out of range
57+
KeyError: If required columns not found
58+
59+
Example:
60+
>>> data = pd.DataFrame({
61+
... 'Month': [1, 2, 3, 4, 5, 6],
62+
... 'Sales': [100, 120, 90, 140, 160, 130]
63+
... })
64+
>>> fig = create_plot(data, x='Month', y='Sales', title='Monthly Sales')
65+
"""
66+
# Input validation
67+
if data.empty:
68+
raise ValueError("Data cannot be empty")
69+
70+
for col in [x, y]:
71+
if col not in data.columns:
72+
available = ", ".join(data.columns)
73+
raise KeyError(f"Column '{col}' not found. Available columns: {available}")
74+
75+
if not 0 <= fill_alpha <= 1:
76+
raise ValueError(f"fill_alpha must be between 0 and 1, got {fill_alpha}")
77+
78+
# Set default color (bokeh blue)
79+
color = line_color or "#1f77b4"
80+
81+
# Sort data by x to ensure proper area rendering
82+
plot_data = data[[x, y]].dropna().sort_values(by=x).reset_index(drop=True)
83+
84+
# Create ColumnDataSource
85+
source = ColumnDataSource(data={
86+
"x": plot_data[x],
87+
"y": plot_data[y],
88+
"y0": [0] * len(plot_data),
89+
})
90+
91+
# Create figure
92+
p = figure(
93+
width=width,
94+
height=height,
95+
title=title or "Area Chart",
96+
x_axis_label=x_label or x,
97+
y_axis_label=y_label or y,
98+
toolbar_location="above",
99+
tools="pan,wheel_zoom,box_zoom,reset,save",
100+
**kwargs,
101+
)
102+
103+
# Draw the filled area from baseline (0) to y values
104+
p.varea(
105+
x="x",
106+
y1="y0",
107+
y2="y",
108+
source=source,
109+
fill_color=color,
110+
fill_alpha=fill_alpha,
111+
)
112+
113+
# Draw line on top for better visibility
114+
p.line(
115+
x="x",
116+
y="y",
117+
source=source,
118+
line_color=color,
119+
line_width=2,
120+
)
121+
122+
# Styling
123+
p.title.text_font_size = "14pt"
124+
p.title.align = "center"
125+
126+
# Grid styling - subtle
127+
p.xgrid.grid_line_alpha = 0.3
128+
p.ygrid.grid_line_alpha = 0.3
129+
p.xgrid.grid_line_dash = [6, 4]
130+
p.ygrid.grid_line_dash = [6, 4]
131+
132+
# Axis styling
133+
p.xaxis.axis_label_text_font_size = "12pt"
134+
p.yaxis.axis_label_text_font_size = "12pt"
135+
p.xaxis.major_label_text_font_size = "10pt"
136+
p.yaxis.major_label_text_font_size = "10pt"
137+
138+
return p
139+
140+
141+
if __name__ == "__main__":
142+
import numpy as np
143+
144+
# Sample data: Monthly website traffic over a year
145+
np.random.seed(42)
146+
months = list(range(1, 13))
147+
base_traffic = [1000, 1100, 1050, 1200, 1400, 1600, 1500, 1550, 1700, 1650, 1800, 2000]
148+
noise = np.random.normal(0, 50, 12)
149+
traffic = [max(0, int(b + n)) for b, n in zip(base_traffic, noise, strict=False)]
150+
151+
data = pd.DataFrame({
152+
"Month": months,
153+
"Visitors": traffic,
154+
})
155+
156+
# Create plot
157+
fig = create_plot(
158+
data,
159+
x="Month",
160+
y="Visitors",
161+
title="Monthly Website Traffic",
162+
x_label="Month",
163+
y_label="Visitors (thousands)",
164+
fill_alpha=0.5,
165+
)
166+
167+
# Save as PNG using webdriver-manager for automatic chromedriver
168+
from bokeh.io import export_png
169+
from selenium import webdriver
170+
from selenium.webdriver.chrome.options import Options
171+
from selenium.webdriver.chrome.service import Service
172+
from webdriver_manager.chrome import ChromeDriverManager
173+
174+
chrome_options = Options()
175+
chrome_options.add_argument("--headless")
176+
chrome_options.add_argument("--no-sandbox")
177+
chrome_options.add_argument("--disable-dev-shm-usage")
178+
179+
service = Service(ChromeDriverManager().install())
180+
driver = webdriver.Chrome(service=service, options=chrome_options)
181+
182+
export_png(fig, filename="plot.png", webdriver=driver)
183+
driver.quit()
184+
print("Plot saved to plot.png")

specs/area-basic.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# area-basic: Basic Area Chart
2+
3+
**Spec Version:** 1.0.0
4+
5+
## Description
6+
7+
A simple filled area chart showing a single data series over time or sequential x-values. The area between the data line and the baseline (typically zero) is filled with a semi-transparent color to emphasize the magnitude of values.
8+
9+
## Data Requirements
10+
11+
- **x**: Sequential or time-series values for the x-axis (numeric or datetime)
12+
- **y**: Numeric values to plot on the y-axis
13+
14+
## Optional Parameters
15+
16+
- `fill_alpha`: Transparency of the filled area (type: float, default: 0.5)
17+
- `line_color`: Color of the line and fill (type: str, default: library default)
18+
- `title`: Chart title (type: str, default: None)
19+
- `x_label`: Label for x-axis (type: str, default: column name)
20+
- `y_label`: Label for y-axis (type: str, default: column name)
21+
22+
## Quality Criteria
23+
24+
- [ ] X and Y axes are labeled with meaningful names
25+
- [ ] Grid is visible but subtle (alpha <= 0.5)
26+
- [ ] Area fill is semi-transparent (alpha between 0.3 and 0.7)
27+
- [ ] Line on top of fill area is visible
28+
- [ ] No overlapping axis labels or tick marks
29+
- [ ] Data accurately represented without distortion
30+
- [ ] Figure has appropriate size (16:9 aspect ratio)
31+
32+
## Expected Output
33+
34+
A clean area chart with a filled region between the data line and the x-axis baseline. The fill should be semi-transparent to allow grid lines to show through slightly. The line defining the top of the area should be clearly visible. Axes should be properly labeled, and a subtle grid should aid in reading values.
35+
36+
## Tags
37+
38+
area, trend, time-series, basic, 2d
39+
40+
## Use Cases
41+
42+
- Visualizing website traffic over time
43+
- Showing cumulative sales or revenue trends
44+
- Displaying stock price history with emphasis on magnitude
45+
- Monitoring system resource usage over time
46+
- Tracking temperature or weather data trends

0 commit comments

Comments
 (0)