Skip to content
Open
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,26 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a

https://github.com/plotly/plotly.rs/pull/350

## [Unreleased]

### Added

- [[#NNN](https://github.com/plotly/plotly.rs/pull/NNN)] Add `Treemap` trace type, with `Tiling`/`PathBar` helpers, a dedicated `treemap::Marker` (`pad`/`corner_radius`/`depth_fade`), and `treemapcolorway`/`extendtreemapcolors` layout options
- [[#NNN](https://github.com/plotly/plotly.rs/pull/NNN)] Add `Sunburst` trace type
- [[#407](https://github.com/plotly/plotly.rs/issues/407)] Expose plotly.js 3.1–3.6 attributes:
- `Layout`: `hoversort`, `hoveranywhere`, `clickanywhere`
- `Axis`: `zerolinelayer` (`ZeroLineLayer`), `minorloglabels`, `modebardisable` (`ModeBarDisable`), `ticklabelposition` (`TickLabelPosition`), `unifiedhovertitle` (`UnifiedHoverTitle`), and `ExponentFormat::SIExtended`
- `Legend`: `maxheight`
- `Configuration`: `displayNotifier`
- `common::Label` (hover labels): `showarrow`
- `common::Pattern`: `path` (arbitrary SVG path fill)
- `Candlestick`/`Ohlc`: `hovertemplate`
- `hovertemplatefallback`/`texttemplatefallback` across applicable traces

### Changed

- [[#407](https://github.com/plotly/plotly.rs/issues/407)] Upgrade bundled plotly.js from 3.0.1 to 3.6.0

## [0.14.1] - 2026-02-15

### Fixed
Expand Down
469 changes: 236 additions & 233 deletions docs/book/plotly.min.js

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions docs/book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
- [Bar Charts](./recipes/basic_charts/bar_charts.md)
- [Pie Charts](./recipes/basic_charts/pie_charts.md)
- [Sankey Diagrams](./recipes/basic_charts/sankey_diagrams.md)
- [Treemap Charts](./recipes/basic_charts/treemap_charts.md)
- [Sunburst Charts](./recipes/basic_charts/sunburst_charts.md)
- [Statistical Charts](./recipes/statistical_charts.md)
- [Error Bars](./recipes/statistical_charts/error_bars.md)
- [Box Plots](./recipes/statistical_charts/box_plots.md)
Expand Down
2 changes: 2 additions & 0 deletions docs/book/src/recipes/basic_charts.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ Line Charts | [![Line Charts](./img/line_shape_options_for_interpolation.png)](.
Bar Charts | [![Bar Charts](./img/bar_chart_with_error_bars.png)](./basic_charts/scatter_plots.md)
Pie Charts | [![Pie Charts](./img/pie_charts.png)](./basic_charts/pie_charts.md)
Sankey Diagrams | [![Sankey Diagrams](./img/basic_sankey.png)](./basic_charts/sankey_diagrams.md)
Treemap Charts | [Treemap Charts](./basic_charts/treemap_charts.md)
Sunburst Charts | [Sunburst Charts](./basic_charts/sunburst_charts.md)
27 changes: 27 additions & 0 deletions docs/book/src/recipes/basic_charts/sunburst_charts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Sunburst Charts

The following imports have been used to produce the plots below:

```rust,no_run
use plotly::common::Orientation;
use plotly::sunburst::Leaf;
use plotly::treemap::BranchValues;
use plotly::{Plot, Sunburst};
```

The `to_inline_html` method is used to produce the html plot displayed in this page.

## Basic Sunburst
```rust,no_run
{{#include ../../../../../examples/basic_charts/src/main.rs:basic_sunburst}}
```

{{#include ../../../../../examples/basic_charts/output/inline_basic_sunburst.html}}


## Styled Sunburst with Branch Values and Leaf Opacity
```rust,no_run
{{#include ../../../../../examples/basic_charts/src/main.rs:styled_sunburst}}
```

{{#include ../../../../../examples/basic_charts/output/inline_styled_sunburst.html}}
25 changes: 25 additions & 0 deletions docs/book/src/recipes/basic_charts/treemap_charts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Treemap Charts

The following imports have been used to produce the plots below:

```rust,no_run
use plotly::treemap::{BranchValues, Packing, PathBar, Side, Tiling};
use plotly::{Plot, Treemap};
```

The `to_inline_html` method is used to produce the html plot displayed in this page.

## Basic Treemap
```rust,no_run
{{#include ../../../../../examples/basic_charts/src/main.rs:basic_treemap}}
```

{{#include ../../../../../examples/basic_charts/output/inline_basic_treemap.html}}


## Styled Treemap with Tiling and Path Bar
```rust,no_run
{{#include ../../../../../examples/basic_charts/src/main.rs:styled_treemap}}
```

{{#include ../../../../../examples/basic_charts/output/inline_styled_treemap.html}}
2 changes: 1 addition & 1 deletion docs/book/theme/header.hbs
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<script src="https://cdn.plot.ly/plotly-3.0.1.min.js"></script>
<script src="https://cdn.plot.ly/plotly-3.6.0.min.js"></script>
114 changes: 113 additions & 1 deletion examples/basic_charts/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ use plotly::{
TicksDirection, TraceOrder,
},
sankey::{Line as SankeyLine, Link, Node},
sunburst::{InsideTextOrientation, Leaf},
traces::table::{
Align as TableAlign, Cells, Fill as TableFill, Font as TableFont, Header, Line as TableLine,
},
Bar, Pie, Plot, Sankey, Scatter, ScatterPolar, Table,
treemap::{BranchValues, Marker as TreemapMarker, Packing, PathBar, Side, Tiling},
Bar, Pie, Plot, Sankey, Scatter, ScatterPolar, Sunburst, Table, Treemap,
};
use plotly_utils::write_example_to_html;
use rand_distr::{Distribution, Normal, Uniform};
Expand Down Expand Up @@ -1043,6 +1045,108 @@ fn grouped_donout_pie_charts(show: bool, file_name: &str) {
}
// ANCHOR_END: grouped_donout_pie_charts

// ANCHOR: basic_treemap
fn basic_treemap(show: bool, file_name: &str) {
let labels = vec![
"Eve", "Cain", "Seth", "Enos", "Noam", "Abel", "Awan", "Enoch", "Azura",
];
let parents = vec![
"", "Eve", "Eve", "Seth", "Seth", "Eve", "Eve", "Awan", "Eve",
];
let trace = Treemap::new(labels, parents)
.values(vec![10.0, 14.0, 12.0, 10.0, 2.0, 6.0, 6.0, 4.0, 4.0])
.text_info("label+value");

let mut plot = Plot::new();
plot.add_trace(trace);

let path = write_example_to_html(&plot, file_name);
if show {
plot.show_html(path);
}
}
// ANCHOR_END: basic_treemap

// ANCHOR: styled_treemap
fn styled_treemap(show: bool, file_name: &str) {
let labels = vec![
"Total",
"Tech",
"Health",
"Finance",
"Software",
"Hardware",
"Pharma",
"Devices",
"Banking",
"Insurance",
];
let parents = vec![
"", "Total", "Total", "Total", "Tech", "Tech", "Health", "Health", "Finance", "Finance",
];
let trace = Treemap::new(labels, parents)
.values(vec![0.0, 0.0, 0.0, 0.0, 40.0, 30.0, 25.0, 15.0, 20.0, 18.0])
.branch_values(BranchValues::Remainder)
.marker(
TreemapMarker::new()
.corner_radius(5.0)
.line(Line::new().width(1.0).color(NamedColor::White)),
)
.tiling(Tiling::new().packing(Packing::Binary).pad(2.0))
.path_bar(PathBar::new().visible(true).side(Side::Top))
.text_info("label+value+percent parent");

let mut plot = Plot::new();
plot.add_trace(trace);

let path = write_example_to_html(&plot, file_name);
if show {
plot.show_html(path);
}
}
// ANCHOR_END: styled_treemap

// ANCHOR: basic_sunburst
fn basic_sunburst(show: bool, file_name: &str) {
let labels = vec![
"Eve", "Cain", "Seth", "Enos", "Noam", "Abel", "Awan", "Enoch", "Azura",
];
let parents = vec![
"", "Eve", "Eve", "Seth", "Seth", "Eve", "Eve", "Awan", "Eve",
];
let trace = Sunburst::new(labels, parents)
.values(vec![10.0, 14.0, 12.0, 10.0, 2.0, 6.0, 6.0, 4.0, 4.0]);

let mut plot = Plot::new();
plot.add_trace(trace);

let path = write_example_to_html(&plot, file_name);
if show {
plot.show_html(path);
}
}
// ANCHOR_END: basic_sunburst

// ANCHOR: styled_sunburst
fn styled_sunburst(show: bool, file_name: &str) {
let labels = vec!["Root", "Branch A", "Branch B", "Leaf A1", "Leaf B1"];
let parents = vec!["", "Root", "Root", "Branch A", "Branch B"];
let trace = Sunburst::new(labels, parents)
.values(vec![8.0, 3.0, 5.0, 3.0, 5.0])
.branch_values(BranchValues::Total)
.leaf(Leaf::new().opacity(0.7))
.inside_text_orientation(InsideTextOrientation::Radial);

let mut plot = Plot::new();
plot.add_trace(trace);

let path = write_example_to_html(&plot, file_name);
if show {
plot.show_html(path);
}
}
// ANCHOR_END: styled_sunburst

// ANCHOR: set_lower_or_upper_bound_on_axis
fn set_lower_or_upper_bound_on_axis(show: bool, file_name: &str) {
use std::fs::File;
Expand Down Expand Up @@ -1200,6 +1304,14 @@ fn main() {

grouped_donout_pie_charts(false, "grouped_donout_pie_charts");

// Treemap Charts
basic_treemap(false, "basic_treemap");
styled_treemap(false, "styled_treemap");

// Sunburst Charts
basic_sunburst(false, "basic_sunburst");
styled_sunburst(false, "styled_sunburst");

// Set Lower or Upper Bound on Axis
set_lower_or_upper_bound_on_axis(false, "set_lower_or_upper_bound_on_axis");
}
469 changes: 236 additions & 233 deletions plotly/resource/plotly.min.js

Large diffs are not rendered by default.

35 changes: 33 additions & 2 deletions plotly/src/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,8 @@ pub enum PlotType {
DensityMapbox,
Table,
Pie,
Treemap,
Sunburst,
}

#[derive(Serialize, Clone, Debug)]
Expand Down Expand Up @@ -612,6 +614,8 @@ pub enum ExponentFormat {
SI,
#[serde(rename = "B")]
B,
#[serde(rename = "SI extended")]
SIExtended,
}

#[derive(Serialize, Clone, Debug)]
Expand Down Expand Up @@ -792,6 +796,9 @@ pub enum PatternFillMode {
#[derive(Serialize, Clone, Debug, FieldSetter)]
pub struct Pattern {
shape: Option<Dim<PatternShape>>,
/// An arbitrary SVG path string to use as the pattern fill, as an
/// alternative to one of the preset `shape` values.
path: Option<Dim<String>>,
#[serde(rename = "fillmode")]
fill_mode: Option<PatternFillMode>,
#[serde(rename = "bgcolor")]
Expand Down Expand Up @@ -977,6 +984,10 @@ pub struct Label {
align: Option<String>,
#[serde(rename = "namelength")]
name_length: Option<Dim<i32>>,
/// Determines whether or not the triangular caret pointing to the data
/// point is shown on the hover label box.
#[serde(rename = "showarrow")]
show_arrow: Option<bool>,
}

impl Label {
Expand Down Expand Up @@ -1622,6 +1633,10 @@ mod tests {
assert_eq!(to_value(ExponentFormat::Power).unwrap(), json!("power"));
assert_eq!(to_value(ExponentFormat::SI).unwrap(), json!("SI"));
assert_eq!(to_value(ExponentFormat::B).unwrap(), json!("B"));
assert_eq!(
to_value(ExponentFormat::SIExtended).unwrap(),
json!("SI extended")
);
}

#[test]
Expand Down Expand Up @@ -1703,10 +1718,12 @@ mod tests {
.foreground_color_array(vec![NamedColor::Red, NamedColor::Green])
.foreground_opacity(0.9)
.size_array(vec![10.0, 20.0])
.solidity_array(vec![0.1, 0.2]);
.solidity_array(vec![0.1, 0.2])
.path_array(vec!["M0,0 L10,10", "M5,5 L15,15"]);

let expected = json!({
"shape": ["-", "|"],
"path": ["M0,0 L10,10", "M5,5 L15,15"],
"fillmode": "overlay",
"bgcolor": ["black", "blue"],
"fgcolor": ["red", "green"],
Expand All @@ -1718,6 +1735,18 @@ mod tests {
assert_eq!(to_value(pattern).unwrap(), expected);
}

#[test]
fn serialize_pattern_path() {
let pattern = Pattern::new().path("M0,0 L10,10");
assert_eq!(to_value(pattern).unwrap(), json!({"path": "M0,0 L10,10"}));

let pattern = Pattern::new().path_array(vec!["M0,0 L10,10", "M5,5 L15,15"]);
assert_eq!(
to_value(pattern).unwrap(),
json!({"path": ["M0,0 L10,10", "M5,5 L15,15"]})
);
}

#[test]
fn serialize_marker() {
let marker = Marker::new()
Expand Down Expand Up @@ -1887,13 +1916,15 @@ mod tests {
.font(Font::new())
.align("something")
.name_length_array(vec![5, 10])
.name_length(6);
.name_length(6)
.show_arrow(false);
let expected = json!({
"bgcolor": "#FFFFFF",
"bordercolor": "#000000",
"font": {},
"align": "something",
"namelength": 6,
"showarrow": false,
});

assert_eq!(to_value(label).unwrap(), expected);
Expand Down
10 changes: 10 additions & 0 deletions plotly/src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ pub struct Configuration {
plot_gl_pixel_ratio: Option<PlotGLPixelRatio>,
show_send_to_cloud: Option<bool>,
queue_length: Option<usize>,
display_notifier: Option<bool>,
}

impl Configuration {
Expand Down Expand Up @@ -420,6 +421,13 @@ impl Configuration {
self
}

/// Determines whether the notifier is displayed in the top right area of
/// the viewport.
pub fn display_notifier(mut self, display_notifier: bool) -> Self {
self.display_notifier = Some(display_notifier);
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, <script src="https://cdn.plot.ly/plotly-locale-fr-latest.js"></script> must be present.
Expand Down Expand Up @@ -552,6 +560,7 @@ mod tests {
.topojson_url("topojson_url")
.mapbox_access_token("123")
.queue_length(100)
.display_notifier(true)
.locale("en");

let expected = json!({
Expand Down Expand Up @@ -583,6 +592,7 @@ mod tests {
"topojsonURL": "topojson_url",
"mapboxAccessToken": "123",
"queueLength": 100,
"displayNotifier": true,
"locale": "en"
});

Expand Down
Loading
Loading