Skip to content

Commit

Permalink
add examples on building responsive plots and custom HTML pages (#257)
Browse files Browse the repository at this point in the history
Fixes #175
Closes #228

Signed-off-by: Andrei Gherghescu <[email protected]>
  • Loading branch information
andrei-ng authored Dec 6, 2024
1 parent 86e12ae commit 1405731
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 1 deletion.
2 changes: 1 addition & 1 deletion examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

This folder contains a multitude of usage examples covering as many features of the library as possible. Instructions on how to run each example can be found in each example's subdirectory.

Pull requests with more examples of different behaviour are always welcome.
Pull requests with more examples of different behaviour are always welcome.
11 changes: 11 additions & 0 deletions examples/customization/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "customization"
version = "0.1.0"
authors = ["Andrei Gherghescu [email protected]"]
edition = "2021"

[dependencies]
build_html = "2.5.0"
rand = "0.8"
ndarray = "0.16"
plotly = { path = "../../plotly" }
8 changes: 8 additions & 0 deletions examples/customization/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# HTML Customization

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.

The directory [./customization](./customization) 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 using the [`build_html`](https://crates.io/crates/build_html) crate
153 changes: 153 additions & 0 deletions examples/customization/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#![allow(dead_code)]

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,
};
const DEFAULT_HTML_APP_NOT_FOUND: &str = "Could not find default application for HTML files.";

fn density_mapbox_responsive_autofill() {
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));

plot.show();
}

fn multiple_plots_on_same_html_page() {
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();

let file = write_html(&html);
show_with_default_app(&file);
}

fn first_plot() -> String {
let n: usize = 100;
let t: Vec<f64> = Array::linspace(0., 10., n).into_raw_vec_and_offset().0;
let y: Vec<f64> = 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<f64> = Array::linspace(0., 10., n).into_raw_vec_and_offset().0;
let y: Vec<f64> = t.iter().map(|x| x.sin()).collect();
let z: Vec<f64> = 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 write_html(html_data: &str) -> String {
use std::env;
use std::{fs::File, io::Write};

use rand::{
distributions::{Alphanumeric, DistString},
thread_rng,
};

// Set up the temp file with a unique filename.
let mut temp = env::temp_dir();
let mut plot_name = Alphanumeric.sample_string(&mut thread_rng(), 22);
plot_name.push_str(".html");
plot_name = format!("plotly_{}", plot_name);
temp.push(plot_name);

// Save the rendered plot to the temp file.
let temp_path = temp.to_str().unwrap();

{
let mut file = File::create(temp_path).unwrap();
file.write_all(html_data.as_bytes())
.expect("failed to write html output");
file.flush().unwrap();
}
temp_path.to_string()
}

fn main() {
// Uncomment any of these lines to display the example.

// density_mapbox_responsive_autofill();
// multiple_plots_on_same_html_page();
}

0 comments on commit 1405731

Please sign in to comment.