Skip to content

Commit c00b5be

Browse files
committed
add static export functionality with webdriver
- allow user to reuse the exporter object - use data uri for CDN case and file for offline case when generating the html for static image export - there are size restrictions when using data-uri , webdriver cannot load large data-uri files, so for offline mode, default to using html returned by to_file - added build.rs to download webdriver chromedriver/geckodriver - include example on how to use static export for json data - allow user to set browser capabilities via setter - allow user to configure html2pdf timeout - added documentation and add example for plotly_static - included new static export in plotly crate and marked kaleido as deprecated using deprecation warnings - add extra api to reuse static exporter - refactored usage of imageformat between packages - added custom CI setup for Windows as Windows GitHub Action for chrome setup is unique Signed-off-by: Andrei Gherghescu <[email protected]>
1 parent c19e727 commit c00b5be

38 files changed

+8081
-945
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Windows environment setup for plotly static export tests
2+
# This script sets up Chrome, chromedriver, and environment variables for Windows CI
3+
4+
param(
5+
[string]$ChromeVersion,
6+
[string]$ChromePath,
7+
[string]$ChromeDriverPath
8+
)
9+
10+
Write-Host "=== Setting up Windows environment for static export ==="
11+
12+
# Find chromedriver path
13+
$chromedriverPath = $ChromeDriverPath
14+
if (-not (Test-Path $chromedriverPath)) {
15+
Write-Host "Action output chromedriver path not found, searching for alternatives..."
16+
17+
$commonPaths = @(
18+
"C:\Program Files\Google\Chrome\Application\chromedriver.exe",
19+
"C:\Program Files (x86)\Google\Chrome\Application\chromedriver.exe",
20+
"$env:USERPROFILE\AppData\Local\Google\Chrome\Application\chromedriver.exe",
21+
"$env:PROGRAMFILES\Google\Chrome\Application\chromedriver.exe",
22+
"$env:PROGRAMFILES(X86)\Google\Chrome\Application\chromedriver.exe"
23+
)
24+
25+
foreach ($path in $commonPaths) {
26+
if (Test-Path $path) {
27+
Write-Host "Using chromedriver from: $path"
28+
$chromedriverPath = $path
29+
break
30+
}
31+
}
32+
}
33+
34+
# Find Chrome path
35+
$chromePath = $ChromePath
36+
if (-not (Test-Path $chromePath)) {
37+
# Try the tool cache path first
38+
$toolCachePath = "C:\hostedtoolcache\windows\setup-chrome\chromium\$ChromeVersion\x64\chrome.exe"
39+
if (Test-Path $toolCachePath) {
40+
$chromePath = $toolCachePath
41+
Write-Host "Using Chrome from setup-chrome installation: $chromePath"
42+
} else {
43+
# Fallback: search for Chrome in the tool cache
44+
$toolCacheDir = "C:\hostedtoolcache\windows\setup-chrome\chromium"
45+
if (Test-Path $toolCacheDir) {
46+
$chromeExe = Get-ChildItem -Path $toolCacheDir -Recurse -Name "chrome.exe" | Select-Object -First 1
47+
if ($chromeExe) {
48+
$chromePath = Join-Path $toolCacheDir $chromeExe
49+
Write-Host "Using Chrome from tool cache search: $chromePath"
50+
} else {
51+
$chromePath = "C:\Program Files\Google\Chrome\Application\chrome.exe"
52+
Write-Host "Using system Chrome: $chromePath"
53+
}
54+
} else {
55+
$chromePath = "C:\Program Files\Google\Chrome\Application\chrome.exe"
56+
Write-Host "Using system Chrome: $chromePath"
57+
}
58+
}
59+
}
60+
61+
# Set environment variables
62+
$env:WEBDRIVER_PATH = $chromedriverPath
63+
$env:BROWSER_PATH = $chromePath
64+
$env:RUST_LOG = "debug"
65+
$env:RUST_BACKTRACE = "1"
66+
$env:ANGLE_DEFAULT_PLATFORM = "swiftshader"
67+
68+
Write-Host "Environment variables set:"
69+
Write-Host "WEBDRIVER_PATH: $env:WEBDRIVER_PATH"
70+
Write-Host "BROWSER_PATH: $env:BROWSER_PATH"
71+
Write-Host "RUST_LOG: $env:RUST_LOG"
72+
Write-Host "RUST_BACKTRACE: $env:RUST_BACKTRACE"
73+
74+
# Verify paths exist
75+
if (-not (Test-Path $env:WEBDRIVER_PATH)) {
76+
Write-Error "Chromedriver executable not found at: $env:WEBDRIVER_PATH"
77+
Write-Host "Available chromedriver locations:"
78+
Get-ChildItem -Path "C:\Program Files\Google\Chrome\Application\" -Name "chromedriver*" -ErrorAction SilentlyContinue
79+
Get-ChildItem -Path "C:\Program Files (x86)\Google\Chrome\Application\" -Name "chromedriver*" -ErrorAction SilentlyContinue
80+
exit 1
81+
}
82+
83+
if (-not (Test-Path $env:BROWSER_PATH)) {
84+
Write-Error "Chrome not found at: $env:BROWSER_PATH"
85+
exit 1
86+
}
87+
88+
# Test Chrome version
89+
try {
90+
$chromeVersion = & "$env:BROWSER_PATH" --version 2>&1
91+
Write-Host "Chrome version: $chromeVersion"
92+
} catch {
93+
Write-Host "Failed to get Chrome version: $_"
94+
}
95+
96+
# Test chromedriver version
97+
try {
98+
$chromedriverVersion = & "$env:WEBDRIVER_PATH" --version 2>&1
99+
Write-Host "Chromedriver version: $chromedriverVersion"
100+
} catch {
101+
Write-Host "Failed to get chromedriver version: $_"
102+
}
103+
104+
Write-Host "=== Windows environment setup completed ==="

