Skip to content

Commit 12e6264

Browse files
feat(highcharts): implement line-basic
Add basic line chart implementation for highcharts library. Creates spec file and default.py implementation.
1 parent 58567b5 commit 12e6264

2 files changed

Lines changed: 339 additions & 0 deletions

File tree

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
"""
2+
line-basic: Basic Line Chart
3+
Implementation for: highcharts
4+
Variant: default
5+
Python: 3.10+
6+
7+
Note: Highcharts requires a license for commercial use.
8+
"""
9+
10+
from typing import Optional
11+
12+
import numpy as np
13+
import pandas as pd
14+
from highcharts_core.chart import Chart
15+
from highcharts_core.options import HighchartsOptions
16+
from highcharts_core.options.series.area import LineSeries
17+
18+
19+
def create_plot(
20+
data: pd.DataFrame,
21+
x: str,
22+
y: str,
23+
color: str = "#4A90D9",
24+
linewidth: float = 2.0,
25+
marker: Optional[str] = None,
26+
marker_size: float = 6,
27+
alpha: float = 1.0,
28+
title: Optional[str] = None,
29+
xlabel: Optional[str] = None,
30+
ylabel: Optional[str] = None,
31+
width: int = 1600,
32+
height: int = 900,
33+
**kwargs,
34+
) -> Chart:
35+
"""
36+
Create a basic line chart connecting data points in order using Highcharts.
37+
38+
Args:
39+
data: Input DataFrame with required columns
40+
x: Column name for x-axis values (numeric or categorical)
41+
y: Column name for y-axis values (numeric)
42+
color: Line color (default: "#4A90D9" - a pleasant blue)
43+
linewidth: Line thickness in pixels (default: 2.0)
44+
marker: Marker style at data points, e.g., 'circle', 'square' (default: None)
45+
marker_size: Size of markers if shown (default: 6)
46+
alpha: Line transparency 0.0-1.0 (default: 1.0)
47+
title: Plot title (optional)
48+
xlabel: Custom x-axis label (optional, defaults to x column name)
49+
ylabel: Custom y-axis label (optional, defaults to y column name)
50+
width: Figure width in pixels (default: 1600)
51+
height: Figure height in pixels (default: 900)
52+
**kwargs: Additional parameters for Highcharts configuration
53+
54+
Returns:
55+
Highcharts Chart object
56+
57+
Raises:
58+
ValueError: If data is empty
59+
KeyError: If required columns not found
60+
61+
Example:
62+
>>> data = pd.DataFrame({
63+
... 'Month': ['Jan', 'Feb', 'Mar', 'Apr', 'May'],
64+
... 'Sales': [100, 120, 115, 140, 160]
65+
... })
66+
>>> chart = create_plot(data, x='Month', y='Sales')
67+
"""
68+
# Input validation
69+
if data.empty:
70+
raise ValueError("Data cannot be empty")
71+
72+
# Check required columns
73+
for col in [x, y]:
74+
if col not in data.columns:
75+
available = ", ".join(data.columns)
76+
raise KeyError(f"Column '{col}' not found. Available columns: {available}")
77+
78+
# Prepare data
79+
x_values = data[x].tolist()
80+
y_values = data[y].tolist()
81+
82+
# Determine if x-axis is categorical or numeric
83+
x_is_categorical = not pd.api.types.is_numeric_dtype(data[x])
84+
85+
# Create chart
86+
chart = Chart()
87+
88+
# Configure chart options
89+
chart.options = HighchartsOptions()
90+
91+
# Title
92+
chart.options.title = {
93+
"text": title if title else None,
94+
"style": {"fontSize": "16px", "fontWeight": "bold"},
95+
}
96+
97+
# X-axis configuration
98+
if x_is_categorical:
99+
chart.options.x_axis = {
100+
"categories": x_values,
101+
"title": {
102+
"text": xlabel or x,
103+
"style": {"fontSize": "12px"},
104+
},
105+
"labels": {"style": {"fontSize": "11px"}},
106+
"gridLineWidth": 1,
107+
"gridLineDashStyle": "Dot",
108+
"gridLineColor": "rgba(0, 0, 0, 0.1)",
109+
}
110+
else:
111+
chart.options.x_axis = {
112+
"title": {
113+
"text": xlabel or x,
114+
"style": {"fontSize": "12px"},
115+
},
116+
"labels": {"style": {"fontSize": "11px"}},
117+
"gridLineWidth": 1,
118+
"gridLineDashStyle": "Dot",
119+
"gridLineColor": "rgba(0, 0, 0, 0.1)",
120+
}
121+
122+
# Y-axis configuration
123+
chart.options.y_axis = {
124+
"title": {
125+
"text": ylabel or y,
126+
"style": {"fontSize": "12px"},
127+
},
128+
"labels": {"style": {"fontSize": "11px"}},
129+
"gridLineWidth": 1,
130+
"gridLineDashStyle": "Dot",
131+
"gridLineColor": "rgba(0, 0, 0, 0.3)",
132+
}
133+
134+
# Chart dimensions and background
135+
chart.options.chart = {
136+
"type": "line",
137+
"width": width,
138+
"height": height,
139+
"backgroundColor": "white",
140+
}
141+
142+
# Plot options for line series
143+
plot_options: dict = {
144+
"line": {
145+
"lineWidth": linewidth,
146+
"connectNulls": False,
147+
"animation": False,
148+
}
149+
}
150+
151+
# Handle marker configuration
152+
if marker:
153+
marker_config: dict = {
154+
"enabled": True,
155+
"radius": marker_size,
156+
"symbol": marker,
157+
}
158+
plot_options["line"]["marker"] = marker_config
159+
else:
160+
plot_options["line"]["marker"] = {"enabled": False}
161+
162+
chart.options.plot_options = plot_options
163+
164+
# Tooltip configuration
165+
chart.options.tooltip = {
166+
"shared": False,
167+
"useHTML": True,
168+
"headerFormat": "<b>{point.key}</b><br/>",
169+
"pointFormat": f"{ylabel or y}: <b>{{point.y:.2f}}</b>",
170+
}
171+
172+
# Create line series
173+
line_series = LineSeries()
174+
175+
# Set data based on x-axis type
176+
if x_is_categorical:
177+
line_series.data = y_values
178+
else:
179+
line_series.data = list(zip(x_values, y_values, strict=False))
180+
181+
line_series.name = ylabel or y
182+
183+
# Apply color with alpha
184+
if alpha < 1.0:
185+
# Convert hex color to rgba
186+
if color.startswith("#"):
187+
r = int(color[1:3], 16)
188+
g = int(color[3:5], 16)
189+
b = int(color[5:7], 16)
190+
line_series.color = f"rgba({r}, {g}, {b}, {alpha})"
191+
else:
192+
line_series.color = color
193+
else:
194+
line_series.color = color
195+
196+
chart.add_series(line_series)
197+
198+
# Legend (hide for single series)
199+
chart.options.legend = {"enabled": False}
200+
201+
# Disable credits
202+
chart.options.credits = {"enabled": False}
203+
204+
return chart
205+
206+
207+
if __name__ == "__main__":
208+
# Sample data for testing - simulating monthly sales data
209+
np.random.seed(42)
210+
211+
# Create sample data with 12 months
212+
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
213+
214+
# Generate realistic sales trend with some variation
215+
base_sales = 100
216+
trend = np.linspace(0, 50, 12) # Upward trend
217+
seasonal = 15 * np.sin(np.linspace(0, 2 * np.pi, 12)) # Seasonal variation
218+
noise = np.random.normal(0, 5, 12) # Random noise
219+
sales = base_sales + trend + seasonal + noise
220+
221+
data = pd.DataFrame({"Month": months, "Sales": sales.round(1)})
222+
223+
# Create plot
224+
chart = create_plot(
225+
data,
226+
x="Month",
227+
y="Sales",
228+
title="Monthly Sales Performance",
229+
xlabel="Month",
230+
ylabel="Sales ($K)",
231+
color="#4A90D9",
232+
linewidth=2.5,
233+
)
234+
235+
# Export to PNG via Selenium screenshot
236+
import tempfile
237+
import time
238+
from pathlib import Path
239+
240+
from selenium import webdriver
241+
from selenium.webdriver.chrome.options import Options
242+
243+
# Generate HTML content
244+
html_str = chart.to_js_literal()
245+
html_content = f"""<!DOCTYPE html>
246+
<html>
247+
<head>
248+
<meta charset="utf-8">
249+
<script src="https://code.highcharts.com/highcharts.js"></script>
250+
</head>
251+
<body style="margin:0;">
252+
<div id="container" style="width: 1600px; height: 900px;"></div>
253+
<script>{html_str}</script>
254+
</body>
255+
</html>"""
256+
257+
# Write temp HTML and take screenshot
258+
with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False) as f:
259+
f.write(html_content)
260+
temp_path = f.name
261+
262+
chrome_options = Options()
263+
chrome_options.add_argument("--headless")
264+
chrome_options.add_argument("--no-sandbox")
265+
chrome_options.add_argument("--disable-dev-shm-usage")
266+
chrome_options.add_argument("--window-size=1600,900")
267+
268+
driver = webdriver.Chrome(options=chrome_options)
269+
driver.get(f"file://{temp_path}")
270+
time.sleep(1) # Wait for chart to render
271+
driver.save_screenshot("plot.png")
272+
driver.quit()
273+
274+
Path(temp_path).unlink() # Clean up temp file
275+
print("Plot saved to plot.png")

