Skip to content

Commit a7ac37d

Browse files
authored
Add macOS-specific fixes and tests for Kaleido compatibility (#289)
* add macOS-specific fixes and tests for Kaleido compatibility Introduce macOS-specific arguments for Kaleido to address issue #323. Add new tests to validate image generation (e.g., PNG, JPEG, SVG, PDF) on macOS, ensuring proper functionality. This improves cross-platform support and resolves inconsistencies in the Kaleido backend. * Add macOS-specific test surface creation and adjust imports Introduced a macOS-specific `create_test_surface` function in `plotly_kaleido` and adjusted test-related imports in `plotly`. Ensures compatibility with macOS while keeping non-macOS logic intact. * Refactor imports in plot.rs tests for macOS compatibility issue: #241
1 parent b05315f commit a7ac37d

File tree

2 files changed

+167
-14
lines changed

2 files changed

+167
-14
lines changed

plotly/src/plot.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -586,9 +586,9 @@ impl PartialEq for Plot {
586586
mod tests {
587587
use std::path::PathBuf;
588588

589-
#[cfg(feature = "kaleido")]
590-
use base64::{engine::general_purpose, Engine as _};
591589
use serde_json::{json, to_value};
590+
#[cfg(not(target_os = "macos"))]
591+
use {base64::engine::general_purpose, base64::Engine};
592592

593593
use super::*;
594594
use crate::Scatter;
@@ -866,4 +866,31 @@ mod tests {
866866
const LEN: usize = 10;
867867
assert_eq!(expected[..LEN], image_svg[..LEN]);
868868
}
869+
870+
#[cfg(target_os = "macos")]
871+
#[test]
872+
#[cfg(feature = "kaleido")]
873+
fn save_surface_to_png() {
874+
use crate::Surface;
875+
let mut plot = Plot::new();
876+
let z_matrix = vec![
877+
vec![1.0, 2.0, 3.0],
878+
vec![4.0, 5.0, 6.0],
879+
vec![7.0, 8.0, 9.0],
880+
];
881+
let x_unique = vec![1.0, 2.0, 3.0];
882+
let y_unique = vec![4.0, 5.0, 6.0];
883+
let surface = Surface::new(z_matrix)
884+
.x(x_unique)
885+
.y(y_unique)
886+
.name("Surface");
887+
888+
plot.add_trace(surface);
889+
let dst = PathBuf::from("example.png");
890+
plot.write_image("example.png", ImageFormat::PNG, 800, 600, 1.0);
891+
assert!(dst.exists());
892+
assert!(std::fs::remove_file(&dst).is_ok());
893+
assert!(!dst.exists());
894+
assert!(!plot.to_base64(ImageFormat::PNG, 1024, 680, 1.0).is_empty());
895+
}
869896
}

plotly_kaleido/src/lib.rs

Lines changed: 138 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -185,20 +185,34 @@ impl Kaleido {
185185
) -> Result<String, Box<dyn std::error::Error>> {
186186
let p = self.cmd_path.to_str().unwrap();
187187

188+
#[cfg(not(target_os = "macos"))]
189+
let cmd_args = vec![
190+
"plotly",
191+
"--disable-gpu",
192+
"--allow-file-access-from-files",
193+
"--disable-breakpad",
194+
"--disable-dev-shm-usage",
195+
"--disable-software-rasterizer",
196+
"--single-process",
197+
"--no-sandbox",
198+
];
199+
200+
// Add Kaleido issue #323
201+
#[cfg(target_os = "macos")]
202+
let cmd_args = vec![
203+
"plotly",
204+
"--allow-file-access-from-files",
205+
"--disable-breakpad",
206+
"--disable-dev-shm-usage",
207+
"--disable-software-rasterizer",
208+
"--single-process",
209+
"--no-sandbox",
210+
];
211+
188212
#[allow(clippy::zombie_processes)]
189213
let mut process = Command::new(p)
190214
.current_dir(self.cmd_path.parent().unwrap())
191-
.args([
192-
"plotly",
193-
"--disable-gpu",
194-
"--allow-file-access-from-files",
195-
"--disable-breakpad",
196-
"--disable-dev-shm-usage",
197-
"--disable-software-rasterizer",
198-
"--single-process",
199-
"--disable-gpu",
200-
"--no-sandbox",
201-
])
215+
.args(cmd_args)
202216
.stdin(Stdio::piped())
203217
.stdout(Stdio::piped())
204218
.stderr(Stdio::piped())
@@ -213,7 +227,6 @@ impl Kaleido {
213227
.to_string()
214228
)
215229
});
216-
217230
{
218231
let plot_data = PlotData::new(plotly_data, format, width, height, scale).to_json();
219232
let mut process_stdin = process.stdin.take().unwrap();
@@ -287,6 +300,47 @@ mod tests {
287300
.unwrap()
288301
}
289302

303+
#[cfg(target_os = "macos")]
304+
fn create_test_surface() -> Value {
305+
to_value(json!({
306+
"data": [
307+
{
308+
"name": "Surface",
309+
"type": "surface",
310+
"x": [
311+
1.0,
312+
2.0,
313+
3.0
314+
],
315+
"y": [
316+
4.0,
317+
5.0,
318+
6.0
319+
],
320+
"z": [
321+
[
322+
1.0,
323+
2.0,
324+
3.0
325+
],
326+
[
327+
4.0,
328+
5.0,
329+
6.0
330+
],
331+
[
332+
7.0,
333+
8.0,
334+
9.0
335+
]
336+
]
337+
}
338+
],
339+
"layout": {}
340+
}))
341+
.unwrap()
342+
}
343+
290344
#[test]
291345
fn can_find_kaleido_executable() {
292346
let _k = Kaleido::new();
@@ -378,4 +432,76 @@ mod tests {
378432
assert!(r.is_ok());
379433
assert!(std::fs::remove_file(dst.as_path()).is_ok());
380434
}
435+
436+
// Issue #241 workaround until https://github.com/plotly/Kaleido/issues/323 is resolved
437+
#[cfg(target_os = "macos")]
438+
#[test]
439+
fn save_surface_png() {
440+
let test_plot = create_test_surface();
441+
let k = Kaleido::new();
442+
let dst = PathBuf::from("example.png");
443+
let r = k.save(dst.as_path(), &test_plot, "png", 1200, 900, 4.5);
444+
assert!(r.is_ok());
445+
assert!(dst.exists());
446+
let metadata = std::fs::metadata(&dst).expect("Could not retrieve file metadata");
447+
let file_size = metadata.len();
448+
assert!(file_size > 0,);
449+
assert!(std::fs::remove_file(dst.as_path()).is_ok());
450+
}
451+
#[cfg(target_os = "macos")]
452+
#[test]
453+
fn save_surface_jpeg() {
454+
let test_plot = create_test_surface();
455+
let k = Kaleido::new();
456+
let dst = PathBuf::from("example.jpeg");
457+
let r = k.save(dst.as_path(), &test_plot, "jpeg", 1200, 900, 4.5);
458+
assert!(r.is_ok());
459+
assert!(dst.exists());
460+
let metadata = std::fs::metadata(&dst).expect("Could not retrieve file metadata");
461+
let file_size = metadata.len();
462+
assert!(file_size > 0,);
463+
assert!(std::fs::remove_file(dst.as_path()).is_ok());
464+
}
465+
#[cfg(target_os = "macos")]
466+
#[test]
467+
fn save_surface_webp() {
468+
let test_plot = create_test_surface();
469+
let k = Kaleido::new();
470+
let dst = PathBuf::from("example.webp");
471+
let r = k.save(dst.as_path(), &test_plot, "webp", 1200, 900, 4.5);
472+
assert!(r.is_ok());
473+
assert!(dst.exists());
474+
let metadata = std::fs::metadata(&dst).expect("Could not retrieve file metadata");
475+
let file_size = metadata.len();
476+
assert!(file_size > 0,);
477+
assert!(std::fs::remove_file(dst.as_path()).is_ok());
478+
}
479+
#[cfg(target_os = "macos")]
480+
#[test]
481+
fn save_surface_svg() {
482+
let test_plot = create_test_surface();
483+
let k = Kaleido::new();
484+
let dst = PathBuf::from("example.svg");
485+
let r = k.save(dst.as_path(), &test_plot, "svg", 1200, 900, 4.5);
486+
assert!(r.is_ok());
487+
assert!(dst.exists());
488+
let metadata = std::fs::metadata(&dst).expect("Could not retrieve file metadata");
489+
let file_size = metadata.len();
490+
assert!(file_size > 0,);
491+
assert!(std::fs::remove_file(dst.as_path()).is_ok());
492+
}
493+
#[cfg(target_os = "macos")]
494+
#[test]
495+
fn save_surface_pdf() {
496+
let test_plot = create_test_surface();
497+
let k = Kaleido::new();
498+
let dst = PathBuf::from("example.pdf");
499+
let r = k.save(dst.as_path(), &test_plot, "pdf", 1200, 900, 4.5);
500+
assert!(r.is_ok());
501+
assert!(dst.exists());
502+
let metadata = std::fs::metadata(&dst).expect("Could not retrieve file metadata");
503+
let file_size = metadata.len();
504+
assert!(file_size > 0,);
505+
assert!(std::fs::remove_file(dst.as_path()).is_ok());
506+
}
381507
}

0 commit comments

Comments
 (0)