.github/workflows/ci.yml

Lines changed: 87 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,19 @@ jobs:
3333
runs-on: ubuntu-latest
3434
steps:
3535
- uses: actions/checkout@v4
36+
- name: Setup Chrome
37+
uses: browser-actions/setup-chrome@v1
38+
with:
39+
chrome-version: 'latest'
40+
install-chromedriver: true
3641
- uses: dtolnay/rust-toolchain@stable
3742
with:
3843
components: clippy
3944
targets: wasm32-unknown-unknown
4045
# lint the main library workspace for non-wasm target
41-
- run: cargo clippy --all-features -- -D warnings
46+
- run: cargo clippy --features all -- -D warnings -A deprecated
4247
# lint the non-wasm examples
43-
- run: cd ${{ github.workspace }}/examples && cargo clippy --workspace --exclude "wasm*" -- -D warnings
48+
- run: cd ${{ github.workspace }}/examples && cargo clippy --workspace --exclude "wasm*" --exclude "kaleido" -- -D warnings
4449
# lint the plotly library for wasm target
4550
- run: cargo clippy --package plotly --target wasm32-unknown-unknown -- -D warnings
4651
# lint the wasm examples
@@ -67,12 +72,69 @@ jobs:
6772
matrix:
6873
os: [ubuntu-latest, windows-latest, macos-latest]
6974
runs-on: ${{ matrix.os }}
75+
timeout-minutes: ${{ matrix.os == 'windows-latest' && 30 || 10 }}
7076
steps:
77+
- name: Setup Chrome
78+
uses: browser-actions/setup-chrome@v1
79+
with:
80+
chrome-version: 'latest'
81+
install-chromedriver: true
82+
id: setup-chrome
83+
7184
- uses: actions/checkout@v4
85+
7286
- uses: dtolnay/rust-toolchain@stable
73-
- run: cargo test --features plotly_ndarray,plotly_image,kaleido
74-
- if: ${{ matrix.os == 'windows-latest' }}
75-
run: gci -recurse -filter "*example*"
87+
88+
# Cache cargo registry for all platforms
89+
- name: Cache cargo registry
90+
uses: actions/cache@v4
91+
with:
92+
path: |
93+
~/.cargo/registry/index/
94+
~/.cargo/registry/cache/
95+
~/.cargo/git/db/
96+
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
97+
restore-keys: |
98+
${{ runner.os }}-cargo-registry-
99+
100+
# Windows-specific environment setup for static export tests
101+
- name: Setup Windows environment for static export
102+
if: matrix.os == 'windows-latest'
103+
run: |
104+
.\.github\scripts\setup-windows-static-export.ps1 `
105+
-ChromeVersion "${{ steps.setup-chrome.outputs.chrome-version }}" `
106+
-ChromePath "${{ steps.setup-chrome.outputs.chrome-path }}" `
107+
-ChromeDriverPath "${{ steps.setup-chrome.outputs.chromedriver-path }}"
108+
109+
# Run tests on non-Windows platforms
110+
- name: Run tests (${{ matrix.os }})
111+
if: matrix.os != 'windows-latest'
112+
run: cargo test --verbose --workspace --features plotly_ndarray,plotly_image,static_export_default --exclude plotly_kaleido
113+
114+
# Run tests on Windows with Chrome WebDriver
115+
- name: Run tests (${{ matrix.os }})
116+
if: matrix.os == 'windows-latest'
117+
shell: pwsh
118+
run: |
119+
# Set environment variables for WebDriver
120+
$env:WEBDRIVER_PATH = "${{ steps.setup-chrome.outputs.chromedriver-path }}"
121+
$env:BROWSER_PATH = "${{ steps.setup-chrome.outputs.chrome-path }}"
122+
$env:RUST_LOG = "debug"
123+
$env:RUST_BACKTRACE = "1"
124+
$env:ANGLE_DEFAULT_PLATFORM = "swiftshader"
125+
126+
Write-Host "Environment variables set:"
127+
Write-Host "WEBDRIVER_PATH: $env:WEBDRIVER_PATH"
128+
Write-Host "BROWSER_PATH: $env:BROWSER_PATH"
129+
130+
cargo test --verbose --workspace --features plotly_ndarray,plotly_image,static_export_chromedriver --exclude plotly_kaleido
131+
132+
- name: Upload example.pdf artifact
133+
uses: actions/upload-artifact@v4
134+
with:
135+
name: example-pdf-${{ matrix.os }}
136+
path: ${{ github.workspace }}/plotly_static/example.pdf
137+
retention-days: 30
76138

77139
code-coverage:
78140
name: Code Coverage
@@ -112,6 +174,14 @@ jobs:
112174
runs-on: ubuntu-latest
113175
steps:
114176
- uses: actions/checkout@v4
177+
178+
- name: Setup Chrome (for static_export)
179+
if: matrix.example == 'static_export'
180+
uses: browser-actions/setup-chrome@v1
181+
with:
182+
chrome-version: 'latest'
183+
install-chromedriver: true
184+
115185
- uses: dtolnay/rust-toolchain@stable
116186
- run: cd ${{ github.workspace }}/examples/${{ matrix.example }} && cargo build
117187

@@ -129,11 +199,21 @@ jobs:
129199
targets: wasm32-unknown-unknown
130200
- run: cd ${{ github.workspace }}/examples/wasm-yew/${{ matrix.example }} && cargo build --target wasm32-unknown-unknown
131201

202+
203+
132204
build_book:
133205
name: Build Book
134206
runs-on: ubuntu-latest
135207
steps:
136208
- uses: actions/checkout@v4
209+
210+
- name: Setup Chrome (for static_export)
211+
uses: browser-actions/setup-chrome@v1
212+
with:
213+
chrome-version: 'latest'
214+
install-chromedriver: true
215+
id: setup-chrome
216+
137217
- uses: dtolnay/rust-toolchain@stable
138218
- run: cargo install mdbook --no-default-features --features search --vers "^0.4" --locked --quiet
139219
- name: Build examples to generate needed html files
@@ -146,5 +226,6 @@ jobs:
146226
cd ${{ github.workspace }}/examples/subplots && cargo run
147227
cd ${{ github.workspace }}/examples/shapes && cargo run
148228
cd ${{ github.workspace }}/examples/themes && cargo run
229+
cd ${{ github.workspace }}/examples/static_export && cargo run
149230
- name: Build book
150-
run: mdbook build docs/book
231+
run: mdbook build docs/book

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
[workspace]
22
resolver = "2"
3-
members = ["plotly", "plotly_derive", "plotly_kaleido"]
3+
members = ["plotly", "plotly_derive", "plotly_kaleido", "plotly_static"]

README.md

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ A plotting library for Rust powered by [Plotly.js](https://plot.ly/javascript/).
5353

5454
Documentation and numerous interactive examples are available in the [Plotly.rs Book](https://plotly.github.io/plotly.rs/content/getting_started.html), the [examples/](https://github.com/plotly/plotly.rs/tree/main/examples) directory and [docs.rs](https://docs.rs/crate/plotly).
5555

56-
5756
For changes since the last version, please consult the [changelog](https://github.com/plotly/plotly.rs/tree/main/CHANGELOG.md).
5857

5958
# Basic Usage
@@ -62,7 +61,7 @@ Add this to your `Cargo.toml`:
6261

6362
```toml
6463
[dependencies]
65-
plotly = "0.12"
64+
plotly = "0.13"
6665
```
6766

6867
## Exporting a single Interactive Plot
@@ -108,15 +107,40 @@ When the applications developed with `plotly.rs` are intended for other targets
108107

109108
Kaleido binaries are available on Github [release page](https://github.com/plotly/Kaleido/releases). It currently supports Linux(`x86_64`), Windows(`x86_64`) and MacOS(`x86_64`/`aarch64`).
110109

111-
## Exporting a Static Images
110+
## Exporting Static Images with plotly_static (Recommended)
111+
112+
The recommended way to export static images is using the `plotly_static` backend, which uses a headless browser via WebDriver (Chrome or Firefox) for rendering. This is available via the `static_export_default` feature:
113+
114+
```toml
115+
[dependencies]
116+
plotly = { version = "0.13", features = ["static_export_default"] }
117+
```
118+
119+
This supports PNG, JPEG, WEBP, SVG, and PDF formats:
120+
121+
```rust
122+
use plotly::{Plot, Scatter, ImageFormat};
123+
124+
let mut plot = Plot::new();
125+
plot.add_trace(Scatter::new(vec![0, 1, 2], vec![2, 1, 0]));
126+
127+
plot.write_image("out.png", ImageFormat::PNG, 800, 600, 1.0)?;
128+
plot.write_image("out.svg", ImageFormat::SVG, 800, 600, 1.0)?;
129+
let base64_data = plot.to_base64(ImageFormat::PNG, 800, 600, 1.0)?;
130+
let svg_string = plot.to_svg(800, 600, 1.0)?;
131+
```
132+
133+
**Note:** This feature requires a WebDriver-compatible browser (Chrome or Firefox) as well as a Webdriver (chromedriver/geckodriver) to be available on the system. For advanced usage, see the [`plotly_static` crate documentation](https://docs.rs/plotly_static/).
134+
135+
## Exporting Static Images with Kaleido (to be deprecated)
112136

113137
Enable the `kaleido` feature and opt in for automatic downloading of the `kaleido` binaries by doing the following
114138

115139
```toml
116140
# Cargo.toml
117141

