diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..8cedbd63 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,76 @@ +name: CI + +on: + push: + branches: [ dev ] + pull_request: + branches: [ dev ] + +# Cancel any in-flight jobs for the same PR/branch so there's only one active +# at a time +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + RUST_BACKTRACE: full + +jobs: + rustfmt: + name: Rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@nightly + with: + components: rustfmt + - run: cargo fmt --all -- --check + - run: cd ${{ github.workspace }}/examples && cargo fmt --all -- --check + + clippy: + name: Clippy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy + - run: cargo clippy -- -D warnings + - run: cd ${{ github.workspace }}/examples && cargo clippy -- -D warnings + + test: + name: Tests + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: cargo test --features=plotly_ndarray,kaleido + + build_examples: + name: Build Examples + strategy: + fail-fast: false + matrix: + example: [ # missing jupyter and wasm-yew-minimal + 3d_charts, + basic_charts, + custom_controls, + financial_charts, + images, + kaleido, + maps, + ndarray, + scientific_charts, + shapes, + subplots + ] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: cd ${{ github.workspace }}/examples/${{ matrix.example }} && cargo build + diff --git a/.github/workflows/dev_ci.yml b/.github/workflows/dev_ci.yml deleted file mode 100644 index b22dd34c..00000000 --- a/.github/workflows/dev_ci.yml +++ /dev/null @@ -1,91 +0,0 @@ -name: build_dev - -on: - push: - branches: [ dev ] - pull_request: - branches: [ dev ] - -env: - CARGO_TERM_COLOR: always - -jobs: - build_linux: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: build_linux - run: cargo build --all-features --verbose --release - - name: rustfmt - run: cargo fmt --all -- --check - - name: Run tests - run: cargo test --features plotly_ndarray,kaleido --release --verbose - - name: Run basic charts - run: cargo run --example basic_charts --release - - name: Run financial charts - run: cargo run --example financial_charts --release - - name: Run fundamentals - run: cargo run --example fundamentals --release - - name: Run ndarray support - run: cargo run --example ndarray_support --features plotly_ndarray --release - - name: Run scientific charts - run: cargo run --example scientific_charts --release - - name: Run statistical charts - run: cargo run --example statistical_charts --release - - name: Run subplots - run: cargo run --example subplots --release - - name: Run 3D plots - run: cargo run --example plot3d --release - - build_windows: - runs-on: windows-latest - - steps: - - uses: actions/checkout@v2 - - name: build_windows - run: cargo build --all-features --verbose --release - - name: Run tests - run: cargo test --features plotly_ndarray,kaleido --release --verbose - - name: Run basic charts - run: cargo run --example basic_charts --release - - name: Run financial charts - run: cargo run --example financial_charts --release - - name: Run fundamentals - run: cargo run --example fundamentals --release - - name: Run ndarray support - run: cargo run --example ndarray_support --features plotly_ndarray --release - - name: Run scientific charts - run: cargo run --example scientific_charts --release - - name: Run statistical charts - run: cargo run --example statistical_charts --release - - name: Run subplots - run: cargo run --example subplots --release - - name: Run 3D plots - run: cargo run --example plot3d --release - - build_macos: - runs-on: macos-latest - - steps: - - uses: actions/checkout@v2 - - name: build_macos - run: cargo build --all-features --verbose --release - - name: Run tests - run: cargo test --features plotly_ndarray,kaleido --release --verbose - - name: Run basic charts - run: cargo run --example basic_charts --release - - name: Run financial charts - run: cargo run --example financial_charts --release - - name: Run fundamentals - run: cargo run --example fundamentals --release - - name: Run ndarray support - run: cargo run --example ndarray_support --features plotly_ndarray --release - - name: Run scientific charts - run: cargo run --example scientific_charts --release - - name: Run statistical charts - run: cargo run --example statistical_charts --release - - name: Run subplots - run: cargo run --example subplots --release - - name: Run 3D plots - run: cargo run --example plot3d --release diff --git a/.github/workflows/release_ci.yml b/.github/workflows/release_ci.yml index 57e8ea73..6307fe85 100644 --- a/.github/workflows/release_ci.yml +++ b/.github/workflows/release_ci.yml @@ -1,4 +1,4 @@ -name: build_master +name: Release on: push: @@ -6,86 +6,71 @@ on: pull_request: branches: [ master ] +# Cancel any in-flight jobs for the same PR/branch so there's only one active +# at a time +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + env: - CARGO_TERM_COLOR: always + RUST_BACKTRACE: full jobs: - build_linux: + rustfmt: + name: Rustfmt runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: build_linux - run: cargo build --all-features --verbose --release - - name: rustfmt - run: cargo fmt --all -- --check - - name: Run tests - run: cargo test --features plotly_ndarray,kaleido --release --verbose - - name: Run basic charts - run: cargo run --example basic_charts --release - - name: Run financial charts - run: cargo run --example financial_charts --release - - name: Run fundamentals - run: cargo run --example fundamentals --release - - name: Run ndarray support - run: cargo run --example ndarray_support --features plotly_ndarray --release - - name: Run scientific charts - run: cargo run --example scientific_charts --release - - name: Run statistical charts - run: cargo run --example statistical_charts --release - - name: Run subplots - run: cargo run --example subplots --release - - name: Run 3D plots - run: cargo run --example plot3d --release - - build_windows: - runs-on: windows-latest - + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@nightly + with: + components: rustfmt + - run: cargo fmt --all -- --check + - run: cd ${{ github.workspace }}/examples && cargo fmt --all -- --check + + clippy: + name: Clippy + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: build_windows - run: cargo build --all-features --verbose --release - - name: Run tests - run: cargo test --features plotly_ndarray,kaleido --release --verbose - - name: Run basic charts - run: cargo run --example basic_charts --release - - name: Run financial charts - run: cargo run --example financial_charts --release - - name: Run fundamentals - run: cargo run --example fundamentals --release - - name: Run ndarray support - run: cargo run --example ndarray_support --features plotly_ndarray --release - - name: Run scientific charts - run: cargo run --example scientific_charts --release - - name: Run statistical charts - run: cargo run --example statistical_charts --release - - name: Run subplots - run: cargo run --example subplots --release - - name: Run 3D plots - run: cargo run --example plot3d --release - - build_macos: - runs-on: macos-latest + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy + - run: cargo clippy -- -D warnings + - run: cd ${{ github.workspace }}/examples && cargo clippy -- -D warnings + test: + name: Tests + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: cargo test --features=plotly_ndarray,kaleido + + build_examples: + name: Build Examples + strategy: + fail-fast: false + matrix: + example: [ # missing jupyter and wasm-yew-minimal + 3d_charts, + basic_charts, + custom_controls, + financial_charts, + images, + kaleido, + maps, + ndarray, + scientific_charts, + shapes, + subplots + ] + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: build_macos - run: cargo build --all-features --verbose --release - - name: Run tests - run: cargo test --features plotly_ndarray,kaleido --release --verbose - - name: Run basic charts - run: cargo run --example basic_charts --release - - name: Run financial charts - run: cargo run --example financial_charts --release - - name: Run fundamentals - run: cargo run --example fundamentals --release - - name: Run ndarray support - run: cargo run --example ndarray_support --features plotly_ndarray --release - - name: Run scientific charts - run: cargo run --example scientific_charts --release - - name: Run statistical charts - run: cargo run --example statistical_charts --release - - name: Run subplots - run: cargo run --example subplots --release - - name: Run 3D plots - run: cargo run --example plot3d --release + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: cd ${{ github.workspace }}/examples/${{ matrix.example }} && cargo build + diff --git a/.gitignore b/.gitignore index 4568041f..62bcbed4 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,6 @@ gh-pages/ Untitled* .ipynb_checkpoints/ .DS_Store -.vscode \ No newline at end of file +.vscode +dist/ +out.* \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 55b2a201..432aaa61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.8.2] - 2022-11-03 +### Added +- [[#110](https://github.com/igiagkiozis/plotly/pull/110)] `LegendGroupTitle` to existing traces. +- [[#88](https://github.com/igiagkiozis/plotly/pull/88)] `Mesh3D`, `Image`, `ScatterMapbox` traces. + +### Changed +- [[#113](https://github.com/igiagkiozis/plotly/pull/113)] Refactored the structure of the examples to make them more accessible, whilst adding more examples e.g. for `wasm`. +- [[#115](https://github.com/igiagkiozis/plotly/pull/115)] Simplify the function signature of Plot.to_inline_html() so that it just takes `Option<&str>` as an argument. + ## [0.8.1] - 2022-09-25 ### Added - Button support (i.e. [updatemenus](https://plotly.com/javascript/reference/layout/updatemenus/)) contibuted by [@sreenathkrishnan](https://github.com/sreenathkrishnan). Details and examples in this well written PR [#99](https://github.com/igiagkiozis/plotly/pull/99). diff --git a/Cargo.toml b/Cargo.toml index adc0105d..b6aa8df4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,5 +2,5 @@ members = [ "plotly", "plotly_derive", - "plotly_kaleido" + "plotly_kaleido", ] \ No newline at end of file diff --git a/README.md b/README.md index 22523557..6a5a4b29 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

Plotly.rs

+

Plotly.rs

