Skip to content

Commit e18fda8

Browse files
chore: merge selenium fix
2 parents 17e825a + 001ecc1 commit e18fda8

9 files changed

Lines changed: 168 additions & 617 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: 22 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -1,166 +1,35 @@
11
"""
2-
line-basic: Basic Line Chart
2+
line-basic: Basic Line Plot
33
Library: altair
44
"""
55

6-
from typing import TYPE_CHECKING
7-
86
import altair as alt
97
import pandas as pd
108

119

12-
if TYPE_CHECKING:
13-
from altair import Chart
14-
15-
# Style guide colors
16-
PYTHON_BLUE = "#306998"
17-
18-
19-
def create_plot(
20-
data: pd.DataFrame,
21-
x: str,
22-
y: str,
23-
title: str | None = None,
24-
xlabel: str | None = None,
25-
ylabel: str | None = None,
26-
color: str = PYTHON_BLUE,
27-
linewidth: float = 2,
28-
marker: str | None = None,
29-
marker_size: int = 60,
30-
alpha: float = 1.0,
31-
linestyle: str = "solid",
32-
**kwargs,
33-
) -> "Chart":
34-
"""
35-
Create a basic line chart showing trends over a continuous axis.
36-
37-
Args:
38-
data: Input DataFrame with required columns
39-
x: Column name for x-axis values (typically time or sequence)
40-
y: Column name for y-axis values
41-
title: Plot title (default: None)
42-
xlabel: Custom x-axis label (default: uses column name)
43-
ylabel: Custom y-axis label (default: uses column name)
44-
color: Line color (default: Python Blue #306998)
45-
linewidth: Width of the line (default: 2)
46-
marker: Marker style - 'circle', 'square', 'diamond', etc. (default: None)
47-
marker_size: Size of markers if enabled (default: 60)
48-
alpha: Transparency level for the line (default: 1.0)
49-
linestyle: Line style - 'solid', 'dashed', 'dotted' (default: 'solid')
50-
**kwargs: Additional parameters for altair chart configuration
51-
52-
Returns:
53-
Altair Chart object
54-
55-
Raises:
56-
ValueError: If data is empty
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, 150, 130, 180, 200, 190]
63-
... })
64-
>>> chart = create_plot(data, x='month', y='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-
# Sort data by x-axis to ensure proper line connections
76-
plot_data = data.sort_values(by=x).copy()
10+
# Data
11+
data = pd.DataFrame({"time": [1, 2, 3, 4, 5, 6, 7], "value": [10, 15, 13, 18, 22, 19, 25]})
7712

78-
# Determine x encoding type based on data
79-
x_dtype = plot_data[x].dtype
80-
if pd.api.types.is_datetime64_any_dtype(x_dtype):
81-
x_encoding = f"{x}:T"
82-
else:
83-
x_encoding = f"{x}:Q"
84-
85-
# Map linestyle to altair strokeDash
86-
stroke_dash_map = {"solid": [], "dashed": [8, 4], "dotted": [2, 2]}
87-
stroke_dash = stroke_dash_map.get(linestyle, [])
88-
89-
# Create the line chart
90-
line = (
91-
alt.Chart(plot_data)
92-
.mark_line(color=color, strokeWidth=linewidth, opacity=alpha, strokeDash=stroke_dash)
93-
.encode(
94-
x=alt.X(
95-
x_encoding,
96-
title=xlabel or x,
97-
axis=alt.Axis(labelAngle=0, labelLimit=200, labelFontSize=16, titleFontSize=20),
98-
),
99-
y=alt.Y(
100-
f"{y}:Q",
101-
title=ylabel or y,
102-
scale=alt.Scale(zero=False),
103-
axis=alt.Axis(labelFontSize=16, titleFontSize=20),
104-
),
105-
tooltip=[
106-
alt.Tooltip(x_encoding, title=xlabel or x),
107-
alt.Tooltip(f"{y}:Q", title=ylabel or y, format=".2f"),
108-
],
109-
)
110-
)
111-
112-
# Add markers if specified
113-
if marker:
114-
points = (
115-
alt.Chart(plot_data)
116-
.mark_point(color=color, size=marker_size, filled=True, shape=marker, opacity=alpha)
117-
.encode(
118-
x=alt.X(x_encoding),
119-
y=alt.Y(f"{y}:Q"),
120-
tooltip=[
121-
alt.Tooltip(x_encoding, title=xlabel or x),
122-
alt.Tooltip(f"{y}:Q", title=ylabel or y, format=".2f"),
123-
],
124-
)
125-
)
126-
chart_base = line + points
127-
else:
128-
chart_base = line
129-
130-
# Apply properties and configuration
131-
# Target: 4800 × 2700 px with scale_factor=3.0 -> 1600 × 900 base
132-
title_config = alt.TitleParams(text=title, fontSize=20, anchor="middle") if title else None
133-
chart = (
134-
chart_base.properties(width=1600, height=900, title=title_config)
135-
.configure_view(strokeWidth=0)
136-
.configure_axis(grid=True, gridOpacity=0.3, gridDash=[3, 3], domainWidth=1, tickWidth=1)
13+
# Create line chart
14+
line = (
15+
alt.Chart(data)
16+
.mark_line(strokeWidth=2, color="#306998")
17+
.encode(
18+
x=alt.X("time:Q", title="Time", axis=alt.Axis(labelFontSize=16, titleFontSize=20)),
19+
y=alt.Y("value:Q", title="Value", axis=alt.Axis(labelFontSize=16, titleFontSize=20)),
13720
)
21+
)
13822

139-
return chart
23+
# Add points on the line for clarity
24+
points = alt.Chart(data).mark_point(size=100, color="#306998", filled=True).encode(x="time:Q", y="value:Q")
14025

26+
# Combine and configure chart
27+
chart = (
28+
(line + points)
29+
.properties(width=1600, height=900, title=alt.Title("Basic Line Plot", fontSize=20))
30+
.configure_view(strokeWidth=0)
31+
.configure_axis(grid=True, gridOpacity=0.3)
32+
)
14133

142-
if __name__ == "__main__":
143-
# Sample data for testing - monthly sales trend
144-
sample_data = pd.DataFrame(
145-
{
146-
"Month": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
147-
"Sales": [120, 150, 170, 165, 180, 220, 250, 240, 210, 190, 180, 200],
148-
}
149-
)
150-
151-
# Create plot with markers
152-
chart = create_plot(
153-
sample_data,
154-
x="Month",
155-
y="Sales",
156-
title="Monthly Sales Trend (2024)",
157-
xlabel="Month",
158-
ylabel="Sales (thousands)",
159-
linewidth=2.5,
160-
marker="circle",
161-
marker_size=80,
162-
)
163-
164-
# Save as PNG - scale_factor=3.0 gives 4800 × 2700 px
165-
chart.save("plot.png", scale_factor=3.0)
166-
print("Plot saved to plot.png")
34+
# Save as PNG (1600 × 900 at scale 3 = 4800 × 2700 px)
35+
chart.save("plot.png", scale_factor=3.0)

plots/highcharts/line/line-basic/default.py

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
Library: highcharts
44
"""
55