118142
[dependencies]
119-
plotly = { version = "0.12", features = ["kaleido", "kaleido_download"] }
143+
plotly = { version = "0.13", features = ["kaleido", "kaleido_download"] }
120144
```
121145

122146
Alternatively, enable only the `kaleido` feature and manually install Kaleido.

docs/book/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- [ndarray Support](./fundamentals/ndarray_support.md)
88
- [Shapes](./fundamentals/shapes.md)
99
- [Themes](./fundamentals/themes.md)
10+
- [Static Image Export](./fundamentals/static_image_export.md)
1011
- [Recipes](./recipes.md)
1112
- [Basic Charts](./recipes/basic_charts.md)
1213
- [Scatter Plots](./recipes/basic_charts/scatter_plots.md)

docs/book/src/fundamentals.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,12 @@
1818

1919
# Fundamentals
2020

21-
Functionality that applies to the library as a whole is described in the next sections.
21+
Functionality that applies to the library as a whole is described in the next sections.
22+
23+
## Core Features
24+
25+
- **[Jupyter Support](./fundamentals/jupyter_support.md)**: Interactive plotting in Jupyter notebooks
26+
- **[ndarray Support](./fundamentals/ndarray_support.md)**: Integration with the ndarray crate for numerical computing
27+
- **[Shapes](./fundamentals/shapes.md)**: Adding shapes and annotations to plots
28+
- **[Themes](./fundamentals/themes.md)**: Customizing plot appearance with themes
29+
- **[Static Image Export](./fundamentals/static_image_export.md)**: Exporting plots to static images (PNG, JPEG, SVG, PDF) using WebDriver

0 commit comments

Comments
 (0)