Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introducing DensityMapbox #163

Merged
merged 6 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ 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.5] - 2023-xx-xx
## [0.8.5] - 2024-xx-xx
### Added
- [[#153](https://github.com/igiagkiozis/plotly/pull/153)] Added `LayoutScene`
- [[#163](https://github.com/plotly/plotly.rs/pull/163)] Added `DensityMapbox`.
- [[#153](https://github.com/igiagkiozis/plotly/pull/153)] Added `LayoutScene`.

## [0.8.4] - 2023-07-09
### Added
Expand Down Expand Up @@ -46,7 +47,7 @@ Version 0.8.0 represents a significant release which refactors a lot of the code
- Support for `Sankey` diagrams
- Support for `Plot3D` - 3D plots for scatter, line and surface data
### Changed
- Improve implementation of `private::NumOrString` to support more primitive types ([Issue
- Improve implementation of `private::NumOrString` to support more primitive types ([Issue
#47](https://github.com/igiagkiozis/plotly/issues/47))
- Remove `private::TruthyEnum` in favour of a more robust way of serializing to `String` or `bool`
- Refactor `Color` module
Expand Down
23 changes: 22 additions & 1 deletion examples/maps/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use plotly::{
common::Marker,
layout::{Center, DragMode, Mapbox, MapboxStyle, Margin},
Layout, Plot, ScatterMapbox,
DensityMapbox, Layout, Plot, ScatterMapbox,
};

fn scatter_mapbox() {
Expand All @@ -27,8 +27,29 @@ fn scatter_mapbox() {
plot.show();
}

fn density_mapbox() {
let trace = DensityMapbox::new(vec![45.5017], vec![-73.5673], vec![0.75]).zauto(true);

let layout = Layout::new()
.drag_mode(DragMode::Zoom)
.margin(Margin::new().top(0).left(0).bottom(0).right(0))
.mapbox(
Mapbox::new()
.style(MapboxStyle::OpenStreetMap)
.center(Center::new(45.5017, -73.5673))
.zoom(5),
);

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

plot.show();
}

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

// scatter_mapbox();
// density_mapbox();
}
1 change: 1 addition & 0 deletions plotly/src/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ pub enum PlotType {
Ohlc,
Sankey,
Surface,
DensityMapbox,
}

#[derive(Serialize, Clone, Debug)]
Expand Down
2 changes: 1 addition & 1 deletion plotly/src/layout/update_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ impl ButtonBuilder {
pub fn new() -> Self {
Default::default()
}
pub fn push_restyle(mut self, restyle: impl Restyle + Serialize) -> Self {
pub fn push_restyle(mut self, restyle: impl Restyle) -> Self {
let restyle = serde_json::to_value(&restyle).unwrap();
for (k, v) in restyle.as_object().unwrap() {
self.restyles.insert(k.clone(), v.clone());
Expand Down
4 changes: 2 additions & 2 deletions plotly/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ pub use plot::{ImageFormat, Plot, Trace};
pub use traces::{box_plot, contour, histogram, image, mesh3d, sankey, scatter_mapbox, surface};
// Bring the different trace types into the top-level scope
pub use traces::{
Bar, BoxPlot, Candlestick, Contour, HeatMap, Histogram, Image, Mesh3D, Ohlc, Sankey, Scatter,
Scatter3D, ScatterMapbox, ScatterPolar, Surface,
Bar, BoxPlot, Candlestick, Contour, DensityMapbox, HeatMap, Histogram, Image, Mesh3D, Ohlc,
Sankey, Scatter, Scatter3D, ScatterMapbox, ScatterPolar, Surface,
};

pub trait Restyle: serde::Serialize {}
Expand Down
1 change: 1 addition & 0 deletions plotly/src/plot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct PlotTemplate<'a> {

#[derive(Template)]
#[template(path = "static_plot.html", escape = "none")]
#[cfg(not(target_family = "wasm"))]
struct StaticPlotTemplate<'a> {
plot: &'a Plot,
format: ImageFormat,
Expand Down
146 changes: 146 additions & 0 deletions plotly/src/traces/density_mapbox.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
//! Density mapbox scatter plot

use plotly_derive::FieldSetter;
use serde::Serialize;

use crate::common::{LegendGroupTitle, Line, PlotType, Visible};
use crate::Trace;

#[serde_with::skip_serializing_none]
#[derive(Serialize, Clone, Debug, FieldSetter)]
#[field_setter(box_self, kind = "trace")]
pub struct DensityMapbox<Lat, Lon, Z>
where
Lat: Serialize + Clone,
Lon: Serialize + Clone,
Z: Serialize + Clone,
{
#[field_setter(default = "PlotType::DensityMapbox")]
r#type: PlotType,
/// Sets the trace name. The trace name appear as the legend item and on
/// hover.
name: Option<String>,
/// 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<Visible>,

/// Determines whether or not an item corresponding to this trace is shown
/// in the legend.
#[serde(rename = "showlegend")]
show_legend: Option<bool>,

/// 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<usize>,
/// 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<String>,
/// Set and style the title to appear for the legend group.
#[serde(rename = "legendgrouptitle")]
legend_group_title: Option<LegendGroupTitle>,

/// Line display properties.
line: Option<Line>,

lat: Option<Vec<Lat>>,
lon: Option<Vec<Lon>>,
z: Option<Vec<Z>>,

/// Sets the opacity of the trace.
opacity: Option<f64>,

/// Sets a reference between this trace's data coordinates and a mapbox
/// subplot. If "mapbox" (the default value), the data refer to
/// `layout.mapbox`. If "mapbox2", the data refer to `layout.mapbox2`, and
/// so on.
subplot: Option<String>,

/// Determines whether or not the color domain is computed
/// with respect to the input data (here in `z`) or the bounds set
/// in `zmin` and `zmax`. Defaults to false when `zmin` and `zmax` are
/// set by the user.
zauto: Option<bool>,

/// Sets the upper bound of the color domain. Value should have the
/// same units as in `z` and if set, `zmin` must be set as well.
zmax: Option<Z>,

zmid: Option<Z>,

zmin: Option<Z>,

zoom: Option<u8>,

radius: Option<u8>,
//color_continuous_scale: Option<HashMap<Z, NamedColor>>,
//color_continuous_midpoint: Option<ContinuousColorScale>,
}

impl<Lat, Lon, Z> DensityMapbox<Lat, Lon, Z>
where
Lat: Serialize + Clone + std::default::Default, // TODO why is "+ Default" necessary?
Lon: Serialize + Clone + std::default::Default,
Z: Serialize + Clone + std::default::Default,
{
pub fn new(lat: Vec<Lat>, lon: Vec<Lon>, z: Vec<Z>) -> Box<Self> {
Box::new(Self {
lat: Some(lat),
lon: Some(lon),
z: Some(z),
..Default::default()
})
}
}

impl<Lat, Lon, Z> Trace for DensityMapbox<Lat, Lon, Z>
where
Lat: Serialize + Clone,
Lon: Serialize + Clone,
Z: Serialize + Clone,
{
fn to_json(&self) -> String {
serde_json::to_string(&self).unwrap()
}
}

#[cfg(test)]
mod tests {
use serde_json::{json, to_value};

use super::*;

#[test]
fn test_serialize_density_mapbox() {
let density_mapbox = DensityMapbox::new(vec![45.5017], vec![-73.5673], vec![1.0])
.name("name")
.visible(Visible::True)
.show_legend(true)
.legend_rank(1000)
.legend_group("legend group")
.zoom(5)
.radius(20)
.opacity(0.5);
let expected = json!({
"type": "densitymapbox",
"lat": [45.5017],
"lon": [-73.5673],
"z": [1.0],
"name": "name",
"visible": true,
"showlegend": true,
"legendrank": 1000,
"legendgroup": "legend group",
"opacity": 0.5,
"zoom": 5,
"radius": 20,
});
assert_eq!(to_value(density_mapbox.clone()).unwrap(), expected);
}
}
2 changes: 2 additions & 0 deletions plotly/src/traces/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod bar;
pub mod box_plot;
mod candlestick;
pub mod contour;
mod density_mapbox;
mod heat_map;
pub mod histogram;
pub mod image;
Expand All @@ -20,6 +21,7 @@ pub use bar::Bar;
pub use box_plot::BoxPlot;
pub use candlestick::Candlestick;
pub use contour::Contour;
pub use density_mapbox::DensityMapbox;
pub use heat_map::HeatMap;
pub use histogram::Histogram;
pub use mesh3d::Mesh3D;
Expand Down
Loading