diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a9431a21..e6101429 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -221,6 +221,7 @@ jobs: kaleido, maps, ndarray, + proa, scientific_charts, shapes, statistical_charts, diff --git a/CHANGELOG.md b/CHANGELOG.md index 6913daa1..7fa0ee21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a ### Added +- [[#445](https://github.com/plotly/plotly.rs/pull/445)] Add a Proa example composing three Plotly figures with a reusable document layout, page metadata, and chart components. - [[#406](https://github.com/plotly/plotly.rs/issues/406)] Expose `plotly.js` 3.1–3.6 attributes - [[#410](https://github.com/plotly/plotly.rs/pull/410)] Add `Choropleth` (geo subplot) and `ChoroplethMap` (MapLibre `map` subplot) trace types, with a `LocationMode` enum and a dedicated `choropleth::Marker`; add the MapLibre `map` subplot via `LayoutMap`/`MapStyle`/`MapBounds` - [[#410](https://github.com/plotly/plotly.rs/pull/410)] Add `LayoutGeo` options: `fitbounds` (`GeoFitBounds`), `resolution` (`GeoResolution`, 1:110M/1:50M base-layer detail), and `bgcolor` diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 17dcd263..74205c08 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -13,6 +13,7 @@ members = [ "maps", "ndarray", "plotly_utils", + "proa", "scientific_charts", "shapes", "statistical_charts", diff --git a/examples/README.md b/examples/README.md index 606f4e66..dd51892b 100644 --- a/examples/README.md +++ b/examples/README.md @@ -9,3 +9,5 @@ You can also configure the chosen example to open the resulting plots automatica For more complex examples, instructions on how to run them can be found in the README of each example's subdirectory. Pull requests with more examples of different behavior are always welcome. + +See [`proa`](proa) for three Plotly figures composed into a reusable Rust layout with page metadata and chart components. diff --git a/examples/proa/Cargo.toml b/examples/proa/Cargo.toml new file mode 100644 index 00000000..6d57a6f2 --- /dev/null +++ b/examples/proa/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "proa_example" +version = "0.1.0" +edition = "2021" +# Proa's minimum supported Rust version. +rust-version = "1.93" +publish = false + +[dependencies] +axum = "0.7.9" +ndarray = "0.17" +plotly = { path = "../../plotly" } +proa_core = { git = "https://github.com/proa-labs/proa", rev = "43c28ff2c94b3f148094300df761eac086e618a7" } +proa_framework_axum = { git = "https://github.com/proa-labs/proa", rev = "43c28ff2c94b3f148094300df761eac086e618a7" } +proa_macros = { git = "https://github.com/proa-labs/proa", rev = "43c28ff2c94b3f148094300df761eac086e618a7" } +serde_json = "1" +tokio = { version = "1", features = ["macros", "rt-multi-thread"] } +tower = { version = "0.5", features = ["util"] } diff --git a/examples/proa/README.md b/examples/proa/README.md new file mode 100644 index 00000000..ff2364d2 --- /dev/null +++ b/examples/proa/README.md @@ -0,0 +1,69 @@ +# Proa page composition + +This example adapts the three figures from +[`customization/multiple_plots_example`](../customization/multiple_plots_example) +into a page built with [Proa](https://proa.so). It demonstrates composing Plotly +figures as Rust render components, rather than inserting chart HTML strings +into a page builder. + +## Run + +Requires Rust 1.93 or newer. From this directory: + +```bash +cargo run +``` + +The command writes `output/multiple_plots.html` and exits. Open that file in +your browser. Stdout prints the saved path; it does not contain the HTML. +The page loads Plotly.js 3.7.0 from its CDN, so an internet connection is required. +No listening server, WASM target, JavaScript build tool, or local Proa checkout +is needed. + +## Components + +- `PlotLayout` in `src/layout.rs` owns the HTML document, styles, shared + Plotly.js script, and chart initialization. It accepts any synchronous child. +- `MultiplePlotsPage` in `src/page.rs` owns chart setup, page metadata, and + composition. Its `HeadMetadata` overrides layout defaults at `{cx.head()}`. +- `src/plots.rs` builds the three figures using Plotly.rs's normal API. +- `src/chart.rs` defines `Chart` and `ChartCard`, which supplies the common + section/heading structure. +- `Chart::new` borrows a `Plot` and serializes it during page construction. + Rendering borrows the prepared component and uses Proa's normal text escaping; + serialization stays outside the component render methods. It does not call + `to_html()` or `to_inline_html()` or clone the plot. + +The plot-building functions still use the normal Plotly.rs API. They return +`Plot`, leaving presentation to the components. Change the layout once to change +all pages that use it, or change `ChartCard` once to change every chart wrapper. + +The example pins a public Proa Git revision for the new managed metadata API, +which is not in the released 0.3 crates. Cargo fetches it automatically; no local +Proa checkout is required. The Git dependencies will be replaced with crates.io +versions after Proa 0.4 is released. The revision is from Proa's existing main +branch; no changes to Proa are required. `src/main.rs` configures managed metadata +once with `FrameworkBuilder::with_head`. The route returns +`RouteResponse::ssr(PlotLayout { ... })`, and an in-process request renders the +page through the framework's normal middleware. The response HTML is written to +disk; no listening server or custom response finalizer is required. + +## Plotly.js boundary + +Each chart renders a container followed by an inert `