diff --git a/CHANGELOG.md b/CHANGELOG.md index b64f3c39..09b4e97b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - [[#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` - [[#412](https://github.com/plotly/plotly.rs/pull/412)] Add `Violin` trace type with box, mean line, KDE span, and split/grouped support - [[#414](https://github.com/plotly/plotly.rs/issues/414)] Add `DensityMap` (MapLibre `map` subplot) trace type — density heatmaps with full color-scale and hover support +- [[#417](https://github.com/plotly/plotly.rs/issues/417)] Add `ScatterMap` (MapLibre `map` subplot) trace type — the modern counterpart to `ScatterMapbox` ### Changed diff --git a/plotly/src/common/mod.rs b/plotly/src/common/mod.rs index d5925399..db2fa08e 100644 --- a/plotly/src/common/mod.rs +++ b/plotly/src/common/mod.rs @@ -212,6 +212,7 @@ pub enum PlotType { ScatterGL, Scatter3D, ScatterMapbox, + ScatterMap, ScatterGeo, ScatterPolar, ScatterPolarGL, diff --git a/plotly/src/lib.rs b/plotly/src/lib.rs index 057e197e..7086da40 100644 --- a/plotly/src/lib.rs +++ b/plotly/src/lib.rs @@ -61,13 +61,13 @@ pub use plot::{Plot, Trace, Traces}; // Also provide easy access to modules which contain additional trace-specific types pub use traces::{ box_plot, choropleth, choropleth_map, contour, density_map, heat_map, histogram, image, mesh3d, - sankey, scatter, scatter3d, scatter_mapbox, sunburst, surface, treemap, violin, + sankey, scatter, scatter3d, scatter_map, scatter_mapbox, sunburst, surface, treemap, violin, }; // Bring the different trace types into the top-level scope pub use traces::{ Bar, BoxPlot, Candlestick, Choropleth, ChoroplethMap, Contour, DensityMap, DensityMapbox, HeatMap, Histogram, Image, Mesh3D, Ohlc, Pie, Sankey, Scatter, Scatter3D, ScatterGeo, - ScatterMapbox, ScatterPolar, Sunburst, Surface, Table, Treemap, Violin, + ScatterMap, ScatterMapbox, ScatterPolar, Sunburst, Surface, Table, Treemap, Violin, }; pub trait Restyle: serde::Serialize {} diff --git a/plotly/src/traces/mod.rs b/plotly/src/traces/mod.rs index 354e7f94..850dfe13 100644 --- a/plotly/src/traces/mod.rs +++ b/plotly/src/traces/mod.rs @@ -18,6 +18,7 @@ pub mod sankey; pub mod scatter; pub mod scatter3d; pub mod scatter_geo; +pub mod scatter_map; pub mod scatter_mapbox; mod scatter_polar; pub mod sunburst; @@ -43,6 +44,7 @@ pub use sankey::Sankey; pub use scatter::Scatter; pub use scatter3d::Scatter3D; pub use scatter_geo::ScatterGeo; +pub use scatter_map::ScatterMap; pub use scatter_mapbox::ScatterMapbox; pub use scatter_polar::ScatterPolar; pub use sunburst::Sunburst; diff --git a/plotly/src/traces/scatter_map.rs b/plotly/src/traces/scatter_map.rs new file mode 100644 index 00000000..5b213fff --- /dev/null +++ b/plotly/src/traces/scatter_map.rs @@ -0,0 +1,399 @@ +//! Scatter plot trace for the MapLibre `map` subplot. + +use plotly_derive::FieldSetter; +use serde::Serialize; + +use crate::common::{ + color::Color, Dim, Font, HoverInfo, Label, LegendGroupTitle, Line, Marker, Mode, PlotType, + Position, Visible, +}; +use crate::private::{NumOrString, NumOrStringCollection}; +use crate::Trace; + +#[derive(Serialize, Clone, Debug)] +#[serde(rename_all = "lowercase")] +pub enum Fill { + None, + ToSelf, +} + +#[serde_with::skip_serializing_none] +#[derive(Serialize, Clone, Debug, Default)] +pub struct SelectionMarker { + color: Option>, + opacity: Option, + size: Option>, +} + +#[derive(Serialize, Clone, Debug, Default)] +pub struct Selection { + marker: SelectionMarker, +} + +impl Selection { + pub fn new() -> Self { + Default::default() + } + + /// Sets the marker color of un/selected points. + pub fn color(mut self, color: C) -> Self { + self.marker.color = Some(Box::new(color)); + self + } + + /// Sets the marker opacity of un/selected points. + pub fn opacity(mut self, opacity: f64) -> Self { + self.marker.opacity = Some(opacity); + self + } + + /// Sets the marker size of un/selected points. + pub fn size(mut self, size: usize) -> Self { + self.marker.size = Some(Dim::Scalar(size)); + self + } +} + +/// Construct a scatter trace drawn on the MapLibre `map` subplot +/// (configured via [`LayoutMap`](crate::layout::LayoutMap)). +/// +/// `ScatterMap` is the modern MapLibre-based counterpart to +/// [`ScatterMapbox`](crate::ScatterMapbox): it draws markers and/or lines from +/// `lat`/`lon` coordinates onto the `layout.map` subplot. +/// +/// # Examples +/// +/// ``` +/// use plotly::ScatterMap; +/// +/// let trace = ScatterMap::new(vec![45.5017], vec![-73.5673]).name("montreal"); +/// ``` +#[serde_with::skip_serializing_none] +#[derive(Serialize, Clone, Debug, FieldSetter)] +#[field_setter(box_self, kind = "trace")] +pub struct ScatterMap +where + Lat: Serialize + Clone, + Lon: Serialize + Clone, +{ + #[field_setter(default = "PlotType::ScatterMap")] + r#type: PlotType, + /// Sets the trace name. The trace name appear as the legend item and on + /// hover. + name: Option, + /// Determines whether or not this trace is visible. If + /// `Visible::LegendOnly`, the trace is not drawn, but can appear as a + /// legend item (provided that the legend itself is visible). + visible: Option, + + /// Determines whether or not an item corresponding to this trace is shown + /// in the legend. + #[serde(rename = "showlegend")] + show_legend: Option, + /// Sets the legend rank for this trace. Items and groups with smaller ranks + /// are presented on top/left side while with `"reversed" + /// `legend.trace_order` they are on bottom/right side. The default + /// legendrank is 1000, so that you can use ranks less than 1000 to + /// place certain items before all unranked items, and ranks greater + /// than 1000 to go after all unranked items. + #[serde(rename = "legendrank")] + legend_rank: Option, + /// Sets the legend group for this trace. Traces part of the same legend + /// group show/hide at the same time when toggling legend items. + #[serde(rename = "legendgroup")] + legend_group: Option, + /// Set and style the title to appear for the legend group. + #[serde(rename = "legendgrouptitle")] + legend_group_title: Option, + + /// Sets the opacity of the trace. + opacity: Option, + /// Determines the drawing mode for this scatter trace. If the provided + /// `Mode` includes "Text" then the `text` elements appear at the + /// coordinates. Otherwise, the `text` elements appear on hover. If + /// there are less than 20 points and the trace is not stacked then the + /// default is `Mode::LinesMarkers`, otherwise it is `Mode::Lines`. + mode: Option, + /// Assigns id labels to each datum. These ids for object constancy of data + /// points during animation. Should be an array of strings, not numbers + /// or any other type. + ids: Option>, + + lat: Option>, + lon: Option>, + + /// Sets text elements associated with each (x,y) pair. If a single string, + /// the same string appears over all the data points. If an array of + /// strings, the items are mapped in order to the this trace's (x,y) + /// coordinates. If the trace `HoverInfo` contains a "text" flag and + /// `hover_text` is not set, these elements will be seen in the hover + /// labels. + text: Option>, + /// Sets the positions of the `text` elements with respects to the (x,y) + /// coordinates. + #[serde(rename = "textposition")] + text_position: Option>, + /// Template string used for rendering the information text that appear on + /// points. Note that this will override `textinfo`. Variables are + /// inserted using %{variable}, for example "y: %{y}". Numbers are + /// formatted using d3-format's syntax %{variable:d3-format}, for example "Price: %{y:$.2f}". See [format](https://github.com/d3/d3-3.x-api-reference/blob/master/Formatting.md#d3) + /// for details on the formatting syntax. Dates are formatted using + /// d3-time-format's syntax %{variable|d3-time-format}, for example + /// "Day: %{2019-01-01|%A}". See [format](https://github.com/d3/d3-3.x-api-reference/blob/master/Time-Formatting.md#format) for details + /// on the date formatting syntax. Every attributes that can be specified + /// per-point (the ones that are `arrayOk: true`) are available. + #[serde(rename = "texttemplate")] + text_template: Option>, + #[serde(rename = "texttemplatefallback")] + text_template_fallback: Option>, + /// Sets hover text elements associated with each (x,y) pair. If a single + /// string, the same string appears over all the data points. If an + /// array of string, the items are mapped in order to the this trace's + /// (x,y) coordinates. To be seen, trace `HoverInfo` must contain a + /// "Text" flag. + #[serde(rename = "hovertext")] + hover_text: Option>, + /// Determines which trace information appear on hover. If `HoverInfo::None` + /// or `HoverInfo::Skip` are set, no information is displayed upon + /// hovering. But, if `HoverInfo::None` is set, click and hover events + /// are still fired. + #[serde(rename = "hoverinfo")] + hover_info: Option, + /// Template string used for rendering the information that appear on hover + /// box. Note that this will override `HoverInfo`. Variables are + /// inserted using %{variable}, for example "y: %{y}". Numbers are + /// formatted using d3-format's syntax %{variable:d3-format}, for example + /// "Price: %{y:$.2f}". + /// for details + /// on the formatting syntax. Dates are formatted using d3-time-format's + /// syntax %{variable|d3-time-format}, for example "Day: + /// %{2019-01-01|%A}". for details + /// on the date formatting syntax. The variables available in + /// `hovertemplate` are the ones emitted as event data described at this link . + /// Additionally, every attributes that can be specified per-point (the ones + /// that are `arrayOk: true`) are available. Anything contained in tag + /// `` is displayed in the secondary box, for example + /// "{fullData.name}". To hide the secondary box + /// completely, use an empty tag ``. + #[serde(rename = "hovertemplate")] + hover_template: Option>, + #[serde(rename = "hovertemplatefallback")] + hover_template_fallback: Option>, + + /// Assigns extra meta information associated with this trace that can be + /// used in various text attributes. Attributes such as trace `name`, + /// graph, axis and colorbar `title.text`, annotation `text` + /// `rangeselector`, `updatemenues` and `sliders` `label` text all support + /// `meta`. To access the trace `meta` values in an attribute in the same + /// trace, simply use `%{meta[i]}` where `i` is the index or key of the + /// `meta` item in question. To access trace `meta` in layout + /// attributes, use `%{data[n[.meta[i]}` where `i` is the index or key of + /// the `meta` and `n` is the trace index. + meta: Option, + /// Assigns extra data each datum. This may be useful when listening to + /// hover, click and selection events. Note that, "scatter" traces also + /// appends customdata items in the markers DOM elements. + #[serde(rename = "customdata")] + custom_data: Option, + + /// Sets a reference between this trace's data coordinates and a `map` + /// subplot. If "map" (the default value), the data refer to `layout.map`. + /// If "map2", the data refer to `layout.map2`, and so on. + subplot: Option, + /// Determines how points are displayed and joined. + marker: Option, + + /// Line display properties. + line: Option, + + /// Sets the text font. + #[serde(rename = "textfont")] + text_font: Option, + + /// Vector containing integer indices of selected points. Has an effect only + /// for traces that support selections. Note that an empty vector means + /// an empty selection where the `unselected` are turned on for all + /// points. + #[serde(rename = "selectedpoints")] + selected_points: Option>, + + /// Sets the style of selected points. + selected: Option, + /// Sets the style of unselected points. + unselected: Option, + + /// Determines if this scattermap trace's layers are to be inserted before + /// the layer with the specified ID. By default, scattermap layers are + /// inserted above all the base layers. To place the scattermap layers + /// above every other layer, set `below` to "''". + below: Option, + /// Determines whether or not gaps (i.e. {nan} or missing values) in the + /// provided data arrays are connected. + #[serde(rename = "connectgaps")] + connect_gaps: Option, + + /// Sets the area to fill with a solid color. Defaults to "none" unless this + /// trace is stacked, then it gets "tonexty" ("tonextx") if + /// `orientation` is "v" ("h") Use with `fillcolor` if not + /// "none". "tozerox" and "tozeroy" fill to x=0 and y=0 respectively. + /// "tonextx" and "tonexty" fill between the endpoints of this trace and + /// the endpoints of the trace before it, connecting those endpoints + /// with straight lines (to make a stacked area graph); if there is + /// no trace before it, they behave like "tozerox" and "tozeroy". "toself" + /// connects the endpoints of the trace (or each segment of the trace if + /// it has gaps) into a closed shape. "tonext" fills the space between + /// two traces if one completely encloses the other (eg consecutive + /// contour lines), and behaves like "toself" if there is no trace before + /// it. "tonext" should not be used if one trace does not enclose the + /// other. Traces in a `stackgroup` will only fill to (or be filled to) + /// other traces in the same group. With multiple `stackgroup`s or some + /// traces stacked and some not, if fill-linked traces are not + /// already consecutive, the later ones will be pushed down in the drawing + /// order. + fill: Option, + /// Sets the fill color. Defaults to a half-transparent variant of the line + /// color, marker color, or marker line color, whichever is available. + #[serde(rename = "fillcolor")] + fill_color: Option>, + /// Properties of label displayed on mouse hover. + #[serde(rename = "hoverlabel")] + hover_label: Option