Skip to content

Commit c925feb

Browse files
chore: merge feature branch with selenium fix
2 parents f5c8a9e + cd127fa commit c925feb

11 files changed

Lines changed: 468 additions & 673 deletions

File tree

.github/workflows/ci-plottest.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ jobs:
6666
echo "📦 Installing: uv sync $EXTRAS"
6767
uv sync $EXTRAS
6868
69-
- name: Setup Chrome for Highcharts
70-
if: steps.detect_libs.outputs.has_plots == 'true' && contains(steps.detect_libs.outputs.libraries, 'highcharts')
69+
- name: Setup Chrome for Selenium-based libraries
70+
if: steps.detect_libs.outputs.has_plots == 'true' && (contains(steps.detect_libs.outputs.libraries, 'highcharts') || contains(steps.detect_libs.outputs.libraries, 'bokeh'))
7171
uses: browser-actions/setup-chrome@v1
7272
with:
7373
chrome-version: stable
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""
2+
area-basic: Basic Area Chart
3+
Library: altair
4+
"""
5+
6+
import altair as alt
7+
import pandas as pd
8+
9+
10+
# Data
11+
data = pd.DataFrame(
12+
{
13+
"month": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
14+
"sales": [100, 150, 130, 180, 200, 220, 195, 240, 260, 230, 280, 310],
15+
}
16+
)
17+
18+
# Create chart with area and line
19+
chart = (
20+
alt.Chart(data)
21+
.mark_area(opacity=0.5, color="#306998", line={"color": "#306998", "strokeWidth": 2})
22+
.encode(
23+
x=alt.X("month:Q", title="Month", axis=alt.Axis(labelFontSize=16, titleFontSize=20)),
24+
y=alt.Y("sales:Q", title="Sales", axis=alt.Axis(labelFontSize=16, titleFontSize=20)),
25+
)
26+
.properties(width=1600, height=900, title=alt.TitleParams(text="Basic Area Chart", fontSize=20))
27+
.configure_view(strokeWidth=0)
28+
.configure_axis(grid=True, gridOpacity=0.3)
29+
)
30+
31+
# Save (1600 × 900 × 3 = 4800 × 2700)
32+
chart.save("plot.png", scale_factor=3.0)
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
"""
2+
area-basic: Basic Area Chart
3+
Library: highcharts
4+
"""
5+
6+
import tempfile
7+
import time
8+
import urllib.request
9+
from pathlib import Path
10+
11+
from highcharts_core.chart import Chart
12+
from highcharts_core.options import HighchartsOptions
13+
from highcharts_core.options.series.area import AreaSeries
14+
from selenium import webdriver
15+
from selenium.webdriver.chrome.options import Options
16+
17+
18+
# Data - Monthly sales example
19+
sales = [100, 150, 130, 180, 200, 220, 195, 240, 280, 310, 290, 350]
20+
21+
# Create chart
22+
chart = Chart(container="container")
23+
chart.options = HighchartsOptions()
24+
25+
# Chart configuration
26+
chart.options.chart = {
27+
"type": "area",
28+
"width": 4800,
29+
"height": 2700,
30+
"backgroundColor": "#ffffff",
31+
"style": {"fontFamily": "Arial, sans-serif"},
32+
}
33+
34+
# Title
35+
chart.options.title = {"text": "Monthly Sales Trend", "style": {"fontSize": "48px"}}
36+
37+
# Axes
38+
chart.options.x_axis = {
39+
"title": {"text": "Month", "style": {"fontSize": "40px"}},
40+
"categories": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
41+
"labels": {"style": {"fontSize": "32px"}},
42+
"gridLineWidth": 1,
43+
"gridLineColor": "rgba(0, 0, 0, 0.1)",
44+
}
45+
46+
chart.options.y_axis = {
47+
"title": {"text": "Sales ($)", "style": {"fontSize": "40px"}},
48+
"labels": {"style": {"fontSize": "32px"}},
49+
"gridLineWidth": 1,
50+
"gridLineColor": "rgba(0, 0, 0, 0.1)",
51+
}
52+
53+
# Legend
54+
chart.options.legend = {"enabled": False}
55+
56+
# Create area series
57+
series = AreaSeries()
58+
series.data = sales
59+
series.name = "Sales"
60+
series.color = "#306998"
61+
series.fill_opacity = 0.5
62+
series.line_width = 4
63+
series.marker = {"enabled": True, "radius": 6, "fillColor": "#306998", "lineWidth": 2, "lineColor": "#ffffff"}
64+
65+
chart.add_series(series)
66+
67+
# Download Highcharts JS
68+
highcharts_url = "https://code.highcharts.com/highcharts.js"
69+
with urllib.request.urlopen(highcharts_url, timeout=30) as response:
70+
highcharts_js = response.read().decode("utf-8")
71+
72+
# Generate HTML with inline scripts
73+
html_str = chart.to_js_literal()
74+
html_content = f"""<!DOCTYPE html>
75+
<html>
76+
<head>
77+
<meta charset="utf-8">
78+
<script>{highcharts_js}</script>
79+
</head>
80+
<body style="margin:0;">
81+
<div id="container" style="width: 4800px; height: 2700px;"></div>
82+
<script>{html_str}</script>
83+
</body>
84+
</html>"""
85+
86+
# Write temp HTML and take screenshot
87+
with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False, encoding="utf-8") as f:
88+
f.write(html_content)
89+
temp_path = f.name
90+
91+
chrome_options = Options()
92+
chrome_options.add_argument("--headless")
93+
chrome_options.add_argument("--no-sandbox")
94+
chrome_options.add_argument("--disable-dev-shm-usage")
95+
chrome_options.add_argument("--disable-gpu")
96+
chrome_options.add_argument("--window-size=4800,2700")
97+
98+
driver = webdriver.Chrome(options=chrome_options)
99+
driver.get(f"file://{temp_path}")
100+
time.sleep(5)
101+
driver.save_screenshot("plot.png")
102+
driver.quit()
103+
104+
Path(temp_path).unlink()
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
"""
2+
area-basic: Basic Area Chart
3+
Library: letsplot
4+
"""
5+
6+
import pandas as pd
7+
from lets_plot import (
8+
LetsPlot,
9+
aes,
10+
element_text,
11+
geom_area,
12+
geom_line,
13+
ggplot,
14+
ggsave,
15+
ggsize,
16+
labs,
17+
scale_x_continuous,
18+
theme,
19+
theme_minimal,
20+
)
21+
22+
23+
LetsPlot.setup_html()
24+
25+
# Data
26+
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
27+
data = pd.DataFrame(
28+
{"month_num": range(len(months)), "sales": [120, 135, 148, 162, 175, 195, 210, 198, 185, 170, 158, 190]}
29+
)
30+
31+
# Plot
32+
plot = (
33+
ggplot(data, aes(x="month_num", y="sales"))
34+
+ geom_area(fill="#306998", alpha=0.5)
35+
+ geom_line(color="#306998", size=2)
36+
+ scale_x_continuous(breaks=list(range(len(months))), labels=months)
37+
+ labs(x="Month", y="Sales", title="Basic Area Chart")
38+
+ theme_minimal()
39+
+ theme(axis_title=element_text(size=20), axis_text=element_text(size=16), plot_title=element_text(size=20))
40+
+ ggsize(1600, 900)
41+
)
42+
43+
# Save - scale 3x to get 4800 × 2700 px
44+
ggsave(plot, "plot.png", path=".", scale=3)
Lines changed: 27 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,126 +1,41 @@
11
"""
22
area-basic: Basic Area Chart
3-
Implementation for: matplotlib
4-
Variant: default
5-
Python: 3.10+
3+
Library: matplotlib
64
"""
75

8-
from typing import TYPE_CHECKING, Optional
9-
106
import matplotlib.pyplot as plt
117
import pandas as pd
128

139

14-
if TYPE_CHECKING:
15-
from matplotlib.figure import Figure
16-
17-
18-
def create_plot(
19-
data: pd.DataFrame,
20-
x: str,
21-
y: str,
22-
color: str = "steelblue",
23-
alpha: float = 0.4,
24-
line_color: Optional[str] = None,
25-
line_width: float = 2.0,
26-
title: Optional[str] = None,
27-
xlabel: Optional[str] = None,
28-
ylabel: Optional[str] = None,
29-
figsize: tuple[float, float] = (16, 9),
30-
**kwargs,
31-
) -> "Figure":
32-
"""
33-
Create a basic area chart showing a filled region between the x-axis and a line.
34-
35-
Args:
36-
data: Input DataFrame with required columns
37-
x: Column name for x-axis values (continuous sequence)
38-
y: Column name for y-axis values (numeric values)
39-
color: Fill color for the area (default: "steelblue")
40-
alpha: Transparency level for the filled area 0.0-1.0 (default: 0.4)
41-
line_color: Color of the top edge line (default: same as fill color)
42-
line_width: Width of the top edge line (default: 2.0)
43-
title: Plot title (default: None)
44-
xlabel: Custom x-axis label (default: column name)
45-
ylabel: Custom y-axis label (default: column name)
46-
figsize: Figure size as (width, height) (default: (16, 9))
47-
**kwargs: Additional parameters passed to ax.fill_between()
48-
49-
Returns:
50-
Matplotlib Figure object
51-
52-
Raises:
53-
ValueError: If data is empty
54-
KeyError: If required columns not found
55-
56-
Example:
57-
>>> data = pd.DataFrame({'Time': [1, 2, 3, 4, 5], 'Value': [10, 25, 15, 30, 20]})
58-
>>> fig = create_plot(data, x='Time', y='Value')
59-
"""
60-
# Input validation
61-
if data.empty:
62-
raise ValueError("Data cannot be empty")
63-
64-
# Check required columns
65-
for col in [x, y]:
66-
if col not in data.columns:
67-
available = ", ".join(data.columns)
68-
raise KeyError(f"Column '{col}' not found. Available: {available}")
69-
70-
# Create figure
71-
fig, ax = plt.subplots(figsize=figsize)
72-
73-
# Get data values
74-
x_values = data[x]
75-
y_values = data[y]
76-
77-
# Determine line color (default to fill color if not specified)
78-
edge_color = line_color if line_color else color
79-
80-
# Plot the filled area
81-
ax.fill_between(x_values, y_values, alpha=alpha, color=color, **kwargs)
82-
83-
# Plot the top edge line for clarity
84-
ax.plot(x_values, y_values, color=edge_color, linewidth=line_width)
85-
86-
# Apply styling
87-
ax.set_xlabel(xlabel or x)
88-
ax.set_ylabel(ylabel or y)
89-
ax.grid(True, alpha=0.3, linestyle="--")
90-
91-
# Title
92-
if title:
93-
ax.set_title(title, fontsize=14, fontweight="bold")
94-
95-
# Tight layout to avoid label clipping
96-
plt.tight_layout()
97-
98-
return fig
10+
# Data - Monthly sales from spec
11+
data = pd.DataFrame(
12+
{
13+
"month": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
14+
"sales": [120, 135, 148, 162, 175, 195, 210, 198, 185, 170, 158, 190],
15+
}
16+
)
9917

18+
# Create plot
19+
fig, ax = plt.subplots(figsize=(16, 9))
10020

101-
if __name__ == "__main__":
102-
# Sample data for testing - simulating monthly website traffic
103-
data = pd.DataFrame(
104-
{
105-
"Month": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
106-
"Visitors": [12000, 15000, 18000, 22000, 25000, 28000, 32000, 30000, 27000, 24000, 20000, 18000],
107-
}
108-
)
21+
# Plot area chart - use numeric x-axis for proper fill_between
22+
x = range(len(data))
23+
ax.fill_between(x, data["sales"], alpha=0.5, color="#306998")
24+
ax.plot(x, data["sales"], color="#306998", linewidth=2)
10925

110-
# For a proper area chart, we need numeric x values
111-
# Convert month names to numeric positions for continuous x-axis
112-
data["Month_Num"] = range(1, 13)
26+
# Set x-tick labels to month names
27+
ax.set_xticks(x)
28+
ax.set_xticklabels(data["month"])
11329

114-
# Create plot
115-
fig = create_plot(
116-
data, x="Month_Num", y="Visitors", title="Monthly Website Traffic", xlabel="Month", ylabel="Number of Visitors"
117-
)
30+
# Labels and styling
31+
ax.set_xlabel("Month", fontsize=20)
32+
ax.set_ylabel("Sales", fontsize=20)
33+
ax.set_title("Monthly Sales Volume", fontsize=20)
34+
ax.tick_params(axis="both", labelsize=16)
35+
ax.grid(True, alpha=0.3, linestyle="--")
11836

119-
# Customize x-ticks to show month names
120-
ax = fig.axes[0]
121-
ax.set_xticks(range(1, 13))
122-
ax.set_xticklabels(data["Month"])
37+
# Set y-axis to start from 0 for proper area representation
38+
ax.set_ylim(bottom=0)
12339

124-
# Save for inspection
125-
plt.savefig("plot.png", dpi=300, bbox_inches="tight")
126-
print("Plot saved to plot.png")
40+
plt.tight_layout()
41+
plt.savefig("plot.png", dpi=300, bbox_inches="tight")

0 commit comments

Comments
 (0)