Skip to content

Commit 2de7798

Browse files
authored
Serialize plotly_kaleido::PlotData correctly (#75)
* impl Serialize for Plot * serialize Traces/Layout separately * improve tests * refactor template rendering with serializable plot * add to doctest to prove html tags aren't escaped * serialize PlotData * serialize PlotData * update changelog
1 parent de1489a commit 2de7798

File tree

4 files changed

+76
-40
lines changed

4 files changed

+76
-40
lines changed

Diff for: CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515
- Remove `private::TruthyEnum` in favour of a more robust way of serializing to `String` or `bool`
1616
### Fixed
1717
- Typos in `CONTRIBUTING.md`
18+
- Serialization of `plotly_kaleido::PlotData` ([Issue #50](https://github.com/igiagkiozis/plotly/issues/50))
1819
### Updated
1920
- `ndarray` to `0.15.4`.
2021
- `serde` to `1.0.132`.

Diff for: plotly/src/layout.rs

-1
Original file line numberDiff line numberDiff line change
@@ -3302,7 +3302,6 @@ impl Layout {
33023302
self
33033303
}
33043304
}
3305-
33063305
#[cfg(test)]
33073306
mod tests {
33083307
use serde_json::{json, to_value};

Diff for: plotly/src/plot.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,6 @@ impl Plot {
408408
scale: f64,
409409
) {
410410
let kaleido = plotly_kaleido::Kaleido::new();
411-
let plot_data = self.to_json();
412411
let image_format = match format {
413412
ImageFormat::PNG => "png",
414413
ImageFormat::JPEG => "jpeg",
@@ -420,7 +419,7 @@ impl Plot {
420419
kaleido
421420
.save(
422421
filename.as_ref(),
423-
plot_data.as_str(),
422+
&serde_json::to_value(self).unwrap(),
424423
image_format,
425424
width,
426425
height,

Diff for: plotly_kaleido/src/lib.rs

+74-37
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,13 @@
1111
1212
use directories::ProjectDirs;
1313
use serde::{Deserialize, Serialize};
14+
use serde_json::Value;
1415
use std::fs::File;
1516
use std::io::prelude::*;
1617
use std::io::BufReader;
1718
use std::path::{Path, PathBuf};
1819
use std::process::{Command, Stdio};
1920

20-
#[derive(Serialize)]
21-
struct PlotData {
22-
format: String,
23-
width: usize,
24-
height: usize,
25-
scale: f64,
26-
data: String,
27-
}
28-
2921
#[allow(dead_code)]
3022
#[derive(Deserialize, Debug)]
3123
struct KaleidoResult {
@@ -47,26 +39,32 @@ impl KaleidoResult {
4739
}
4840
}
4941

50-
impl PlotData {
51-
fn new(data: &str, format: &str, width: usize, height: usize, scale: f64) -> PlotData {
42+
#[derive(Serialize)]
43+
struct PlotData<'a> {
44+
// TODO: as with `data`, it would be much better if this were a plotly::ImageFormat, but problems
45+
// with cyclic dependencies.
46+
format: String,
47+
width: usize,
48+
height: usize,
49+
scale: f64,
50+
// TODO: it would be great if this could be a plotly::Plot, but with the current workspace set up,
51+
// that would be a cyclic dependency.
52+
data: &'a Value,
53+
}
54+
55+
impl<'a> PlotData<'a> {
56+
fn new(data: &'a Value, format: &str, width: usize, height: usize, scale: f64) -> PlotData<'a> {
5257
PlotData {
53-
format: String::from(format),
58+
format: format.to_string(),
5459
width,
5560
height,
5661
scale,
57-
data: String::from(data),
62+
data,
5863
}
5964
}
6065

6166
fn to_json(&self) -> String {
62-
let data = format!(
63-
r##"{{"format":"{}","width":{},"height":{},"scale":{},"data":{}}}"##,
64-
self.format, self.width, self.height, self.scale, self.data
65-
);
66-
data.replace(" ", "")
67-
.replace("\n", "")
68-
.replace("\t", "")
69-
.replace("\r", "")
67+
serde_json::to_string(self).unwrap()
7068
}
7169
}
7270

@@ -124,7 +122,7 @@ impl Kaleido {
124122
pub fn save(
125123
&self,
126124
dst: &Path,
127-
plotly_data: &str,
125+
plotly_data: &Value,
128126
image_format: &str,
129127
width: usize,
130128
height: usize,
@@ -183,15 +181,39 @@ impl Kaleido {
183181

184182
#[cfg(test)]
185183
mod tests {
186-
use super::*;
184+
use serde_json::{json, to_value};
187185
use std::path::PathBuf;
188186

189-
const TEST_PLOT: &str = r#"{
190-
"data": [{"type":"scatter","x":[1,2,3,4],"y":[10,15,13,17],"name":"trace1","mode":"markers"},
191-
{"type":"scatter","x":[2,3,4,5],"y":[16,5,11,9],"name":"trace2","mode":"lines"},
192-
{"type":"scatter","x":[1,2,3,4],"y":[12,9,15,12],"name":"trace3"}],
193-
"layout": {}
194-
}"#;
187+
use super::*;
188+
189+
fn create_test_plot() -> Value {
190+
to_value(json!({
191+
"data": [
192+
{
193+
"type": "scatter",
194+
"x": [1, 2, 3, 4],
195+
"y": [10, 15, 13, 17],
196+
"name": "trace1",
197+
"mode": "markers"
198+
},
199+
{
200+
"type": "scatter",
201+
"x": [2, 3, 4, 5],
202+
"y": [16, 5, 11, 9],
203+
"name": "trace2",
204+
"mode": "lines"
205+
},
206+
{
207+
"type": "scatter",
208+
"x": [1, 2, 3, 4],
209+
"y": [12, 9, 15, 12],
210+
"name": "trace3",
211+
}
212+
],
213+
"layout": {}
214+
}))
215+
.unwrap()
216+
}
195217

196218
#[test]
197219
fn test_can_find_kaleido_executable() {
@@ -200,61 +222,76 @@ mod tests {
200222

201223
#[test]
202224
fn test_plot_data_to_json() {
203-
let d = PlotData::new(TEST_PLOT, "png", 400, 500, 1.);
204-
println!("{}", d.to_json());
225+
let test_plot = create_test_plot();
226+
let kaleido_data = PlotData::new(&test_plot, "png", 400, 500, 1.);
227+
let expected = json!({
228+
"data": test_plot,
229+
"format": "png",
230+
"width": 400,
231+
"height": 500,
232+
"scale": 1.0
233+
});
234+
235+
assert_eq!(to_value(kaleido_data).unwrap(), expected);
205236
}
206237

207238
#[test]
208239
fn test_save_png() {
240+
let test_plot = create_test_plot();
209241
let k = Kaleido::new();
210242
let dst = PathBuf::from("example.png");
211-
let r = k.save(dst.as_path(), TEST_PLOT, "png", 1200, 900, 4.5);
243+
let r = k.save(dst.as_path(), &test_plot, "png", 1200, 900, 4.5);
212244
assert!(r.is_ok());
213245
assert!(std::fs::remove_file(dst.as_path()).is_ok());
214246
}
215247

216248
#[test]
217249
fn test_save_jpeg() {
250+
let test_plot = create_test_plot();
218251
let k = Kaleido::new();
219252
let dst = PathBuf::from("example.jpeg");
220-
let r = k.save(dst.as_path(), TEST_PLOT, "jpeg", 1200, 900, 4.5);
253+
let r = k.save(dst.as_path(), &test_plot, "jpeg", 1200, 900, 4.5);
221254
assert!(r.is_ok());
222255
assert!(std::fs::remove_file(dst.as_path()).is_ok());
223256
}
224257

225258
#[test]
226259
fn test_save_webp() {
260+
let test_plot = create_test_plot();
227261
let k = Kaleido::new();
228262
let dst = PathBuf::from("example.webp");
229-
let r = k.save(dst.as_path(), TEST_PLOT, "webp", 1200, 900, 4.5);
263+
let r = k.save(dst.as_path(), &test_plot, "webp", 1200, 900, 4.5);
230264
assert!(r.is_ok());
231265
assert!(std::fs::remove_file(dst.as_path()).is_ok());
232266
}
233267

234268
#[test]
235269
fn test_save_svg() {
270+
let test_plot = create_test_plot();
236271
let k = Kaleido::new();
237272
let dst = PathBuf::from("example.svg");
238-
let r = k.save(dst.as_path(), TEST_PLOT, "svg", 1200, 900, 4.5);
273+
let r = k.save(dst.as_path(), &test_plot, "svg", 1200, 900, 4.5);
239274
assert!(r.is_ok());
240275
assert!(std::fs::remove_file(dst.as_path()).is_ok());
241276
}
242277

243278
#[test]
244279
fn test_save_pdf() {
280+
let test_plot = create_test_plot();
245281
let k = Kaleido::new();
246282
let dst = PathBuf::from("example.pdf");
247-
let r = k.save(dst.as_path(), TEST_PLOT, "pdf", 1200, 900, 4.5);
283+
let r = k.save(dst.as_path(), &test_plot, "pdf", 1200, 900, 4.5);
248284
assert!(r.is_ok());
249285
assert!(std::fs::remove_file(dst.as_path()).is_ok());
250286
}
251287

252288
#[test]
253289
#[ignore]
254290
fn test_save_eps() {
291+
let test_plot = create_test_plot();
255292
let k = Kaleido::new();
256293
let dst = PathBuf::from("example.eps");
257-
let r = k.save(dst.as_path(), TEST_PLOT, "eps", 1200, 900, 4.5);
294+
let r = k.save(dst.as_path(), &test_plot, "eps", 1200, 900, 4.5);
258295
assert!(r.is_ok());
259296
assert!(std::fs::remove_file(dst.as_path()).is_ok());
260297
}

0 commit comments

Comments
 (0)