1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
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 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);
}
}