6-
import json
76
import tempfile
87
import time
98
import urllib.request
@@ -18,9 +17,9 @@
1817

1918
# Data
2019
time_values = ["1", "2", "3", "4", "5", "6", "7"]
21-
values = [10, 15, 13, 18, 22, 19, 25]
20+
value_data = [10, 15, 13, 18, 22, 19, 25]
2221

23-
# Create chart with container
22+
# Create chart
2423
chart = Chart(container="container")
2524
chart.options = HighchartsOptions()
2625

@@ -39,43 +38,38 @@
3938
# Axes
4039
chart.options.x_axis = {
4140
"title": {"text": "Time", "style": {"fontSize": "40px"}},
42-
"labels": {"style": {"fontSize": "32px"}, "enabled": True},
4341
"categories": time_values,
44-
"gridLineWidth": 1,
45-
"gridLineColor": "#e0e0e0",
42+
"labels": {"style": {"fontSize": "32px"}},
4643
"lineWidth": 2,
4744
"tickWidth": 2,
4845
}
4946
chart.options.y_axis = {
5047
"title": {"text": "Value", "style": {"fontSize": "40px"}},
5148
"labels": {"style": {"fontSize": "32px"}},
49+
"gridLineWidth": 1,
5250
"gridLineColor": "#e0e0e0",
53-
"lineWidth": 2,
5451
}
5552

