Skip to content

Commit b6155ab

Browse files
authored
allow users to set Kaleido path via envionment variable (#262)
* allow users to set Kaleido path via envionment variable - introduced a new feature to allow users to download Kaleido at compile time when the applications are targeted for the host machine - this can be overriden by the runtime environment variable * add no-sanbox arg to Kaleido process - something fishy is happening in the CI, without this argument empty files are generated because of chromium security issues - print stderr of Kaleido to console Signed-off-by: Andrei Gherghescu <[email protected]>
1 parent ea8d95c commit b6155ab

File tree

8 files changed

+185
-94
lines changed

8 files changed

+185
-94
lines changed

README.md

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
* [Introduction](#introduction)
4141
* [Basic Usage](#basic-usage)
4242
* [Exporting an Interactive Plot](#exporting-an-interactive-plot)
43-
* [Exporting a Static Image](#exporting-a-static-image)
43+
* [Exporting Static Images with Kaleido](#exporting-static-images-with-kaleido)
4444
* [Usage Within a Wasm Environment](#usage-within-a-wasm-environment)
4545
* [Crate Feature Flags](#crate-feature-flags)
4646
* [Contributing](#contributing)
@@ -96,18 +96,38 @@ If you only want to view the plot in the browser quickly, use the `Plot.show()`
9696
plot.show(); // The default web browser will open, displaying an interactive plot
9797
```
9898

99-
## Exporting a Static Image
99+
## Exporting Static Images with Kaleido
100100

101-
To save a plot as a static image, the `kaleido` feature is required:
101+
To save a plot as a static image, the `kaleido` feature is required as well as installing an **external dependency**.
102102

103+
### Kaleido external dependency
104+
105+
When developing applications for your host, enabling both `kaleido` and `kaleido_download` features will ensure that the `kaleido` binary is downloaded for your system's architecture at compile time. After download, it is unpacked into a specific path, e.g., on Linux this is `/home/USERNAME/.config/kaleido`. With these two features enabled, static images can be exported as described in the next section as long as the application run on the same host where where this crate was compiled on.
106+
107+
When the applications developed with `plotly.rs` are intended for other targets or when the user wants to control where the `kaleido` binary is installed then Kaleido must be manually downloaded and installed. Setting the environment variable `KALEIDO_PATH=/path/installed/kaleido/` will ensure that applications that were built with the `kaleido` feature enabled can locate the `kaleido` executable and use it to generate static images.
108+
109+
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`).
110+
111+
## Exporting a Static Images
112+
113+
Enable the `kaleido` feature and opt in for automatic downloading of the `kaleido` binaries by doing the following
114+
115+
```toml
116+
# Cargo.toml
117+
118+
[dependencies]
119+
plotly = { version = "0.11", features = ["kaleido", "kaleido_download"] }
120+
```
121+
122+
Alternatively, enable only the `kaleido` feature and manually install Kaleido.
103123
```toml
104124
# Cargo.toml
105125

106126
[dependencies]
107127
plotly = { version = "0.11", features = ["kaleido"] }
108128
```
109129

110-
With this feature enabled, plots can be saved as any of `png`, `jpeg`, `webp`, `svg`, `pdf` and `eps`. Note that the plot will be a static image, i.e. they will be non-interactive.
130+
With the feature enabled, plots can be saved as any of `png`, `jpeg`, `webp`, `svg`, `pdf` and `eps`. Note that the plot will be a static image, i.e. they will be non-interactive.
111131

112132
Exporting a simple plot looks like this:
113133

@@ -121,12 +141,6 @@ plot.add_trace(trace);
121141
plot.write_image("out.png", ImageFormat::PNG, 800, 600, 1.0);
122142
```
123143

124-
### _Kaleido dependency_
125-
126-
On your host, when building this project with the `kaleido` feature enabled the Kaleido binary is downloaded automatically for your system's architecture at compile time from the official Kaleido [release page](https://github.com/plotly/Kaleido/releases). This library currently supports `x86_64` on Linux and Windows, and both `x86_64` and `aarch64` on macOS.
127-
128-
When building application for other targets that depend on this feature, the `Kaleido` binary will need to be installed manually on the target machine. Currently, the location where the binary is expected is hardcoded depending on the target OS. E.g., on Linux this defaults to `~/.config/kaleido`. This is defined in source code [here](https://github.com/plotly/plotly.rs/blob/1405731b5121c1343b491e307222a21ef4becc5e/plotly_kaleido/src/lib.rs#L89)
129-
130144
## Usage Within a Wasm Environment
131145

132146
Using `Plotly.rs` in a Wasm-based frontend framework is possible by enabling the `wasm` feature:
@@ -198,6 +212,13 @@ The following feature flags are available:
198212

199213
Adds plot save functionality to the following formats: `png`, `jpeg`, `webp`, `svg`, `pdf` and `eps`.
200214

215+
Requires `Kaleido` to have been previously installed on the host machine. See the following feature flag and [Kaleido external dependency](#kaleido-external-dependency).
216+
217+
### `kaleido_download`
218+
219+
Enable download and install of Kaleido binary at build time from [Kaleido releases](https://github.com/plotly/Kaleido/releases/) on the host machine.
220+
See [Kaleido external dependency](#kaleido-external-dependency) for more details.
221+
201222
### `plotly_image`
202223

203224
Adds trait implementations so that `image::RgbImage` and `image::RgbaImage` can be used more directly with the `plotly::Image` trace.

examples/kaleido/Cargo.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
[package]
22
name = "kaleido"
33
version = "0.1.0"
4-
authors = ["Michael Freeborn <[email protected]>"]
4+
authors = [
5+
"Michael Freeborn <[email protected]>",
6+
"Andrei Gherghescu [email protected]",
7+
]
58
edition = "2021"
69

710
[dependencies]
8-
plotly = { path = "../../plotly", features = ["kaleido"] }
11+
plotly = { path = "../../plotly", features = ["kaleido", "kaleido_download"] }

examples/kaleido/src/main.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,21 @@ fn main() {
55
let trace = Scatter::new(vec![0, 1, 2], vec![2, 1, 0]);
66
plot.add_trace(trace);
77

8-
// Adjust these arguments to set the image format, width and height of the
8+
// Adjust these arguments to set the width and height of the
99
// output image.
1010
let filename = "out";
11-
let image_format = ImageFormat::PNG;
1211
let width = 800;
1312
let height = 600;
1413
let scale = 1.0;
1514

1615
// The image will be saved to format!("{filename}.{image_format}") relative to
1716
// the current working directory.
18-
plot.write_image(filename, image_format, width, height, scale);
17+
plot.write_image(filename, ImageFormat::EPS, width, height, scale);
18+
plot.write_image(filename, ImageFormat::JPEG, width, height, scale);
19+
plot.write_image(filename, ImageFormat::PDF, width, height, scale);
20+
plot.write_image(filename, ImageFormat::PNG, width, height, scale);
21+
plot.write_image(filename, ImageFormat::SVG, width, height, scale);
22+
plot.write_image(filename, ImageFormat::WEBP, width, height, scale);
23+
24+
let _svg_string = plot.to_svg(width, height, scale);
1925
}

plotly/Cargo.toml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ exclude = ["target/*"]
1515

1616
[features]
1717
kaleido = ["plotly_kaleido"]
18+
kaleido_download = ["plotly_kaleido/download"]
19+
1820
plotly_ndarray = ["ndarray"]
1921
plotly_image = ["image"]
20-
# Embed JavaScript into library and templates for offline use
2122
plotly_embed_js = []
23+
2224
wasm = ["getrandom", "js-sys", "wasm-bindgen", "wasm-bindgen-futures"]
2325
with-axum = ["rinja/with-axum", "rinja_axum"]
2426

@@ -48,6 +50,8 @@ image = "0.25"
4850
itertools = ">=0.10, <0.14"
4951
itertools-num = "0.1"
5052
ndarray = "0.16"
51-
plotly_kaleido = { version = "0.11", path = "../plotly_kaleido" }
53+
plotly_kaleido = { version = "0.11", path = "../plotly_kaleido", features = [
54+
"download",
55+
] }
5256
rand_distr = "0.4"
5357
base64 = "0.22"

plotly/src/plot.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -749,7 +749,7 @@ mod tests {
749749
assert!(!dst.exists());
750750
}
751751

752-
#[cfg(target_os = "linux")]
752+
#[cfg(not(target_os = "macos"))]
753753
#[test]
754754
#[cfg(feature = "kaleido")]
755755
fn test_save_to_png() {
@@ -761,7 +761,7 @@ mod tests {
761761
assert!(!dst.exists());
762762
}
763763

764-
#[cfg(target_os = "linux")]
764+
#[cfg(not(target_os = "macos"))]
765765
#[test]
766766
#[cfg(feature = "kaleido")]
767767
fn test_save_to_jpeg() {
@@ -773,7 +773,7 @@ mod tests {
773773
assert!(!dst.exists());
774774
}
775775

776-
#[cfg(target_os = "linux")]
776+
#[cfg(not(target_os = "macos"))]
777777
#[test]
778778
#[cfg(feature = "kaleido")]
779779
fn test_save_to_svg() {
@@ -797,7 +797,7 @@ mod tests {
797797
assert!(!dst.exists());
798798
}
799799

800-
#[cfg(target_os = "linux")]
800+
#[cfg(not(target_os = "macos"))]
801801
#[test]
802802
#[cfg(feature = "kaleido")]
803803
fn test_save_to_pdf() {
@@ -809,7 +809,7 @@ mod tests {
809809
assert!(!dst.exists());
810810
}
811811

812-
#[cfg(target_os = "linux")]
812+
#[cfg(not(target_os = "macos"))]
813813
#[test]
814814
#[cfg(feature = "kaleido")]
815815
fn test_save_to_webp() {
@@ -821,8 +821,8 @@ mod tests {
821821
assert!(!dst.exists());
822822
}
823823

824-
#[cfg(target_os = "linux")]
825824
#[test]
825+
#[cfg(not(target_os = "macos"))]
826826
#[cfg(feature = "kaleido")]
827827
fn test_image_to_base64() {
828828
let plot = create_test_plot();
@@ -849,8 +849,8 @@ mod tests {
849849
assert!(image_base64.is_empty());
850850
}
851851

852-
#[cfg(target_os = "linux")]
853852
#[test]
853+
#[cfg(not(target_os = "macos"))]
854854
#[cfg(feature = "kaleido")]
855855
fn test_image_to_svg_string() {
856856
let plot = create_test_plot();

plotly_kaleido/Cargo.toml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
name = "plotly_kaleido"
33
version = "0.11.0"
44
description = "Additional output format support for plotly using Kaleido"
5-
authors = ["Ioannis Giagkiozis <[email protected]>"]
5+
authors = [
6+
"Ioannis Giagkiozis <[email protected]>",
7+
"Andrei Gherghescu [email protected]",
8+
]
69
license = "MIT"
710
readme = "README.md"
811
workspace = ".."
@@ -14,12 +17,17 @@ keywords = ["plot", "chart", "plotly", "ndarray"]
1417

1518
exclude = ["target/*", "kaleido/*", "examples/*"]
1619

20+
[features]
21+
download = []
22+
1723
[dependencies]
1824
serde = { version = "1.0", features = ["derive"] }
1925
serde_json = "1.0"
20-
base64 = "0.22"
2126
dunce = "1.0"
22-
directories = ">=4, <6"
27+
base64 = "0.22"
28+
29+
[dev-dependencies]
30+
plotly_kaleido = { version = "0.11", path = ".", features = ["download"] }
2331

2432
[build-dependencies]
2533
zip = "2.1"

plotly_kaleido/build.rs

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,12 @@ const KALEIDO_URL: &str =
3030
const KALEIDO_URL: &str =
3131
"https://github.com/plotly/Kaleido/releases/download/v0.2.1/kaleido_mac_arm64.zip";
3232

33-
#[cfg(target_os = "linux")]
33+
#[cfg(any(target_os = "linux", target_os = "macos"))]
3434
const KALEIDO_BIN: &str = "kaleido";
3535

3636
#[cfg(target_os = "windows")]
3737
const KALEIDO_BIN: &str = "kaleido.exe";
3838

39-
#[cfg(target_os = "macos")]
40-
const KALEIDO_BIN: &str = "kaleido";
41-
4239
fn extract_zip(p: &Path, zip_file: &Path) -> Result<()> {
4340
let file = fs::File::open(zip_file).unwrap();
4441
let mut archive = zip::ZipArchive::new(file).unwrap();
@@ -95,35 +92,57 @@ fn extract_zip(p: &Path, zip_file: &Path) -> Result<()> {
9592
}
9693

9794
fn main() -> Result<()> {
98-
let project_dirs = ProjectDirs::from("org", "plotly", "kaleido")
99-
.expect("Could not create plotly_kaleido config directory.");
100-
let dst: PathBuf = project_dirs.config_dir().into();
95+
if cfg!(feature = "download") {
96+
let project_dirs = ProjectDirs::from("org", "plotly", "kaleido")
97+
.expect("Could not create Kaleido config directory path.");
98+
let dst: PathBuf = project_dirs.config_dir().into();
99+
100+
let kaleido_binary = dst.join("bin").join(KALEIDO_BIN);
101+
102+
println!("cargo:rerun-if-changed=src/lib.rs");
103+
println!(
104+
"cargo::rerun-if-changed={}",
105+
kaleido_binary.to_string_lossy()
106+
);
107+
108+
println!(
109+
"cargo:rustc-env=KALEIDO_COMPILE_TIME_DLD_PATH={}",
110+
dst.to_string_lossy()
111+
);
112+
113+
if kaleido_binary.exists() {
114+
return Ok(());
115+
}
101116

102-
let kaleido_binary = dst.join("bin").join(KALEIDO_BIN);
103-
if kaleido_binary.exists() {
104-
return Ok(());
117+
let msg = format!(
118+
"Downloaded Plotly Kaleido from {KALEIDO_URL} to '{}'",
119+
dst.to_string_lossy()
120+
);
121+
println!("cargo::warning={msg}");
122+
123+
let p = PathBuf::from(env::var("OUT_DIR").unwrap());
124+
let kaleido_zip_file = p.join("kaleido.zip");
125+
126+
let mut cmd = Command::new("cargo")
127+
.args(["install", "ruget"])
128+
.spawn()
129+
.unwrap();
130+
cmd.wait()?;
131+
132+
let mut cmd = Command::new("ruget")
133+
.args([
134+
KALEIDO_URL,
135+
"-o",
136+
kaleido_zip_file.as_path().to_str().unwrap(),
137+
])
138+
.spawn()
139+
.unwrap();
140+
cmd.wait()?;
141+
142+
extract_zip(&dst, &kaleido_zip_file)?;
143+
} else {
144+
let msg = "'download' feature disabled. Please install Kaleido manually and make the environment variable 'KALEIDO_PATH' point to it.".to_string();
145+
println!("cargo::warning={msg}");
105146
}
106-
107-
let p = PathBuf::from(env::var("OUT_DIR").unwrap());
108-
let kaleido_zip_file = p.join("kaleido.zip");
109-
110-
let mut cmd = Command::new("cargo")
111-
.args(["install", "ruget"])
112-
.spawn()
113-
.unwrap();
114-
cmd.wait()?;
115-
116-
let mut cmd = Command::new("ruget")
117-
.args([
118-
KALEIDO_URL,
119-
"-o",
120-
kaleido_zip_file.as_path().to_str().unwrap(),
121-
])
122-
.spawn()
123-
.unwrap();
124-
cmd.wait()?;
125-
126-
extract_zip(&dst, &kaleido_zip_file)?;
127-
println!("cargo:rerun-if-changed=src/lib.rs");
128147
Ok(())
129148
}

0 commit comments

Comments
 (0)