Plotly for Rust
@@ -11,69 +11,204 @@ | Changelog - +
- + build status - + Crates.io - + Downloads - + Documentation - + Minimum Version
+
+ +# Table of Contents + +* [Introduction](#introduction) +* [Basic Usage](#basic-usage) + * [Exporting an Interactive Plot](#exporting-an-interactive-plot) + * [Exporting a Static Image](#exporting-a-static-image) + * [Usage Within a Wasm Environment](#usage-within-a-wasm-environment) +* [Crate Feature Flags](#crate-feature-flags) +* [Contributing](#contributing) +* [License](#license) + +# Introduction A plotting library for Rust powered by [Plotly.js](https://plot.ly/javascript/). +Documentation and numerous interactive examples are available in the [Plotly.rs Book](https://igiagkiozis.github.io/plotly/content/getting_started.html), the [examples/](https://github.com/igiagkiozis/plotly/tree/master/examples) directory and [docs.rs](https://docs.rs/crate/plotly). -## Usage + +For changes since the last version, please consult the [changelog](https://github.com/igiagkiozis/plotly/blob/master/CHANGELOG.md). + +# Basic Usage Add this to your `Cargo.toml`: ```toml [dependencies] -plotly = "0.8.1" +plotly = "0.8.2" ``` -Documentation is available in the [Plotly.rs Book](https://igiagkiozis.github.io/plotly/content/getting_started.html) and [Recipes](https://igiagkiozis.github.io/plotly/content/recipes.html). +## Exporting an Interactive Plot -For changes since the last version please consult the [change log](https://github.com/igiagkiozis/plotly/blob/master/CHANGELOG.md). +Any figure can be saved as an HTML file using the `Plot.write_html()` method. These HTML files can be opened in any web browser to access the fully interactive figure. -## Crate Feature Flags -The following feature flags are available: -* `kaleido` - * Optional, compatible with Rust stable. - * Adds plot save functionality to the following formats: png, jpeg, webp, svg, pdf and eps. - * Requires some additional configuration, see [plotly_kaleido](https://github.com/igiagkiozis/plotly/tree/master/plotly_kaleido). -* `plotly_ndarray` - * Optional, compatible with Rust stable. - * Adds support for creating plots directly using [ndarray](https://github.com/rust-ndarray/ndarray) types. -* `wasm` - * Optional, compatible with Rust stable. - * Disables OS-specific functions, therefore allowing compilation in WASM environments. Note that `examples` won't compile when this feature is enabled, as they require OS-specific functions. - -Saving to png, jpeg, webp, svg, pdf and eps formats can be made available by enabling the `kaleido` feature: +```rust +use plotly::{Plot, Scatter}; + +let mut plot = Plot::new(); +let trace = Scatter::new(vec![0, 1, 2], vec![2, 1, 0]); +plot.add_trace(trace); + +plot.write_html("out.html"); +``` + +By default, the Plotly JavaScript library will be included via CDN, which results in a smaller filesize, but slightly slower first load as the JavaScript library has to be downloaded first. To instead embed the JavaScript library (several megabytes in size) directly into the HTML file, the following can be done: + +```rust +// <-- Create a `Plot` --> + +plot.use_local_plotly(); +plot.write_html("out.html"); +``` + +If you only want to view the plot in the browser quickly, use the `Plot.show()` method. + +```rust +// <-- Create a `Plot` --> + +plot.show(); // The default web browser will open, displaying an interactive plot +``` + +## Exporting a Static Image + +To save a plot as a static image, the `kaleido` feature is required: ```toml +# Cargo.toml + [dependencies] -plotly = { version = "0.8.1", features = ["kaleido"] } +plotly = { version = "0.8.2", features = ["kaleido"] } ``` -For further details please see [plotly_kaleido](https://github.com/igiagkiozis/plotly/tree/master/plotly_kaleido). +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. + +The Kaleido binary is downloaded 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. + +Exporting a simple plot looks like this: + +```rust +use plotly::{ImageFormat, Plot}; + +let mut plot = Plot::new(); +let trace = Scatter::new(vec![0, 1, 2], vec![2, 1, 0]); +plot.add_trace(trace); + +plot.write_image("out.png", ImageFormat::PNG, 800, 600, 1.0); +``` + +## Usage Within a Wasm Environment + +Using `Plotly.rs` in a Wasm-based frontend framework is possible by enabling the `wasm` feature: + +```toml +# Cargo.toml + +[dependencies] +plotly = { version = "0.8.2", features = ["wasm"] } +``` + +First, make sure that you have the Plotly JavaScript library in your base HTML template: + +```html + + + + + + + + + + +``` + +A simple `Plot` component would look as follows, using `Yew` as an example frontend framework: + +```rust +use plotly::{Plot, Scatter}; +use yew::prelude::*; + + +#[function_component(PlotComponent)] +pub fn plot_component() -> Html { + let p = yew_hooks::use_async::<_, _, ()>({ + let id = "plot-div"; + let mut plot = Plot::new(); + let trace = Scatter::new(vec![0, 1, 2], vec![2, 1, 0]); + plot.add_trace(trace); + + async move { + plotly::bindings::new_plot(id, &plot).await; + Ok(()) + } + }); + + + use_effect_with_deps(move |_| { + p.run(); + || () + }, (), + ); + + + html! { +
+ } +} +``` + +More detailed standalone examples can be found in the [examples/](https://github.com/igiagkiozis/plotly/tree/master/examples) directory. + +# Crate Feature Flags + +The following feature flags are available: + +### `kaleido` + +Adds plot save functionality to the following formats: `png`, `jpeg`, `webp`, `svg`, `pdf` and `eps`. + +### `plotly_image` + +Adds trait implementations so that `image::RgbImage` and `image::RgbaImage` can be used more directly with the `plotly::Image` trace. + +### `plotly_ndarray` + +Adds support for creating plots directly using [ndarray](https://github.com/rust-ndarray/ndarray) types. + +### `wasm` + +Enables compilation for the `wasm32-unknown-unknown` target and provides access to a `bindings` module containing wrappers around functions exported by the plotly.js library. # Contributing -Please consult the [contributing guide](https://github.com/igiagkiozis/plotly/blob/master/CONTRIBUTING.md). +* If you've spotted a bug or would like to see a new feature, please submit an issue on the [issue tracker](https://github.com/igiagkiozis/plotly/issues). + +* Pull requests are welcome, see the [contributing guide](https://github.com/igiagkiozis/plotly/blob/master/CONTRIBUTING.md) for more information. # License -Plotly.rs is distributed under the terms of the MIT license. +`Plotly.rs` is distributed under the terms of the MIT license. -See [LICENSE-MIT](https://github.com/igiagkiozis/plotly/blob/master/LICENSE-MIT), and [COPYRIGHT](https://github.com/igiagkiozis/plotly/blob/master/COPYRIGHT) for details. +See [LICENSE-MIT](https://github.com/igiagkiozis/plotly/blob/master/LICENSE-MIT), and [COPYRIGHT](https://github.com/igiagkiozis/plotly/blob/master/COPYRIGHT) for details. \ No newline at end of file diff --git a/docs/book/src/getting_started.md b/docs/book/src/getting_started.md index 156c7736..a3e54e06 100644 --- a/docs/book/src/getting_started.md +++ b/docs/book/src/getting_started.md @@ -22,7 +22,7 @@ To start using [plotly.rs](https://github.com/igiagkiozis/plotly) in your projec ```toml [dependencies] -plotly = "0.8.1" +plotly = "0.8.2" ``` [Plotly.rs](https://github.com/igiagkiozis/plotly) is ultimately a thin wrapper around the `plotly.js` library. The main job of this library is to provide `structs` and `enums` which get serialized to `json` and passed to the `plotly.js` library to actually do the heavy lifting. As such, if you are familiar with `plotly.js` or its derivatives (e.g. the equivalent Python library), then you should find [`plotly.rs`](https://github.com/igiagkiozis/plotly) intuitive to use. @@ -97,7 +97,7 @@ To add the ability to save plots in the following formats: png, jpeg, webp, svg, ```toml [dependencies] -plotly = { version = "0.8.1", features = ["kaleido"] } +plotly = { version = "0.8.2", features = ["kaleido"] } ``` ## WebAssembly Support diff --git a/examples/3d_charts/Cargo.toml b/examples/3d_charts/Cargo.toml new file mode 100644 index 00000000..21a4f1ce --- /dev/null +++ b/examples/3d_charts/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "three-d-charts" +version = "0.1.0" +authors = ["Michael Freeborn "] +edition = "2021" + +[dependencies] +ndarray = "0.15.6" +plotly = { path = "../../plotly" } diff --git a/examples/3d_charts/README.md b/examples/3d_charts/README.md new file mode 100644 index 00000000..f5babb6d --- /dev/null +++ b/examples/3d_charts/README.md @@ -0,0 +1,6 @@ +# 3D Charts + +## How to Run + +1. Configure which example(s) you want to run by commenting/uncommenting lines in the `main` function, located in `src/main.rs`. +2. Run `cargo run`. \ No newline at end of file diff --git a/plotly/examples/plot3d.rs b/examples/3d_charts/src/main.rs similarity index 66% rename from plotly/examples/plot3d.rs rename to examples/3d_charts/src/main.rs index bc09288b..d5bf785a 100644 --- a/plotly/examples/plot3d.rs +++ b/examples/3d_charts/src/main.rs @@ -1,14 +1,16 @@ -use itertools_num::linspace; +#![allow(dead_code)] + +use ndarray::Array; use plotly::{ common::{ColorScale, ColorScalePalette, Marker, MarkerSymbol, Mode, Title}, layout::{Axis, Layout}, - Plot, Scatter3D, Surface, + Mesh3D, Plot, Scatter3D, Surface, }; // 3D Scatter Plots -fn simple_scatter3d_plot(show: bool) { +fn simple_scatter3d_plot() { let n: usize = 100; - let t: Vec = linspace(0., 10., n).collect(); + let t: Vec = Array::linspace(0., 10., n).into_raw_vec(); let y: Vec = t.iter().map(|x| x.sin()).collect(); let z: Vec = t.iter().map(|x| x.cos()).collect(); @@ -16,14 +18,12 @@ fn simple_scatter3d_plot(show: bool) { let mut plot = Plot::new(); plot.add_trace(trace); - if show { - plot.show(); - } + plot.show(); } -fn customized_scatter3d_plot(show: bool) { +fn customized_scatter3d_plot() { let n: usize = 100; - let t: Vec = linspace::(0., 10., n).collect(); + let t: Vec = Array::linspace(0., 10., n).into_raw_vec(); let y: Vec = t.iter().map(|x| x.sin()).collect(); let z: Vec = t.iter().map(|x| x.cos()).collect(); let sizelookup = z.clone(); @@ -63,15 +63,13 @@ fn customized_scatter3d_plot(show: bool) { .z_axis(Axis::new().title("z Axis".into())); plot.set_layout(layout); - if show { - plot.show(); - } + plot.show(); } // 3D Line Plots -fn simple_line3d_plot(show: bool) { +fn simple_line3d_plot() { let n: usize = 100; - let t: Vec = linspace(0., 10., n).collect(); + let t: Vec = Array::linspace(0., 10., n).into_raw_vec(); let y: Vec = t.iter().map(|x| x.sin()).collect(); let z: Vec = t.iter().map(|x| x.cos()).collect(); @@ -79,16 +77,14 @@ fn simple_line3d_plot(show: bool) { let mut plot = Plot::new(); plot.add_trace(trace); - if show { - plot.show(); - } + plot.show(); } // 3D Surface Plot -fn surface_plot(show: bool) { +fn surface_plot() { let n: usize = 100; - let x: Vec = linspace(-10., 10., n).collect(); - let y: Vec = linspace(-10., 10., n).collect(); + let x: Vec = Array::linspace(-10., 10., n).into_raw_vec(); + let y: Vec = Array::linspace(-10., 10., n).into_raw_vec(); let z: Vec> = x .iter() .map(|i| { @@ -102,16 +98,38 @@ fn surface_plot(show: bool) { let mut plot = Plot::new(); plot.add_trace(trace); - if show { - plot.show(); - } + plot.show(); +} + +fn mesh_3d_plot() { + let trace = Mesh3D::new( + vec![0, 1, 2, 0], + vec![0, 0, 1, 2], + vec![0, 2, 0, 1], + vec![0, 0, 0, 1], + vec![1, 2, 3, 2], + vec![2, 3, 1, 3], + ) + .intensity(vec![0.0, 0.33, 0.66, 1.0]) + .color_scale(ColorScale::Palette(ColorScalePalette::Rainbow)); + + let mut plot = Plot::new(); + plot.add_trace(trace); + + plot.show(); } -fn main() -> std::io::Result<()> { +fn main() { + // Uncomment any of these lines to display the example. + // Scatter3D Plots - simple_scatter3d_plot(true); - simple_line3d_plot(true); - customized_scatter3d_plot(true); - surface_plot(true); - Ok(()) + // simple_scatter3d_plot(); + // simple_line3d_plot(); + // customized_scatter3d_plot(); + + // Surface Plots + // surface_plot(); + + // Mesh Plots + // mesh_3d_plot(); } diff --git a/examples/Cargo.toml b/examples/Cargo.toml new file mode 100644 index 00000000..fb11e879 --- /dev/null +++ b/examples/Cargo.toml @@ -0,0 +1,3 @@ +[workspace] +members = ["*"] +exclude = ["jupyter", "target"] \ No newline at end of file diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000..e848a986 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,5 @@ +# Examples + +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. \ No newline at end of file diff --git a/examples/basic_charts/Cargo.toml b/examples/basic_charts/Cargo.toml new file mode 100644 index 00000000..82e198a4 --- /dev/null +++ b/examples/basic_charts/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "basic-charts" +version = "0.1.0" +authors = ["Michael Freeborn "] +edition = "2021" + +[dependencies] +ndarray = "0.15.6" +plotly = { path = "../../plotly" } +rand = "0.8.5" +rand_distr = "0.4.3" diff --git a/examples/basic_charts/README.md b/examples/basic_charts/README.md new file mode 100644 index 00000000..e9ae3fc6 --- /dev/null +++ b/examples/basic_charts/README.md @@ -0,0 +1,6 @@ +# Basic Charts + +## How to Run + +1. Configure which example(s) you want to run by commenting/uncommenting lines in the `main` function, located in `src/main.rs`. +2. Run `cargo run`. \ No newline at end of file diff --git a/plotly/examples/basic_charts.rs b/examples/basic_charts/src/main.rs similarity index 82% rename from plotly/examples/basic_charts.rs rename to examples/basic_charts/src/main.rs index 8a030f5d..65518e2f 100644 --- a/plotly/examples/basic_charts.rs +++ b/examples/basic_charts/src/main.rs @@ -1,4 +1,6 @@ -use itertools_num::linspace; +#![allow(dead_code)] + +use ndarray::Array; use plotly::{ color::{NamedColor, Rgb, Rgba}, common::{ @@ -12,24 +14,22 @@ use plotly::{ use rand_distr::{Distribution, Normal, Uniform}; // Scatter Plots -fn simple_scatter_plot(show: bool) { +fn simple_scatter_plot() { let n: usize = 100; - let t: Vec = linspace(0., 10., n).collect(); + let t: Vec = Array::linspace(0., 10., n).into_raw_vec(); 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); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("simple_scatter_plot"))); + + plot.show(); } -fn line_and_scatter_plots(show: bool) { +fn line_and_scatter_plots() { let n: usize = 100; let mut rng = rand::thread_rng(); - let random_x: Vec = linspace(0., 1., n).collect(); + let random_x: Vec = Array::linspace(0., 1., n).into_raw_vec(); let random_y0: Vec = Normal::new(5., 1.) .unwrap() .sample_iter(&mut rng) @@ -60,13 +60,11 @@ fn line_and_scatter_plots(show: bool) { plot.add_trace(trace1); plot.add_trace(trace2); plot.add_trace(trace3); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("line_and_scatter_plots"))); + + plot.show(); } -fn bubble_scatter_plots(show: bool) { +fn bubble_scatter_plots() { let trace1 = Scatter::new(vec![1, 2, 3, 4], vec![10, 11, 12, 13]) .mode(Mode::Markers) .marker( @@ -81,15 +79,13 @@ fn bubble_scatter_plots(show: bool) { ); let mut plot = Plot::new(); plot.add_trace(trace1); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("bubble_scatter_plots"))); + + plot.show(); } -fn polar_scatter_plot(show: bool) { +fn polar_scatter_plot() { let n: usize = 400; - let theta: Vec = linspace(0., 360., n).collect(); + let theta: Vec = Array::linspace(0., 360., n).into_raw_vec(); let r: Vec = theta .iter() .map(|x| { @@ -102,13 +98,11 @@ fn polar_scatter_plot(show: bool) { let trace = ScatterPolar::new(theta, r).mode(Mode::Lines); let mut plot = Plot::new(); plot.add_trace(trace); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("polar_scatter_plot"))); + + plot.show(); } -fn data_labels_hover(show: bool) { +fn data_labels_hover() { let trace1 = Scatter::new(vec![1, 2, 3, 4, 5], vec![1, 6, 3, 6, 1]) .mode(Mode::Markers) .name("Team A") @@ -127,13 +121,11 @@ fn data_labels_hover(show: bool) { .x_axis(Axis::new().title("x".into()).range(vec![0.75, 5.25])) .y_axis(Axis::new().title("y".into()).range(vec![0., 8.])); plot.set_layout(layout); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("data_labels_hover"))); + + plot.show(); } -fn data_labels_on_the_plot(show: bool) { +fn data_labels_on_the_plot() { let trace1 = Scatter::new(vec![1, 2, 3, 4, 5], vec![1, 6, 3, 6, 1]) .mode(Mode::Markers) .name("Team A") @@ -154,13 +146,11 @@ fn data_labels_on_the_plot(show: bool) { .x_axis(Axis::new().range(vec![0.75, 5.25])) .y_axis(Axis::new().range(vec![0., 8.])); plot.set_layout(layout); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("data_labels_on_the_plot"))); + + plot.show(); } -fn colored_and_styled_scatter_plot(show: bool) { +fn colored_and_styled_scatter_plot() { let trace1 = Scatter::new(vec![52698, 43117], vec![53, 31]) .mode(Mode::Markers) .name("North America") @@ -239,16 +229,11 @@ fn colored_and_styled_scatter_plot(show: bool) { plot.add_trace(trace3); plot.add_trace(trace4); plot.set_layout(layout); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("colored_and_styled_scatter_plot")) - ); + + plot.show(); } -fn large_data_sets(show: bool) { +fn large_data_sets() { let n: usize = 100_000; let mut rng = rand::thread_rng(); let r: Vec = Uniform::new(0., 1.).sample_iter(&mut rng).take(n).collect(); @@ -279,14 +264,11 @@ fn large_data_sets(show: bool) { let mut plot = Plot::new(); plot.add_trace(trace); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("large_data_sets"))); + plot.show(); } // Line Charts -fn adding_names_to_line_and_scatter_plot(show: bool) { +fn adding_names_to_line_and_scatter_plot() { let trace1 = Scatter::new(vec![1, 2, 3, 4], vec![10, 15, 13, 17]) .mode(Mode::Markers) .name("Scatter"); @@ -303,16 +285,11 @@ fn adding_names_to_line_and_scatter_plot(show: bool) { plot.add_trace(trace2); plot.add_trace(trace3); plot.set_layout(layout); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("adding_names_to_line_and_scatter_plot")) - ); + + plot.show(); } -fn line_and_scatter_styling(show: bool) { +fn line_and_scatter_styling() { let trace1 = Scatter::new(vec![1, 2, 3, 4], vec![10, 15, 13, 17]) .mode(Mode::Markers) .name("trace1") @@ -333,13 +310,11 @@ fn line_and_scatter_styling(show: bool) { plot.add_trace(trace2); plot.add_trace(trace3); plot.set_layout(layout); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("line_and_scatter_styling"))); + + plot.show(); } -fn styling_line_plot(show: bool) { +fn styling_line_plot() { let trace1 = Scatter::new(vec![1, 2, 3, 4], vec![10, 15, 13, 17]) .mode(Mode::Markers) .name("Red") @@ -357,13 +332,11 @@ fn styling_line_plot(show: bool) { plot.add_trace(trace1); plot.add_trace(trace2); plot.set_layout(layout); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("styling_line_plot"))); + + plot.show(); } -fn line_shape_options_for_interpolation(show: bool) { +fn line_shape_options_for_interpolation() { let trace1 = Scatter::new(vec![1, 2, 3, 4, 5], vec![1, 3, 2, 3, 1]) .mode(Mode::LinesMarkers) .name("linear") @@ -403,16 +376,11 @@ fn line_shape_options_for_interpolation(show: bool) { plot.add_trace(trace4); plot.add_trace(trace5); plot.add_trace(trace6); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("line_shape_options_for_interpolation")) - ); + + plot.show(); } -fn line_dash(show: bool) { +fn line_dash() { let trace1 = Scatter::new(vec![1, 2, 3, 4, 5], vec![1, 3, 2, 3, 1]) .mode(Mode::LinesMarkers) .name("solid") @@ -455,13 +423,11 @@ fn line_dash(show: bool) { plot.add_trace(trace4); plot.add_trace(trace5); plot.add_trace(trace6); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("line_dash"))); + + plot.show(); } -fn filled_lines(show: bool) { +fn filled_lines() { let x1 = vec![ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 10.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, @@ -552,25 +518,21 @@ fn filled_lines(show: bool) { plot.add_trace(trace4); plot.add_trace(trace5); plot.add_trace(trace6); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("filled_lines"))); + + plot.show(); } // Bar Charts -fn basic_bar_chart(show: bool) { +fn basic_bar_chart() { let animals = vec!["giraffes", "orangutans", "monkeys"]; let t = Bar::new(animals, vec![20, 14, 23]); let mut plot = Plot::new(); plot.add_trace(t); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("basic_bar_chart"))); + + plot.show(); } -fn grouped_bar_chart(show: bool) { +fn grouped_bar_chart() { let animals1 = vec!["giraffes", "orangutans", "monkeys"]; let trace1 = Bar::new(animals1, vec![20, 14, 23]).name("SF Zoo"); @@ -583,13 +545,11 @@ fn grouped_bar_chart(show: bool) { plot.add_trace(trace1); plot.add_trace(trace2); plot.set_layout(layout); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("grouped_bar_chart"))); + + plot.show(); } -fn stacked_bar_chart(show: bool) { +fn stacked_bar_chart() { let animals1 = vec!["giraffes", "orangutans", "monkeys"]; let trace1 = Bar::new(animals1, vec![20, 14, 23]).name("SF Zoo"); @@ -602,14 +562,12 @@ fn stacked_bar_chart(show: bool) { plot.add_trace(trace1); plot.add_trace(trace2); plot.set_layout(layout); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("stacked_bar_chart"))); + + plot.show(); } // Sankey Diagrams -fn basic_sankey_diagram(show: bool) { +fn basic_sankey_diagram() { // https://plotly.com/javascript/sankey-diagram/#basic-sankey-diagram let trace = Sankey::new() .orientation(Orientation::Horizontal) @@ -643,38 +601,35 @@ fn basic_sankey_diagram(show: bool) { plot.add_trace(trace); plot.set_layout(layout); - if show { - plot.show(); - } - - println!("{}", plot.to_inline_html(Some("basic_sankey_diagram"))); + plot.show(); } -fn main() -> std::io::Result<()> { +fn main() { + // Uncomment any of these lines to display the example. + // Scatter Plots - simple_scatter_plot(true); - line_and_scatter_plots(true); - bubble_scatter_plots(true); - polar_scatter_plot(true); - data_labels_hover(true); - data_labels_on_the_plot(true); - colored_and_styled_scatter_plot(true); - large_data_sets(true); + // simple_scatter_plot(); + // line_and_scatter_plots(); + // bubble_scatter_plots(); + // polar_scatter_plot(); + // data_labels_hover(); + // data_labels_on_the_plot(); + // colored_and_styled_scatter_plot(); + // large_data_sets(); // Line Charts - adding_names_to_line_and_scatter_plot(true); - line_and_scatter_styling(true); - styling_line_plot(true); - line_shape_options_for_interpolation(true); - line_dash(true); - filled_lines(true); + // adding_names_to_line_and_scatter_plot(); + // line_and_scatter_styling(); + // styling_line_plot(); + // line_shape_options_for_interpolation(); + // line_dash(); + // filled_lines(); // Bar Charts - basic_bar_chart(true); - grouped_bar_chart(true); - stacked_bar_chart(true); + // basic_bar_chart(); + // grouped_bar_chart(); + // stacked_bar_chart(); // Sankey Diagrams - basic_sankey_diagram(true); - Ok(()) + // basic_sankey_diagram(); } diff --git a/examples/custom_controls/Cargo.toml b/examples/custom_controls/Cargo.toml new file mode 100644 index 00000000..ffcb1423 --- /dev/null +++ b/examples/custom_controls/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "custom-controls" +version = "0.1.0" +authors = ["Michael Freeborn "] +edition = "2021" + +[dependencies] +itertools = "0.10.3" +plotly = { path = "../../plotly" } \ No newline at end of file diff --git a/examples/custom_controls/README.md b/examples/custom_controls/README.md new file mode 100644 index 00000000..19d72b4d --- /dev/null +++ b/examples/custom_controls/README.md @@ -0,0 +1,6 @@ +# Custom Controls + +## How to Run + +1. Configure which example(s) you want to run by commenting/uncommenting lines in the `main` function, located in `src/main.rs`. +2. Run `cargo run`. diff --git a/plotly/examples/buttons.rs b/examples/custom_controls/src/main.rs similarity index 77% rename from plotly/examples/buttons.rs rename to examples/custom_controls/src/main.rs index b1ad8e73..2f285361 100644 --- a/plotly/examples/buttons.rs +++ b/examples/custom_controls/src/main.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + use itertools::Itertools; use plotly::{ common::{Anchor, ColorScalePalette, Visible}, @@ -8,16 +10,17 @@ use plotly::{ Bar, HeatMap, Layout, Plot, }; -// Dropdown to alternate between two bar plots -fn bar_plot_visible_dropdown(show: bool) { +/// Display a bar chart with an associated dropdown selector to show different +/// data. +fn bar_plot_with_dropdown_for_different_data() { type BarType = Bar<&'static str, i32>; let mut plot = Plot::new(); plot.add_trace( - BarType::new(vec!["giraffes", "orangutans", "monkeys"], vec![20, 14, 23]).name("Animals"), + BarType::new(vec!["Giraffes", "Orangutans", "Monkeys"], vec![20, 14, 23]).name("Animals"), ); plot.add_trace( BarType::new( - vec!["parrot", "chicken", "bluebird", "own"], + vec!["Little Grebes", "Nuthatches", "Firecrests", "Goldfinches"], vec![8, 23, 17, 2], ) .name("Birds") @@ -34,14 +37,13 @@ fn bar_plot_visible_dropdown(show: bool) { .build(), ]; plot.set_layout(Layout::new().update_menus(vec![UpdateMenu::new().y(0.8).buttons(buttons)])); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("bar_plot_visible_dropdown"))); + + plot.show(); } -// Heatmap with buttons to choose colorscale -fn basic_heat_map(show: bool) { +/// Display a heat map, with buttons to allow for toggling of different +/// colorscales. +fn heat_map_with_modifiable_colorscale() { type HeatMapType = HeatMap>; let gauss = |v: i32| (-v as f64 * v as f64 / 200.0).exp(); let z = (-30..30) @@ -69,14 +71,12 @@ fn basic_heat_map(show: bool) { .y(0.8) .buttons(buttons)])); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("basic_heat_map"))); + plot.show(); } -// Button to change barmode -fn bar_plot_relayout(show: bool) { +/// Display a bar chart, with buttons to toggle between stacked or grouped +/// display maodes. +fn bar_chart_with_modifiable_bar_mode() { type BarType = Bar<&'static str, i32>; let mut plot = Plot::new(); plot.add_trace( @@ -103,15 +103,14 @@ fn bar_plot_relayout(show: bool) { .ty(UpdateMenuType::Buttons) .direction(UpdateMenuDirection::Right) .buttons(buttons)])); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("bar_plot_relayout"))); + + plot.show(); } -fn main() -> std::io::Result<()> { - bar_plot_visible_dropdown(true); - basic_heat_map(true); - bar_plot_relayout(true); - Ok(()) +fn main() { + // Uncomment any of these lines to display the example. + + // bar_plot_with_dropdown_for_different_data(); + // heat_map_with_modifiable_colorscale(); + // bar_chart_with_modifiable_bar_mode(); } diff --git a/examples/financial_charts/Cargo.toml b/examples/financial_charts/Cargo.toml new file mode 100644 index 00000000..e6dc4964 --- /dev/null +++ b/examples/financial_charts/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "financial-charts" +version = "0.1.0" +authors = ["Michael Freeborn "] +edition = "2021" + +[dependencies] +csv = "1.1.6" +plotly = { path = "../../plotly" } +serde = "1.0.147" diff --git a/examples/financial_charts/README.md b/examples/financial_charts/README.md new file mode 100644 index 00000000..196c30dc --- /dev/null +++ b/examples/financial_charts/README.md @@ -0,0 +1,6 @@ +# Financial Charts + +## How to Run + +1. Configure which example(s) you want to run by commenting/uncommenting lines in the `main` function, located in `src/main.rs`. +2. Run `cargo run`. \ No newline at end of file diff --git a/plotly/examples/finance_charts_apple.csv b/examples/financial_charts/assets/finance_charts_apple.csv similarity index 100% rename from plotly/examples/finance_charts_apple.csv rename to examples/financial_charts/assets/finance_charts_apple.csv diff --git a/plotly/examples/financial_charts.rs b/examples/financial_charts/src/main.rs similarity index 86% rename from plotly/examples/financial_charts.rs rename to examples/financial_charts/src/main.rs index 366cc4d7..2805482b 100644 --- a/plotly/examples/financial_charts.rs +++ b/examples/financial_charts/src/main.rs @@ -1,9 +1,12 @@ +#![allow(dead_code)] + +use std::env; +use std::path::PathBuf; + use plotly::common::{TickFormatStop, Title}; use plotly::layout::{Axis, RangeSelector, RangeSlider, SelectorButton, SelectorStep, StepMode}; use plotly::{Candlestick, Layout, Ohlc, Plot, Scatter}; use serde::Deserialize; -use std::env; -use std::path::PathBuf; #[derive(Deserialize)] #[allow(dead_code)] @@ -23,8 +26,7 @@ struct FinData { fn load_apple_data() -> Vec { let mut p = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); - println!("{:?}", p); - p = p.join("examples").join("finance_charts_apple.csv"); + p = p.join("assets").join("finance_charts_apple.csv"); let mut rdr = csv::Reader::from_path(p).unwrap(); let mut out = Vec::new(); for result in rdr.deserialize() { @@ -36,7 +38,7 @@ fn load_apple_data() -> Vec { } // Time Series and Date Axes -fn time_series_plot_with_custom_date_range(show: bool) { +fn time_series_plot_with_custom_date_range() { let data = load_apple_data(); let date: Vec = data.iter().map(|d| d.date.clone()).collect(); let high: Vec = data.iter().map(|d| d.high).collect(); @@ -51,16 +53,10 @@ fn time_series_plot_with_custom_date_range(show: bool) { .title(Title::new("Manually Set Date Range")); plot.set_layout(layout); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("time_series_plot_with_custom_date_range")) - ); + plot.show(); } -fn time_series_with_range_slider(show: bool) { +fn time_series_with_range_slider() { let data = load_apple_data(); let date: Vec = data.iter().map(|d| d.date.clone()).collect(); let high: Vec = data.iter().map(|d| d.high).collect(); @@ -75,16 +71,10 @@ fn time_series_with_range_slider(show: bool) { .title(Title::new("Manually Set Date Range")); plot.set_layout(layout); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("time_series_with_range_slider")) - ); + plot.show(); } -fn time_series_with_range_selector_buttons(show: bool) { +fn time_series_with_range_selector_buttons() { let data = load_apple_data(); let date: Vec = data.iter().map(|d| d.date.clone()).collect(); let high: Vec = data.iter().map(|d| d.high).collect(); @@ -123,16 +113,10 @@ fn time_series_with_range_selector_buttons(show: bool) { ); plot.set_layout(layout); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("time_series_with_range_selector_buttons")) - ); + plot.show(); } -fn customizing_tick_label_formatting_by_zoom_level(show: bool) { +fn customizing_tick_label_formatting_by_zoom_level() { let data = load_apple_data(); let date: Vec = data.iter().map(|d| d.date.clone()).collect(); let high: Vec = data.iter().map(|d| d.high).collect(); @@ -168,17 +152,11 @@ fn customizing_tick_label_formatting_by_zoom_level(show: bool) { ); plot.set_layout(layout); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("customizing_tick_label_formatting_by_zoom_level")) - ); + plot.show(); } // Candlestick Charts -fn simple_candlestick_chart(show: bool) { +fn simple_candlestick_chart() { let x = vec![ "2017-01-04", "2017-01-05", @@ -240,14 +218,12 @@ fn simple_candlestick_chart(show: bool) { let mut plot = Plot::new(); plot.add_trace(trace1); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("simple_candlestick_chart"))); + + plot.show(); } // OHLC Charts -fn simple_ohlc_chart(show: bool) { +fn simple_ohlc_chart() { let x = vec![ "2017-01-04", "2017-01-05", @@ -309,24 +285,22 @@ fn simple_ohlc_chart(show: bool) { let mut plot = Plot::new(); plot.add_trace(trace1); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("simple_ohlc_chart"))); + + plot.show(); } -fn main() -> std::io::Result<()> { +fn main() { + // Uncomment any of these lines to display the example. + // Time Series and Date Axes - time_series_plot_with_custom_date_range(true); - time_series_with_range_slider(true); - time_series_with_range_selector_buttons(true); - customizing_tick_label_formatting_by_zoom_level(true); + // time_series_plot_with_custom_date_range(); + // time_series_with_range_slider(); + // time_series_with_range_selector_buttons(); + // customizing_tick_label_formatting_by_zoom_level(); // Candlestick Charts - simple_candlestick_chart(true); + // simple_candlestick_chart(); // OHLC Charts - simple_ohlc_chart(true); - - Ok(()) + // simple_ohlc_chart(); } diff --git a/examples/images/Cargo.toml b/examples/images/Cargo.toml new file mode 100644 index 00000000..144ac7a4 --- /dev/null +++ b/examples/images/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "images" +version = "0.1.0" +authors = ["Michael Freeborn "] +edition = "2021" + +[dependencies] +image = "0.24.4" +ndarray = "0.15.6" +plotly = { path = "../../plotly", features = ["plotly_image", "plotly_ndarray"] } diff --git a/examples/images/README.md b/examples/images/README.md new file mode 100644 index 00000000..917e0c6c --- /dev/null +++ b/examples/images/README.md @@ -0,0 +1,6 @@ +# Images + +## How to Run + +1. Configure which example(s) you want to run by commenting/uncommenting lines in the `main` function, located in `src/main.rs`. +2. Run `cargo run`. \ No newline at end of file diff --git a/examples/images/assets/mario.png b/examples/images/assets/mario.png new file mode 100644 index 00000000..0919e912 Binary files /dev/null and b/examples/images/assets/mario.png differ diff --git a/examples/images/src/main.rs b/examples/images/src/main.rs new file mode 100644 index 00000000..362736aa --- /dev/null +++ b/examples/images/src/main.rs @@ -0,0 +1,98 @@ +#![allow(dead_code)] + +use ndarray::arr2; +use plotly::{color::Rgb, image::ColorModel, Image, Plot}; + +fn basic_image() { + let w = Rgb::new(255, 255, 255); + let b = Rgb::new(0, 0, 0); + let r = Rgb::new(240, 8, 5); + let db = Rgb::new(145, 67, 7); + let lb = Rgb::new(251, 200, 129); + let s = Rgb::new(153, 75, 10); + let bl = Rgb::new(3, 111, 191); + let y = Rgb::new(251, 250, 15); + + let pixels = vec![ + vec![w, w, w, w, r, r, r, r, r, w, w, w, w, w, w], + vec![w, w, w, r, r, r, r, r, r, r, r, r, w, w, w], + vec![w, w, w, db, db, db, lb, lb, b, lb, w, w, w, w, w], + vec![w, w, db, lb, db, lb, lb, lb, b, lb, lb, lb, w, w, w], + vec![w, w, db, lb, db, db, lb, lb, lb, db, lb, lb, lb, w, w], + vec![w, w, db, db, lb, lb, lb, lb, db, db, db, db, w, w, w], + vec![w, w, w, w, lb, lb, lb, lb, lb, lb, lb, w, w, w, w], + vec![w, w, w, r, r, bl, r, r, r, w, w, w, w, w, w], + vec![w, w, r, r, r, bl, r, r, bl, r, r, r, w, w, w], + vec![w, r, r, r, r, bl, bl, bl, bl, r, r, r, r, w, w], + vec![w, lb, lb, r, bl, y, bl, bl, y, bl, r, lb, lb, w, w], + vec![w, lb, lb, lb, bl, bl, bl, bl, bl, bl, lb, lb, lb, w, w], + vec![w, lb, lb, bl, bl, bl, bl, bl, bl, bl, bl, lb, lb, w, w], + vec![w, w, w, bl, bl, bl, w, w, bl, bl, bl, w, w, w, w], + vec![w, w, s, s, s, w, w, w, w, s, s, s, w, w, w], + vec![w, s, s, s, s, w, w, w, w, w, s, s, s, s, w], + ]; + let trace = Image::new(pixels).color_model(ColorModel::RGB); + + let mut plot = Plot::new(); + plot.add_trace(trace); + + plot.show() +} + +fn trace_from_image_crate_rgb() { + let im = image::open("assets/mario.png").unwrap().into_rgb8(); + let trace = Image::new(im).color_model(ColorModel::RGB); + + let mut plot = Plot::new(); + plot.add_trace(trace); + + plot.show() +} + +fn trace_from_image_crate_rgba() { + let im = image::open("assets/mario.png").unwrap().into_rgba8(); + let trace = Image::new(im).color_model(ColorModel::RGBA); + + let mut plot = Plot::new(); + plot.add_trace(trace); + + plot.show() +} + +fn trace_from_ndarray_rgb() { + let pixels = arr2(&[ + [(255, 255, 255), (0, 0, 0)], + [(0, 0, 0), (255, 255, 255)], + [(255, 255, 255), (0, 0, 0)], + ]); + let trace = Image::new(pixels).color_model(ColorModel::RGB); + + let mut plot = Plot::new(); + plot.add_trace(trace); + + plot.show() +} + +fn trace_from_ndarray_rgba() { + let pixels = arr2(&[ + [(255, 255, 255, 1.), (0, 0, 0, 0.25)], + [(0, 0, 0, 0.5), (255, 255, 255, 1.)], + [(255, 255, 255, 1.), (0, 0, 0, 0.75)], + ]); + let trace = Image::new(pixels).color_model(ColorModel::RGBA); + + let mut plot = Plot::new(); + plot.add_trace(trace); + + plot.show() +} + +fn main() { + // Uncomment any of these lines to display the example. + + // basic_image(); + // trace_from_image_crate_rgb(); + // trace_from_image_crate_rgba(); + // trace_from_ndarray_rgb(); + // trace_from_ndarray_rgba(); +} diff --git a/examples/jupyter/README.md b/examples/jupyter/README.md new file mode 100644 index 00000000..236ffb90 --- /dev/null +++ b/examples/jupyter/README.md @@ -0,0 +1,9 @@ +# Jupyter + +## Prerequisites + +1. Install [Jupyter Notebook](https://jupyter.org/install) or [Jupyter Lab](https://jupyterlab.readthedocs.io/en/stable/getting_started/installation.html). +2. Download the `rust` kernel with `cargo install evcxr_jupyter`. +3. Install the kernel with `evcxr_jupyter --install`. +4. Ensure you have installed the jupyter lab plotly extension installed. +4. Open the desirbed `.pynb` notebook or lab examples and run them in the `Jupyter` environment. diff --git a/examples/jupyter/jupyter_lab.ipynb b/examples/jupyter/jupyter_lab.ipynb new file mode 100644 index 00000000..489961f6 --- /dev/null +++ b/examples/jupyter/jupyter_lab.ipynb @@ -0,0 +1,75 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + ":dep ndarray = \"0.15.6\"\n", + ":dep plotly = { version = \">=0.7.0\" }" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "extern crate ndarray;\n", + "extern crate plotly;\n", + "extern crate rand_distr;" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "use ndarray::Array;\n", + "use plotly::common::Mode;\n", + "use plotly::layout::{Layout};\n", + "use plotly::{Plot, Scatter};\n", + "use rand_distr::{num_traits::Float, Distribution};" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "let x0 = Array::linspace(1.0, 3.0, 200).into_raw_vec();\n", + "let y0 = x0.iter().map(|v| *v * (v.powf(2.)).sin() + 1.).collect();\n", + "\n", + "let trace = Scatter::new(x0, y0);\n", + "let mut plot = Plot::new();\n", + "plot.add_trace(trace);\n", + "\n", + "let layout = Layout::new().height(525);\n", + "plot.set_layout(layout);\n", + "\n", + "plot.lab_display();\n", + "format!(\"EVCXR_BEGIN_CONTENT application/vnd.plotly.v1+json\\n{}\\nEVCXR_END_CONTENT\", plot.to_json())" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Rust", + "language": "rust", + "name": "rust" + }, + "language_info": { + "codemirror_mode": "rust", + "file_extension": ".rs", + "mimetype": "text/rust", + "name": "Rust", + "pygment_lexer": "rust", + "version": "" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/examples/jupyter/jupyter_notebook.ipynb b/examples/jupyter/jupyter_notebook.ipynb new file mode 100644 index 00000000..9422daa5 --- /dev/null +++ b/examples/jupyter/jupyter_notebook.ipynb @@ -0,0 +1,78 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + ":dep ndarray = \"0.15.6\"\n", + ":dep plotly = { version = \">=0.7.0\" }" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "extern crate ndarray;\n", + "extern crate plotly;\n", + "extern crate rand_distr;" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "use ndarray::Array;\n", + "use plotly::common::Mode;\n", + "use plotly::layout::{Layout};\n", + "use plotly::{Plot, Scatter};\n", + "use rand_distr::{num_traits::Float, Distribution};" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "let x0 = Array::linspace(1.0, 3.0, 200).into_raw_vec();\n", + "let y0 = x0.iter().map(|v| *v * (v.powf(2.)).sin() + 1.).collect();\n", + "\n", + "let trace = Scatter::new(x0, y0);\n", + "let mut plot = Plot::new();\n", + "plot.add_trace(trace);\n", + "\n", + "let layout = Layout::new().height(525);\n", + "plot.set_layout(layout);\n", + "\n", + "plot.notebook_display();" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Rust", + "language": "rust", + "name": "rust" + }, + "language_info": { + "codemirror_mode": "rust", + "file_extension": ".rs", + "mimetype": "text/rust", + "name": "Rust", + "pygment_lexer": "rust", + "version": "" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/examples/kaleido/Cargo.toml b/examples/kaleido/Cargo.toml new file mode 100644 index 00000000..4d3bc714 --- /dev/null +++ b/examples/kaleido/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "kaleido" +version = "0.1.0" +authors = ["Michael Freeborn "] +edition = "2021" + +[dependencies] +plotly = { path = "../../plotly", features = ["kaleido"] } \ No newline at end of file diff --git a/examples/kaleido/README.md b/examples/kaleido/README.md new file mode 100644 index 00000000..b006bbbd --- /dev/null +++ b/examples/kaleido/README.md @@ -0,0 +1,6 @@ +# Shapes + +## How to Run + +1. Configure the settings got the image export in the `main` function, located in `src/main.rs`. +2. Run `cargo run`. \ No newline at end of file diff --git a/examples/kaleido/src/main.rs b/examples/kaleido/src/main.rs new file mode 100644 index 00000000..02d9e300 --- /dev/null +++ b/examples/kaleido/src/main.rs @@ -0,0 +1,19 @@ +use plotly::{ImageFormat, Plot, Scatter}; + +fn main() { + let mut plot = Plot::new(); + let trace = Scatter::new(vec![0, 1, 2], vec![2, 1, 0]); + plot.add_trace(trace); + + // Adjust these arguments to set the image format, width and height of the + // output image. + let filename = "out"; + let image_format = ImageFormat::PNG; + let width = 800; + let height = 600; + let scale = 1.0; + + // The image will be saved to format!("{filename}.{image_format}") relative to + // the current working directory. + plot.write_image(filename, image_format, width, height, scale); +} diff --git a/examples/maps/Cargo.toml b/examples/maps/Cargo.toml new file mode 100644 index 00000000..6d3bf304 --- /dev/null +++ b/examples/maps/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "maps" +version = "0.1.0" +authors = ["Michael Freeborn "] +edition = "2021" + +[dependencies] +plotly = { path = "../../plotly" } diff --git a/examples/maps/README.md b/examples/maps/README.md new file mode 100644 index 00000000..5fecb44a --- /dev/null +++ b/examples/maps/README.md @@ -0,0 +1,6 @@ +# Maps + +## How to Run + +1. Configure which example(s) you want to run by commenting/uncommenting lines in the `main` function, located in `src/main.rs`. +2. Run `cargo run`. \ No newline at end of file diff --git a/examples/maps/src/main.rs b/examples/maps/src/main.rs new file mode 100644 index 00000000..10312ced --- /dev/null +++ b/examples/maps/src/main.rs @@ -0,0 +1,34 @@ +#![allow(dead_code)] + +use plotly::{ + common::Marker, + layout::{Center, DragMode, Mapbox, MapboxStyle, Margin}, + Layout, Plot, ScatterMapbox, +}; + +fn scatter_mapbox() { + let trace = ScatterMapbox::new(vec![45.5017], vec![-73.5673]) + .marker(Marker::new().size(25).opacity(0.9)); + + 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.show(); +} + +fn main() { + // Uncomment any of these lines to display the example. + + // scatter_mapbox(); +} diff --git a/examples/ndarray/Cargo.toml b/examples/ndarray/Cargo.toml new file mode 100644 index 00000000..4383ff13 --- /dev/null +++ b/examples/ndarray/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "plotly_ndarray" +version = "0.1.0" +authors = ["Michael Freeborn "] +edition = "2021" + +[dependencies] +ndarray = "0.15.6" +plotly = { path = "../../plotly", features = ["plotly_ndarray"] } diff --git a/examples/ndarray/README.md b/examples/ndarray/README.md new file mode 100644 index 00000000..3e212739 --- /dev/null +++ b/examples/ndarray/README.md @@ -0,0 +1,6 @@ +# ndarray Support + +## How to Run + +1. Configure which example(s) you want to run by commenting/uncommenting lines in the `main` function, located in `src/main.rs`. +2. Run `cargo run`. \ No newline at end of file diff --git a/plotly/examples/ndarray_support.rs b/examples/ndarray/src/main.rs similarity index 58% rename from plotly/examples/ndarray_support.rs rename to examples/ndarray/src/main.rs index 7724158a..8754b27f 100644 --- a/plotly/examples/ndarray_support.rs +++ b/examples/ndarray/src/main.rs @@ -1,14 +1,11 @@ -#[cfg(feature = "plotly_ndarray")] +#![allow(dead_code)] + use ndarray::{Array, Ix1, Ix2}; -#[cfg(feature = "plotly_ndarray")] use plotly::common::Mode; -#[cfg(feature = "plotly_ndarray")] use plotly::ndarray::ArrayTraces; -#[cfg(feature = "plotly_ndarray")] use plotly::{Plot, Scatter}; -#[cfg(feature = "plotly_ndarray")] -fn single_ndarray_trace(show: bool) { +fn single_ndarray_trace() { let n: usize = 11; let t: Array = Array::range(0., 10., 10. / n as f64); let ys: Array = t.iter().map(|v| (*v).powf(2.)).collect(); @@ -17,14 +14,11 @@ fn single_ndarray_trace(show: bool) { let mut plot = Plot::new(); plot.add_trace(trace); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("single_ndarray_trace"))); + + plot.show(); } -#[cfg(feature = "plotly_ndarray")] -fn multiple_ndarray_traces_over_columns(show: bool) { +fn multiple_ndarray_traces_over_columns() { let n: usize = 11; let t: Array = Array::range(0., 10., 10. / n as f64); let mut ys: Array = Array::zeros((11, 11)); @@ -43,17 +37,11 @@ fn multiple_ndarray_traces_over_columns(show: bool) { let mut plot = Plot::new(); plot.add_traces(traces); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("multiple_ndarray_traces_over_columns")) - ); + + plot.show(); } -#[cfg(feature = "plotly_ndarray")] -fn multiple_ndarray_traces_over_rows(show: bool) { +fn multiple_ndarray_traces_over_rows() { let n: usize = 11; let t: Array = Array::range(0., 10., 10. / n as f64); let mut ys: Array = Array::zeros((11, 11)); @@ -72,23 +60,14 @@ fn multiple_ndarray_traces_over_rows(show: bool) { let mut plot = Plot::new(); plot.add_traces(traces); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("multiple_ndarray_traces_over_rows")) - ); + + plot.show(); } -#[cfg(feature = "plotly_ndarray")] -fn main() -> std::io::Result<()> { - single_ndarray_trace(true); - multiple_ndarray_traces_over_columns(true); - multiple_ndarray_traces_over_rows(true); +fn main() { + // Uncomment any of these lines to display the example. - Ok(()) + // single_ndarray_trace(); + // multiple_ndarray_traces_over_columns(); + // multiple_ndarray_traces_over_rows(); } - -#[cfg(not(feature = "plotly_ndarray"))] -fn main() {} diff --git a/examples/scientific_charts/Cargo.toml b/examples/scientific_charts/Cargo.toml new file mode 100644 index 00000000..4f12010d --- /dev/null +++ b/examples/scientific_charts/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "scientific-charts" +version = "0.1.0" +authors = ["Michael Freeborn "] +edition = "2021" + +[dependencies] +plotly = { path = "../../plotly" } diff --git a/examples/scientific_charts/README.md b/examples/scientific_charts/README.md new file mode 100644 index 00000000..c2eef8e2 --- /dev/null +++ b/examples/scientific_charts/README.md @@ -0,0 +1,6 @@ +# Scientific Charts + +## How to Run + +1. Configure which example(s) you want to run by commenting/uncommenting lines in the `main` function, located in `src/main.rs`. +2. Run `cargo run`. \ No newline at end of file diff --git a/plotly/examples/scientific_charts.rs b/examples/scientific_charts/src/main.rs similarity index 70% rename from plotly/examples/scientific_charts.rs rename to examples/scientific_charts/src/main.rs index 719bba4e..20d98a94 100644 --- a/plotly/examples/scientific_charts.rs +++ b/examples/scientific_charts/src/main.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + use std::f64::consts::PI; use plotly::common::{ColorScale, ColorScalePalette, Title}; @@ -5,7 +7,7 @@ use plotly::contour::Contours; use plotly::{Contour, HeatMap, Layout, Plot}; // Contour Plots -fn simple_contour_plot(show: bool) { +fn simple_contour_plot() { let n = 200; let mut x = Vec::::new(); let mut y = Vec::::new(); @@ -31,13 +33,11 @@ fn simple_contour_plot(show: bool) { let mut plot = Plot::new(); plot.add_trace(trace); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("simple_contour_plot"))); + + plot.show(); } -fn colorscale_for_contour_plot(show: bool) { +fn colorscale_for_contour_plot() { let z = vec![ vec![10.0, 10.625, 12.5, 15.625, 20.0], vec![5.625, 6.25, 8.125, 11.25, 15.625], @@ -51,16 +51,11 @@ fn colorscale_for_contour_plot(show: bool) { let mut plot = Plot::new(); plot.set_layout(layout); plot.add_trace(trace); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("colorscale_for_contour_plot")) - ); + + plot.show(); } -fn customizing_size_and_range_of_a_contour_plots_contours(show: bool) { +fn customizing_size_and_range_of_a_contour_plots_contours() { let z = vec![ vec![10.0, 10.625, 12.5, 15.625, 20.0], vec![5.625, 6.25, 8.125, 11.25, 15.625], @@ -77,18 +72,11 @@ fn customizing_size_and_range_of_a_contour_plots_contours(show: bool) { let mut plot = Plot::new(); plot.set_layout(layout); plot.add_trace(trace); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some( - "customizing_size_and_range_of_a_contour_plots_contours" - )) - ); + + plot.show(); } -fn customizing_spacing_between_x_and_y_ticks(show: bool) { +fn customizing_spacing_between_x_and_y_ticks() { let z = vec![ vec![10.0, 10.625, 12.5, 15.625, 20.0], vec![5.625, 6.25, 8.125, 11.25, 15.625], @@ -107,35 +95,29 @@ fn customizing_spacing_between_x_and_y_ticks(show: bool) { let mut plot = Plot::new(); plot.set_layout(layout); plot.add_trace(trace); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("customizing_spacing_between_x_and_y_ticks")) - ); + + plot.show(); } // Heatmaps -fn basic_heat_map(show: bool) { +fn basic_heat_map() { let z = vec![vec![1, 20, 30], vec![20, 1, 60], vec![30, 60, 1]]; let trace = HeatMap::new_z(z); let mut plot = Plot::new(); plot.add_trace(trace); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("basic_heat_map"))); + + plot.show(); } -fn main() -> std::io::Result<()> { +fn main() { + // Uncomment any of these lines to display the example. + // Contour Plots - simple_contour_plot(true); - colorscale_for_contour_plot(true); - customizing_size_and_range_of_a_contour_plots_contours(true); - customizing_spacing_between_x_and_y_ticks(true); + simple_contour_plot(); + colorscale_for_contour_plot(); + customizing_size_and_range_of_a_contour_plots_contours(); + customizing_spacing_between_x_and_y_ticks(); // Heatmaps - basic_heat_map(true); - Ok(()) + basic_heat_map(); } diff --git a/examples/shapes/Cargo.toml b/examples/shapes/Cargo.toml new file mode 100644 index 00000000..23361d74 --- /dev/null +++ b/examples/shapes/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "shapes" +version = "0.1.0" +authors = ["Michael Freeborn "] +edition = "2021" + +[dependencies] +ndarray = "0.15.6" +plotly = { path = "../../plotly" } +rand = "0.8.5" +rand_distr = "0.4.3" diff --git a/examples/shapes/README.md b/examples/shapes/README.md new file mode 100644 index 00000000..f924de7d --- /dev/null +++ b/examples/shapes/README.md @@ -0,0 +1,6 @@ +# Shapes + +## How to Run + +1. Configure which example(s) you want to run by commenting/uncommenting lines in the `main` function, located in `src/main.rs`. +2. Run `cargo run`. \ No newline at end of file diff --git a/plotly/examples/fundamentals.rs b/examples/shapes/src/main.rs similarity index 84% rename from plotly/examples/fundamentals.rs rename to examples/shapes/src/main.rs index 3289118f..871986d1 100644 --- a/plotly/examples/fundamentals.rs +++ b/examples/shapes/src/main.rs @@ -1,4 +1,6 @@ -use itertools_num::linspace; +#![allow(dead_code)] + +use ndarray::Array; use plotly::{ color::NamedColor, common::{DashType, Fill, Font, Mode}, @@ -8,23 +10,22 @@ use plotly::{ Bar, Plot, Scatter, }; use rand::thread_rng; -use rand_distr::{Distribution, Normal}; +use rand_distr::{num_traits::Float, Distribution, Normal}; -// Shapes -fn filled_area_chart(show: bool) { +fn filled_area_chart() { let trace1 = Scatter::new(vec![0, 1, 2, 0], vec![0, 2, 0, 0]).fill(Fill::ToSelf); let trace2 = Scatter::new(vec![3, 3, 5, 5, 3], vec![0.5, 1.5, 1.5, 0.5, 0.5]).fill(Fill::ToSelf); + let mut plot = Plot::new(); plot.add_trace(trace1); plot.add_trace(trace2); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("filled_area_chart"))); + println!("{}", plot.to_json()); + + plot.show(); } -fn vertical_and_horizontal_lines_positioned_relative_to_axes(show: bool) { +fn vertical_and_horizontal_lines_positioned_relative_to_axes() { let trace = Scatter::new(vec![2.0, 3.5, 6.0], vec![1.0, 1.5, 1.0]) .text_array(vec![ "Vertical Line", @@ -32,6 +33,7 @@ fn vertical_and_horizontal_lines_positioned_relative_to_axes(show: bool) { "Diagonal dotted Line", ]) .mode(Mode::Text); + let mut plot = Plot::new(); plot.add_trace(trace); @@ -48,6 +50,7 @@ fn vertical_and_horizontal_lines_positioned_relative_to_axes(show: bool) { .y1(2) .line(ShapeLine::new().color(NamedColor::RoyalBlue).width(3.)), ); + layout.add_shape( Shape::new() .shape_type(ShapeType::Line) @@ -62,6 +65,7 @@ fn vertical_and_horizontal_lines_positioned_relative_to_axes(show: bool) { .dash(DashType::DashDot), ), ); + layout.add_shape( Shape::new() .shape_type(ShapeType::Line) @@ -78,24 +82,18 @@ fn vertical_and_horizontal_lines_positioned_relative_to_axes(show: bool) { ); plot.set_layout(layout); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some( - "vertical_and_horizontal_lines_positioned_relative_to_axes" - )) - ); + + plot.show(); } -fn lines_positioned_relative_to_the_plot_and_to_the_axes(show: bool) { +fn lines_positioned_relative_to_the_plot_and_to_the_axes() { let trace = Scatter::new(vec![2.0, 6.0], vec![1.0, 1.0]) .text_array(vec![ "Line positioned relative to the plot", "Line positioned relative to the axes", ]) .mode(Mode::Text); + let mut plot = Plot::new(); plot.add_trace(trace); @@ -127,20 +125,13 @@ fn lines_positioned_relative_to_the_plot_and_to_the_axes(show: bool) { ); plot.set_layout(layout); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some( - "lines_positioned_relative_to_the_plot_and_to_the_axes" - )) - ); + + plot.show(); } -fn creating_tangent_lines_with_shapes(show: bool) { - let x0: Vec = linspace(1.0, 3.0, 200).collect(); - let y0: Vec = x0.iter().map(|v| *v * (v.powf(2.)).sin() + 1.).collect(); +fn creating_tangent_lines_with_shapes() { + let x0 = Array::linspace(1.0, 3.0, 200).into_raw_vec(); + let y0 = x0.iter().map(|v| *v * (v.powf(2.)).sin() + 1.).collect(); let trace = Scatter::new(x0, y0); let mut plot = Plot::new(); @@ -161,6 +152,7 @@ fn creating_tangent_lines_with_shapes(show: bool) { .y1(2.30756) .line(ShapeLine::new().color(NamedColor::Crimson).width(2.5)), ); + layout.add_shape( Shape::new() .x_ref("x") @@ -173,6 +165,7 @@ fn creating_tangent_lines_with_shapes(show: bool) { .y1(3.80796) .line(ShapeLine::new().color(NamedColor::Crimson).width(2.5)), ); + layout.add_shape( Shape::new() .x_ref("x") @@ -187,16 +180,11 @@ fn creating_tangent_lines_with_shapes(show: bool) { ); plot.set_layout(layout); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("creating_tangent_lines_with_shapes")) - ); + + plot.show(); } -fn rectangles_positioned_relative_to_the_axes(show: bool) { +fn rectangles_positioned_relative_to_the_axes() { let trace = Scatter::new(vec![1.5, 4.5], vec![0.75, 0.75]) .text_array(vec!["Unfilled Rectangle", "Filled Rectangle"]) .mode(Mode::Text); @@ -218,6 +206,7 @@ fn rectangles_positioned_relative_to_the_axes(show: bool) { .y1(3.) .line(ShapeLine::new().color(NamedColor::RoyalBlue)), ); + layout.add_shape( Shape::new() .x_ref("x") @@ -232,22 +221,18 @@ fn rectangles_positioned_relative_to_the_axes(show: bool) { ); plot.set_layout(layout); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("rectangles_positioned_relative_to_the_axes")) - ); + + plot.show(); } -fn rectangle_positioned_relative_to_the_plot_and_to_the_axes(show: bool) { +fn rectangle_positioned_relative_to_the_plot_and_to_the_axes() { let trace = Scatter::new(vec![1.5, 3.], vec![2.5, 2.5]) .text_array(vec![ "Rectangle reference to the plot", "Rectangle reference to the axes", ]) .mode(Mode::Text); + let mut plot = Plot::new(); plot.add_trace(trace); @@ -267,6 +252,7 @@ fn rectangle_positioned_relative_to_the_plot_and_to_the_axes(show: bool) { .line(ShapeLine::new().color(NamedColor::RoyalBlue).width(3.)) .fill_color(NamedColor::LightSkyBlue), ); + layout.add_shape( Shape::new() .x_ref("paper") @@ -281,18 +267,11 @@ fn rectangle_positioned_relative_to_the_plot_and_to_the_axes(show: bool) { ); plot.set_layout(layout); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some( - "rectangle_positioned_relative_to_the_plot_and_to_the_axes" - )) - ); + + plot.show(); } -fn highlighting_time_series_regions_with_rectangle_shapes(show: bool) { +fn highlighting_time_series_regions_with_rectangle_shapes() { let x = vec![ "2015-02-01", "2015-02-02", @@ -327,6 +306,7 @@ fn highlighting_time_series_regions_with_rectangle_shapes(show: bool) { -14, -17, -8, -4, -7, -10, -12, -14, -12, -7, -11, -7, -18, -14, -14, -16, -13, -7, -8, -14, -8, -3, -9, -9, -4, -13, -9, -6, ]; + let trace = Scatter::new(x, y).mode(Mode::Lines).name("temperature"); let mut plot = Plot::new(); plot.add_trace(trace); @@ -347,6 +327,7 @@ fn highlighting_time_series_regions_with_rectangle_shapes(show: bool) { .layer(ShapeLayer::Below) .line(ShapeLine::new().width(0.)), ); + layout.add_shape( Shape::new() .x_ref("x") @@ -363,21 +344,15 @@ fn highlighting_time_series_regions_with_rectangle_shapes(show: bool) { ); plot.set_layout(layout); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some( - "highlighting_time_series_regions_with_rectangle_shapes" - )) - ); + + plot.show(); } -fn circles_positioned_relative_to_the_axes(show: bool) { +fn circles_positioned_relative_to_the_axes() { let trace = Scatter::new(vec![1.5, 3.5], vec![0.75, 2.5]) .text_array(vec!["Unfilled Circle", "Filled Circle"]) .mode(Mode::Text); + let mut plot = Plot::new(); plot.add_trace(trace); @@ -398,6 +373,7 @@ fn circles_positioned_relative_to_the_axes(show: bool) { .y1(3) .line(ShapeLine::new().color(NamedColor::LightSeaGreen)), ); + layout.add_shape( Shape::new() .x_ref("x") @@ -412,16 +388,11 @@ fn circles_positioned_relative_to_the_axes(show: bool) { ); plot.set_layout(layout); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("circles_positioned_relative_to_the_axes")) - ); + + plot.show(); } -fn highlighting_clusters_of_scatter_points_with_circle_shapes(show: bool) { +fn highlighting_clusters_of_scatter_points_with_circle_shapes() { let mut rng = thread_rng(); let x0 = Normal::new(2., 0.45) .unwrap() @@ -529,18 +500,11 @@ fn highlighting_clusters_of_scatter_points_with_circle_shapes(show: bool) { ); plot.set_layout(layout); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some( - "highlighting_clusters_of_scatter_points_with_circle_shapes" - )) - ); + + plot.show(); } -fn venn_diagram_with_circle_shapes(show: bool) { +fn venn_diagram_with_circle_shapes() { let mut plot = Plot::new(); plot.add_trace( Scatter::new(vec![1., 1.75, 2.5], vec![1., 1., 1.]) @@ -602,16 +566,11 @@ fn venn_diagram_with_circle_shapes(show: bool) { ); plot.set_layout(layout); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("venn_diagram_with_circle_shapes")) - ); + + plot.show(); } -fn adding_shapes_to_subplots(show: bool) { +fn adding_shapes_to_subplots() { let mut plot = Plot::new(); plot.add_trace( Scatter::new(vec![2, 6], vec![1, 1]) @@ -693,13 +652,11 @@ fn adding_shapes_to_subplots(show: bool) { ); plot.set_layout(layout); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("adding_shapes_to_subplots"))); + + plot.show(); } -fn svg_paths(show: bool) { +fn svg_paths() { let mut plot = Plot::new(); plot.add_trace( Scatter::new(vec![2, 1, 8, 8], vec![0.25, 9., 2., 6.]) @@ -753,26 +710,23 @@ fn svg_paths(show: bool) { ); plot.set_layout(layout); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("svg_paths"))); + + plot.show(); } -fn main() -> std::io::Result<()> { - // Shapes - filled_area_chart(true); - vertical_and_horizontal_lines_positioned_relative_to_axes(true); - lines_positioned_relative_to_the_plot_and_to_the_axes(true); - creating_tangent_lines_with_shapes(true); - rectangles_positioned_relative_to_the_axes(true); - rectangle_positioned_relative_to_the_plot_and_to_the_axes(true); - highlighting_time_series_regions_with_rectangle_shapes(true); - circles_positioned_relative_to_the_axes(true); - highlighting_clusters_of_scatter_points_with_circle_shapes(true); - venn_diagram_with_circle_shapes(true); - adding_shapes_to_subplots(true); - svg_paths(true); - - Ok(()) +fn main() { + // Uncomment any of these lines to display the example. + + filled_area_chart(); + // vertical_and_horizontal_lines_positioned_relative_to_axes(); + // lines_positioned_relative_to_the_plot_and_to_the_axes(); + // creating_tangent_lines_with_shapes(); + // rectangles_positioned_relative_to_the_axes(); + // rectangle_positioned_relative_to_the_plot_and_to_the_axes(); + // highlighting_time_series_regions_with_rectangle_shapes(); + // circles_positioned_relative_to_the_axes(); + // highlighting_clusters_of_scatter_points_with_circle_shapes(); + // venn_diagram_with_circle_shapes(); + // adding_shapes_to_subplots(); + // svg_paths(); } diff --git a/examples/statistical_charts/Cargo.toml b/examples/statistical_charts/Cargo.toml new file mode 100644 index 00000000..df5a20ac --- /dev/null +++ b/examples/statistical_charts/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "statistical-charts" +version = "0.1.0" +authors = ["Michael Freeborn "] +edition = "2021" + +[dependencies] +ndarray = "0.15.6" +plotly = { path = "../../plotly" } +rand = "0.8.5" +rand_distr = "0.4.3" diff --git a/examples/statistical_charts/README.md b/examples/statistical_charts/README.md new file mode 100644 index 00000000..2dd9ad5a --- /dev/null +++ b/examples/statistical_charts/README.md @@ -0,0 +1,6 @@ +# Statistical Charts + +## How to Run + +1. Configure which example(s) you want to run by commenting/uncommenting lines in the `main` function, located in `src/main.rs`. +2. Run `cargo run`. \ No newline at end of file diff --git a/plotly/examples/statistical_charts.rs b/examples/statistical_charts/src/main.rs similarity index 75% rename from plotly/examples/statistical_charts.rs rename to examples/statistical_charts/src/main.rs index 09190624..5d2a7190 100644 --- a/plotly/examples/statistical_charts.rs +++ b/examples/statistical_charts/src/main.rs @@ -1,4 +1,6 @@ -use itertools_num::linspace; +#![allow(dead_code)] + +use ndarray::Array; use plotly::{ box_plot::{BoxMean, BoxPoints}, color::{NamedColor, Rgb, Rgba}, @@ -10,23 +12,18 @@ use plotly::{ use rand_distr::{Distribution, Normal, Uniform}; // Error Bars -fn basic_symmetric_error_bars(show: bool) { +fn basic_symmetric_error_bars() { let trace1 = Scatter::new(vec![0, 1, 2], vec![6, 10, 2]) .name("trace1") .error_y(ErrorData::new(ErrorType::Data).array(vec![1.0, 2.0, 3.0])); let mut plot = Plot::new(); plot.add_trace(trace1); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("basic_symmetric_error_bars")) - ); + + plot.show(); } -fn asymmetric_error_bars(show: bool) { +fn asymmetric_error_bars() { let trace1 = Scatter::new(vec![1, 2, 3, 4], vec![2, 1, 3, 4]) .name("trace1") .error_y( @@ -37,29 +34,22 @@ fn asymmetric_error_bars(show: bool) { let mut plot = Plot::new(); plot.add_trace(trace1); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("asymmetric_error_bars"))); + + plot.show(); } -fn error_bars_as_a_percentage_of_the_y_value(show: bool) { +fn error_bars_as_a_percentage_of_the_y_value() { let trace1 = Scatter::new(vec![0, 1, 2], vec![6, 10, 2]) .name("trace1") .error_y(ErrorData::new(ErrorType::Percent).value(50.).visible(true)); let mut plot = Plot::new(); plot.add_trace(trace1); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("error_bars_as_a_percentage_of_the_y_value")) - ); + + plot.show(); } -fn asymmetric_error_bars_with_a_constant_offset(show: bool) { +fn asymmetric_error_bars_with_a_constant_offset() { let trace1 = Scatter::new(vec![1, 2, 3, 4], vec![2, 1, 3, 4]) .name("trace1") .error_y( @@ -71,29 +61,22 @@ fn asymmetric_error_bars_with_a_constant_offset(show: bool) { let mut plot = Plot::new(); plot.add_trace(trace1); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("asymmetric_error_bars_with_a_constant_offset")) - ); + + plot.show(); } -fn horizontal_error_bars(show: bool) { +fn horizontal_error_bars() { let trace1 = Scatter::new(vec![1, 2, 3, 4], vec![2, 1, 3, 4]) .name("trace1") .error_x(ErrorData::new(ErrorType::Percent).value(10.)); let mut plot = Plot::new(); plot.add_trace(trace1); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("horizontal_error_bars"))); + + plot.show(); } -fn bar_chart_with_error_bars(show: bool) { +fn bar_chart_with_error_bars() { let trace_c = Bar::new(vec!["Trial 1", "Trial 2", "Trial 3"], vec![3, 6, 4]) .error_y(ErrorData::new(ErrorType::Data).array(vec![1., 0.5, 1.5])); let trace_e = Bar::new(vec!["Trial 1", "Trial 2", "Trial 3"], vec![4, 7, 3]) @@ -106,14 +89,11 @@ fn bar_chart_with_error_bars(show: bool) { let layout = Layout::new().bar_mode(BarMode::Group); plot.set_layout(layout); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("bar_chart_with_error_bars"))); + plot.show(); } -fn colored_and_styled_error_bars(show: bool) { - let x_theo: Vec = linspace(-4., 4., 100).collect(); +fn colored_and_styled_error_bars() { + let x_theo: Vec = Array::linspace(-4., 4., 100).into_raw_vec(); let sincx: Vec = x_theo .iter() .map(|x| (x * std::f64::consts::PI).sin() / (*x * std::f64::consts::PI)) @@ -149,17 +129,11 @@ fn colored_and_styled_error_bars(show: bool) { plot.add_trace(trace1); plot.add_trace(trace2); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("colored_and_styled_error_bars")) - ); + plot.show(); } // Box Plots -fn basic_box_plot(show: bool) { +fn basic_box_plot() { let mut rng = rand::thread_rng(); let uniform1 = Uniform::new(0.0, 1.0); let uniform2 = Uniform::new(1.0, 2.0); @@ -178,42 +152,33 @@ fn basic_box_plot(show: bool) { let mut plot = Plot::new(); plot.add_trace(trace1); plot.add_trace(trace2); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("basic_box_plot"))); + + plot.show(); } -fn box_plot_that_displays_the_underlying_data(show: bool) { +fn box_plot_that_displays_the_underlying_data() { let trace1 = BoxPlot::new(vec![0, 1, 1, 2, 3, 5, 8, 13, 21]) .box_points(BoxPoints::All) .jitter(0.3) .point_pos(-1.8); let mut plot = Plot::new(); plot.add_trace(trace1); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("box_plot_that_displays_the_underlying_data")) - ); + + plot.show(); } -fn horizontal_box_plot(show: bool) { +fn horizontal_box_plot() { let trace1 = BoxPlot::new(vec![1, 2, 3, 4, 4, 4, 8, 9, 10]).name("Set 1"); let trace2 = BoxPlot::new(vec![2, 3, 3, 3, 3, 5, 6, 6, 7]).name("Set 2"); let mut plot = Plot::new(); plot.add_trace(trace1); plot.add_trace(trace2); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("horizontal_box_plot"))); + + plot.show(); } -fn grouped_box_plot(show: bool) { +fn grouped_box_plot() { let x = vec![ "day 1", "day 1", "day 1", "day 1", "day 1", "day 1", "day 2", "day 2", "day 2", "day 2", "day 2", "day 2", @@ -246,13 +211,11 @@ fn grouped_box_plot(show: bool) { .box_mode(BoxMode::Group); plot.set_layout(layout); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("grouped_box_plot"))); + + plot.show(); } -fn box_plot_styling_outliers(show: bool) { +fn box_plot_styling_outliers() { let y = vec![ 0.75, 5.25, 5.5, 6.0, 6.2, 6.6, 6.80, 7.0, 7.2, 7.5, 7.5, 7.75, 8.15, 8.15, 8.65, 8.93, 9.2, 9.5, 10.0, 10.25, 11.5, 12.0, 16.0, 20.90, 22.3, 23.25, @@ -293,13 +256,11 @@ fn box_plot_styling_outliers(show: bool) { plot.add_trace(trace2); plot.add_trace(trace3); plot.add_trace(trace4); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("box_plot_styling_outliers"))); + + plot.show(); } -fn box_plot_styling_mean_and_standard_deviation(show: bool) { +fn box_plot_styling_mean_and_standard_deviation() { let y = vec![ 2.37, 2.16, 4.82, 1.73, 1.04, 0.23, 1.32, 2.91, 0.11, 4.51, 0.51, 3.75, 1.35, 2.98, 4.50, 0.18, 4.66, 1.30, 2.06, 1.19, @@ -319,16 +280,11 @@ fn box_plot_styling_mean_and_standard_deviation(show: bool) { plot.set_layout(layout); plot.add_trace(trace1); plot.add_trace(trace2); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("box_plot_styling_mean_and_standard_deviation")) - ); + + plot.show(); } -fn grouped_horizontal_box_plot(show: bool) { +fn grouped_horizontal_box_plot() { let x = vec![ "day 1", "day 1", "day 1", "day 1", "day 1", "day 1", "day 2", "day 2", "day 2", "day 2", "day 2", "day 2", @@ -374,16 +330,11 @@ fn grouped_horizontal_box_plot(show: bool) { .box_mode(BoxMode::Group); plot.set_layout(layout); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("grouped_horizontal_box_plot")) - ); + + plot.show(); } -fn fully_styled_box_plot(show: bool) { +fn fully_styled_box_plot() { let rnd_sample = |num, mul| -> Vec { let mut v: Vec = Vec::with_capacity(num); let mut rng = rand::thread_rng(); @@ -449,10 +400,8 @@ fn fully_styled_box_plot(show: bool) { .line(Line::new().width(2.0)); plot.add_trace(trace); } - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("fully_styled_box_plot"))); + + plot.show(); } // Histograms @@ -476,18 +425,16 @@ fn sample_uniform_distribution(n: usize, lb: f64, ub: f64) -> Vec { v } -fn basic_histogram(show: bool) { +fn basic_histogram() { let samples = sample_normal_distribution(10_000, 0.0, 1.0); let trace = Histogram::new(samples).name("h"); let mut plot = Plot::new(); plot.add_trace(trace); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("basic_histogram"))); + + plot.show(); } -fn horizontal_histogram(show: bool) { +fn horizontal_histogram() { let samples = sample_normal_distribution(10_000, 0.0, 1.0); let trace = Histogram::new_vertical(samples) .name("h") @@ -495,13 +442,11 @@ fn horizontal_histogram(show: bool) { let mut plot = Plot::new(); plot.add_trace(trace); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("horizontal_histogram"))); + + plot.show(); } -fn overlaid_histogram(show: bool) { +fn overlaid_histogram() { let samples1 = sample_normal_distribution(500, 0.0, 1.0); let trace1 = Histogram::new(samples1) .name("trace 1") @@ -520,13 +465,11 @@ fn overlaid_histogram(show: bool) { let layout = Layout::new().bar_mode(BarMode::Overlay); plot.set_layout(layout); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("overlaid_histogram"))); + + plot.show(); } -fn stacked_histograms(show: bool) { +fn stacked_histograms() { let samples1 = sample_normal_distribution(500, 0.0, 1.0); let trace1 = Histogram::new(samples1) .name("trace 1") @@ -545,13 +488,11 @@ fn stacked_histograms(show: bool) { let layout = Layout::new().bar_mode(BarMode::Stack); plot.set_layout(layout); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("stacked_histograms"))); + + plot.show(); } -fn colored_and_styled_histograms(show: bool) { +fn colored_and_styled_histograms() { let n = 500; let x1 = sample_uniform_distribution(n, 0.0, 5.0); let x2 = sample_uniform_distribution(n, 0.0, 10.0); @@ -592,16 +533,11 @@ fn colored_and_styled_histograms(show: bool) { plot.set_layout(layout); plot.add_trace(trace1); plot.add_trace(trace2); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("colored_and_styled_histograms")) - ); + + plot.show(); } -fn cumulative_histogram(show: bool) { +fn cumulative_histogram() { let n = 500; let x = sample_uniform_distribution(n, 0.0, 1.0); let trace = Histogram::new(x) @@ -609,13 +545,11 @@ fn cumulative_histogram(show: bool) { .marker(Marker::new().color(NamedColor::BurlyWood)); let mut plot = Plot::new(); plot.add_trace(trace); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("cumulative_histogram"))); + + plot.show(); } -fn normalized_histogram(show: bool) { +fn normalized_histogram() { let n = 500; let x = sample_uniform_distribution(n, 0.0, 1.0); let trace = Histogram::new(x) @@ -623,14 +557,12 @@ fn normalized_histogram(show: bool) { .marker(Marker::new().color(NamedColor::SeaGreen)); let mut plot = Plot::new(); plot.add_trace(trace); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("normalized_histogram"))); + + plot.show(); } -fn specify_binning_function(show: bool) { - let x = vec!["Apples", "Apples", "Apples", "Organges", "Bananas"]; +fn specify_binning_function() { + let x = vec!["Apples", "Apples", "Apples", "Oranges", "Bananas"]; let y = vec!["5", "10", "3", "10", "5"]; let trace1 = Histogram::new_xy(x.clone(), y.clone()) @@ -643,41 +575,39 @@ fn specify_binning_function(show: bool) { let mut plot = Plot::new(); plot.add_trace(trace1); plot.add_trace(trace2); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("specify_binning_function"))); + + plot.show(); } -fn main() -> std::io::Result<()> { +fn main() { + // Uncomment any of these lines to display the example. + // Error Bars - basic_symmetric_error_bars(true); - asymmetric_error_bars(true); - error_bars_as_a_percentage_of_the_y_value(true); - asymmetric_error_bars_with_a_constant_offset(true); - horizontal_error_bars(true); - bar_chart_with_error_bars(true); - colored_and_styled_error_bars(true); + // basic_symmetric_error_bars(); + // asymmetric_error_bars(); + // error_bars_as_a_percentage_of_the_y_value(); + // asymmetric_error_bars_with_a_constant_offset(); + // horizontal_error_bars(); + // bar_chart_with_error_bars(); + // colored_and_styled_error_bars(); // Box Plots - basic_box_plot(true); - box_plot_that_displays_the_underlying_data(true); - horizontal_box_plot(true); - grouped_box_plot(true); - box_plot_styling_outliers(true); - box_plot_styling_mean_and_standard_deviation(true); - grouped_horizontal_box_plot(true); - fully_styled_box_plot(true); + // basic_box_plot(); + // box_plot_that_displays_the_underlying_data(); + // horizontal_box_plot(); + // grouped_box_plot(); + // box_plot_styling_outliers(); + // box_plot_styling_mean_and_standard_deviation(); + // grouped_horizontal_box_plot(); + // fully_styled_box_plot(); // Histograms - basic_histogram(true); - horizontal_histogram(true); - overlaid_histogram(true); - stacked_histograms(true); - colored_and_styled_histograms(true); - cumulative_histogram(true); - normalized_histogram(true); - specify_binning_function(true); - - Ok(()) + // basic_histogram(); + // horizontal_histogram(); + // overlaid_histogram(); + // stacked_histograms(); + // colored_and_styled_histograms(); + // cumulative_histogram(); + // normalized_histogram(); + // specify_binning_function(); } diff --git a/examples/subplots/Cargo.toml b/examples/subplots/Cargo.toml new file mode 100644 index 00000000..79c9e582 --- /dev/null +++ b/examples/subplots/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "subplots" +version = "0.1.0" +authors = ["Michael Freeborn "] +edition = "2021" + +[dependencies] +plotly = { path = "../../plotly" } diff --git a/examples/subplots/README.md b/examples/subplots/README.md new file mode 100644 index 00000000..52ef9cc9 --- /dev/null +++ b/examples/subplots/README.md @@ -0,0 +1,6 @@ +# Subplots + +## How to Run + +1. Configure which example(s) you want to run by commenting/uncommenting lines in the `main` function, located in `src/main.rs`. +2. Run `cargo run`. \ No newline at end of file diff --git a/plotly/examples/subplots.rs b/examples/subplots/src/main.rs similarity index 82% rename from plotly/examples/subplots.rs rename to examples/subplots/src/main.rs index 93f304ec..88af0dcb 100644 --- a/plotly/examples/subplots.rs +++ b/examples/subplots/src/main.rs @@ -1,9 +1,11 @@ +#![allow(dead_code)] + use plotly::common::{AxisSide, Font, Title}; use plotly::layout::{Axis, GridPattern, Layout, LayoutGrid, Legend, RowOrder, TraceOrder}; use plotly::{color::Rgb, Plot, Scatter}; // Subplots -fn simple_subplot(show: bool) { +fn simple_subplot() { let trace1 = Scatter::new(vec![1, 2, 3], vec![4, 5, 6]).name("trace1"); let trace2 = Scatter::new(vec![20, 30, 40], vec![50, 60, 70]) .name("trace2") @@ -21,13 +23,11 @@ fn simple_subplot(show: bool) { .pattern(GridPattern::Independent), ); plot.set_layout(layout); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("simple_subplot"))); + + plot.show(); } -fn custom_sized_subplot(show: bool) { +fn custom_sized_subplot() { let trace1 = Scatter::new(vec![1, 2, 3], vec![4, 5, 6]).name("trace1"); let trace2 = Scatter::new(vec![20, 30, 40], vec![50, 60, 70]) .name("trace2") @@ -43,13 +43,11 @@ fn custom_sized_subplot(show: bool) { .y_axis2(Axis::new().anchor("x2")) .x_axis2(Axis::new().domain(&[0.8, 1.])); plot.set_layout(layout); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("custom_sized_subplot"))); + + plot.show(); } -fn multiple_subplots(show: bool) { +fn multiple_subplots() { let trace1 = Scatter::new(vec![1, 2, 3], vec![4, 5, 6]).name("trace1"); let trace2 = Scatter::new(vec![20, 30, 40], vec![50, 60, 70]) .name("trace2") @@ -75,13 +73,11 @@ fn multiple_subplots(show: bool) { .pattern(GridPattern::Independent), ); plot.set_layout(layout); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("multiple_subplots"))); + + plot.show(); } -fn stacked_subplots(show: bool) { +fn stacked_subplots() { let trace1 = Scatter::new(vec![0, 1, 2], vec![10, 11, 12]).name("trace1"); let trace2 = Scatter::new(vec![2, 3, 4], vec![100, 110, 120]) .name("trace2") @@ -104,13 +100,11 @@ fn stacked_subplots(show: bool) { .row_order(RowOrder::BottomToTop), ); plot.set_layout(layout); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("stacked_subplots"))); + + plot.show(); } -fn stacked_subplots_with_shared_x_axis(show: bool) { +fn stacked_subplots_with_shared_x_axis() { let trace1 = Scatter::new(vec![0, 1, 2], vec![10, 11, 12]).name("trace1"); let trace2 = Scatter::new(vec![2, 3, 4], vec![100, 110, 120]) .name("trace2") @@ -128,16 +122,11 @@ fn stacked_subplots_with_shared_x_axis(show: bool) { .y_axis2(Axis::new().domain(&[0.33, 0.66])) .y_axis3(Axis::new().domain(&[0.66, 1.])); plot.set_layout(layout); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("stacked_subplots_with_shared_x_axis")) - ); + + plot.show(); } -fn multiple_custom_sized_subplots(show: bool) { +fn multiple_custom_sized_subplots() { let trace1 = Scatter::new(vec![1, 2], vec![1, 2]).name("(1,1)"); let trace2 = Scatter::new(vec![1, 2], vec![1, 2]) .name("(1,2,1)") @@ -169,17 +158,12 @@ fn multiple_custom_sized_subplots(show: bool) { .x_axis4(Axis::new().domain(&[0., 1.]).anchor("y4")) .y_axis4(Axis::new().domain(&[0., 0.45]).anchor("x4")); plot.set_layout(layout); - if show { - plot.show(); - } - println!( - "{}", - plot.to_inline_html(Some("multiple_custom_sized_subplots")) - ); + + plot.show(); } // Multiple Axes -fn two_y_axes(show: bool) { +fn two_y_axes() { let trace1 = Scatter::new(vec![1, 2, 3], vec![40, 50, 60]).name("trace1"); let trace2 = Scatter::new(vec![2, 3, 4], vec![4, 5, 6]) .name("trace2") @@ -200,13 +184,11 @@ fn two_y_axes(show: bool) { .side(AxisSide::Right), ); plot.set_layout(layout); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("two_y_axes"))); + + plot.show(); } -fn multiple_axes(show: bool) { +fn multiple_axes() { let trace1 = Scatter::new(vec![1, 2, 3], vec![4, 5, 6]).name("trace1"); let trace2 = Scatter::new(vec![2, 3, 4], vec![40, 50, 60]) .name("trace2") @@ -256,24 +238,22 @@ fn multiple_axes(show: bool) { .position(0.85), ); plot.set_layout(layout); - if show { - plot.show(); - } - println!("{}", plot.to_inline_html(Some("multiple_axes"))); + + plot.show(); } -fn main() -> std::io::Result<()> { +fn main() { + // Uncomment any of these lines to display the example. + // Subplots - simple_subplot(true); - custom_sized_subplot(true); - multiple_subplots(true); - stacked_subplots(true); - stacked_subplots_with_shared_x_axis(true); - multiple_custom_sized_subplots(true); + // simple_subplot(); + // custom_sized_subplot(); + // multiple_subplots(); + // stacked_subplots(); + // stacked_subplots_with_shared_x_axis(); + // multiple_custom_sized_subplots(); // Multiple Axes - two_y_axes(true); - multiple_axes(true); - - Ok(()) + // two_y_axes(); + // multiple_axes(); } diff --git a/examples/wasm-yew-minimal/Cargo.toml b/examples/wasm-yew-minimal/Cargo.toml new file mode 100644 index 00000000..ea8d220d --- /dev/null +++ b/examples/wasm-yew-minimal/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "wasm-yew-minimal" +version = "0.1.0" +authors = ["Michael Freeborn "] +edition = "2021" + +[dependencies] +plotly = { path = "../../plotly", features = ["wasm"] } +yew = "0.19.0" +yew-hooks = "0.1.56" +log = "0.4.6" +wasm-logger = "0.2" \ No newline at end of file diff --git a/examples/wasm-yew-minimal/README.md b/examples/wasm-yew-minimal/README.md new file mode 100644 index 00000000..a62a6681 --- /dev/null +++ b/examples/wasm-yew-minimal/README.md @@ -0,0 +1,9 @@ +# Wasm Yew Minimal + +## Prerequisites + +1. Install [Trunk](https://trunkrs.dev/) using `cargo install --locked trunk`. + +## How to Run + +1. Run `trunk serve --open` in this directory to build and serve the application, opening the default web browser automatically. \ No newline at end of file diff --git a/examples/wasm-yew-minimal/index.html b/examples/wasm-yew-minimal/index.html new file mode 100644 index 00000000..88480a2e --- /dev/null +++ b/examples/wasm-yew-minimal/index.html @@ -0,0 +1,12 @@ + + + + + + Plotly Yew + + + + + + \ No newline at end of file diff --git a/examples/wasm-yew-minimal/src/main.rs b/examples/wasm-yew-minimal/src/main.rs new file mode 100644 index 00000000..8649c03c --- /dev/null +++ b/examples/wasm-yew-minimal/src/main.rs @@ -0,0 +1,38 @@ +use plotly::{Plot, Scatter}; +use yew::prelude::*; + +#[function_component(App)] +pub fn plot_component() -> Html { + let p = yew_hooks::use_async::<_, _, ()>({ + let id = "plot-div"; + let mut plot = Plot::new(); + let trace = Scatter::new(vec![0, 1, 2], vec![2, 1, 0]); + plot.add_trace(trace); + + let layout = + plotly::Layout::new().title(plotly::common::Title::new("Displaying a Chart in Yew")); + plot.set_layout(layout); + + async move { + plotly::bindings::new_plot(id, &plot).await; + Ok(()) + } + }); + + use_effect_with_deps( + move |_| { + p.run(); + || () + }, + (), + ); + + html! { +
+ } +} + +fn main() { + wasm_logger::init(wasm_logger::Config::default()); + yew::start_app::(); +} diff --git a/plotly/Cargo.toml b/plotly/Cargo.toml index f97a1bea..8426b0e2 100644 --- a/plotly/Cargo.toml +++ b/plotly/Cargo.toml @@ -1,10 +1,9 @@ [package] name = "plotly" -version = "0.8.1" +version = "0.8.2" description = "A plotting library powered by Plotly.js" authors = ["Ioannis Giagkiozis "] license = "MIT" -workspace = ".." readme = "README.md" homepage = "https://github.com/igiagkiozis/plotly" documentation = "https://docs.rs/plotly" @@ -15,9 +14,9 @@ keywords = ["plot", "chart", "plotly"] exclude = ["target/*"] [features] -# Adds plot save functionality to the following formats: png, jpeg, webp, svg, pdf and eps. kaleido = ["plotly_kaleido"] plotly_ndarray = ["ndarray"] +plotly_image = ["image"] wasm = ["getrandom", "js-sys", "wasm-bindgen", "wasm-bindgen-futures"] [dependencies] @@ -25,9 +24,10 @@ askama = { version = "0.11.0", features = ["serde-json"] } dyn-clone = "1" erased-serde = "0.3" getrandom = { version = "0.2", features = ["js"], optional = true } +image = { version = "0.24.2", optional = true } js-sys = { version = "0.3", optional = true } +plotly_derive = { version = "0.8.2", path = "../plotly_derive" } plotly_kaleido = { version = "0.3.0", path = "../plotly_kaleido", optional = true } -plotly_derive = { version = "0.8.1", path = "../plotly_derive" } ndarray = { version = "0.15.4", optional = true } once_cell = "1" serde = { version = "1.0.132", features = ["derive"] } @@ -35,13 +35,14 @@ serde_json = "1.0.73" serde_repr = "0.1" serde_with = "2" rand = "0.8" -rand_distr = "0.4" wasm-bindgen = { version = "0.2", optional = true } wasm-bindgen-futures = { version = "0.4", optional = true } [dev-dependencies] -plotly_kaleido = { version = "0.3.0", path = "../plotly_kaleido" } +csv = "1.1.6" +image = "0.24.4" itertools = "0.10.3" itertools-num = "0.1.3" -csv = "1.1.6" ndarray = "0.15.4" +plotly_kaleido = { version = "0.3.0", path = "../plotly_kaleido" } +rand_distr = "0.4" diff --git a/plotly/README.md b/plotly/README.md index 84a1d9ee..94054955 100644 --- a/plotly/README.md +++ b/plotly/README.md @@ -1,77 +1,3 @@ -

Plotly.rs

+# Plotly.rs -
Plotly for Rust
- -
- Getting Started - | - Recipes - | - API Docs - | - Changelog -
- - - -A plotting library for Rust powered by [Plotly.js](https://plot.ly/javascript/). - - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -plotly = "0.8.1" -``` - -For changes since the last version please consult the [change log](https://github.com/igiagkiozis/plotly/blob/master/CHANGELOG.md). - -## Crate Feature Flags -The following feature flags are available: -* `kaleido` - * Optional, compatible with Rust stable. - * Adds plot save functionality to the following formats: png, jpeg, webp, svg, pdf and eps. - * Requires some additional configuration, see [plotly_kaleido](https://github.com/igiagkiozis/plotly/tree/master/plotly_kaleido). -* `plotly_ndarray` - * Optional, compatible with Rust stable. - * Adds support for creating plots directly using [ndarray](https://github.com/rust-ndarray/ndarray) types. -* `wasm` - * Optional, compatible with Rust stable. - * Adds support for building with wasm-unknown-unknown target triple, enabling use within web development. - -Saving to png, jpeg, webp, svg, pdf and eps formats can be made available by enabling the `kaleido` feature: - -```toml -[dependencies] -plotly = { version = "0.8.1", features = ["kaleido"] } -``` -For further details please see [plotly_kaleido](https://github.com/igiagkiozis/plotly/tree/master/plotly_kaleido). - - -# Contributing - -Please consult the [contributing guide](https://github.com/igiagkiozis/plotly/blob/master/CONTRIBUTING.md). - -# License - -Plotly.rs is distributed under the terms of the MIT license. - -See [LICENSE-MIT](https://github.com/igiagkiozis/plotly/blob/master/LICENSE-MIT), and [COPYRIGHT](https://github.com/igiagkiozis/plotly/blob/master/COPYRIGHT) for details. +See the [project root](https://github.com/igiagkiozis/plotly) for the Plotly.rs REAEDME. \ No newline at end of file diff --git a/plotly/examples/jupyter_lab_examples.ipynb b/plotly/examples/jupyter_lab_examples.ipynb deleted file mode 100644 index b4df6af5..00000000 --- a/plotly/examples/jupyter_lab_examples.ipynb +++ /dev/null @@ -1,87 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - ":dep plotly = { version = \">=0.7.0\" }\n", - ":dep itertools-num = \"0.1.3\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "extern crate plotly;\n", - "extern crate rand_distr;\n", - "extern crate itertools_num;\n", - "extern crate itertools;" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "use itertools_num::linspace;\n", - "use plotly::common::{\n", - " ColorScale, ColorScalePalette, DashType, Fill, Font, Line, LineShape, Marker, Mode, Title,\n", - "};\n", - "use plotly::layout::{Axis, BarMode, Layout, Legend, TicksDirection};\n", - "use plotly::{Bar, NamedColor, Plot, Rgb, Rgba, Scatter};\n", - "use rand_distr::{Distribution, Normal, Uniform};" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fn simple_scatter_plot(show: bool) {\n", - " let n: usize = 100;\n", - " let t: Vec = linspace(0., 10., n).collect();\n", - " let y: Vec = t.iter().map(|x| x.sin()).collect();\n", - "\n", - " let trace = Scatter::new(t, y).mode(Mode::Markers);\n", - " let mut plot = Plot::new();\n", - " plot.add_trace(trace);\n", - " let layout = Layout::new().height(800);\n", - " plot.set_layout(layout);\n", - " plot.lab_display();\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "simple_scatter_plot(true)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Rust", - "language": "rust", - "name": "rust" - }, - "language_info": { - "codemirror_mode": "rust", - "file_extension": ".rs", - "mimetype": "text/rust", - "name": "Rust", - "pygment_lexer": "rust", - "version": "" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/plotly/examples/jupyter_notebook_examples.ipynb b/plotly/examples/jupyter_notebook_examples.ipynb deleted file mode 100644 index 228a5a54..00000000 --- a/plotly/examples/jupyter_notebook_examples.ipynb +++ /dev/null @@ -1,130 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - ":dep plotly = { version = \">=0.7.0\" }\n", - ":dep itertools-num = \"0.1.3\"" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "extern crate plotly;\n", - "extern crate rand_distr;\n", - "extern crate itertools_num;\n", - "extern crate itertools;" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "use itertools_num::linspace;\n", - "use plotly::common::{\n", - " ColorScale, ColorScalePalette, DashType, Fill, Font, Line, LineShape, Marker, Mode, Title,\n", - "};\n", - "use plotly::layout::{Axis, BarMode, Layout, Legend, TicksDirection};\n", - "use plotly::{Bar, NamedColor, Plot, Rgb, Rgba, Scatter};\n", - "use rand_distr::{Distribution, Normal, Uniform};" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "
\n", - " \n", - "
" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "let n: usize = 100;\n", - "let t = vec![1,2,3,4,5,6,7,8,9,10];\n", - "let y = t.iter().map(|v| (*v as f64).powf(2.0)).collect::>();\n", - "let trace = Scatter::new(t,y).mode(Mode::Markers);\n", - "let mut plot = Plot::new();\n", - "plot.add_trace(trace);\n", - "let layout = Layout::new().height(525);\n", - "plot.set_layout(layout);\n", - "plot.notebook_display();" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Rust", - "language": "rust", - "name": "rust" - }, - "language_info": { - "codemirror_mode": "rust", - "file_extension": ".rs", - "mimetype": "text/rust", - "name": "Rust", - "pygment_lexer": "rust", - "version": "" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/plotly/src/bindings.rs b/plotly/src/bindings.rs index 8595308c..ecb3f43e 100644 --- a/plotly/src/bindings.rs +++ b/plotly/src/bindings.rs @@ -1,5 +1,6 @@ -//! Bindings to the underlying plotly.js Javascript API. To be used in a WASM context, where it is assumed that a -//! remote copy of the Javascript Plotly library is available, (i.e. via a CDN). +//! Bindings to the underlying plotly.js Javascript API. To be used in a WASM +//! context, where it is assumed that a remote copy of the Javascript Plotly +//! library is available, (i.e. via a CDN). use js_sys::Object; use wasm_bindgen::prelude::*; @@ -18,14 +19,15 @@ extern "C" { /// A wrapper around the plotly.js [newPlot](https://plotly.com/javascript/plotlyjs-function-reference/#plotlynewplot) /// function. /// -/// The function signature is slightly constrained in that `id` is a `&str` which represents -/// the `id` of an existing HTML `div` element, rather than also allowing an instance of a `div` -/// element, itself. +/// The function signature is slightly constrained in that `id` is a `&str` +/// which represents the `id` of an existing HTML `div` element, rather than +/// also allowing an instance of a `div` element, itself. pub async fn new_plot(id: &str, plot: &Plot) { let plot_obj = &plot.to_js_object(); - // This will only fail if the Rust Plotly library has produced plotly-incompatible JSON. An error here - // should have been handled by the library, rather than down here. + // This will only fail if the Rust Plotly library has produced + // plotly-incompatible JSON. An error here should have been handled by the + // library, rather than down here. new_plot_(id, &plot_obj) .await .expect("Error plotting chart"); @@ -34,13 +36,14 @@ pub async fn new_plot(id: &str, plot: &Plot) { /// A wrapper around the plotly.js [react](https://plotly.com/javascript/plotlyjs-function-reference/#react) /// function. /// -/// The function signature is slightly constrained in that `id` is a `&str` which represents -/// the `id` of an existing HTML `div` element, rather than also allowing an instance of a `div` -/// element, itself. +/// The function signature is slightly constrained in that `id` is a `&str` +/// which represents the `id` of an existing HTML `div` element, rather than +/// also allowing an instance of a `div` element, itself. pub async fn react(id: &str, plot: &Plot) { let plot_obj = &plot.to_js_object(); - // This will only fail if the Rust Plotly library has produced plotly-incompatible JSON. An error here - // should have been handled by the library, rather than down here. + // This will only fail if the Rust Plotly library has produced + // plotly-incompatible JSON. An error here should have been handled by the + // library, rather than down here. react_(id, &plot_obj).await.expect("Error plotting chart"); } diff --git a/plotly/src/common/color.rs b/plotly/src/common/color.rs index ba867270..06121ef8 100644 --- a/plotly/src/common/color.rs +++ b/plotly/src/common/color.rs @@ -1,15 +1,19 @@ -//! This module provides several user interfaces for describing a color to be used throughout the rest of the library. -//! The easiest way of describing a colour is to use a `&str` or `String`, which is simply serialized as-is and -//! passed on to the underlying `plotly.js` library. `plotly.js` supports [`CSS color formats`], and will fallback -//! to some default color if the color string is malformed. +//! This module provides several user interfaces for describing a color to be +//! used throughout the rest of the library. The easiest way of describing a +//! colour is to use a `&str` or `String`, which is simply serialized as-is and +//! passed on to the underlying `plotly.js` library. `plotly.js` supports [`CSS +//! color formats`], and will fallback to some default color if the color string +//! is malformed. //! -//! For a more type-safe approach, the `RGB` or `RGBA` structs can be used to construct a valid color, which will then -//! get serialized to an appropriate string representation. Cross-browser compatible [`predefined colors`] are +//! For a more type-safe approach, the `RGB` or `RGBA` structs can be used to +//! construct a valid color, which will then get serialized to an appropriate +//! string representation. Cross-browser compatible [`predefined colors`] are //! supported via the `NamedColor` enum. //! -//! The `Color` trait is public, and so can be implemented for custom colour types. The user can then implement -//! a valid serialization function according to their own requirements. On the whole, that should be largely -//! unnecessary given the functionality already provided within this module. +//! The `Color` trait is public, and so can be implemented for custom colour +//! types. The user can then implement a valid serialization function according +//! to their own requirements. On the whole, that should be largely unnecessary +//! given the functionality already provided within this module. //! //! [`CSS color formats`]: https://www.w3schools.com/cssref/css_colors_legal.asp //! [`predefined colors`]: https://www.w3schools.com/cssref/css_colors.asp @@ -30,8 +34,9 @@ impl Color for String {} impl Color for Rgb {} impl Color for Rgba {} -/// ColorArray is only used internally to provide a helper method for converting Vec to -/// Vec>, as we would otherwise fall foul of the orphan rules. +/// ColorArray is only used internally to provide a helper method for converting +/// Vec to Vec>, as we would otherwise fall foul of +/// the orphan rules. pub(crate) struct ColorArray(pub(crate) Vec); #[allow(clippy::from_over_into)] @@ -44,12 +49,13 @@ impl Into>> for ColorArray { } } -/// A type-safe way of constructing a valid RGB color from constituent R, G and B channels. +/// A type-safe way of constructing a valid RGB color from constituent R, G and +/// B channels. #[derive(Debug, Clone, Copy)] pub struct Rgb { - r: u8, - g: u8, - b: u8, + pub(crate) r: u8, + pub(crate) g: u8, + pub(crate) b: u8, } impl Rgb { @@ -68,13 +74,14 @@ impl Serialize for Rgb { } } -/// A type-safe way of constructing a valid RGBA color from constituent R, G, B and A channels. +/// A type-safe way of constructing a valid RGBA color from constituent R, G, B +/// and A channels. #[derive(Debug, Clone, Copy)] pub struct Rgba { - r: u8, - g: u8, - b: u8, - a: f64, + pub(crate) r: u8, + pub(crate) g: u8, + pub(crate) b: u8, + pub(crate) a: f64, } impl Rgba { diff --git a/plotly/src/common/mod.rs b/plotly/src/common/mod.rs index 2aa5bea2..1b2a4257 100644 --- a/plotly/src/common/mod.rs +++ b/plotly/src/common/mod.rs @@ -186,6 +186,7 @@ pub enum PlotType { Scatter, ScatterGL, Scatter3D, + ScatterMapbox, ScatterPolar, ScatterPolarGL, Bar, @@ -195,6 +196,8 @@ pub enum PlotType { HeatMap, Histogram, Histogram2dContour, + Image, + Mesh3D, Ohlc, Sankey, Surface, @@ -1487,7 +1490,8 @@ mod tests { #[test] fn test_serialize_direction() { - // TODO: I think `Direction` would be better as a struct, with `fillcolor` and `line` attributes + // TODO: I think `Direction` would be better as a struct, with `fillcolor` and + // `line` attributes let inc = Direction::Increasing { line: Line::new() }; let expected = json!({"line": {}}); assert_eq!(to_value(inc).unwrap(), expected); diff --git a/plotly/src/configuration.rs b/plotly/src/configuration.rs index 539c5a12..95043caf 100644 --- a/plotly/src/configuration.rs +++ b/plotly/src/configuration.rs @@ -51,8 +51,8 @@ impl ToImageButtonOptions { self } - /// Set the scale of the downloaded plot image. Title, legend, axis and canvas sizes - /// will all be multiplied by `scale`. + /// Set the scale of the downloaded plot image. Title, legend, axis and + /// canvas sizes will all be multiplied by `scale`. pub fn scale(mut self, scale: usize) -> Self { self.scale = Some(scale); self @@ -189,91 +189,99 @@ pub struct Configuration { } impl Configuration { - /// Create a new default `Configuration` object. Options can be configured using the - /// provided setter methods. + /// Create a new default `Configuration` object. Options can be configured + /// using the provided setter methods. pub fn new() -> Self { Default::default() } - /// Determines whether the graphs are interactive or not. If `false`, no interactivity, - /// for export or image generation. + /// Determines whether the graphs are interactive or not. If `false`, no + /// interactivity, for export or image generation. pub fn static_plot(mut self, static_plot: bool) -> Self { self.static_plot = Some(static_plot); self } - /// Determines whether math should be typeset or not, when MathJax (either v2 or v3) is present on the page. + /// Determines whether math should be typeset or not, when MathJax (either + /// v2 or v3) is present on the page. pub fn typeset_math(mut self, typeset_math: bool) -> Self { self.typeset_math = Some(typeset_math); self } - /// When set it determines base URL for the "Edit in Chart Studio" `show_edit_in_chart_studio`/`show_send_to_cloud` - /// mode bar button and the show_link/send_data on-graph link. To enable sending your data to Chart Studio - /// Cloud, you need to set both `plotly_server_url` to "https://chart-studio.plotly.com" and + /// When set it determines base URL for the "Edit in Chart Studio" + /// `show_edit_in_chart_studio`/`show_send_to_cloud` mode bar button and + /// the show_link/send_data on-graph link. To enable sending your data to + /// Chart Studio Cloud, you need to set both `plotly_server_url` to "https://chart-studio.plotly.com" and /// also set `showSendToCloud` to `true`. pub fn plotly_server_url(mut self, plotly_server_url: &str) -> Self { self.plotly_server_url = Some(plotly_server_url.to_string()); self } - /// Determines whether the graph is editable or not. Sets all pieces of `edits` unless a separate - /// `edits` config item overrides individual parts. + /// Determines whether the graph is editable or not. Sets all pieces of + /// `edits` unless a separate `edits` config item overrides individual + /// parts. pub fn editable(mut self, editable: bool) -> Self { self.editable = Some(editable); self } - /// Determines whether the graphs are plotted with respect to layout.auto_size: true and infer - /// its container size. + /// Determines whether the graphs are plotted with respect to + /// layout.auto_size: true and infer its container size. pub fn autosizable(mut self, autosizable: bool) -> Self { self.autosizable = Some(autosizable); self } - /// Determines whether to change the layout size when window is resized. In v3, this option will be - /// removed and will always be true. + /// Determines whether to change the layout size when window is resized. In + /// v3, this option will be removed and will always be true. pub fn responsive(mut self, responsive: bool) -> Self { self.responsive = Some(responsive); self } - /// When `layout.auto_size` is turned on, determines whether the graph fills the container - /// (the default) or the screen (if set to `true`). + /// When `layout.auto_size` is turned on, determines whether the graph fills + /// the container (the default) or the screen (if set to `true`). pub fn fill_frame(mut self, fill_frame: bool) -> Self { self.fill_frame = Some(fill_frame); self } - /// When `layout.auto_size` is turned on, set the frame margins in fraction of the graph size. + /// When `layout.auto_size` is turned on, set the frame margins in fraction + /// of the graph size. pub fn frame_margins(mut self, frame_margins: f64) -> Self { // TODO: plotly supports a minimum value of 0 and a maximum value of 0.5 self.frame_margins = Some(frame_margins); self } - /// Determines whether mouse wheel or two-finger scroll zooms is enable. Turned on by default for - /// gl3d, geo and mapbox subplots (as these subplot types do not have zoombox via pan), but - /// turned off by default for cartesian subplots. Set `scroll_zoom` to `false` to disable scrolling for - /// all subplots. + /// Determines whether mouse wheel or two-finger scroll zooms is enable. + /// Turned on by default for gl3d, geo and mapbox subplots (as these + /// subplot types do not have zoombox via pan), but turned off by + /// default for cartesian subplots. Set `scroll_zoom` to `false` to disable + /// scrolling for all subplots. pub fn scroll_zoom(mut self, scroll_zoom: bool) -> Self { self.scroll_zoom = Some(scroll_zoom); self } - /// Sets the double click interaction mode. Has an effect only in cartesian plots. If `false`, - /// double click is disable. If `reset`, double click resets the axis ranges to their initial values. - /// If `autosize`, double click set the axis ranges to their autorange values. If `reset+autosize`, - /// the odd double clicks resets the axis ranges to their initial values and even double clicks set - /// the axis ranges to their autorange values. + /// Sets the double click interaction mode. Has an effect only in cartesian + /// plots. If `false`, double click is disable. If `reset`, double click + /// resets the axis ranges to their initial values. If `autosize`, + /// double click set the axis ranges to their autorange values. If + /// `reset+autosize`, the odd double clicks resets the axis ranges to + /// their initial values and even double clicks set the axis ranges to + /// their autorange values. pub fn double_click(mut self, double_click: DoubleClick) -> Self { self.double_click = Some(double_click); self } - /// Sets the delay for registering a double-click in ms. This is the time interval (in ms) between - /// first mousedown and 2nd mouseup to constitute a double-click. This setting propagates to all - /// on-subplot double clicks (except for geo and mapbox) and on-legend double clicks. + /// Sets the delay for registering a double-click in ms. This is the time + /// interval (in ms) between first mousedown and 2nd mouseup to + /// constitute a double-click. This setting propagates to all on-subplot + /// double clicks (except for geo and mapbox) and on-legend double clicks. pub fn double_click_delay(mut self, double_click_delay: usize) -> Self { self.double_click_delay = Some(double_click_delay); self @@ -285,21 +293,24 @@ impl Configuration { self } - /// Set to `false` to omit direct range entry at the pan/zoom drag points, note that `show_axis_drag_handles` - /// must be enabled to have an effect. + /// Set to `false` to omit direct range entry at the pan/zoom drag points, + /// note that `show_axis_drag_handles` must be enabled to have an + /// effect. pub fn show_axis_range_entry_boxes(mut self, show_axis_range_entry_boxes: bool) -> Self { self.show_axis_range_entry_boxes = Some(show_axis_range_entry_boxes); self } - /// Determines whether or not tips are shown while interacting with the resulting graphs. + /// Determines whether or not tips are shown while interacting with the + /// resulting graphs. pub fn show_tips(mut self, show_tips: bool) -> Self { self.show_tips = Some(show_tips); self } - /// Determines whether a link to Chart Studio Cloud is displayed at the bottom right corner of resulting - /// graphs. Use with `send_data` and `link_text`. + /// Determines whether a link to Chart Studio Cloud is displayed at the + /// bottom right corner of resulting graphs. Use with `send_data` and + /// `link_text`. pub fn show_link(mut self, show_link: bool) -> Self { self.show_link = Some(show_link); self @@ -311,34 +322,40 @@ impl Configuration { self } - /// If `show_link` is true, does it contain data just link to a Chart Studio Cloud file? + /// If `show_link` is true, does it contain data just link to a Chart Studio + /// Cloud file? pub fn send_data(mut self, send_data: bool) -> Self { self.send_data = Some(send_data); self } - /// Determines the mode bar display mode. If `true`, the mode bar is always visible. If `false`, - /// the mode bar is always hidden. If `hover`, the mode bar is visible while the mouse cursor - /// is on the graph container. + /// Determines the mode bar display mode. If `true`, the mode bar is always + /// visible. If `false`, the mode bar is always hidden. If `hover`, the + /// mode bar is visible while the mouse cursor is on the graph + /// container. pub fn display_mode_bar(mut self, display_mode_bar: DisplayModeBar) -> Self { self.display_mode_bar = Some(display_mode_bar); self } - /// Should we include a ModeBar button, labeled "Edit in Chart Studio" that sends this chart to - /// chart-studio.plotly.com (formerly plot.ly) or another plotly server as specified by `plotly_server_url` - /// for editing, export, etc? Prior to version 1.43.0 this button was included by default, now it is - /// opt-in using this flag. Note that this button can (depending on `plotly_server_url` being set) send your - /// data to an external server. However that server does not persist your data until you arrive at the Chart - /// Studio and explicitly click "Save". + /// Should we include a ModeBar button, labeled "Edit in Chart Studio" that + /// sends this chart to chart-studio.plotly.com (formerly plot.ly) or + /// another plotly server as specified by `plotly_server_url` + /// for editing, export, etc? Prior to version 1.43.0 this button was + /// included by default, now it is opt-in using this flag. Note that + /// this button can (depending on `plotly_server_url` being set) send your + /// data to an external server. However that server does not persist your + /// data until you arrive at the Chart Studio and explicitly click + /// "Save". pub fn show_send_to_cloud(mut self, show_send_to_cloud: bool) -> Self { self.show_send_to_cloud = Some(show_send_to_cloud); self } - /// Same as `show_send_to_cloud`, but use a pencil icon instead of a floppy-disk. Note that if both - /// `show_send_to_cloud` and `show_edit_in_chart_studio` are turned on, only `show_edit_in_chart_studio` will - /// be honored. + /// Same as `show_send_to_cloud`, but use a pencil icon instead of a + /// floppy-disk. Note that if both `show_send_to_cloud` and + /// `show_edit_in_chart_studio` are turned on, only + /// `show_edit_in_chart_studio` will be honored. pub fn show_edit_in_chart_studio(mut self, show_edit_in_chart_studio: bool) -> Self { self.show_edit_in_chart_studio = Some(show_edit_in_chart_studio); self @@ -362,7 +379,8 @@ impl Configuration { self } - /// Determines whether or not the plotly logo is displayed on the end of the mode bar. + /// Determines whether or not the plotly logo is displayed on the end of the + /// mode bar. pub fn display_logo(mut self, display_logo: bool) -> Self { self.display_logo = Some(display_logo); self @@ -380,16 +398,18 @@ impl Configuration { self } - /// Set the URL to topojson used in geo charts. By default, the topojson files are fetched from - /// cdn.plot.ly. For example, set this option to: "/dist/topojson/" to render - /// geographical feature using the topojson files that ship with the plotly.js module. + /// Set the URL to topojson used in geo charts. By default, the topojson + /// files are fetched from cdn.plot.ly. For example, set this option to: + /// "/dist/topojson/" to render geographical feature + /// using the topojson files that ship with the plotly.js module. pub fn topojson_url(mut self, topojson_url: &str) -> Self { self.topojson_url = Some(topojson_url.to_string()); self } - /// Mapbox access token (required to plot mapbox trace types). If using an Mapbox Atlas server, set - /// this option to "" so that plotly.js won't attempt to authenticate to the public Mapbox server. + /// Mapbox access token (required to plot mapbox trace types). If using an + /// Mapbox Atlas server, set this option to "" so that plotly.js won't + /// attempt to authenticate to the public Mapbox server. pub fn mapbox_access_token(mut self, mapbox_access_token: &str) -> Self { self.mapbox_access_token = Some(mapbox_access_token.to_string()); self @@ -401,9 +421,9 @@ impl Configuration { self } - /// Sets which localization to use. When using this setting, make sure that the appropriate locale is - /// present in the HTML file. For example, to use the "fr" locale, - /// must be present. + /// Sets which localization to use. When using this setting, make sure that + /// the appropriate locale is present in the HTML file. For example, to + /// use the "fr" locale, must be present. pub fn locale(mut self, locale: &str) -> Self { self.locale = Some(locale.to_string()); self diff --git a/plotly/src/layout/mod.rs b/plotly/src/layout/mod.rs index a1af744b..2f77871b 100644 --- a/plotly/src/layout/mod.rs +++ b/plotly/src/layout/mod.rs @@ -5,6 +5,7 @@ use std::borrow::Cow; use plotly_derive::FieldSetter; use serde::{Serialize, Serializer}; +use update_menu::UpdateMenu; use crate::{ color::Color, @@ -14,7 +15,6 @@ use crate::{ }, private::{NumOrString, NumOrStringCollection}, }; -use update_menu::UpdateMenu; #[derive(Serialize, Debug, Clone)] #[serde(rename_all = "lowercase")] @@ -755,8 +755,9 @@ pub struct ShapeLine { color: Option>, /// Sets the line width (in px). width: Option, - /// Sets the dash style of lines. Set to a dash type string ("solid", "dot", "dash", "longdash", - /// "dashdot", or "longdashdot") or a dash length list in px (eg "5px,10px,2px,2px"). + /// Sets the dash style of lines. Set to a dash type string ("solid", "dot", + /// "dash", "longdash", "dashdot", or "longdashdot") or a dash length + /// list in px (eg "5px,10px,2px,2px"). dash: Option, } @@ -775,95 +776,116 @@ pub struct Shape { r#type: Option, /// Specifies whether shapes are drawn below or above traces. layer: Option, - /// Sets the shape's x coordinate axis. If set to an x axis id (e.g. "x" or "x2"), the `x` - /// position refers to an x coordinate. If set to "paper", the `x` position refers to the - /// distance from the left side of the plotting area in normalized coordinates where "0" ("1") - /// corresponds to the left (right) side. If the axis `type` is "log", then you must take the - /// log of your desired range. If the axis `type` is "date", then you must convert the date to - /// unix time in milliseconds. + /// Sets the shape's x coordinate axis. If set to an x axis id (e.g. "x" or + /// "x2"), the `x` position refers to an x coordinate. If set to + /// "paper", the `x` position refers to the distance from the left side + /// of the plotting area in normalized coordinates where "0" ("1") + /// corresponds to the left (right) side. If the axis `type` is "log", then + /// you must take the log of your desired range. If the axis `type` is + /// "date", then you must convert the date to unix time in milliseconds. #[serde(rename = "xref")] x_ref: Option, - /// Sets the shapes's sizing mode along the x axis. If set to "scaled", `x0`, `x1` and x - /// coordinates within `path` refer to data values on the x axis or a fraction of the plot - /// area's width (`xref` set to "paper"). If set to "pixel", `xanchor` specifies the x position - /// in terms of data or plot fraction but `x0`, `x1` and x coordinates within `path` are pixels - /// relative to `xanchor`. This way, the shape can have a fixed width while maintaining a - /// position relative to data or plot fraction. + /// Sets the shapes's sizing mode along the x axis. If set to "scaled", + /// `x0`, `x1` and x coordinates within `path` refer to data values on + /// the x axis or a fraction of the plot area's width (`xref` set to + /// "paper"). If set to "pixel", `xanchor` specifies the x position + /// in terms of data or plot fraction but `x0`, `x1` and x coordinates + /// within `path` are pixels relative to `xanchor`. This way, the shape + /// can have a fixed width while maintaining a position relative to data + /// or plot fraction. #[serde(rename = "xsizemode")] x_size_mode: Option, - /// Only relevant in conjunction with `xsizemode` set to "pixel". Specifies the anchor point on - /// the x axis to which `x0`, `x1` and x coordinates within `path` are relative to. E.g. useful - /// to attach a pixel sized shape to a certain data value. No effect when `xsizemode` not set - /// to "pixel". + /// Only relevant in conjunction with `xsizemode` set to "pixel". Specifies + /// the anchor point on the x axis to which `x0`, `x1` and x coordinates + /// within `path` are relative to. E.g. useful to attach a pixel sized + /// shape to a certain data value. No effect when `xsizemode` not set to + /// "pixel". #[serde(rename = "xanchor")] x_anchor: Option, - /// Sets the shape's starting x position. See `type` and `xsizemode` for more info. + /// Sets the shape's starting x position. See `type` and `xsizemode` for + /// more info. x0: Option, - /// Sets the shape's end x position. See `type` and `xsizemode` for more info. + /// Sets the shape's end x position. See `type` and `xsizemode` for more + /// info. x1: Option, - /// Sets the annotation's y coordinate axis. If set to an y axis id (e.g. "y" or "y2"), - /// the `y` position refers to an y coordinate If set to "paper", the `y` position refers to - /// the distance from the bottom of the plotting area in normalized coordinates where "0" ("1") + /// Sets the annotation's y coordinate axis. If set to an y axis id (e.g. + /// "y" or "y2"), the `y` position refers to an y coordinate If set to + /// "paper", the `y` position refers to the distance from the bottom of + /// the plotting area in normalized coordinates where "0" ("1") /// corresponds to the bottom (top). #[serde(rename = "yref")] y_ref: Option, - /// Sets the shapes's sizing mode along the y axis. If set to "scaled", `y0`, `y1` and y - /// coordinates within `path` refer to data values on the y axis or a fraction of the plot - /// area's height (`yref` set to "paper"). If set to "pixel", `yanchor` specifies the y position - /// in terms of data or plot fraction but `y0`, `y1` and y coordinates within `path` are pixels - /// relative to `yanchor`. This way, the shape can have a fixed height while maintaining a - /// position relative to data or plot fraction. + /// Sets the shapes's sizing mode along the y axis. If set to "scaled", + /// `y0`, `y1` and y coordinates within `path` refer to data values on + /// the y axis or a fraction of the plot area's height (`yref` set to + /// "paper"). If set to "pixel", `yanchor` specifies the y position + /// in terms of data or plot fraction but `y0`, `y1` and y coordinates + /// within `path` are pixels relative to `yanchor`. This way, the shape + /// can have a fixed height while maintaining a position relative to + /// data or plot fraction. #[serde(rename = "ysizemode")] y_size_mode: Option, - /// Only relevant in conjunction with `ysizemode` set to "pixel". Specifies the anchor point on - /// the y axis to which `y0`, `y1` and y coordinates within `path` are relative to. E.g. useful - /// to attach a pixel sized shape to a certain data value. No effect when `ysizemode` not set - /// to "pixel". + /// Only relevant in conjunction with `ysizemode` set to "pixel". Specifies + /// the anchor point on the y axis to which `y0`, `y1` and y coordinates + /// within `path` are relative to. E.g. useful to attach a pixel sized + /// shape to a certain data value. No effect when `ysizemode` not set to + /// "pixel". #[serde(rename = "yanchor")] y_anchor: Option, - /// Sets the shape's starting y position. See `type` and `ysizemode` for more info. + /// Sets the shape's starting y position. See `type` and `ysizemode` for + /// more info. y0: Option, - /// Sets the shape's end y position. See `type` and `ysizemode` for more info. + /// Sets the shape's end y position. See `type` and `ysizemode` for more + /// info. y1: Option, - /// For `type` "path" - a valid SVG path with the pixel values replaced by data values in - /// `xsizemode`/`ysizemode` being "scaled" and taken unmodified as pixels relative to - /// `xanchor` and `yanchor` in case of "pixel" size mode. There are a few restrictions / quirks + /// For `type` "path" - a valid SVG path with the pixel values replaced by + /// data values in `xsizemode`/`ysizemode` being "scaled" and taken + /// unmodified as pixels relative to `xanchor` and `yanchor` in case of + /// "pixel" size mode. There are a few restrictions / quirks /// only absolute instructions, not relative. So the allowed segments - /// are: M, L, H, V, Q, C, T, S, and Z arcs (A) are not allowed because radius rx and ry are - /// relative. In the future we could consider supporting relative commands, but we would have - /// to decide on how to handle date and log axes. Note that even as is, Q and C Bezier paths - /// that are smooth on linear axes may not be smooth on log, and vice versa. no chained - /// "polybezier" commands - specify the segment type for each one. On category axes, values are - /// numbers scaled to the serial numbers of categories because using the categories themselves - /// there would be no way to describe fractional positions On data axes: because space and T are - /// both normal components of path strings, we can't use either to separate date from time parts. - /// Therefore we'll use underscore for this purpose: 2015-02-21_13:45:56.789 + /// are: M, L, H, V, Q, C, T, S, and Z arcs (A) are not allowed because + /// radius rx and ry are relative. In the future we could consider + /// supporting relative commands, but we would have to decide on how to + /// handle date and log axes. Note that even as is, Q and C Bezier paths + /// that are smooth on linear axes may not be smooth on log, and vice versa. + /// no chained "polybezier" commands - specify the segment type for each + /// one. On category axes, values are numbers scaled to the serial + /// numbers of categories because using the categories themselves + /// there would be no way to describe fractional positions On data axes: + /// because space and T are both normal components of path strings, we + /// can't use either to separate date from time parts. Therefore we'll + /// use underscore for this purpose: 2015-02-21_13:45:56.789 path: Option, /// Sets the opacity of the shape. Number between or equal to 0 and 1. opacity: Option, /// Sets the shape line properties (`color`, `width`, `dash`). line: Option, - /// Sets the color filling the shape's interior. Only applies to closed shapes. + /// Sets the color filling the shape's interior. Only applies to closed + /// shapes. #[serde(rename = "fillcolor")] fill_color: Option>, - /// Determines which regions of complex paths constitute the interior. For more info please - /// visit https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule + /// Determines which regions of complex paths constitute the interior. For + /// more info please visit https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule #[serde(rename = "fillrule")] fill_rule: Option, - /// Determines whether the shape could be activated for edit or not. Has no effect when the - /// older editable shapes mode is enabled via `config.editable` or `config.edits.shapePosition`. + /// Determines whether the shape could be activated for edit or not. Has no + /// effect when the older editable shapes mode is enabled via + /// `config.editable` or `config.edits.shapePosition`. editable: Option, - /// When used in a template, named items are created in the output figure in addition to any - /// items the figure already has in this array. You can modify these items in the output figure - /// by making your own item with `templateitemname` matching this `name` alongside your - /// modifications (including `visible: false` or `enabled: false` to hide it). Has no effect - /// outside of a template. + /// When used in a template, named items are created in the output figure in + /// addition to any items the figure already has in this array. You can + /// modify these items in the output figure by making your own item with + /// `templateitemname` matching this `name` alongside your modifications + /// (including `visible: false` or `enabled: false` to hide it). Has no + /// effect outside of a template. name: Option, - /// Used to refer to a named item in this array in the template. Named items from the template - /// will be created even without a matching item in the input figure, but you can modify one - /// by making an item with `templateitemname` matching its `name`, alongside your modifications - /// (including `visible: false` or `enabled: false` to hide it). If there is no template or no - /// matching item, this item will be hidden unless you explicitly show it with `visible: true`. + /// Used to refer to a named item in this array in the template. Named items + /// from the template will be created even without a matching item in + /// the input figure, but you can modify one by making an item with + /// `templateitemname` matching its `name`, alongside your modifications + /// (including `visible: false` or `enabled: false` to hide it). If there is + /// no template or no matching item, this item will be hidden unless you + /// explicitly show it with `visible: true`. #[serde(rename = "templateitemname")] template_item_name: Option, } @@ -873,13 +895,14 @@ impl Shape { Default::default() } - /// Specifies the shape type to be drawn. If "line", a line is drawn from (`x0`,`y0`) to - /// (`x1`,`y1`) with respect to the axes' sizing mode. If "circle", a circle is drawn from - /// ((`x0`+`x1`)/2, (`y0`+`y1`)/2)) with radius (|(`x0`+`x1`)/2 - `x0`|, |(`y0`+`y1`)/2 -`y0`)|) - /// with respect to the axes' sizing mode. If "rect", a rectangle is drawn linking - /// (`x0`,`y0`), (`x1`,`y0`), (`x1`,`y1`), (`x0`,`y1`), (`x0`,`y0`) with respect to the axes' - /// sizing mode. If "path", draw a custom SVG path using `path`. with respect to the axes' - /// sizing mode. + /// Specifies the shape type to be drawn. If "line", a line is drawn from + /// (`x0`,`y0`) to (`x1`,`y1`) with respect to the axes' sizing mode. If + /// "circle", a circle is drawn from ((`x0`+`x1`)/2, (`y0`+`y1`)/2)) + /// with radius (|(`x0`+`x1`)/2 - `x0`|, |(`y0`+`y1`)/2 -`y0`)|) + /// with respect to the axes' sizing mode. If "rect", a rectangle is drawn + /// linking (`x0`,`y0`), (`x1`,`y0`), (`x1`,`y1`), (`x0`,`y1`), + /// (`x0`,`y0`) with respect to the axes' sizing mode. If "path", draw a + /// custom SVG path using `path`. with respect to the axes' sizing mode. pub fn shape_type(mut self, shape_type: ShapeType) -> Self { self.r#type = Some(shape_type); self @@ -900,9 +923,10 @@ pub enum DrawDirection { pub struct NewShape { /// Sets the shape line properties (`color`, `width`, `dash`). line: Option, - /// Sets the color filling new shapes' interior. Please note that if using a fillcolor with - /// alpha greater than half, drag inside the active shape starts moving the shape underneath, - /// otherwise a new shape could be started over. + /// Sets the color filling new shapes' interior. Please note that if using a + /// fillcolor with alpha greater than half, drag inside the active shape + /// starts moving the shape underneath, otherwise a new shape could be + /// started over. #[serde(rename = "fillcolor")] fill_color: Option>, /// Determines the path's interior. For more info please @@ -913,10 +937,12 @@ pub struct NewShape { opacity: Option, /// Specifies whether new shapes are drawn below or above traces. layer: Option, - /// When `dragmode` is set to "drawrect", "drawline" or "drawcircle" this limits the drag to be - /// horizontal, vertical or diagonal. Using "diagonal" there is no limit e.g. in drawing lines - /// in any direction. "ortho" limits the draw to be either horizontal or vertical. "horizontal" - /// allows horizontal extend. "vertical" allows vertical extend. + /// When `dragmode` is set to "drawrect", "drawline" or "drawcircle" this + /// limits the drag to be horizontal, vertical or diagonal. Using + /// "diagonal" there is no limit e.g. in drawing lines in any direction. + /// "ortho" limits the draw to be either horizontal or vertical. + /// "horizontal" allows horizontal extend. "vertical" allows vertical + /// extend. #[serde(rename = "drawdirection")] draw_direction: Option, } @@ -933,7 +959,8 @@ pub struct ActiveShape { /// Sets the color filling the active shape' interior. #[serde(rename = "fillcolor")] fill_color: Option>, - /// Sets the opacity of the active shape. Number between or equal to 0 and 1. + /// Sets the opacity of the active shape. Number between or equal to 0 and + /// 1. opacity: Option, } @@ -978,29 +1005,33 @@ impl Serialize for ClickToShow { pub struct Annotation { /// Determines whether or not this annotation is visible. visible: Option, - /// Sets the text associated with this annotation. Plotly uses a subset of HTML tags to do - /// things like newline (
), bold (), italics (), hyperlinks - /// (). Tags , , are also supported. + /// Sets the text associated with this annotation. Plotly uses a subset of + /// HTML tags to do things like newline (
), bold (), italics + /// (), hyperlinks (). Tags , , + /// are also supported. text: Option, - /// Sets the angle at which the `text` is drawn with respect to the horizontal. + /// Sets the angle at which the `text` is drawn with respect to the + /// horizontal. #[serde(rename = "textangle")] text_angle: Option, /// Sets the annotation text font. font: Option, - /// Sets an explicit width for the text box. null (default) lets the text set the box width. - /// Wider text will be clipped. There is no automatic wrapping; use
to start a new line. + /// Sets an explicit width for the text box. null (default) lets the text + /// set the box width. Wider text will be clipped. There is no automatic + /// wrapping; use
to start a new line. width: Option, - /// Sets an explicit height for the text box. null (default) lets the text set the box height. - /// Taller text will be clipped. + /// Sets an explicit height for the text box. null (default) lets the text + /// set the box height. Taller text will be clipped. height: Option, /// Sets the opacity of the annotation (text + arrow). opacity: Option, - /// Sets the horizontal alignment of the `text` within the box. Has an effect only if `text` - /// spans two or more lines (i.e. `text` contains one or more
HTML tags) or if an explicit - /// width is set to override the text width. + /// Sets the horizontal alignment of the `text` within the box. Has an + /// effect only if `text` spans two or more lines (i.e. `text` contains + /// one or more
HTML tags) or if an explicit width is set to + /// override the text width. align: Option, - /// Sets the vertical alignment of the `text` within the box. Has an effect only if an explicit - /// height is set to override the text height. + /// Sets the vertical alignment of the `text` within the box. Has an effect + /// only if an explicit height is set to override the text height. valign: Option, /// Sets the background color of the annotation. #[serde(rename = "bgcolor")] @@ -1014,157 +1045,186 @@ pub struct Annotation { /// Sets the width (in px) of the border enclosing the annotation `text`. #[serde(rename = "borderwidth")] border_width: Option, - /// Determines whether or not the annotation is drawn with an arrow. If "True", `text` is - /// placed near the arrow's tail. If "False", `text` lines up with the `x` and `y` provided. + /// Determines whether or not the annotation is drawn with an arrow. If + /// "True", `text` is placed near the arrow's tail. If "False", `text` + /// lines up with the `x` and `y` provided. #[serde(rename = "showarrow")] show_arrow: Option, /// Sets the color of the annotation arrow. #[serde(rename = "arrowcolor")] arrow_color: Option>, - /// Sets the end annotation arrow head style. Integer between or equal to 0 and 8. + /// Sets the end annotation arrow head style. Integer between or equal to 0 + /// and 8. #[serde(rename = "arrowhead")] arrow_head: Option, - /// Sets the start annotation arrow head style. Integer between or equal to 0 and 8. + /// Sets the start annotation arrow head style. Integer between or equal to + /// 0 and 8. #[serde(rename = "startarrowhead")] start_arrow_head: Option, /// Sets the annotation arrow head position. #[serde(rename = "arrowside")] arrow_side: Option, - /// Sets the size of the end annotation arrow head, relative to `arrowwidth`. A value of 1 - /// (default) gives a head about 3x as wide as the line. + /// Sets the size of the end annotation arrow head, relative to + /// `arrowwidth`. A value of 1 (default) gives a head about 3x as wide + /// as the line. #[serde(rename = "arrowsize")] arrow_size: Option, - /// Sets the size of the start annotation arrow head, relative to `arrowwidth`. A value of 1 - /// (default) gives a head about 3x as wide as the line. + /// Sets the size of the start annotation arrow head, relative to + /// `arrowwidth`. A value of 1 (default) gives a head about 3x as wide + /// as the line. #[serde(rename = "startarrowsize")] start_arrow_size: Option, /// Sets the width (in px) of annotation arrow line. #[serde(rename = "arrowwidth")] arrow_width: Option, - /// Sets a distance, in pixels, to move the end arrowhead away from the position it is pointing - /// at, for example to point at the edge of a marker independent of zoom. Note that this - /// shortens the arrow from the `ax` / `ay` vector, in contrast to `xshift` / `yshift` which + /// Sets a distance, in pixels, to move the end arrowhead away from the + /// position it is pointing at, for example to point at the edge of a + /// marker independent of zoom. Note that this shortens the arrow from + /// the `ax` / `ay` vector, in contrast to `xshift` / `yshift` which /// moves everything by this amount. #[serde(rename = "standoff")] stand_off: Option, - /// Sets a distance, in pixels, to move the start arrowhead away from the position it is - /// pointing at, for example to point at the edge of a marker independent of zoom. Note that - /// this shortens the arrow from the `ax` / `ay` vector, in contrast to `xshift` / `yshift` + /// Sets a distance, in pixels, to move the start arrowhead away from the + /// position it is pointing at, for example to point at the edge of a + /// marker independent of zoom. Note that this shortens the arrow from + /// the `ax` / `ay` vector, in contrast to `xshift` / `yshift` /// which moves everything by this amount. #[serde(rename = "startstandoff")] start_stand_off: Option, - /// Sets the x component of the arrow tail about the arrow head. If `axref` is `pixel`, a - /// positive (negative) component corresponds to an arrow pointing from right to left (left - /// to right). If `axref` is an axis, this is an absolute value on that axis, like `x`, NOT a + /// Sets the x component of the arrow tail about the arrow head. If `axref` + /// is `pixel`, a positive (negative) component corresponds to an arrow + /// pointing from right to left (left to right). If `axref` is an axis, + /// this is an absolute value on that axis, like `x`, NOT a /// relative value. ax: Option, - /// Sets the y component of the arrow tail about the arrow head. If `ayref` is `pixel`, a - /// positive (negative) component corresponds to an arrow pointing from bottom to top (top to - /// bottom). If `ayref` is an axis, this is an absolute value on that axis, like `y`, NOT a + /// Sets the y component of the arrow tail about the arrow head. If `ayref` + /// is `pixel`, a positive (negative) component corresponds to an arrow + /// pointing from bottom to top (top to bottom). If `ayref` is an axis, + /// this is an absolute value on that axis, like `y`, NOT a /// relative value. ay: Option, - /// Indicates in what terms the tail of the annotation (ax,ay) is specified. If `pixel`, `ax` - /// is a relative offset in pixels from `x`. If set to an x axis id (e.g. "x" or "x2"), `ax` is - /// specified in the same terms as that axis. This is useful for trendline annotations which + /// Indicates in what terms the tail of the annotation (ax,ay) is specified. + /// If `pixel`, `ax` is a relative offset in pixels from `x`. If set to + /// an x axis id (e.g. "x" or "x2"), `ax` is specified in the same terms + /// as that axis. This is useful for trendline annotations which /// should continue to indicate the correct trend when zoomed. #[serde(rename = "axref")] ax_ref: Option, - /// Indicates in what terms the tail of the annotation (ax,ay) is specified. If `pixel`, `ay` - /// is a relative offset in pixels from `y`. If set to a y axis id (e.g. "y" or "y2"), `ay` is - /// specified in the same terms as that axis. This is useful for trendline annotations which + /// Indicates in what terms the tail of the annotation (ax,ay) is specified. + /// If `pixel`, `ay` is a relative offset in pixels from `y`. If set to + /// a y axis id (e.g. "y" or "y2"), `ay` is specified in the same terms + /// as that axis. This is useful for trendline annotations which /// should continue to indicate the correct trend when zoomed. #[serde(rename = "ayref")] ay_ref: Option, - /// Sets the annotation's x coordinate axis. If set to an x axis id (e.g. "x" or "x2"), the `x` - /// position refers to an x coordinate If set to "paper", the `x` position refers to the - /// distance from the left side of the plotting area in normalized coordinates where 0 (1) + /// Sets the annotation's x coordinate axis. If set to an x axis id (e.g. + /// "x" or "x2"), the `x` position refers to an x coordinate If set to + /// "paper", the `x` position refers to the distance from the left side + /// of the plotting area in normalized coordinates where 0 (1) /// corresponds to the left (right) side. #[serde(rename = "xref")] x_ref: Option, - /// Sets the annotation's x position. If the axis `type` is "log", then you must take the log - /// of your desired range. If the axis `type` is "date", it should be date strings, like date - /// data, though Date objects and unix milliseconds will be accepted and converted to strings. - /// If the axis `type` is "category", it should be numbers, using the scale where each category - /// is assigned a serial number from zero in the order it appears. + /// Sets the annotation's x position. If the axis `type` is "log", then you + /// must take the log of your desired range. If the axis `type` is + /// "date", it should be date strings, like date data, though Date + /// objects and unix milliseconds will be accepted and converted to strings. + /// If the axis `type` is "category", it should be numbers, using the scale + /// where each category is assigned a serial number from zero in the + /// order it appears. x: Option, - /// Sets the text box's horizontal position anchor This anchor binds the `x` position to the - /// "left", "center" or "right" of the annotation. For example, if `x` is set to 1, `xref` to - /// "paper" and `xanchor` to "right" then the right-most portion of the annotation lines up with - /// the right-most edge of the plotting area. If "auto", the anchor is equivalent to "center" - /// for data-referenced annotations or if there is an arrow, whereas for paper-referenced with - /// no arrow, the anchor picked corresponds to the closest side. + /// Sets the text box's horizontal position anchor This anchor binds the `x` + /// position to the "left", "center" or "right" of the annotation. For + /// example, if `x` is set to 1, `xref` to "paper" and `xanchor` to + /// "right" then the right-most portion of the annotation lines up with + /// the right-most edge of the plotting area. If "auto", the anchor is + /// equivalent to "center" for data-referenced annotations or if there + /// is an arrow, whereas for paper-referenced with no arrow, the anchor + /// picked corresponds to the closest side. #[serde(rename = "xanchor")] x_anchor: Option, - /// Shifts the position of the whole annotation and arrow to the right (positive) or left - /// (negative) by this many pixels. + /// Shifts the position of the whole annotation and arrow to the right + /// (positive) or left (negative) by this many pixels. #[serde(rename = "xshift")] x_shift: Option, - /// Sets the annotation's y coordinate axis. If set to an y axis id (e.g. "y" or "y2"), the `y` - /// position refers to an y coordinate If set to "paper", the `y` position refers to the - /// distance from the bottom of the plotting area in normalized coordinates where 0 (1) - /// corresponds to the bottom (top). + /// Sets the annotation's y coordinate axis. If set to an y axis id (e.g. + /// "y" or "y2"), the `y` position refers to an y coordinate If set to + /// "paper", the `y` position refers to the distance from the bottom of + /// the plotting area in normalized coordinates where 0 (1) corresponds + /// to the bottom (top). #[serde(rename = "yref")] y_ref: Option, - /// Sets the annotation's y position. If the axis `type` is "log", then you must take the log of - /// your desired range. If the axis `type` is "date", it should be date strings, like date data, - /// though Date objects and unix milliseconds will be accepted and converted to strings. If the - /// axis `type` is "category", it should be numbers, using the scale where each category is - /// assigned a serial number from zero in the order it appears. + /// Sets the annotation's y position. If the axis `type` is "log", then you + /// must take the log of your desired range. If the axis `type` is + /// "date", it should be date strings, like date data, though Date + /// objects and unix milliseconds will be accepted and converted to strings. + /// If the axis `type` is "category", it should be numbers, using the + /// scale where each category is assigned a serial number from zero in + /// the order it appears. y: Option, - /// Sets the text box's vertical position anchor This anchor binds the `y` position to the - /// "top", "middle" or "bottom" of the annotation. For example, if `y` is set to 1, `yref` to - /// "paper" and `yanchor` to "top" then the top-most portion of the annotation lines up with the - /// top-most edge of the plotting area. If "auto", the anchor is equivalent to "middle" for - /// data-referenced annotations or if there is an arrow, whereas for paper-referenced with no - /// arrow, the anchor picked corresponds to the closest side. + /// Sets the text box's vertical position anchor This anchor binds the `y` + /// position to the "top", "middle" or "bottom" of the annotation. For + /// example, if `y` is set to 1, `yref` to "paper" and `yanchor` to + /// "top" then the top-most portion of the annotation lines up with the + /// top-most edge of the plotting area. If "auto", the anchor is equivalent + /// to "middle" for data-referenced annotations or if there is an arrow, + /// whereas for paper-referenced with no arrow, the anchor picked + /// corresponds to the closest side. #[serde(rename = "yanchor")] y_anchor: Option, - /// Shifts the position of the whole annotation and arrow up (positive) or down (negative) by - /// this many pixels. + /// Shifts the position of the whole annotation and arrow up (positive) or + /// down (negative) by this many pixels. #[serde(rename = "yshift")] y_shift: Option, - /// Makes this annotation respond to clicks on the plot. If you click a data point that exactly - /// matches the `x` and `y` values of this annotation, and it is hidden (visible: false), it - /// will appear. In "onoff" mode, you must click the same point again to make it disappear, so - /// if you click multiple points, you can show multiple annotations. In "onout" mode, a click - /// anywhere else in the plot (on another data point or not) will hide this annotation. If you - /// need to show/hide this annotation in response to different `x` or `y` values, you can set - /// `xclick` and/or `yclick`. This is useful for example to label the side of a bar. To label - /// markers though, `standoff` is preferred over `xclick` and `yclick`. + /// Makes this annotation respond to clicks on the plot. If you click a data + /// point that exactly matches the `x` and `y` values of this + /// annotation, and it is hidden (visible: false), it will appear. In + /// "onoff" mode, you must click the same point again to make it disappear, + /// so if you click multiple points, you can show multiple annotations. + /// In "onout" mode, a click anywhere else in the plot (on another data + /// point or not) will hide this annotation. If you need to show/hide + /// this annotation in response to different `x` or `y` values, you can set + /// `xclick` and/or `yclick`. This is useful for example to label the side + /// of a bar. To label markers though, `standoff` is preferred over + /// `xclick` and `yclick`. #[serde(rename = "clicktoshow")] click_to_show: Option, - /// Toggle this annotation when clicking a data point whose `x` value is `xclick` rather than - /// the annotation's `x` value. + /// Toggle this annotation when clicking a data point whose `x` value is + /// `xclick` rather than the annotation's `x` value. #[serde(rename = "xclick")] x_click: Option, - /// Toggle this annotation when clicking a data point whose `y` value is `yclick` rather than - /// the annotation's `y` value. + /// Toggle this annotation when clicking a data point whose `y` value is + /// `yclick` rather than the annotation's `y` value. #[serde(rename = "yclick")] y_click: Option, - /// Sets text to appear when hovering over this annotation. If omitted or blank, no hover label - /// will appear. + /// Sets text to appear when hovering over this annotation. If omitted or + /// blank, no hover label will appear. #[serde(rename = "hovertext")] hover_text: Option, /// Label displayed on mouse hover. #[serde(rename = "hoverlabel")] hover_label: Option