56-
# Legend (not needed for single series)
53+
# Legend
5754
chart.options.legend = {"enabled": False}
5855

59-
# Disable credits
60-
chart.options.credits = {"enabled": False}
61-
62-
# Create and add series
56+
# Create series
6357
series = LineSeries()
64-
series.data = values
58+
series.data = value_data
6559
series.name = "Value"
6660
series.color = "#306998"
67-
series.marker = {"enabled": True, "radius": 8, "fillColor": "#306998"}
6861
series.line_width = 4
62+
series.marker = {"enabled": True, "radius": 8, "fillColor": "#306998"}
6963

7064
chart.add_series(series)
7165

72-
# Download Highcharts JS for inline embedding
66+
# Download Highcharts JS for headless Chrome
7367
highcharts_url = "https://code.highcharts.com/highcharts.js"
7468
with urllib.request.urlopen(highcharts_url, timeout=30) as response:
7569
highcharts_js = response.read().decode("utf-8")
7670

77-
# Generate HTML with inline scripts using JSON approach for reliability
78-
opts_json = json.dumps(chart.options.to_dict())
71+
# Generate HTML with inline scripts
72+
html_str = chart.to_js_literal()
7973
html_content = f"""<!DOCTYPE html>
8074
<html>
8175
<head>
@@ -84,9 +78,7 @@
8478
</head>
8579
<body style="margin:0;">
8680
<div id="container" style="width: 4800px; height: 2700px;"></div>
87-
<script>
88-
Highcharts.chart('container', {opts_json});
89-
</script>
81+
<script>{html_str}</script>
9082
</body>
9183
</html>"""
9284

@@ -100,15 +92,12 @@
10092
chrome_options.add_argument("--no-sandbox")
10193
chrome_options.add_argument("--disable-dev-shm-usage")
10294
chrome_options.add_argument("--disable-gpu")
103-
chrome_options.add_argument("--window-size=4800,2800")
95+
chrome_options.add_argument("--window-size=4800,2700")
10496

10597
driver = webdriver.Chrome(options=chrome_options)
10698
driver.get(f"file://{temp_path}")
10799
time.sleep(5)
108-
109-
# Take screenshot of just the chart container element
110-
container = driver.find_element("id", "container")
111-
container.screenshot("plot.png")
100+
driver.save_screenshot("plot.png")
112101
driver.quit()
113102

114103
Path(temp_path).unlink()

plots/letsplot/line/line-basic/default.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from lets_plot import (
88
LetsPlot,
99
aes,
10-
element_line,
1110
element_text,
1211
geom_line,
1312
geom_point,
@@ -28,17 +27,11 @@
2827
# Plot
2928
plot = (
3029
ggplot(data, aes(x="time", y="value"))
31-
+ geom_line(color="#306998", size=2, alpha=1.0)
32-
+ geom_point(color="#306998", size=4, alpha=1.0)
30+
+ geom_line(color="#306998", size=2)
31+
+ geom_point(color="#306998", size=4)
3332
+ labs(x="Time", y="Value", title="Basic Line Plot")
3433
+ theme_minimal()
35-
+ theme(
36-
plot_title=element_text(size=20, face="bold"),
37-
axis_title=element_text(size=20),
38-
axis_text=element_text(size=16),
39-
panel_grid_major=element_line(color="#CCCCCC", size=0.5),
40-
panel_grid_minor=element_line(color="#EEEEEE", size=0.3),
41-
)
34+
+ theme(plot_title=element_text(size=20), axis_title=element_text(size=20), axis_text=element_text(size=16))
4235
+ ggsize(1600, 900)
4336
)
4437

plots/matplotlib/plot/line-basic/default.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
# Data
1111
data = pd.DataFrame({"time": [1, 2, 3, 4, 5, 6, 7], "value": [10, 15, 13, 18, 22, 19, 25]})
1212

13-
# Plot
13+
# Create plot
1414
fig, ax = plt.subplots(figsize=(16, 9))
15-
ax.plot(data["time"], data["value"], color="#306998", linewidth=2, marker="o", markersize=6)
15+
ax.plot(data["time"], data["value"], linewidth=2, color="#306998", marker="o", markersize=8)
1616

1717
# Labels and styling
1818
ax.set_xlabel("Time", fontsize=20)

0 commit comments

Comments
 (0)