diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5322232e..cc382cfc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -95,7 +95,9 @@ jobs: 3d_charts, basic_charts, custom_controls, - customization, + customization/consistent_static_format_export, + customization/density_mapbox_example, + customization/multiple_plots_example, financial_charts, images, kaleido, @@ -103,6 +105,7 @@ jobs: ndarray, scientific_charts, shapes, + statistical_charts, subplots, themes, ] diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 7839492e..3550ecb3 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -1,4 +1,21 @@ [workspace] -members = ["*", "plotly_utils"] +members = [ + "3d_charts", + "basic_charts", + "custom_controls", + "customization/consistent_static_format_export", + "customization/density_mapbox_example", + "customization/multiple_plots_example", + "financial_charts", + "images", + "kaleido", + "maps", + "ndarray", + "plotly_utils", + "scientific_charts", + "shapes", + "statistical_charts", + "subplots", + "themes" +] resolver = "2" -exclude = ["jupyter", "target", "wasm-yew"] diff --git a/examples/customization/Cargo.toml b/examples/customization/Cargo.toml deleted file mode 100644 index fa5f9a54..00000000 --- a/examples/customization/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "customization" -version = "0.1.0" -authors = ["Andrei Gherghescu andrei-ng@protonmail.com"] -edition = "2021" - -[dependencies] -build_html = "2.5.0" -rand = "0.9" -ndarray = "0.16" -plotly = { path = "../../plotly" } -plotly_utils = { path = "../plotly_utils" } diff --git a/examples/customization/README.md b/examples/customization/README.md index 7fdf8df2..c5f3551f 100644 --- a/examples/customization/README.md +++ b/examples/customization/README.md @@ -2,7 +2,34 @@ We often get issues/questions regarding customization of the HTML output. In most situations, these are not related to Plotly functionality but rather custom behavior related to HTML rendering. -This example pacakge contains examples of the most frequent raised questions by users of `plotly-rs`, such as +This directory contains examples of the most frequent raised questions by users of `plotly-rs`, such as: - making the resulting HTML plot responsive on browser window size change - making the resulting HTML fill the entire browser page - placing multiple plots in the same HTML page, e.g., by using the [`build_html`](https://crates.io/crates/build_html) crate +- exporting plots to different formats with consistent font rendering + +## Examples + +### Density Mapbox Example +Demonstrates creating a responsive density mapbox plot with OpenStreetMap styling and zoom controls. + +```bash +cd density_mapbox_example +cargo run +``` + +### Multiple Plots Example +Shows how to embed multiple plotly plots on a single HTML page using inline HTML generation. + +```bash +cd multiple_plots_example +cargo run +``` + +### Consistent Format Export Example +Demonstrates exporting plots to SVG, PNG, and PDF formats with consistent font rendering across browsers. + +```bash +cd consistent_static_format_export +cargo run +``` diff --git a/examples/customization/consistent_static_format_export/Cargo.toml b/examples/customization/consistent_static_format_export/Cargo.toml new file mode 100644 index 00000000..84ab4165 --- /dev/null +++ b/examples/customization/consistent_static_format_export/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "consistent_static_format_export" +version = "0.1.0" +edition = "2021" +authors = ["Yuriy D. Sibirmovsky"] +description = "This example demonstrates exporting a plot to SVG, PNG, and PDF and keeping the font size consistent across all formats." + +[dependencies] +plotly = { path = "../../../plotly", features = ["kaleido", "kaleido_download"] } \ No newline at end of file diff --git a/examples/customization/consistent_static_format_export/README.md b/examples/customization/consistent_static_format_export/README.md new file mode 100644 index 00000000..a10d024a --- /dev/null +++ b/examples/customization/consistent_static_format_export/README.md @@ -0,0 +1,34 @@ +# SVG Export Example + +This example demonstrates exporting a plot to SVG, PNG, and PDF using plotly.rs and keeping font size and style consistent accross SVG and other formats. + +This example is based on [GitHub Issue #171](https://github.com/plotly/plotly.rs/issues/171). + + +**Summary:** + +For consistent font rendering across browsers and export formats, always set the `font.family` property explicitly in your plot configuration. Relying on default or generic font settings can lead to differences in appearance, especially for font size and legend layout, depending on the browser or export backend. + +**Recommendation:** + +Always set the `font.family` property (e.g., to `"Times New Roman, serif"`) for all text elements (titles, axes, legends) to ensure consistent results in all output formats. + +## Overview + +This example creates a line and scatter plot with custom styling, including: +- Large font sizes for titles, legends, and axes +- Custom legend positioning and styling +- Border shapes around the plot +- Export to multiple formats (PDF, SVG, PNG) + +## Running the Example + +```bash +cd examples/customization/svg_export_example +cargo run +``` + +This will generate three output files: +- `Data_plot.pdf` - PDF format (typically renders correctly) +- `Data_plot.svg` - SVG format (may have font/legend issues) +- `Data_plot.png` - PNG format (typically renders correctly) diff --git a/examples/customization/consistent_static_format_export/assets/data_file.dat b/examples/customization/consistent_static_format_export/assets/data_file.dat new file mode 100644 index 00000000..39f1e618 --- /dev/null +++ b/examples/customization/consistent_static_format_export/assets/data_file.dat @@ -0,0 +1,122 @@ +-6 0.34813262986687 0.157822391633258 -6 0 +-5.9 0.46875653919673 0.328028117967049 -5.8 5 +-5.8 0.628027231301822 0.52369472427333 -5.6 0 +-5.7 0.837217193670763 0.75930808002296 -5.4 0 +-5.6 1.11051986051416 1.05151591736406 -5.2 0 +-5.5 1.46569311773448 1.41993951938828 -5 0 +-5.4 1.92481189963786 1.88806100382544 -4.8 5 +-5.3 2.51513944788948 2.48420179043188 -4.6 20 +-5.2 3.2701251243082 3.24260528612921 -4.4 5 +-5.1 4.23053409419851 4.20463343680189 -4.2 25 +-5 5.44571057588177 5.42008243904707 -4 50 +-4.9 6.97497154752718 6.94861744626477 -3.8 75 +-4.8 8.88912170219436 8.861319429385 -3.6 105 +-4.7 11.2720729739824 11.2423293883596 -3.4 135 +-4.6 14.2225431063134 14.1905658358818 -3.2 195 +-4.5 17.855797555045 17.8214809418407 -3 250 +-4.4 22.3053876622905 22.2688090784502 -2.8 380 +-4.3 27.7248257559954 27.6862489913022 -2.6 560 +-4.2 34.2891249995171 34.2490078103487 -2.4 710 +-4.1 42.1961189368502 42.1551221052607 -2.2 765 +-4 51.6674633852301 51.6264588107484 -2 1080 +-3.9 62.9492123746017 62.909287852889 -1.8 1230 +-3.8 76.3118510886195 76.2743095595762 -1.6 1650 +-3.7 92.0496631724023 92.0160143808758 -1.4 1765 +-3.6 110.479308330028 110.451251065321 -1.2 1895 +-3.5 131.937489825376 131.916883215734 -1 2225 +-3.4 156.777601242171 156.766423994451 -0.8 2360 +-3.3 185.36525843517 185.365555436519 -0.6 2635 +-3.2 218.072646584863 218.086462920878 -0.4 2875 +-3.1 255.271643934383 255.300947114738 -0.2 2710 +-3 297.325723059073 297.372315053109 0 2715 +-2.9 344.580676889233 344.646098425783 0.2 2870 +-2.8 397.354269193195 397.439699625933 0.4 2765 +-2.7 455.924966347558 456.031123176121 0.6 2750 +-2.6 520.519966990174 520.647009799593 0.8 2250 +-2.5 591.302806118227 591.450250194341 1 2255 +-2.4 668.360867508848 668.527512647483 1.2 2075 +-2.3 751.693189860458 751.877069862752 1.4 1605 +-2.2 841.19899448311 841.397352480169 1.6 1440 +-2.1 936.667392426119 936.876686481779 1.8 1165 +-2 1037.76874355149 1037.98468595164 2 1000 +-1.9 1144.04813658796 1144.2657688615 2.2 850 +-1.8 1254.92143560091 1255.13523967822 2.4 695 +-1.7 1369.67429337025 1369.87833744239 2.6 530 +-1.6 1487.46446564367 1487.65258133184 2.8 420 +-1.5 1607.32767298802 1607.49365847972 3 295 +-1.4 1728.18715102635 1728.32499300291 3.2 205 +-1.3 1848.86690841628 1848.97101401134 3.4 185 +-1.2 1968.10857928572 1968.17400809455 3.6 70 +-1.1 2084.59161822864 2084.61430363873 3.8 55 +-1 2196.95644733861 2196.93339625419 4 25 +-0.9 2303.83003253055 2303.75949296752 4.2 25 +-0.8 2403.85324709827 2403.7348341459 4.4 10 +-0.7 2495.70928036152 2495.5440526166 4.6 0 +-0.6 2578.15227404741 2577.94275475925 4.8 5 +-0.5 2650.03532344029 2649.78546315613 5 15 +-0.4 2710.33696776216 2710.05204809582 5.2 10 +-0.3 2758.18531662706 2757.87179772837 5.4 0 +-0.2 2792.87901697234 2792.5443341764 5.6 0 +-0.1 2813.90435606505 2813.5566738726 5.8 0 +0 2820.94791773878 2820.59585155634 6 5 +0.1 2813.90435606505 2813.5566738726 +0.2 2792.87901697234 2792.5443341764 +0.3 2758.18531662706 2757.87179772837 +0.4 2710.33696776216 2710.05204809582 +0.5 2650.03532344029 2649.78546315613 +0.6 2578.15227404741 2577.94275475925 +0.7 2495.70928036152 2495.5440526166 +0.8 2403.85324709827 2403.7348341459 +0.9 2303.83003253055 2303.75949296752 +1 2196.95644733861 2196.93339625419 +1.1 2084.59161822864 2084.61430363873 +1.2 1968.10857928572 1968.17400809455 +1.3 1848.86690841628 1848.97101401134 +1.4 1728.18715102635 1728.32499300291 +1.5 1607.32767298802 1607.49365847972 +1.6 1487.46446564367 1487.65258133184 +1.7 1369.67429337025 1369.87833744239 +1.8 1254.92143560091 1255.13523967822 +1.9 1144.04813658796 1144.2657688615 +2 1037.76874355149 1037.98468595164 +2.1 936.667392426119 936.876686481779 +2.2 841.19899448311 841.397352480169 +2.3 751.693189860458 751.877069862752 +2.4 668.360867508848 668.527512647482 +2.5 591.302806118227 591.45025019434 +2.6 520.519966990174 520.647009799593 +2.7 455.924966347558 456.03112317612 +2.8 397.354269193195 397.439699625933 +2.9 344.580676889233 344.646098425782 +3 297.325723059073 297.372315053109 +3.1 255.271643934383 255.300947114738 +3.2 218.072646584863 218.086462920877 +3.3 185.36525843517 185.365555436519 +3.4 156.777601242171 156.766423994451 +3.5 131.937489825376 131.916883215733 +3.6 110.479308330028 110.451251065321 +3.7 92.0496631724023 92.0160143808757 +3.8 76.3118510886195 76.2743095595761 +3.9 62.9492123746017 62.9092878528889 +4 51.6674633852301 51.6264588107483 +4.1 42.1961189368502 42.1551221052606 +4.2 34.2891249995171 34.2490078103487 +4.3 27.7248257559954 27.6862489913022 +4.4 22.3053876622905 22.2688090784502 +4.5 17.855797555045 17.8214809418407 +4.6 14.2225431063134 14.1905658358818 +4.7 11.2720729739824 11.2423293883595 +4.8 8.88912170219436 8.86131942938499 +4.9 6.97497154752718 6.94861744626476 +5 5.44571057588177 5.42008243904706 +5.1 4.23053409419851 4.20463343680188 +5.2 3.2701251243082 3.2426052861292 +5.3 2.51513944788948 2.48420179043187 +5.4 1.92481189963786 1.88806100382543 +5.5 1.46569311773448 1.41993951938828 +5.6 1.11051986051416 1.05151591736406 +5.7 0.837217193670763 0.759308080022959 +5.8 0.628027231301822 0.523694724273329 +5.9 0.46875653919673 0.328028117967048 +6 0.34813262986687 0.157822391633258 + diff --git a/examples/customization/consistent_static_format_export/src/main.rs b/examples/customization/consistent_static_format_export/src/main.rs new file mode 100644 index 00000000..2bf7b595 --- /dev/null +++ b/examples/customization/consistent_static_format_export/src/main.rs @@ -0,0 +1,214 @@ +use plotly::color::{NamedColor, Rgb}; +use plotly::common::{Anchor, Font, Line, Marker, MarkerSymbol, Mode, Title}; +use plotly::layout::{Axis, ItemSizing, Legend, Margin, Shape, ShapeLine, ShapeType}; +use plotly::{ImageFormat, Layout, Plot, Scatter}; + +fn line_and_scatter_plot( + x1: Vec, + y1: Vec, + x2: Vec, + y2: Vec, + flnm: &str, + title: &str, +) { + let bgcol = Rgb::new(255, 255, 255); + let linecol1 = NamedColor::DarkBlue; + let linecol2 = NamedColor::DarkRed; + let forecol = Rgb::new(0, 0, 0); + let gridcol = Rgb::new(180, 180, 180); + let transp = NamedColor::Transparent; + let thick: usize = 3; + let medium: usize = 3; + let _thin: usize = 2; + let msize: usize = 10; + let fsz_title: usize = 40; + let fsz_legend: usize = 35; + let fsz_ticks: usize = 30; + let fsz_axes: usize = 35; + + let trace1 = Scatter::new(x1, y1) + .name("Diffusion") + .mode(Mode::Lines) + .line(Line::new().color(linecol1).width(medium as f64)); + + let trace2 = Scatter::new(x2, y2) + .name("Random walk") + .mode(Mode::Markers) + .marker( + Marker::new() + .size(msize) + .color(linecol2) + .symbol(MarkerSymbol::Circle), + ); + + let title = Title::from(title).font( + Font::new() + .size(fsz_title) + .family("Times New Roman, serif") + .color(forecol), + ); + + let legend = Legend::new() + .x(0.99) + .x_anchor(Anchor::Right) + .y(1.0 - 0.0133) + .y_anchor(Anchor::Top) + .font( + Font::new() + .size(fsz_legend) + .color(forecol) + .family("Times New Roman, serif"), + ) + .border_width(medium) + .border_color(forecol) + .background_color(bgcol) + .item_width(52) + .item_sizing(ItemSizing::Trace); + + let axis = Axis::new() + .position(0.0) + .show_line(true) + .line_color(forecol) + .line_width(thick) + .tick_length(9) + .tick_width(medium) + .tick_color(forecol) + .tick_font(Font::new().color(forecol)) + .zero_line(false) + .show_grid(true) + .grid_color(gridcol); + + let axisx = axis.clone().title( + Title::from("x. a.u.").font( + Font::new() + .size(fsz_axes) + .color(forecol) + .family("Times New Roman, serif"), + ), + ); + + let axisy = axis + .clone() + .title( + Title::from("Number of particles").font( + Font::new() + .size(fsz_axes) + .color(forecol) + .family("Times New Roman, serif"), + ), + ) + .tick_angle(270.0); + + let line_top = Shape::new() + .shape_type(ShapeType::Line) + .x_ref("paper") + .y_ref("paper") + .x0(0.) + .y0(1.) + .x1(1.) + .y1(1.) + .line(ShapeLine::new().color(forecol).width(thick as f64)); + + let line_right = Shape::new() + .shape_type(ShapeType::Line) + .x_ref("paper") + .y_ref("paper") + .x0(1.) + .y0(0.) + .x1(1.) + .y1(1.) + .line(ShapeLine::new().color(forecol).width(thick as f64)); + + let mut layout = Layout::new() + .width(1024) + .height(768) + .font(Font::new().size(fsz_ticks)) + .title(title) + .legend(legend) + .show_legend(true) + .x_axis(axisx) + .y_axis(axisy) + .plot_background_color(transp) + .paper_background_color(bgcol) + .margin(Margin::new().left(105).bottom(105)); + + layout.add_shape(line_top); + layout.add_shape(line_right); + + let mut plot = Plot::new(); + plot.add_trace(trace1); + plot.add_trace(trace2); + plot.set_layout(layout); + + // Export to multiple formats to demonstrate the SVG export issue + println!("Exporting plot to multiple formats..."); + println!("Note: SVG export may have font sizing issues compared to PNG/PDF"); + + plot.write_image(flnm, ImageFormat::PDF, 1280, 960, 1.0); + plot.write_image(flnm, ImageFormat::SVG, 1280, 960, 1.0); + plot.write_image(flnm, ImageFormat::PNG, 1280, 960, 1.0); + + println!("Export complete. Check the output files:"); + println!(" - {flnm}.pdf"); + println!(" - {flnm}.svg"); + println!(" - {flnm}.png"); +} + +fn read_from_file(file_path: &str) -> Vec> { + use std::fs::File; + use std::io::BufRead; + use std::io::BufReader; + + let file = File::open(file_path).expect("Error opening file"); + let reader = BufReader::new(file); + let mut file_contents: Vec = Vec::new(); + + for line in reader.lines() { + file_contents.push(line.unwrap()); + } + + let mut data_rows: Vec> = Vec::new(); + let mut data_columns: Vec> = Vec::new(); + + let mut n_columns: Vec = Vec::new(); + let mut n_rows: usize = 0; + + for line in file_contents { + let row: Vec = line + .split([' ', '\t', ',']) + .map(|s| s.trim()) + .filter(|s| !s.is_empty()) + .map(|s| s.parse().unwrap()) + .collect(); + + n_columns.push(row.len()); + n_rows += 1; + + data_rows.push(row) + } + + let n1 = n_columns[1]; + + for _i in 0..n1 { + let column: Vec = Vec::new(); + data_columns.push(column) + } + + for j in 0..n_rows { + for (i, column) in data_columns.iter_mut().enumerate().take(n_columns[j]) { + column.push(data_rows[j][i]) + } + } + + data_columns +} + +fn main() { + let data = read_from_file("assets/data_file.dat"); + let x1 = data[0].clone(); + let y1 = data[1].clone(); + let x2 = data[3].clone(); + let y2 = data[4].clone(); + + line_and_scatter_plot(x1, y1, x2, y2, "Data_plot", "Initial state δ(x)"); +} diff --git a/examples/customization/density_mapbox_example/Cargo.toml b/examples/customization/density_mapbox_example/Cargo.toml new file mode 100644 index 00000000..dce499ea --- /dev/null +++ b/examples/customization/density_mapbox_example/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "density_mapbox_example" +version = "0.1.0" +edition = "2021" + +[dependencies] +plotly = { path = "../../../plotly" } +plotly_utils = { path = "../../plotly_utils" } \ No newline at end of file diff --git a/examples/customization/density_mapbox_example/src/main.rs b/examples/customization/density_mapbox_example/src/main.rs new file mode 100644 index 00000000..f1ea471e --- /dev/null +++ b/examples/customization/density_mapbox_example/src/main.rs @@ -0,0 +1,27 @@ +use plotly::{ + layout::{Center, DragMode, Mapbox, MapboxStyle, Margin}, + Configuration, DensityMapbox, Layout, Plot, +}; +use plotly_utils::write_example_to_html; + +fn main() { + let trace = DensityMapbox::new(vec![45.5017], vec![-73.5673], vec![0.75]).zauto(true); + + let layout = Layout::new() + .drag_mode(DragMode::Zoom) + .margin(Margin::new().top(0).left(0).bottom(0).right(0)) + .mapbox( + Mapbox::new() + .style(MapboxStyle::OpenStreetMap) + .center(Center::new(45.5017, -73.5673)) + .zoom(5), + ); + + let mut plot = Plot::new(); + plot.add_trace(trace); + plot.set_layout(layout); + plot.set_configuration(Configuration::default().responsive(true).fill_frame(true)); + + let path = write_example_to_html(&plot, "density_mapbox"); + println!("Density mapbox plot saved to: {path}"); +} diff --git a/examples/customization/multiple_plots_example/Cargo.toml b/examples/customization/multiple_plots_example/Cargo.toml new file mode 100644 index 00000000..261e1834 --- /dev/null +++ b/examples/customization/multiple_plots_example/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "multiple_plots_example" +version = "0.1.0" +edition = "2021" + +[dependencies] +plotly = { path = "../../../plotly" } +plotly_utils = { path = "../../plotly_utils" } +build_html = "2.5.0" +ndarray = "0.16" \ No newline at end of file diff --git a/examples/customization/multiple_plots_example/src/main.rs b/examples/customization/multiple_plots_example/src/main.rs new file mode 100644 index 00000000..c11e538d --- /dev/null +++ b/examples/customization/multiple_plots_example/src/main.rs @@ -0,0 +1,75 @@ +use std::fs::File; +use std::io::Write; + +use build_html::*; +use ndarray::Array; +use plotly::{ + color::NamedColor, + common::{Marker, Mode, Title}, + Layout, Plot, Scatter, Scatter3D, +}; + +fn main() { + let html: String = HtmlPage::new() + .with_title("Plotly-rs Multiple Plots") + .with_script_link("https://cdn.plot.ly/plotly-latest.min.js") + .with_header(1, "Multiple Plotly plots on the same HTML page") + .with_raw(first_plot()) + .with_raw(second_plot()) + .with_raw(third_plot()) + .to_html_string(); + + std::fs::create_dir_all("./output").unwrap(); + let path = "./output/multiple_plots.html"; + let mut file = File::create(path).unwrap(); + file.write_all(html.as_bytes()) + .expect("failed to write html output"); + file.flush().unwrap(); + + println!("Multiple plots HTML page saved to: {path}"); +} + +fn first_plot() -> String { + let n: usize = 100; + let t: Vec = Array::linspace(0., 10., n).into_raw_vec_and_offset().0; + let y: Vec = t.iter().map(|x| x.sin()).collect(); + + let trace = Scatter::new(t, y).mode(Mode::Markers); + let mut plot = Plot::new(); + plot.add_trace(trace); + plot.to_inline_html(Some("scatter_1")) +} + +fn second_plot() -> String { + let trace = Scatter::new(vec![1, 2, 3, 4], vec![10, 11, 12, 13]) + .mode(Mode::Markers) + .marker( + Marker::new() + .size_array(vec![40, 60, 80, 100]) + .color_array(vec![ + NamedColor::Red, + NamedColor::Blue, + NamedColor::Cyan, + NamedColor::OrangeRed, + ]), + ); + let mut plot = Plot::new(); + plot.add_trace(trace); + plot.to_inline_html(Some("scatter_2")) +} + +fn third_plot() -> String { + let n: usize = 100; + let t: Vec = Array::linspace(0., 10., n).into_raw_vec_and_offset().0; + let y: Vec = t.iter().map(|x| x.sin()).collect(); + let z: Vec = t.iter().map(|x| x.cos()).collect(); + + let trace = Scatter3D::new(t, y, z).mode(Mode::Markers); + let mut plot = Plot::new(); + plot.add_trace(trace); + let l = Layout::new() + .title(Title::with_text("Scatter3d")) + .height(800); + plot.set_layout(l); + plot.to_inline_html(Some("scatter_3_3d")) +} diff --git a/examples/customization/src/main.rs b/examples/customization/src/main.rs deleted file mode 100644 index 5bd32532..00000000 --- a/examples/customization/src/main.rs +++ /dev/null @@ -1,139 +0,0 @@ -#![allow(dead_code)] - -use std::fs::File; -use std::io::Write; - -use build_html::*; -use ndarray::Array; -use plotly::{ - color::NamedColor, - common::{Marker, Mode, Title}, - layout::{Center, DragMode, Mapbox, MapboxStyle, Margin}, - Configuration, DensityMapbox, Layout, Plot, Scatter, Scatter3D, -}; -use plotly_utils::write_example_to_html; -const DEFAULT_HTML_APP_NOT_FOUND: &str = "Could not find default application for HTML files."; - -fn density_mapbox_responsive_autofill(show: bool, file_name: &str) { - let trace = DensityMapbox::new(vec![45.5017], vec![-73.5673], vec![0.75]).zauto(true); - - let layout = Layout::new() - .drag_mode(DragMode::Zoom) - .margin(Margin::new().top(0).left(0).bottom(0).right(0)) - .mapbox( - Mapbox::new() - .style(MapboxStyle::OpenStreetMap) - .center(Center::new(45.5017, -73.5673)) - .zoom(5), - ); - - let mut plot = Plot::new(); - plot.add_trace(trace); - plot.set_layout(layout); - plot.set_configuration(Configuration::default().responsive(true).fill_frame(true)); - - let path = write_example_to_html(&plot, file_name); - if show { - plot.show_html(path); - } -} - -fn multiple_plots_on_same_html_page(show: bool, file_name: &str) { - let html: String = HtmlPage::new() - .with_title("Plotly-rs Multiple Plots") - .with_script_link("https://cdn.plot.ly/plotly-latest.min.js") - .with_header(1, "Multiple Plotly plots on the same HTML page") - .with_raw(first_plot()) - .with_raw(second_plot()) - .with_raw(third_plot()) - .to_html_string(); - - std::fs::create_dir_all("./output").unwrap(); - let path = format!("./output/inline_{file_name}.html"); - let mut file = File::create(&path).unwrap(); - file.write_all(html.as_bytes()) - .expect("failed to write html output"); - file.flush().unwrap(); - if show { - show_with_default_app(&path); - } -} - -fn first_plot() -> String { - let n: usize = 100; - let t: Vec = Array::linspace(0., 10., n).into_raw_vec_and_offset().0; - let y: Vec = t.iter().map(|x| x.sin()).collect(); - - let trace = Scatter::new(t, y).mode(Mode::Markers); - let mut plot = Plot::new(); - plot.add_trace(trace); - plot.to_inline_html(Some("scattter_1")) -} - -fn second_plot() -> String { - let trace = Scatter::new(vec![1, 2, 3, 4], vec![10, 11, 12, 13]) - .mode(Mode::Markers) - .marker( - Marker::new() - .size_array(vec![40, 60, 80, 100]) - .color_array(vec![ - NamedColor::Red, - NamedColor::Blue, - NamedColor::Cyan, - NamedColor::OrangeRed, - ]), - ); - let mut plot = Plot::new(); - plot.add_trace(trace); - plot.to_inline_html(Some("scatter_2")) -} - -fn third_plot() -> String { - let n: usize = 100; - let t: Vec = Array::linspace(0., 10., n).into_raw_vec_and_offset().0; - let y: Vec = t.iter().map(|x| x.sin()).collect(); - let z: Vec = t.iter().map(|x| x.cos()).collect(); - - let trace = Scatter3D::new(t, y, z).mode(Mode::Markers); - let mut plot = Plot::new(); - plot.add_trace(trace); - let l = Layout::new() - .title(Title::with_text("Scatter3d")) - .height(800); - plot.set_layout(l); - plot.to_inline_html(Some("scatter_3_3d")) -} - -#[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))] -fn show_with_default_app(temp_path: &str) { - use std::process::Command; - Command::new("xdg-open") - .args([temp_path]) - .output() - .expect(DEFAULT_HTML_APP_NOT_FOUND); -} - -#[cfg(target_os = "macos")] -fn show_with_default_app(temp_path: &str) { - use std::process::Command; - Command::new("open") - .args([temp_path]) - .output() - .expect(DEFAULT_HTML_APP_NOT_FOUND); -} - -#[cfg(target_os = "windows")] -fn show_with_default_app(temp_path: &str) { - use std::process::Command; - Command::new("cmd") - .args(&["/C", "start", &format!(r#"{}"#, temp_path)]) - .spawn() - .expect(DEFAULT_HTML_APP_NOT_FOUND); -} - -fn main() { - // Switch the boolean flag to `true` to display the example, otherwise manually - // open the generated file in the `output` folder. - density_mapbox_responsive_autofill(false, "density_mapbox"); - multiple_plots_on_same_html_page(false, "multiple_plots"); -}