specs/line-basic.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# line-basic: Basic Line Chart
2+
3+
<!--
4+
Spec Template Version: 1.0.0
5+
Created: 2025-12-01
6+
Last Updated: 2025-12-01
7+
-->
8+
9+
**Spec Version:** 1.0.0
10+
11+
## Description
12+
13+
Create a simple line chart connecting data points in order, ideal for showing trends and continuous data over a sequence.
14+
Perfect for visualizing time series data, tracking changes over intervals, and displaying relationships between ordered data points.
15+
Works with any dataset containing sequential x-values (numeric or categorical) and corresponding y-values.
16+
17+
## Data Requirements
18+
19+
- **x**: Sequential values for the x-axis (numeric or categorical: represents order, time, or sequence index)
20+
- **y**: Numeric values for the y-axis (numeric: continuous values to be plotted)
21+
22+
## Optional Parameters
23+
24+
- `color`: Line color (type: string, default: "steelblue")
25+
- `linewidth`: Line thickness (type: float, default: 2.0)
26+
- `marker`: Marker style at data points (type: string or None, default: None)
27+
- `marker_size`: Size of markers if shown (type: float, default: 6)
28+
- `alpha`: Line transparency (type: float 0.0-1.0, default: 1.0)
29+
- `title`: Plot title (type: string, default: None)
30+
- `xlabel`: Custom x-axis label (type: string, default: column name)
31+
- `ylabel`: Custom y-axis label (type: string, default: column name)
32+
- `figsize`: Figure size (type: tuple, default: (10, 6))
33+
34+
## Quality Criteria
35+
36+
- [ ] X and Y axes are labeled with column names (or custom labels if provided)
37+
- [ ] Grid is visible but subtle with alpha=0.3
38+
- [ ] Line is clearly visible with appropriate width (minimum 1.5px)
39+
- [ ] No overlapping axis labels or tick marks
40+
- [ ] Appropriate figure size (10x6 inches default) for readability
41+
- [ ] Title is centered and clearly readable if provided (fontsize 14, bold)
42+
- [ ] Data points are connected in correct order
43+
- [ ] Line color provides good contrast against white background
44+
45+
## Expected Output
46+
47+
A clean line chart with a single line connecting data points in sequence.
48+
The plot should clearly show the trend or pattern in the data.
49+
Grid lines should help with reading values without overpowering the data.
50+
The x-axis should show the sequence values and the y-axis should show the corresponding numeric values.
51+
All text elements (labels, title, and tick labels) should be legible at standard display sizes.
52+
53+
## Tags
54+
55+
line, trend, timeseries, basic, sequential, continuous, exploratory
56+
57+
## Use Cases
58+
59+
- Stock price movement over time (e.g., daily closing prices)
60+
- Temperature changes throughout the day (e.g., hourly readings)
61+
- Website traffic over time (e.g., daily page views)
62+
- Sales performance tracking (e.g., monthly revenue)
63+
- Sensor data visualization (e.g., continuous measurements)
64+
- Progress tracking (e.g., project completion over weeks)

0 commit comments

Comments
 (0)