diff --git a/plotly/src/common/mod.rs b/plotly/src/common/mod.rs index 28e3bd2b..c5a4d98e 100644 --- a/plotly/src/common/mod.rs +++ b/plotly/src/common/mod.rs @@ -893,6 +893,16 @@ pub enum Reference { Paper, } +/// Axis id for a 2D cartesian x axis. +/// +/// Use `"x"` for the primary axis, `"x2"` for the second axis, and so on. +pub type XAxisId = String; + +/// Axis id for a 2D cartesian y axis. +/// +/// Use `"y"` for the primary axis, `"y2"` for the second axis, and so on. +pub type YAxisId = String; + #[derive(Serialize, Clone, Debug)] pub struct Pad { t: usize, @@ -1799,6 +1809,14 @@ mod tests { assert_eq!(to_value(Reference::Paper).unwrap(), json!("paper")); } + #[test] + fn serialize_axis_id() { + assert_eq!(to_value(XAxisId::from("x")).unwrap(), json!("x")); + assert_eq!(to_value(XAxisId::from("x3")).unwrap(), json!("x3")); + assert_eq!(to_value(YAxisId::from("y")).unwrap(), json!("y")); + assert_eq!(to_value(YAxisId::from("y8")).unwrap(), json!("y8")); + } + #[test] #[rustfmt::skip] fn serialize_legend_group_title() { diff --git a/plotly/src/traces/bar.rs b/plotly/src/traces/bar.rs index ca852b7e..86525f03 100644 --- a/plotly/src/traces/bar.rs +++ b/plotly/src/traces/bar.rs @@ -6,7 +6,7 @@ use serde::Serialize; use crate::{ common::{ Calendar, ConstrainText, Dim, ErrorData, Font, HoverInfo, Label, LegendGroupTitle, Marker, - Orientation, PlotType, TextAnchor, TextPosition, Visible, + Orientation, PlotType, TextAnchor, TextPosition, Visible, XAxisId, YAxisId, }, Trace, }; @@ -70,9 +70,9 @@ where #[serde(rename = "hovertemplate")] hover_template: Option>, #[serde(rename = "xaxis")] - x_axis: Option, + x_axis: Option, #[serde(rename = "yaxis")] - y_axis: Option, + y_axis: Option, orientation: Option, #[serde(rename = "alignmentgroup")] alignment_group: Option, diff --git a/plotly/src/traces/box_plot.rs b/plotly/src/traces/box_plot.rs index 604eb1d3..170812b6 100644 --- a/plotly/src/traces/box_plot.rs +++ b/plotly/src/traces/box_plot.rs @@ -7,7 +7,7 @@ use crate::{ color::Color, common::{ Calendar, Dim, HoverInfo, Label, LegendGroupTitle, Line, Marker, Orientation, PlotType, - Visible, + Visible, XAxisId, YAxisId, }, Trace, }; @@ -124,9 +124,9 @@ where #[serde(rename = "hovertemplate")] hover_template: Option>, #[serde(rename = "xaxis")] - x_axis: Option, + x_axis: Option, #[serde(rename = "yaxis")] - y_axis: Option, + y_axis: Option, orientation: Option, #[serde(rename = "alignmentgroup")] alignment_group: Option, diff --git a/plotly/src/traces/candlestick.rs b/plotly/src/traces/candlestick.rs index 9eaacce4..f14eb324 100644 --- a/plotly/src/traces/candlestick.rs +++ b/plotly/src/traces/candlestick.rs @@ -7,6 +7,7 @@ use crate::{ color::NamedColor, common::{ Calendar, Dim, Direction, HoverInfo, Label, LegendGroupTitle, Line, PlotType, Visible, + XAxisId, YAxisId, }, Trace, }; @@ -72,9 +73,9 @@ where #[serde(rename = "hoverinfo")] hover_info: Option, #[serde(rename = "xaxis")] - x_axis: Option, + x_axis: Option, #[serde(rename = "yaxis")] - y_axis: Option, + y_axis: Option, line: Option, #[serde(rename = "whiskerwidth")] whisker_width: Option, diff --git a/plotly/src/traces/contour.rs b/plotly/src/traces/contour.rs index 359eaf37..3dcce897 100644 --- a/plotly/src/traces/contour.rs +++ b/plotly/src/traces/contour.rs @@ -7,7 +7,7 @@ use crate::{ color::Color, common::{ Calendar, ColorBar, ColorScale, Dim, Font, HoverInfo, Label, LegendGroupTitle, Line, - PlotType, Visible, + PlotType, Visible, XAxisId, YAxisId, }, private, Trace, }; @@ -137,9 +137,9 @@ where #[serde(rename = "hovertemplate")] hover_template: Option>, #[serde(rename = "xaxis")] - x_axis: Option, + x_axis: Option, #[serde(rename = "yaxis")] - y_axis: Option, + y_axis: Option, line: Option, #[serde(rename = "colorbar")] color_bar: Option, @@ -403,8 +403,8 @@ where Box::new(self) } - pub fn x_axis(mut self, axis: &str) -> Box { - self.x_axis = Some(axis.to_string()); + pub fn x_axis(mut self, axis: impl Into) -> Box { + self.x_axis = Some(axis.into()); Box::new(self) } @@ -418,8 +418,8 @@ where Box::new(self) } - pub fn y_axis(mut self, axis: &str) -> Box { - self.y_axis = Some(axis.to_string()); + pub fn y_axis(mut self, axis: impl Into) -> Box { + self.y_axis = Some(axis.into()); Box::new(self) } @@ -657,4 +657,27 @@ mod tests { assert_eq!(to_value(trace).unwrap(), expected); } + + #[test] + fn serialize_contour_axis_ids() { + use crate::common::{XAxisId, YAxisId}; + + let x_axis: XAxisId = "x2".into(); + let y_axis: YAxisId = "y12".into(); + + let trace = Contour::new(vec![0., 1.], vec![2., 3.], vec![4., 5.]) + .x_axis(x_axis) + .y_axis(y_axis); + + let expected = json!({ + "type": "contour", + "x": [0.0, 1.0], + "y": [2.0, 3.0], + "z": [4.0, 5.0], + "xaxis": "x2", + "yaxis": "y12", + }); + + assert_eq!(to_value(trace).unwrap(), expected); + } } diff --git a/plotly/src/traces/heat_map.rs b/plotly/src/traces/heat_map.rs index b5514784..75557620 100644 --- a/plotly/src/traces/heat_map.rs +++ b/plotly/src/traces/heat_map.rs @@ -6,6 +6,7 @@ use serde::Serialize; use crate::{ common::{ Calendar, ColorBar, ColorScale, Dim, HoverInfo, Label, LegendGroupTitle, PlotType, Visible, + XAxisId, YAxisId, }, private::{NumOrString, NumOrStringCollection}, Trace, @@ -106,14 +107,14 @@ where visible: Option, x: Option>, #[serde(rename = "xaxis")] - x_axis: Option, + x_axis: Option, #[serde(rename = "xcalendar")] x_calendar: Option, #[serde(rename = "xgap")] x_gap: Option, y: Option>, #[serde(rename = "yaxis")] - y_axis: Option, + y_axis: Option, #[serde(rename = "ycalendar")] y_calendar: Option, #[serde(rename = "ygap")] diff --git a/plotly/src/traces/histogram.rs b/plotly/src/traces/histogram.rs index e1e8c422..6f5c40e1 100644 --- a/plotly/src/traces/histogram.rs +++ b/plotly/src/traces/histogram.rs @@ -10,7 +10,7 @@ use crate::ndarray::ArrayTraces; use crate::{ common::{ Calendar, Dim, ErrorData, HoverInfo, Label, LegendGroupTitle, Marker, Orientation, - PlotType, Visible, + PlotType, Visible, XAxisId, YAxisId, }, Trace, }; @@ -155,14 +155,14 @@ where visible: Option, x: Option>, #[serde(rename = "xaxis")] - x_axis: Option, + x_axis: Option, #[serde(rename = "xbins")] x_bins: Option, #[serde(rename = "xcalendar")] x_calendar: Option, y: Option>, #[serde(rename = "yaxis")] - y_axis: Option, + y_axis: Option, #[serde(rename = "ybins")] y_bins: Option, #[serde(rename = "ycalendar")] diff --git a/plotly/src/traces/image.rs b/plotly/src/traces/image.rs index 7fb4dd08..8768d281 100644 --- a/plotly/src/traces/image.rs +++ b/plotly/src/traces/image.rs @@ -8,7 +8,7 @@ use plotly_derive::FieldSetter; use serde::Serialize; use crate::color::{Rgb, Rgba}; -use crate::common::{Dim, HoverInfo, Label, LegendGroupTitle, PlotType, Visible}; +use crate::common::{Dim, HoverInfo, Label, LegendGroupTitle, PlotType, Visible, XAxisId, YAxisId}; use crate::private::{NumOrString, NumOrStringCollection}; use crate::Trace; @@ -280,13 +280,13 @@ pub struct Image { /// `Layout::x_axis`. If "x2", the x coordinates /// refer to `Layout::x_axis2`, and so on. #[serde(rename = "xaxis")] - x_axis: Option, + x_axis: Option, /// Sets a reference between this trace's y coordinates and a 2D cartesian y /// axis. If "y" (the default value), the y coordinates refer to /// `Layout::y_axis`. If "y2", the y coordinates /// refer to `Layout::y_axis2`, and so on. #[serde(rename = "yaxis")] - y_axis: Option, + y_axis: Option, /// Color model used to map the numerical color components described in `z` /// into colors. If `source` is specified, this attribute will be set to diff --git a/plotly/src/traces/scatter.rs b/plotly/src/traces/scatter.rs index e96784c3..6f5424bf 100644 --- a/plotly/src/traces/scatter.rs +++ b/plotly/src/traces/scatter.rs @@ -11,7 +11,7 @@ use crate::{ color::Color, common::{ Calendar, Dim, ErrorData, Fill, Font, HoverInfo, HoverOn, Label, LegendGroupTitle, Line, - Marker, Mode, Orientation, PlotType, Position, Visible, + Marker, Mode, Orientation, PlotType, Position, Visible, XAxisId, YAxisId, }, private::{NumOrString, NumOrStringCollection}, Trace, @@ -180,13 +180,13 @@ where /// `Layout::x_axis`. If "x2", the x coordinates /// refer to `Layout::x_axis2`, and so on. #[serde(rename = "xaxis")] - x_axis: Option, + x_axis: Option, /// Sets a reference between this trace's y coordinates and a 2D cartesian y /// axis. If "y" (the default value), the y coordinates refer to /// `Layout::y_axis`. If "y2", the y coordinates /// refer to `Layout::y_axis2`, and so on. #[serde(rename = "yaxis")] - y_axis: Option, + y_axis: Option, /// Only relevant when `stackgroup` is used, and only the first /// `orientation` found in the `stackgroup` will be used - including if /// `visible` is "legendonly" but not if it is `false`. @@ -528,4 +528,26 @@ mod tests { assert_eq!(to_value(trace).unwrap(), expected); } + + #[test] + fn serialize_scatter_axis_ids() { + use crate::common::{XAxisId, YAxisId}; + + let x_axis: XAxisId = "x2".into(); + let y_axis: YAxisId = "y12".into(); + + let trace = Scatter::new(vec![0, 1], vec![2, 3]) + .x_axis(x_axis) + .y_axis(y_axis); + + let expected = json!({ + "type": "scatter", + "x": [0, 1], + "y": [2, 3], + "xaxis": "x2", + "yaxis": "y12", + }); + + assert_eq!(to_value(trace).unwrap(), expected); + } } diff --git a/plotly_derive/src/field_setter.rs b/plotly_derive/src/field_setter.rs index 7f6b6b2b..bcc87554 100644 --- a/plotly_derive/src/field_setter.rs +++ b/plotly_derive/src/field_setter.rs @@ -341,7 +341,13 @@ impl FieldReceiver { quote![value.as_ref().to_owned()], quote![], ), - FieldType::OptionOther(inner_ty) => (quote![#inner_ty], quote![value], quote![]), + FieldType::OptionOther(inner_ty) => { + if matches!(field_ident.to_string().as_str(), "x_axis" | "y_axis") { + (quote![impl Into<#inner_ty>], quote![value.into()], quote![]) + } else { + (quote![#inner_ty], quote![value], quote![]) + } + } FieldType::OptionVecString => ( quote![Vec>], quote![value.into_iter().map(|v| v.as_ref().to_owned()).collect()],