plotly/layout/
mod.rs

1pub mod themes;
2pub mod update_menu;
3
4use std::borrow::Cow;
5
6use plotly_derive::FieldSetter;
7use serde::{Serialize, Serializer};
8use update_menu::UpdateMenu;
9
10use crate::common::Domain;
11use crate::{
12    color::Color,
13    common::{
14        Anchor, AxisSide, Calendar, ColorBar, ColorScale, DashType, ExponentFormat, Font, Label,
15        Orientation, TickFormatStop, TickMode, Title,
16    },
17    private::{NumOrString, NumOrStringCollection},
18};
19
20#[derive(Serialize, Debug, Clone)]
21#[serde(rename_all = "lowercase")]
22pub enum AxisType {
23    #[serde(rename = "-")]
24    Default,
25    Linear,
26    Log,
27    Date,
28    Category,
29    MultiCategory,
30}
31
32#[derive(Serialize, Debug, Clone)]
33#[serde(rename_all = "lowercase")]
34pub enum AxisConstrain {
35    Range,
36    Domain,
37}
38
39#[derive(Serialize, Debug, Clone)]
40#[serde(rename_all = "lowercase")]
41pub enum ConstrainDirection {
42    Left,
43    Center,
44    Right,
45    Top,
46    Middle,
47    Bottom,
48}
49
50#[derive(Serialize, Debug, Clone)]
51#[serde(rename_all = "lowercase")]
52pub enum RangeMode {
53    Normal,
54    ToZero,
55    NonNegative,
56}
57
58#[derive(Serialize, Debug, Clone)]
59#[serde(rename_all = "lowercase")]
60pub enum TicksDirection {
61    Outside,
62    Inside,
63}
64
65#[derive(Serialize, Debug, Clone)]
66#[serde(rename_all = "lowercase")]
67pub enum TicksPosition {
68    Labels,
69    Boundaries,
70}
71
72#[derive(Serialize, Debug, Clone)]
73#[serde(rename_all = "lowercase")]
74pub enum ArrayShow {
75    All,
76    First,
77    Last,
78    None,
79}
80
81#[derive(Serialize, Debug, Clone)]
82#[serde(rename_all = "lowercase")]
83pub enum BarMode {
84    Stack,
85    Group,
86    Overlay,
87    Relative,
88}
89
90#[derive(Serialize, Debug, Clone)]
91#[serde(rename_all = "lowercase")]
92pub enum BarNorm {
93    #[serde(rename = "")]
94    Empty,
95    Fraction,
96    Percent,
97}
98
99#[derive(Serialize, Debug, Clone)]
100#[serde(rename_all = "lowercase")]
101pub enum BoxMode {
102    Group,
103    Overlay,
104}
105
106#[derive(Serialize, Debug, Clone)]
107#[serde(rename_all = "lowercase")]
108pub enum ViolinMode {
109    Group,
110    Overlay,
111}
112
113#[derive(Serialize, Debug, Clone)]
114#[serde(rename_all = "lowercase")]
115pub enum WaterfallMode {
116    Group,
117    Overlay,
118}
119
120#[derive(Serialize, Debug, Clone)]
121#[serde(rename_all = "lowercase")]
122pub enum TraceOrder {
123    Reversed,
124    Grouped,
125    #[serde(rename = "reversed+grouped")]
126    ReversedGrouped,
127    Normal,
128}
129
130#[derive(Serialize, Debug, Clone)]
131#[serde(rename_all = "lowercase")]
132pub enum ItemSizing {
133    Trace,
134    Constant,
135}
136
137#[derive(Debug, Clone)]
138pub enum ItemClick {
139    Toggle,
140    ToggleOthers,
141    False,
142}
143
144impl Serialize for ItemClick {
145    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
146    where
147        S: serde::Serializer,
148    {
149        match *self {
150            Self::Toggle => serializer.serialize_str("toggle"),
151            Self::ToggleOthers => serializer.serialize_str("toggleothers"),
152            Self::False => serializer.serialize_bool(false),
153        }
154    }
155}
156
157#[derive(Serialize, Debug, Clone)]
158#[serde(rename_all = "lowercase")]
159pub enum GroupClick {
160    ToggleItem,
161    ToggleGroup,
162}
163
164#[serde_with::skip_serializing_none]
165#[derive(Serialize, Debug, Clone, FieldSetter)]
166pub struct Legend {
167    #[serde(rename = "bgcolor")]
168    background_color: Option<Box<dyn Color>>,
169    #[serde(rename = "bordercolor")]
170    border_color: Option<Box<dyn Color>>,
171    #[serde(rename = "borderwidth")]
172    border_width: Option<usize>,
173    font: Option<Font>,
174    orientation: Option<Orientation>,
175    #[serde(rename = "traceorder")]
176    trace_order: Option<TraceOrder>,
177    #[serde(rename = "tracegroupgap")]
178    trace_group_gap: Option<usize>,
179    #[serde(rename = "itemsizing")]
180    item_sizing: Option<ItemSizing>,
181    #[serde(rename = "itemclick")]
182    item_click: Option<ItemClick>,
183    #[serde(rename = "itemdoubleclick")]
184    item_double_click: Option<ItemClick>,
185    x: Option<f64>,
186    #[serde(rename = "xanchor")]
187    x_anchor: Option<Anchor>,
188    y: Option<f64>,
189    #[serde(rename = "yanchor")]
190    y_anchor: Option<Anchor>,
191    valign: Option<VAlign>,
192    title: Option<Title>,
193    #[serde(rename = "groupclick")]
194    group_click: Option<GroupClick>,
195    #[serde(rename = "itemwidth")]
196    item_width: Option<usize>,
197}
198
199impl Legend {
200    pub fn new() -> Self {
201        Default::default()
202    }
203}
204
205#[derive(Serialize, Debug, Clone)]
206#[serde(rename_all = "lowercase")]
207pub enum VAlign {
208    Top,
209    Middle,
210    Bottom,
211}
212
213#[derive(Serialize, Debug, Clone)]
214#[serde(rename_all = "lowercase")]
215pub enum HAlign {
216    Left,
217    Center,
218    Right,
219}
220
221#[serde_with::skip_serializing_none]
222#[derive(Serialize, Debug, Clone, FieldSetter)]
223pub struct Margin {
224    #[serde(rename = "l")]
225    left: Option<usize>,
226    #[serde(rename = "r")]
227    right: Option<usize>,
228    #[serde(rename = "t")]
229    top: Option<usize>,
230    #[serde(rename = "b")]
231    bottom: Option<usize>,
232    pad: Option<usize>,
233    #[serde(rename = "autoexpand")]
234    auto_expand: Option<bool>,
235}
236
237impl Margin {
238    pub fn new() -> Self {
239        Default::default()
240    }
241}
242
243#[serde_with::skip_serializing_none]
244#[derive(Serialize, Debug, Clone, FieldSetter)]
245pub struct LayoutColorScale {
246    sequential: Option<ColorScale>,
247    #[serde(rename = "sequentialminus")]
248    sequential_minus: Option<ColorScale>,
249    diverging: Option<ColorScale>,
250}
251
252impl LayoutColorScale {
253    pub fn new() -> Self {
254        Default::default()
255    }
256}
257
258#[derive(Serialize, Debug, Clone)]
259#[serde(rename_all = "lowercase")]
260pub enum SliderRangeMode {
261    Auto,
262    Fixed,
263    Match,
264}
265
266#[serde_with::skip_serializing_none]
267#[derive(Serialize, Debug, Clone, FieldSetter)]
268pub struct RangeSliderYAxis {
269    #[serde(rename = "rangemode")]
270    range_mode: Option<SliderRangeMode>,
271    range: Option<NumOrStringCollection>,
272}
273
274impl RangeSliderYAxis {
275    pub fn new() -> Self {
276        Default::default()
277    }
278}
279
280#[serde_with::skip_serializing_none]
281#[derive(Serialize, Debug, Clone, FieldSetter)]
282pub struct RangeSlider {
283    #[serde(rename = "bgcolor")]
284    background_color: Option<Box<dyn Color>>,
285    #[serde(rename = "bordercolor")]
286    border_color: Option<Box<dyn Color>>,
287    #[serde(rename = "borderwidth")]
288    border_width: Option<u64>,
289    #[serde(rename = "autorange")]
290    auto_range: Option<bool>,
291    range: Option<NumOrStringCollection>,
292    thickness: Option<f64>,
293    visible: Option<bool>,
294    #[serde(rename = "yaxis")]
295    y_axis: Option<RangeSliderYAxis>,
296}
297
298impl RangeSlider {
299    pub fn new() -> Self {
300        Default::default()
301    }
302}
303
304#[derive(Serialize, Debug, Clone)]
305#[serde(rename_all = "lowercase")]
306pub enum SelectorStep {
307    Month,
308    Year,
309    Day,
310    Hour,
311    Minute,
312    Second,
313    All,
314}
315
316#[derive(Serialize, Debug, Clone)]
317#[serde(rename_all = "lowercase")]
318pub enum StepMode {
319    Backward,
320    ToDate,
321}
322
323#[serde_with::skip_serializing_none]
324#[derive(Serialize, Debug, Clone, FieldSetter)]
325pub struct SelectorButton {
326    visible: Option<bool>,
327    step: Option<SelectorStep>,
328    #[serde(rename = "stepmode")]
329    step_mode: Option<StepMode>,
330    count: Option<usize>,
331    label: Option<String>,
332    name: Option<String>,
333    #[serde(rename = "templateitemname")]
334    template_item_name: Option<String>,
335}
336
337impl SelectorButton {
338    pub fn new() -> Self {
339        Default::default()
340    }
341}
342
343#[serde_with::skip_serializing_none]
344#[derive(Serialize, Debug, Clone, FieldSetter)]
345pub struct RangeSelector {
346    visible: Option<bool>,
347    buttons: Option<Vec<SelectorButton>>,
348    x: Option<f64>,
349    #[serde(rename = "xanchor")]
350    x_anchor: Option<Anchor>,
351    y: Option<f64>,
352    #[serde(rename = "yanchor")]
353    y_anchor: Option<Anchor>,
354    font: Option<Font>,
355    #[serde(rename = "bgcolor")]
356    background_color: Option<Box<dyn Color>>,
357    #[serde(rename = "activecolor")]
358    active_color: Option<Box<dyn Color>>,
359    #[serde(rename = "bordercolor")]
360    border_color: Option<Box<dyn Color>>,
361    #[serde(rename = "borderwidth")]
362    border_width: Option<usize>,
363}
364
365impl RangeSelector {
366    pub fn new() -> Self {
367        Default::default()
368    }
369}
370
371#[serde_with::skip_serializing_none]
372#[derive(Serialize, Debug, Clone, FieldSetter)]
373pub struct ColorAxis {
374    cauto: Option<bool>,
375    cmin: Option<f64>,
376    cmax: Option<f64>,
377    cmid: Option<f64>,
378    #[serde(rename = "colorscale")]
379    color_scale: Option<ColorScale>,
380    #[serde(rename = "autocolorscale")]
381    auto_color_scale: Option<bool>,
382    #[serde(rename = "reversescale")]
383    reverse_scale: Option<bool>,
384    #[serde(rename = "showscale")]
385    show_scale: Option<bool>,
386    #[serde(rename = "colorbar")]
387    color_bar: Option<ColorBar>,
388}
389
390impl ColorAxis {
391    pub fn new() -> Self {
392        Default::default()
393    }
394}
395
396#[derive(Serialize, Debug, Clone)]
397#[serde(rename_all = "lowercase")]
398pub enum SpikeMode {
399    ToAxis,
400    Across,
401    Marker,
402    #[serde(rename = "toaxis+across")]
403    ToaxisAcross,
404    #[serde(rename = "toaxis+marker")]
405    ToAxisMarker,
406    #[serde(rename = "across+marker")]
407    AcrossMarker,
408    #[serde(rename = "toaxis+across+marker")]
409    ToaxisAcrossMarker,
410}
411
412#[derive(Serialize, Debug, Clone)]
413#[serde(rename_all = "lowercase")]
414pub enum SpikeSnap {
415    Data,
416    Cursor,
417    #[serde(rename = "hovered data")]
418    HoveredData,
419}
420
421#[derive(Serialize, Debug, Clone)]
422pub enum CategoryOrder {
423    #[serde(rename = "trace")]
424    Trace,
425    #[serde(rename = "category ascending")]
426    CategoryAscending,
427    #[serde(rename = "category descending")]
428    CategoryDescending,
429    #[serde(rename = "array")]
430    Array,
431    #[serde(rename = "total ascending")]
432    TotalAscending,
433    #[serde(rename = "total descending")]
434    TotalDescending,
435    #[serde(rename = "min ascending")]
436    MinAscending,
437    #[serde(rename = "min descending")]
438    MinDescending,
439    #[serde(rename = "max ascending")]
440    MaxAscending,
441    #[serde(rename = "max descending")]
442    MaxDescending,
443    #[serde(rename = "sum ascending")]
444    SumAscending,
445    #[serde(rename = "sum descending")]
446    SumDescending,
447    #[serde(rename = "mean ascending")]
448    MeanAscending,
449    #[serde(rename = "mean descending")]
450    MeanDescending,
451    #[serde(rename = "geometric mean ascending")]
452    GeometricMeanAscending,
453    #[serde(rename = "geometric mean descending")]
454    GeometricMeanDescending,
455    #[serde(rename = "median ascending")]
456    MedianAscending,
457    #[serde(rename = "median descending")]
458    MedianDescending,
459}
460
461#[serde_with::skip_serializing_none]
462#[derive(Serialize, Debug, Clone, FieldSetter)]
463pub struct Axis {
464    visible: Option<bool>,
465    /// Sets the order in which categories on this axis appear. Only has an
466    /// effect if `category_order` is set to [`CategoryOrder::Array`].
467    /// Used with `category_order`.
468    #[serde(rename = "categoryarray")]
469    category_array: Option<NumOrStringCollection>,
470    /// Specifies the ordering logic for the case of categorical variables.
471    /// By default, plotly uses [`CategoryOrder::Trace`], which specifies
472    /// the order that is present in the data supplied. Set `category_order` to
473    /// [`CategoryOrder::CategoryAscending`] or
474    /// [`CategoryOrder::CategoryDescending`] if order should be determined
475    /// by the alphanumerical order of the category names. Set `category_order`
476    /// to [`CategoryOrder::Array`] to derive the ordering from the attribute
477    /// `category_array`. If a category is not found in the `category_array`
478    /// array, the sorting behavior for that attribute will be identical to the
479    /// [`CategoryOrder::Trace`] mode. The unspecified categories will follow
480    /// the categories in `category_array`. Set `category_order` to
481    /// [`CategoryOrder::TotalAscending`] or
482    /// [`CategoryOrder::TotalDescending`] if order should be determined by the
483    /// numerical order of the values. Similarly, the order can be determined
484    /// by the min, max, sum, mean, geometric mean or median of all the values.
485    #[serde(rename = "categoryorder")]
486    category_order: Option<CategoryOrder>,
487    color: Option<Box<dyn Color>>,
488    title: Option<Title>,
489    #[field_setter(skip)]
490    r#type: Option<AxisType>,
491    #[serde(rename = "autorange")]
492    auto_range: Option<bool>,
493    #[serde(rename = "rangemode")]
494    range_mode: Option<RangeMode>,
495    range: Option<NumOrStringCollection>,
496    #[serde(rename = "fixedrange")]
497    fixed_range: Option<bool>,
498    constrain: Option<AxisConstrain>,
499    #[serde(rename = "constraintoward")]
500    constrain_toward: Option<ConstrainDirection>,
501    #[serde(rename = "tickmode")]
502    tick_mode: Option<TickMode>,
503    #[serde(rename = "nticks")]
504    n_ticks: Option<usize>,
505
506    #[serde(rename = "scaleanchor")]
507    scale_anchor: Option<String>,
508
509    tick0: Option<f64>,
510    dtick: Option<f64>,
511
512    #[field_setter(skip)]
513    matches: Option<String>,
514
515    #[serde(rename = "tickvals")]
516    tick_values: Option<Vec<f64>>,
517    #[serde(rename = "ticktext")]
518    tick_text: Option<Vec<String>>,
519    ticks: Option<TicksDirection>,
520    #[serde(rename = "tickson")]
521    ticks_on: Option<TicksPosition>,
522    mirror: Option<bool>,
523    #[serde(rename = "ticklen")]
524    tick_length: Option<usize>,
525    #[serde(rename = "tickwidth")]
526    tick_width: Option<usize>,
527    #[serde(rename = "tickcolor")]
528    tick_color: Option<Box<dyn Color>>,
529    #[serde(rename = "showticklabels")]
530    show_tick_labels: Option<bool>,
531    #[serde(rename = "automargin")]
532    auto_margin: Option<bool>,
533    #[serde(rename = "showspikes")]
534    show_spikes: Option<bool>,
535    #[serde(rename = "spikecolor")]
536    spike_color: Option<Box<dyn Color>>,
537    #[serde(rename = "spikethickness")]
538    spike_thickness: Option<usize>,
539    #[serde(rename = "spikedash")]
540    spike_dash: Option<DashType>,
541    #[serde(rename = "spikemode")]
542    spike_mode: Option<SpikeMode>,
543    #[serde(rename = "spikesnap")]
544    spike_snap: Option<SpikeSnap>,
545    #[serde(rename = "tickfont")]
546    tick_font: Option<Font>,
547    #[serde(rename = "tickangle")]
548    tick_angle: Option<f64>,
549    #[serde(rename = "tickprefix")]
550    tick_prefix: Option<String>,
551    #[serde(rename = "showtickprefix")]
552    show_tick_prefix: Option<ArrayShow>,
553    #[serde(rename = "ticksuffix")]
554    tick_suffix: Option<String>,
555    #[serde(rename = "showticksuffix")]
556    show_tick_suffix: Option<ArrayShow>,
557    #[serde(rename = "showexponent")]
558    show_exponent: Option<ArrayShow>,
559    #[serde(rename = "exponentformat")]
560    exponent_format: Option<ExponentFormat>,
561    #[serde(rename = "separatethousands")]
562    separate_thousands: Option<bool>,
563    #[serde(rename = "tickformat")]
564    tick_format: Option<String>,
565    #[serde(rename = "tickformatstops")]
566    tick_format_stops: Option<Vec<TickFormatStop>>,
567    #[serde(rename = "hoverformat")]
568    hover_format: Option<String>,
569    #[serde(rename = "showline")]
570    show_line: Option<bool>,
571    #[serde(rename = "linecolor")]
572    line_color: Option<Box<dyn Color>>,
573    #[serde(rename = "linewidth")]
574    line_width: Option<usize>,
575    #[serde(rename = "showgrid")]
576    show_grid: Option<bool>,
577    #[serde(rename = "gridcolor")]
578    grid_color: Option<Box<dyn Color>>,
579    #[serde(rename = "gridwidth")]
580    grid_width: Option<usize>,
581    #[serde(rename = "zeroline")]
582    zero_line: Option<bool>,
583    #[serde(rename = "zerolinecolor")]
584    zero_line_color: Option<Box<dyn Color>>,
585    #[serde(rename = "zerolinewidth")]
586    zero_line_width: Option<usize>,
587    #[serde(rename = "showdividers")]
588    show_dividers: Option<bool>,
589    #[serde(rename = "dividercolor")]
590    divider_color: Option<Box<dyn Color>>,
591    #[serde(rename = "dividerwidth")]
592    divider_width: Option<usize>,
593    anchor: Option<String>,
594    side: Option<AxisSide>,
595    overlaying: Option<String>,
596    #[field_setter(skip)]
597    domain: Option<Vec<f64>>,
598    position: Option<f64>,
599    #[serde(rename = "rangeslider")]
600    range_slider: Option<RangeSlider>,
601    #[serde(rename = "rangeselector")]
602    range_selector: Option<RangeSelector>,
603    calendar: Option<Calendar>,
604}
605
606impl Axis {
607    pub fn new() -> Self {
608        Default::default()
609    }
610
611    pub fn matches(mut self, matches: &str) -> Self {
612        self.matches = Some(matches.to_string());
613        self
614    }
615
616    pub fn type_(mut self, t: AxisType) -> Self {
617        self.r#type = Some(t);
618        self
619    }
620
621    pub fn domain(mut self, domain: &[f64]) -> Self {
622        self.domain = Some(domain.to_vec());
623        self
624    }
625}
626
627#[derive(Serialize, Debug, Clone)]
628pub enum RowOrder {
629    #[serde(rename = "top to bottom")]
630    TopToBottom,
631    #[serde(rename = "bottom to top")]
632    BottomToTop,
633}
634
635#[derive(Serialize, Debug, Clone)]
636#[serde(rename_all = "lowercase")]
637pub enum GridPattern {
638    Independent,
639    Coupled,
640}
641
642#[derive(Serialize, Debug, Clone)]
643#[serde(rename_all = "lowercase")]
644pub enum GridXSide {
645    Bottom,
646    #[serde(rename = "bottom plot")]
647    BottomPlot,
648    #[serde(rename = "top plot")]
649    TopPlot,
650    Top,
651}
652
653#[derive(Serialize, Debug, Clone)]
654#[serde(rename_all = "lowercase")]
655pub enum GridYSide {
656    Left,
657    #[serde(rename = "left plot")]
658    LeftPlot,
659    #[serde(rename = "right plot")]
660    RightPlot,
661    Right,
662}
663
664#[serde_with::skip_serializing_none]
665#[derive(Serialize, Debug, Clone, FieldSetter)]
666pub struct GridDomain {
667    x: Option<Vec<f64>>,
668    y: Option<Vec<f64>>,
669}
670
671impl GridDomain {
672    pub fn new() -> Self {
673        Default::default()
674    }
675}
676
677#[serde_with::skip_serializing_none]
678#[derive(Serialize, Debug, Clone, FieldSetter)]
679pub struct LayoutGrid {
680    rows: Option<usize>,
681    #[serde(rename = "roworder")]
682    row_order: Option<RowOrder>,
683    columns: Option<usize>,
684    #[serde(rename = "subplots")]
685    sub_plots: Option<Vec<String>>,
686    #[serde(rename = "xaxes")]
687    x_axes: Option<Vec<String>>,
688    #[serde(rename = "yaxes")]
689    y_axes: Option<Vec<String>>,
690    pattern: Option<GridPattern>,
691    #[serde(rename = "xgap")]
692    x_gap: Option<f64>,
693    #[serde(rename = "ygap")]
694    y_gap: Option<f64>,
695    domain: Option<GridDomain>,
696    #[serde(rename = "xside")]
697    x_side: Option<GridXSide>,
698    #[serde(rename = "yside")]
699    y_side: Option<GridYSide>,
700}
701
702impl LayoutGrid {
703    pub fn new() -> Self {
704        Default::default()
705    }
706}
707
708#[derive(Debug, Clone)]
709pub enum UniformTextMode {
710    False,
711    Hide,
712    Show,
713}
714
715impl Serialize for UniformTextMode {
716    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
717    where
718        S: Serializer,
719    {
720        match *self {
721            Self::False => serializer.serialize_bool(false),
722            Self::Hide => serializer.serialize_str("hide"),
723            Self::Show => serializer.serialize_str("show"),
724        }
725    }
726}
727
728#[serde_with::skip_serializing_none]
729#[derive(Serialize, Debug, Clone, FieldSetter)]
730pub struct UniformText {
731    mode: Option<UniformTextMode>,
732    #[serde(rename = "minsize")]
733    min_size: Option<usize>,
734}
735
736impl UniformText {
737    pub fn new() -> Self {
738        Default::default()
739    }
740}
741
742#[derive(Debug, Clone)]
743pub enum HoverMode {
744    X,
745    Y,
746    Closest,
747    False,
748    XUnified,
749    YUnified,
750}
751
752impl Serialize for HoverMode {
753    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
754    where
755        S: Serializer,
756    {
757        match *self {
758            Self::X => serializer.serialize_str("x"),
759            Self::Y => serializer.serialize_str("y"),
760            Self::Closest => serializer.serialize_str("closest"),
761            Self::False => serializer.serialize_bool(false),
762            Self::XUnified => serializer.serialize_str("x unified"),
763            Self::YUnified => serializer.serialize_str("y unified"),
764        }
765    }
766}
767
768#[serde_with::skip_serializing_none]
769#[derive(Serialize, Debug, Clone, FieldSetter)]
770pub struct ModeBar {
771    orientation: Option<Orientation>,
772    #[serde(rename = "bgcolor")]
773    background_color: Option<Box<dyn Color>>,
774    color: Option<Box<dyn Color>>,
775    #[serde(rename = "activecolor")]
776    active_color: Option<Box<dyn Color>>,
777}
778
779impl ModeBar {
780    pub fn new() -> Self {
781        Default::default()
782    }
783}
784
785#[derive(Serialize, Debug, Clone)]
786#[serde(rename_all = "lowercase")]
787pub enum ShapeType {
788    Circle,
789    Rect,
790    Path,
791    Line,
792}
793
794#[derive(Serialize, Debug, Clone)]
795#[serde(rename_all = "lowercase")]
796pub enum ShapeLayer {
797    Below,
798    Above,
799}
800
801#[derive(Serialize, Debug, Clone)]
802#[serde(rename_all = "lowercase")]
803pub enum ShapeSizeMode {
804    Scaled,
805    Pixel,
806}
807
808#[derive(Serialize, Debug, Clone)]
809#[serde(rename_all = "lowercase")]
810pub enum FillRule {
811    EvenOdd,
812    NonZero,
813}
814
815#[serde_with::skip_serializing_none]
816#[derive(Serialize, Debug, Clone, FieldSetter)]
817pub struct ShapeLine {
818    /// Sets the line color.
819    color: Option<Box<dyn Color>>,
820    /// Sets the line width (in px).
821    width: Option<f64>,
822    /// Sets the dash style of lines. Set to a dash type string ("solid", "dot",
823    /// "dash", "longdash", "dashdot", or "longdashdot") or a dash length
824    /// list in px (eg "5px,10px,2px,2px").
825    dash: Option<DashType>,
826}
827
828impl ShapeLine {
829    pub fn new() -> Self {
830        Default::default()
831    }
832}
833
834#[serde_with::skip_serializing_none]
835#[derive(Serialize, Debug, Clone, FieldSetter)]
836pub struct Shape {
837    /// Determines whether or not this shape is visible.
838    visible: Option<bool>,
839    #[field_setter(skip)]
840    r#type: Option<ShapeType>,
841    /// Specifies whether shapes are drawn below or above traces.
842    layer: Option<ShapeLayer>,
843    /// Sets the shape's x coordinate axis. If set to an x axis id (e.g. "x" or
844    /// "x2"), the `x` position refers to an x coordinate. If set to
845    /// "paper", the `x` position refers to the distance from the left side
846    /// of the plotting area in normalized coordinates where "0" ("1")
847    /// corresponds to the left (right) side. If the axis `type` is "log", then
848    /// you must take the log of your desired range. If the axis `type` is
849    /// "date", then you must convert the date to unix time in milliseconds.
850    #[serde(rename = "xref")]
851    x_ref: Option<String>,
852    /// Sets the shapes's sizing mode along the x axis. If set to "scaled",
853    /// `x0`, `x1` and x coordinates within `path` refer to data values on
854    /// the x axis or a fraction of the plot area's width (`xref` set to
855    /// "paper"). If set to "pixel", `xanchor` specifies the x position
856    /// in terms of data or plot fraction but `x0`, `x1` and x coordinates
857    /// within `path` are pixels relative to `xanchor`. This way, the shape
858    /// can have a fixed width while maintaining a position relative to data
859    /// or plot fraction.
860    #[serde(rename = "xsizemode")]
861    x_size_mode: Option<ShapeSizeMode>,
862    /// Only relevant in conjunction with `xsizemode` set to "pixel". Specifies
863    /// the anchor point on the x axis to which `x0`, `x1` and x coordinates
864    /// within `path` are relative to. E.g. useful to attach a pixel sized
865    /// shape to a certain data value. No effect when `xsizemode` not set to
866    /// "pixel".
867    #[serde(rename = "xanchor")]
868    x_anchor: Option<NumOrString>,
869    /// Sets the shape's starting x position. See `type` and `xsizemode` for
870    /// more info.
871    x0: Option<NumOrString>,
872    /// Sets the shape's end x position. See `type` and `xsizemode` for more
873    /// info.
874    x1: Option<NumOrString>,
875    /// Sets the annotation's y coordinate axis. If set to an y axis id (e.g.
876    /// "y" or "y2"), the `y` position refers to an y coordinate If set to
877    /// "paper", the `y` position refers to the distance from the bottom of
878    /// the plotting area in normalized coordinates where "0" ("1")
879    /// corresponds to the bottom (top).
880    #[serde(rename = "yref")]
881    y_ref: Option<String>,
882    /// Sets the shapes's sizing mode along the y axis. If set to "scaled",
883    /// `y0`, `y1` and y coordinates within `path` refer to data values on
884    /// the y axis or a fraction of the plot area's height (`yref` set to
885    /// "paper"). If set to "pixel", `yanchor` specifies the y position
886    /// in terms of data or plot fraction but `y0`, `y1` and y coordinates
887    /// within `path` are pixels relative to `yanchor`. This way, the shape
888    /// can have a fixed height while maintaining a position relative to
889    /// data or plot fraction.
890    #[serde(rename = "ysizemode")]
891    y_size_mode: Option<ShapeSizeMode>,
892    /// Only relevant in conjunction with `ysizemode` set to "pixel". Specifies
893    /// the anchor point on the y axis to which `y0`, `y1` and y coordinates
894    /// within `path` are relative to. E.g. useful to attach a pixel sized
895    /// shape to a certain data value. No effect when `ysizemode` not set to
896    /// "pixel".
897    #[serde(rename = "yanchor")]
898    y_anchor: Option<NumOrString>,
899    /// Sets the shape's starting y position. See `type` and `ysizemode` for
900    /// more info.
901    y0: Option<NumOrString>,
902    /// Sets the shape's end y position. See `type` and `ysizemode` for more
903    /// info.
904    y1: Option<NumOrString>,
905    /// For `type` "path" - a valid SVG path with the pixel values replaced by
906    /// data values in `xsizemode`/`ysizemode` being "scaled" and taken
907    /// unmodified as pixels relative to `xanchor` and `yanchor` in case of
908    /// "pixel" size mode. There are a few restrictions / quirks
909    /// only absolute instructions, not relative. So the allowed segments
910    /// are: M, L, H, V, Q, C, T, S, and Z arcs (A) are not allowed because
911    /// radius rx and ry are relative. In the future we could consider
912    /// supporting relative commands, but we would have to decide on how to
913    /// handle date and log axes. Note that even as is, Q and C Bezier paths
914    /// that are smooth on linear axes may not be smooth on log, and vice versa.
915    /// no chained "polybezier" commands - specify the segment type for each
916    /// one. On category axes, values are numbers scaled to the serial
917    /// numbers of categories because using the categories themselves
918    /// there would be no way to describe fractional positions On data axes:
919    /// because space and T are both normal components of path strings, we
920    /// can't use either to separate date from time parts. Therefore we'll
921    /// use underscore for this purpose: 2015-02-21_13:45:56.789
922    path: Option<String>,
923    /// Sets the opacity of the shape. Number between or equal to 0 and 1.
924    opacity: Option<f64>,
925    /// Sets the shape line properties (`color`, `width`, `dash`).
926    line: Option<ShapeLine>,
927    /// Sets the color filling the shape's interior. Only applies to closed
928    /// shapes.
929    #[serde(rename = "fillcolor")]
930    fill_color: Option<Box<dyn Color>>,
931    /// Determines which regions of complex paths constitute the interior. For
932    /// more info please visit <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule>
933    #[serde(rename = "fillrule")]
934    fill_rule: Option<FillRule>,
935    /// Determines whether the shape could be activated for edit or not. Has no
936    /// effect when the older editable shapes mode is enabled via
937    /// `config.editable` or `config.edits.shapePosition`.
938    editable: Option<bool>,
939    /// When used in a template, named items are created in the output figure in
940    /// addition to any items the figure already has in this array. You can
941    /// modify these items in the output figure by making your own item with
942    /// `templateitemname` matching this `name` alongside your modifications
943    /// (including `visible: false` or `enabled: false` to hide it). Has no
944    /// effect outside of a template.
945    name: Option<String>,
946    /// Used to refer to a named item in this array in the template. Named items
947    /// from the template will be created even without a matching item in
948    /// the input figure, but you can modify one by making an item with
949    /// `templateitemname` matching its `name`, alongside your modifications
950    /// (including `visible: false` or `enabled: false` to hide it). If there is
951    /// no template or no matching item, this item will be hidden unless you
952    /// explicitly show it with `visible: true`.
953    #[serde(rename = "templateitemname")]
954    template_item_name: Option<String>,
955}
956
957impl Shape {
958    pub fn new() -> Self {
959        Default::default()
960    }
961
962    /// Specifies the shape type to be drawn. If "line", a line is drawn from
963    /// (`x0`,`y0`) to (`x1`,`y1`) with respect to the axes' sizing mode. If
964    /// "circle", a circle is drawn from ((`x0`+`x1`)/2, (`y0`+`y1`)/2))
965    /// with radius (|(`x0`+`x1`)/2 - `x0`|, |(`y0`+`y1`)/2 -`y0`)|)
966    /// with respect to the axes' sizing mode. If "rect", a rectangle is drawn
967    /// linking (`x0`,`y0`), (`x1`,`y0`), (`x1`,`y1`), (`x0`,`y1`),
968    /// (`x0`,`y0`) with respect to the axes' sizing mode. If "path", draw a
969    /// custom SVG path using `path`. with respect to the axes' sizing mode.
970    pub fn shape_type(mut self, shape_type: ShapeType) -> Self {
971        self.r#type = Some(shape_type);
972        self
973    }
974}
975
976#[derive(Serialize, Debug, Clone)]
977#[serde(rename_all = "lowercase")]
978pub enum DrawDirection {
979    Ortho,
980    Horizontal,
981    Vertical,
982    Diagonal,
983}
984
985#[serde_with::skip_serializing_none]
986#[derive(Serialize, Debug, Clone, FieldSetter)]
987pub struct NewShape {
988    /// Sets the shape line properties (`color`, `width`, `dash`).
989    line: Option<ShapeLine>,
990    /// Sets the color filling new shapes' interior. Please note that if using a
991    /// fillcolor with alpha greater than half, drag inside the active shape
992    /// starts moving the shape underneath, otherwise a new shape could be
993    /// started over.
994    #[serde(rename = "fillcolor")]
995    fill_color: Option<Box<dyn Color>>,
996    /// Determines the path's interior. For more info please
997    /// visit <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule>
998    #[serde(rename = "fillrule")]
999    fill_rule: Option<FillRule>,
1000    /// Sets the opacity of new shapes. Number between or equal to 0 and 1.
1001    opacity: Option<f64>,
1002    /// Specifies whether new shapes are drawn below or above traces.
1003    layer: Option<ShapeLayer>,
1004    /// When `dragmode` is set to "drawrect", "drawline" or "drawcircle" this
1005    /// limits the drag to be horizontal, vertical or diagonal. Using
1006    /// "diagonal" there is no limit e.g. in drawing lines in any direction.
1007    /// "ortho" limits the draw to be either horizontal or vertical.
1008    /// "horizontal" allows horizontal extend. "vertical" allows vertical
1009    /// extend.
1010    #[serde(rename = "drawdirection")]
1011    draw_direction: Option<DrawDirection>,
1012}
1013
1014impl NewShape {
1015    pub fn new() -> Self {
1016        Default::default()
1017    }
1018}
1019
1020#[serde_with::skip_serializing_none]
1021#[derive(Serialize, Debug, Clone, FieldSetter)]
1022pub struct ActiveShape {
1023    /// Sets the color filling the active shape' interior.
1024    #[serde(rename = "fillcolor")]
1025    fill_color: Option<Box<dyn Color>>,
1026    /// Sets the opacity of the active shape. Number between or equal to 0 and
1027    /// 1.
1028    opacity: Option<f64>,
1029}
1030
1031impl ActiveShape {
1032    pub fn new() -> Self {
1033        Default::default()
1034    }
1035}
1036
1037#[derive(Serialize, Debug, Clone)]
1038#[serde(rename_all = "lowercase")]
1039pub enum ArrowSide {
1040    End,
1041    Start,
1042    #[serde(rename = "end+start")]
1043    StartEnd,
1044    None,
1045}
1046
1047#[derive(Debug, Clone)]
1048pub enum ClickToShow {
1049    False,
1050    OnOff,
1051    OnOut,
1052}
1053
1054impl Serialize for ClickToShow {
1055    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1056    where
1057        S: Serializer,
1058    {
1059        match *self {
1060            Self::False => serializer.serialize_bool(false),
1061            Self::OnOff => serializer.serialize_str("onoff"),
1062            Self::OnOut => serializer.serialize_str("onout"),
1063        }
1064    }
1065}
1066
1067#[serde_with::skip_serializing_none]
1068#[derive(Serialize, Debug, Clone, FieldSetter)]
1069pub struct Annotation {
1070    /// Determines whether or not this annotation is visible.
1071    visible: Option<bool>,
1072    /// Sets the text associated with this annotation. Plotly uses a subset of
1073    /// HTML tags to do things like newline (<br>), bold (<b></b>), italics
1074    /// (<i></i>), hyperlinks (<a href='...'></a>). Tags <em></em>, <sup></sup>,
1075    /// <sub></sub> <span></span> are also supported.
1076    text: Option<String>,
1077    /// Sets the angle at which the `text` is drawn with respect to the
1078    /// horizontal.
1079    #[serde(rename = "textangle")]
1080    text_angle: Option<f64>,
1081    /// Sets the annotation text font.
1082    font: Option<Font>,
1083    /// Sets an explicit width for the text box. null (default) lets the text
1084    /// set the box width. Wider text will be clipped. There is no automatic
1085    /// wrapping; use <br> to start a new line.
1086    width: Option<f64>,
1087    /// Sets an explicit height for the text box. null (default) lets the text
1088    /// set the box height. Taller text will be clipped.
1089    height: Option<f64>,
1090    /// Sets the opacity of the annotation (text + arrow).
1091    opacity: Option<f64>,
1092    /// Sets the horizontal alignment of the `text` within the box. Has an
1093    /// effect only if `text` spans two or more lines (i.e. `text` contains
1094    /// one or more <br> HTML tags) or if an explicit width is set to
1095    /// override the text width.
1096    align: Option<HAlign>,
1097    /// Sets the vertical alignment of the `text` within the box. Has an effect
1098    /// only if an explicit height is set to override the text height.
1099    valign: Option<VAlign>,
1100    /// Sets the background color of the annotation.
1101    #[serde(rename = "bgcolor")]
1102    background_color: Option<Box<dyn Color>>,
1103    /// Sets the color of the border enclosing the annotation `text`.
1104    #[serde(rename = "bordercolor")]
1105    border_color: Option<Box<dyn Color>>,
1106    /// Sets the padding (in px) between the `text` and the enclosing border.
1107    #[serde(rename = "borderpad")]
1108    border_pad: Option<f64>,
1109    /// Sets the width (in px) of the border enclosing the annotation `text`.
1110    #[serde(rename = "borderwidth")]
1111    border_width: Option<f64>,
1112    /// Determines whether or not the annotation is drawn with an arrow. If
1113    /// "True", `text` is placed near the arrow's tail. If "False", `text`
1114    /// lines up with the `x` and `y` provided.
1115    #[serde(rename = "showarrow")]
1116    show_arrow: Option<bool>,
1117    /// Sets the color of the annotation arrow.
1118    #[serde(rename = "arrowcolor")]
1119    arrow_color: Option<Box<dyn Color>>,
1120    /// Sets the end annotation arrow head style. Integer between or equal to 0
1121    /// and 8.
1122    #[serde(rename = "arrowhead")]
1123    arrow_head: Option<u8>,
1124    /// Sets the start annotation arrow head style. Integer between or equal to
1125    /// 0 and 8.
1126    #[serde(rename = "startarrowhead")]
1127    start_arrow_head: Option<u8>,
1128    /// Sets the annotation arrow head position.
1129    #[serde(rename = "arrowside")]
1130    arrow_side: Option<ArrowSide>,
1131    /// Sets the size of the end annotation arrow head, relative to
1132    /// `arrowwidth`. A value of 1 (default) gives a head about 3x as wide
1133    /// as the line.
1134    #[serde(rename = "arrowsize")]
1135    arrow_size: Option<f64>,
1136    /// Sets the size of the start annotation arrow head, relative to
1137    /// `arrowwidth`. A value of 1 (default) gives a head about 3x as wide
1138    /// as the line.
1139    #[serde(rename = "startarrowsize")]
1140    start_arrow_size: Option<f64>,
1141    /// Sets the width (in px) of annotation arrow line.
1142    #[serde(rename = "arrowwidth")]
1143    arrow_width: Option<f64>,
1144    /// Sets a distance, in pixels, to move the end arrowhead away from the
1145    /// position it is pointing at, for example to point at the edge of a
1146    /// marker independent of zoom. Note that this shortens the arrow from
1147    /// the `ax` / `ay` vector, in contrast to `xshift` / `yshift` which
1148    /// moves everything by this amount.
1149    #[serde(rename = "standoff")]
1150    stand_off: Option<f64>,
1151    /// Sets a distance, in pixels, to move the start arrowhead away from the
1152    /// position it is pointing at, for example to point at the edge of a
1153    /// marker independent of zoom. Note that this shortens the arrow from
1154    /// the `ax` / `ay` vector, in contrast to `xshift` / `yshift`
1155    /// which moves everything by this amount.
1156    #[serde(rename = "startstandoff")]
1157    start_stand_off: Option<f64>,
1158    /// Sets the x component of the arrow tail about the arrow head. If `axref`
1159    /// is `pixel`, a positive (negative) component corresponds to an arrow
1160    /// pointing from right to left (left to right). If `axref` is an axis,
1161    /// this is an absolute value on that axis, like `x`, NOT a
1162    /// relative value.
1163    ax: Option<NumOrString>,
1164    /// Sets the y component of the arrow tail about the arrow head. If `ayref`
1165    /// is `pixel`, a positive (negative) component corresponds to an arrow
1166    /// pointing from bottom to top (top to bottom). If `ayref` is an axis,
1167    /// this is an absolute value on that axis, like `y`, NOT a
1168    /// relative value.
1169    ay: Option<NumOrString>,
1170    /// Indicates in what terms the tail of the annotation (ax,ay) is specified.
1171    /// If `pixel`, `ax` is a relative offset in pixels from `x`. If set to
1172    /// an x axis id (e.g. "x" or "x2"), `ax` is specified in the same terms
1173    /// as that axis. This is useful for trendline annotations which
1174    /// should continue to indicate the correct trend when zoomed.
1175    #[serde(rename = "axref")]
1176    ax_ref: Option<String>,
1177    /// Indicates in what terms the tail of the annotation (ax,ay) is specified.
1178    /// If `pixel`, `ay` is a relative offset in pixels from `y`. If set to
1179    /// a y axis id (e.g. "y" or "y2"), `ay` is specified in the same terms
1180    /// as that axis. This is useful for trendline annotations which
1181    /// should continue to indicate the correct trend when zoomed.
1182    #[serde(rename = "ayref")]
1183    ay_ref: Option<String>,
1184    /// Sets the annotation's x coordinate axis. If set to an x axis id (e.g.
1185    /// "x" or "x2"), the `x` position refers to an x coordinate If set to
1186    /// "paper", the `x` position refers to the distance from the left side
1187    /// of the plotting area in normalized coordinates where 0 (1)
1188    /// corresponds to the left (right) side.
1189    #[serde(rename = "xref")]
1190    x_ref: Option<String>,
1191    /// Sets the annotation's x position. If the axis `type` is "log", then you
1192    /// must take the log of your desired range. If the axis `type` is
1193    /// "date", it should be date strings, like date data, though Date
1194    /// objects and unix milliseconds will be accepted and converted to strings.
1195    /// If the axis `type` is "category", it should be numbers, using the scale
1196    /// where each category is assigned a serial number from zero in the
1197    /// order it appears.
1198    x: Option<NumOrString>,
1199    /// Sets the text box's horizontal position anchor This anchor binds the `x`
1200    /// position to the "left", "center" or "right" of the annotation. For
1201    /// example, if `x` is set to 1, `xref` to "paper" and `xanchor` to
1202    /// "right" then the right-most portion of the annotation lines up with
1203    /// the right-most edge of the plotting area. If "auto", the anchor is
1204    /// equivalent to "center" for data-referenced annotations or if there
1205    /// is an arrow, whereas for paper-referenced with no arrow, the anchor
1206    /// picked corresponds to the closest side.
1207    #[serde(rename = "xanchor")]
1208    x_anchor: Option<Anchor>,
1209    /// Shifts the position of the whole annotation and arrow to the right
1210    /// (positive) or left (negative) by this many pixels.
1211    #[serde(rename = "xshift")]
1212    x_shift: Option<f64>,
1213    /// Sets the annotation's y coordinate axis. If set to an y axis id (e.g.
1214    /// "y" or "y2"), the `y` position refers to an y coordinate If set to
1215    /// "paper", the `y` position refers to the distance from the bottom of
1216    /// the plotting area in normalized coordinates where 0 (1) corresponds
1217    /// to the bottom (top).
1218    #[serde(rename = "yref")]
1219    y_ref: Option<String>,
1220    /// Sets the annotation's y position. If the axis `type` is "log", then you
1221    /// must take the log of your desired range. If the axis `type` is
1222    /// "date", it should be date strings, like date data, though Date
1223    /// objects and unix milliseconds will be accepted and converted to strings.
1224    /// If the axis `type` is "category", it should be numbers, using the
1225    /// scale where each category is assigned a serial number from zero in
1226    /// the order it appears.
1227    y: Option<NumOrString>,
1228    /// Sets the text box's vertical position anchor This anchor binds the `y`
1229    /// position to the "top", "middle" or "bottom" of the annotation. For
1230    /// example, if `y` is set to 1, `yref` to "paper" and `yanchor` to
1231    /// "top" then the top-most portion of the annotation lines up with the
1232    /// top-most edge of the plotting area. If "auto", the anchor is equivalent
1233    /// to "middle" for data-referenced annotations or if there is an arrow,
1234    /// whereas for paper-referenced with no arrow, the anchor picked
1235    /// corresponds to the closest side.
1236    #[serde(rename = "yanchor")]
1237    y_anchor: Option<Anchor>,
1238    /// Shifts the position of the whole annotation and arrow up (positive) or
1239    /// down (negative) by this many pixels.
1240    #[serde(rename = "yshift")]
1241    y_shift: Option<f64>,
1242    /// Makes this annotation respond to clicks on the plot. If you click a data
1243    /// point that exactly matches the `x` and `y` values of this
1244    /// annotation, and it is hidden (visible: false), it will appear. In
1245    /// "onoff" mode, you must click the same point again to make it disappear,
1246    /// so if you click multiple points, you can show multiple annotations.
1247    /// In "onout" mode, a click anywhere else in the plot (on another data
1248    /// point or not) will hide this annotation. If you need to show/hide
1249    /// this annotation in response to different `x` or `y` values, you can set
1250    /// `xclick` and/or `yclick`. This is useful for example to label the side
1251    /// of a bar. To label markers though, `standoff` is preferred over
1252    /// `xclick` and `yclick`.
1253    #[serde(rename = "clicktoshow")]
1254    click_to_show: Option<ClickToShow>,
1255    /// Toggle this annotation when clicking a data point whose `x` value is
1256    /// `xclick` rather than the annotation's `x` value.
1257    #[serde(rename = "xclick")]
1258    x_click: Option<NumOrString>,
1259    /// Toggle this annotation when clicking a data point whose `y` value is
1260    /// `yclick` rather than the annotation's `y` value.
1261    #[serde(rename = "yclick")]
1262    y_click: Option<NumOrString>,
1263    /// Sets text to appear when hovering over this annotation. If omitted or
1264    /// blank, no hover label will appear.
1265    #[serde(rename = "hovertext")]
1266    hover_text: Option<String>,
1267    /// Label displayed on mouse hover.
1268    #[serde(rename = "hoverlabel")]
1269    hover_label: Option<Label>,
1270    /// Determines whether the annotation text box captures mouse move and click
1271    /// events, or allows those events to pass through to data points in the
1272    /// plot that may be behind the annotation. By default `captureevents`
1273    /// is "false" unless `hovertext` is provided. If you use the event
1274    /// `plotly_clickannotation` without `hovertext` you must explicitly enable
1275    /// `captureevents`.
1276    #[serde(rename = "captureevents")]
1277    capture_events: Option<bool>,
1278    /// When used in a template, named items are created in the output figure in
1279    /// addition to any items the figure already has in this array. You can
1280    /// modify these items in the output figure by making your own item with
1281    /// `templateitemname` matching this `name` alongside your modifications
1282    /// (including `visible: false` or `enabled: false` to hide it). Has no
1283    /// effect outside of a template.
1284    name: Option<String>,
1285    /// Used to refer to a named item in this array in the template. Named items
1286    /// from the template will be created even without a matching item in
1287    /// the input figure, but you can modify one by making an item with
1288    /// `templateitemname` matching its `name`, alongside your modifications
1289    /// (including `visible: false` or `enabled: false` to hide it). If there is
1290    /// no template or no matching item, this item will be hidden unless you
1291    /// explicitly show it with `visible: true`.
1292    #[serde(rename = "templateitemname")]
1293    template_item_name: Option<String>,
1294}
1295
1296impl Annotation {
1297    pub fn new() -> Self {
1298        Default::default()
1299    }
1300}
1301
1302#[derive(Serialize, Debug, Clone)]
1303#[serde(rename_all = "lowercase")]
1304pub enum ClickMode {
1305    Event,
1306    Select,
1307    #[serde(rename = "event+select")]
1308    EventAndSelect,
1309    None,
1310}
1311
1312#[derive(Debug, Clone)]
1313pub enum DragMode {
1314    Zoom,
1315    Pan,
1316    Select,
1317    Lasso,
1318    DrawClosedPath,
1319    DrawOpenPath,
1320    DrawLine,
1321    DrawRect,
1322    DrawCircle,
1323    Orbit,
1324    Turntable,
1325    False,
1326}
1327
1328impl Serialize for DragMode {
1329    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1330    where
1331        S: serde::Serializer,
1332    {
1333        match *self {
1334            Self::Zoom => serializer.serialize_str("zoom"),
1335            Self::Pan => serializer.serialize_str("pan"),
1336            Self::Select => serializer.serialize_str("select"),
1337            Self::Lasso => serializer.serialize_str("lasso"),
1338            Self::DrawClosedPath => serializer.serialize_str("drawclosedpath"),
1339            Self::DrawOpenPath => serializer.serialize_str("drawopenpath"),
1340            Self::DrawLine => serializer.serialize_str("drawline"),
1341            Self::DrawRect => serializer.serialize_str("drawrect"),
1342            Self::DrawCircle => serializer.serialize_str("drawcircle"),
1343            Self::Orbit => serializer.serialize_str("orbit"),
1344            Self::Turntable => serializer.serialize_str("turntable"),
1345            Self::False => serializer.serialize_bool(false),
1346        }
1347    }
1348}
1349
1350#[derive(Debug, Clone)]
1351/// Determines the mode of drag interactions.
1352pub enum DragMode3D {
1353    Zoom,
1354    Pan,
1355    Turntable,
1356    Orbit,
1357    False,
1358}
1359
1360impl Serialize for DragMode3D {
1361    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1362    where
1363        S: serde::Serializer,
1364    {
1365        match *self {
1366            Self::Zoom => serializer.serialize_str("zoom"),
1367            Self::Pan => serializer.serialize_str("pan"),
1368            Self::Turntable => serializer.serialize_str("turntable"),
1369            Self::Orbit => serializer.serialize_str("orbit"),
1370            Self::False => serializer.serialize_bool(false),
1371        }
1372    }
1373}
1374
1375#[derive(Serialize, Debug, Clone)]
1376#[serde(rename_all = "lowercase")]
1377pub enum SelectDirection {
1378    #[serde(rename = "h")]
1379    Horizontal,
1380    #[serde(rename = "v")]
1381    Vertical,
1382    #[serde(rename = "d")]
1383    Diagonal,
1384    Any,
1385}
1386
1387/// Defines the latitude and longitude at which a map will be centered.
1388#[derive(Serialize, Clone, Debug)]
1389pub struct Center {
1390    lat: f64,
1391    lon: f64,
1392}
1393
1394impl Center {
1395    /// Create a new instance of `Center`.
1396    ///
1397    /// `lat` is the number of degrees north, `lon` is the number of degrees
1398    /// east.
1399    pub fn new(lat: f64, lon: f64) -> Self {
1400        Center { lat, lon }
1401    }
1402}
1403
1404#[derive(Serialize, Clone, Debug)]
1405#[serde(rename_all = "kebab-case")]
1406pub enum MapboxStyle {
1407    #[serde(rename = "carto-darkmatter")]
1408    CartoDarkMatter,
1409    CartoPositron,
1410    OpenStreetMap,
1411    StamenTerrain,
1412    StamenToner,
1413    StamenWatercolor,
1414    WhiteBg,
1415    Basic,
1416    Streets,
1417    Outdoors,
1418    Light,
1419    Dark,
1420    Satellite,
1421    SatelliteStreets,
1422}
1423
1424#[derive(Serialize, Clone, Debug, FieldSetter)]
1425pub struct Mapbox {
1426    /// Sets the mapbox access token to be used for this mapbox map. Note that
1427    /// `access_token`s are only required when `style` (e.g with values: basic,
1428    /// streets, outdoors, light, dark, satellite, satellite-streets)
1429    /// and/or a layout layer references the Mapbox server.
1430    #[serde(rename = "accesstoken")]
1431    access_token: Option<String>,
1432    /// Sets the bearing angle of the map in degrees counter-clockwise from
1433    /// North.
1434    bearing: Option<f64>,
1435    /// Sets the latitude and longitude of the center of the map.
1436    center: Option<Center>,
1437    /// Sets the domain within which the mapbox will be drawn.
1438    domain: Option<Domain>,
1439    /// Sets the pitch angle of the map in degrees, where `0` means
1440    /// perpendicular to the surface of the map.
1441    pitch: Option<f64>,
1442    /// Sets the style of the map.
1443    style: Option<MapboxStyle>,
1444    /// Sets the zoom level of the map.
1445    zoom: Option<u8>,
1446}
1447
1448impl Mapbox {
1449    pub fn new() -> Self {
1450        Default::default()
1451    }
1452}
1453
1454#[derive(Serialize, Debug, Clone)]
1455/// If "cube", this scene's axes are drawn as a cube, regardless of the axes'
1456/// ranges. If "data", this scene's axes are drawn in proportion with the axes'
1457/// ranges. If "manual", this scene's axes are drawn in proportion with the
1458/// input of "aspectratio" (the default behavior if "aspectratio" is provided).
1459/// If "auto", this scene's axes are drawn using the results of "data" except
1460/// when one axis is more than four times the size of the two others, where in
1461/// that case the results of "cube" are used.
1462/// Default: "auto"
1463#[derive(Default)]
1464pub enum AspectMode {
1465    #[serde(rename = "auto")]
1466    #[default]
1467    Auto,
1468    #[serde(rename = "cube")]
1469    Cube,
1470    #[serde(rename = "data")]
1471    Data,
1472    #[serde(rename = "manual")]
1473    Manual,
1474}
1475
1476#[serde_with::skip_serializing_none]
1477#[derive(Serialize, Debug, Clone, FieldSetter)]
1478/// Sets the (x, y, z) components of the 'eye' camera vector. This vector
1479/// determines the view point about the origin of this scene.
1480/// Default: {x: 1.25, y: 1.25, z: 1.25}
1481pub struct Eye {
1482    x: Option<f64>,
1483    y: Option<f64>,
1484    z: Option<f64>,
1485}
1486
1487impl Eye {
1488    pub fn new() -> Self {
1489        Eye {
1490            x: Some(1.25),
1491            y: Some(1.25),
1492            z: Some(1.25),
1493        }
1494    }
1495}
1496
1497impl From<(f64, f64, f64)> for Eye {
1498    fn from((x, y, z): (f64, f64, f64)) -> Self {
1499        Eye {
1500            x: Some(x),
1501            y: Some(y),
1502            z: Some(z),
1503        }
1504    }
1505}
1506
1507#[serde_with::skip_serializing_none]
1508#[derive(Serialize, Debug, Clone, FieldSetter)]
1509/// Sets the (x, y, z) components of the 'up' camera vector. This vector
1510/// determines the up direction of this scene with respect to the page. The
1511/// Default: {x: 0, y: 0, z: 1} which means that the z axis points up.
1512pub struct Up {
1513    x: Option<f64>,
1514    y: Option<f64>,
1515    z: Option<f64>,
1516}
1517
1518impl Up {
1519    pub fn new() -> Self {
1520        Up {
1521            x: Some(0.0),
1522            y: Some(0.0),
1523            z: Some(1.0),
1524        }
1525    }
1526}
1527
1528impl From<(f64, f64, f64)> for Up {
1529    fn from((x, y, z): (f64, f64, f64)) -> Self {
1530        Up {
1531            x: Some(x),
1532            y: Some(y),
1533            z: Some(z),
1534        }
1535    }
1536}
1537
1538#[derive(Default, Serialize, Debug, Clone)]
1539/// Sets the projection type. The projection type could be either "perspective"
1540/// or "orthographic".
1541/// Default: "perspective"
1542pub enum ProjectionType {
1543    #[default]
1544    #[serde(rename = "perspective")]
1545    Perspective,
1546    #[serde(rename = "orthographic")]
1547    Orthographic,
1548}
1549
1550impl From<ProjectionType> for Projection {
1551    fn from(projection_type: ProjectionType) -> Self {
1552        Projection {
1553            projection_type: Some(projection_type),
1554        }
1555    }
1556}
1557
1558#[serde_with::skip_serializing_none]
1559#[derive(Serialize, Debug, Clone, FieldSetter)]
1560/// Container for Projection options.
1561pub struct Projection {
1562    #[serde(rename = "type")]
1563    projection_type: Option<ProjectionType>,
1564}
1565
1566impl Projection {
1567    pub fn new() -> Self {
1568        Default::default()
1569    }
1570}
1571
1572#[serde_with::skip_serializing_none]
1573#[derive(Serialize, Debug, Clone, FieldSetter)]
1574/// Sets the (x, y, z) components of the 'center' camera vector. This vector
1575/// determines the translation (x, y, z) space about the center of this scene.
1576/// Default: {x: 0, y: 0, z: 0} which means that the center of the scene is at
1577/// the origin.
1578pub struct CameraCenter {
1579    x: Option<f64>,
1580    y: Option<f64>,
1581    z: Option<f64>,
1582}
1583
1584impl CameraCenter {
1585    pub fn new() -> Self {
1586        CameraCenter {
1587            x: Some(0.0),
1588            y: Some(0.0),
1589            z: Some(0.0),
1590        }
1591    }
1592}
1593
1594impl From<(f64, f64, f64)> for CameraCenter {
1595    fn from((x, y, z): (f64, f64, f64)) -> Self {
1596        CameraCenter {
1597            x: Some(x),
1598            y: Some(y),
1599            z: Some(z),
1600        }
1601    }
1602}
1603
1604#[serde_with::skip_serializing_none]
1605#[derive(Serialize, Debug, Clone, FieldSetter)]
1606/// Container for CameraCenter, Eye, Up, and Projection objects. The camera of a
1607/// 3D scene.
1608pub struct Camera {
1609    center: Option<CameraCenter>,
1610    eye: Option<Eye>,
1611    up: Option<Up>,
1612    projection: Option<Projection>,
1613}
1614
1615impl Camera {
1616    pub fn new() -> Self {
1617        Default::default()
1618    }
1619}
1620
1621#[serde_with::skip_serializing_none]
1622#[derive(Serialize, Debug, Clone, FieldSetter)]
1623/// Sets this scene's axis aspectratio.
1624/// x, y, z must be positive.
1625/// Default: {x: 1, y: 1, z: 1}
1626pub struct AspectRatio {
1627    x: Option<f64>,
1628    y: Option<f64>,
1629    z: Option<f64>,
1630}
1631
1632impl AspectRatio {
1633    pub fn new() -> Self {
1634        AspectRatio {
1635            x: Some(1.0),
1636            y: Some(1.0),
1637            z: Some(1.0),
1638        }
1639    }
1640}
1641
1642impl From<(f64, f64, f64)> for AspectRatio {
1643    fn from((x, y, z): (f64, f64, f64)) -> Self {
1644        AspectRatio {
1645            x: Some(x),
1646            y: Some(y),
1647            z: Some(z),
1648        }
1649    }
1650}
1651
1652#[serde_with::skip_serializing_none]
1653#[derive(Serialize, Debug, Clone, FieldSetter)]
1654/// 3D scene layout
1655pub struct LayoutScene {
1656    #[serde(rename = "bgcolor")]
1657    background_color: Option<Box<dyn Color>>,
1658    camera: Option<Camera>,
1659    #[serde(rename = "aspectmode")]
1660    aspect_mode: Option<AspectMode>,
1661    #[serde(rename = "aspectratio")]
1662    aspect_ratio: Option<AspectRatio>,
1663    #[serde(rename = "xaxis")]
1664    x_axis: Option<Axis>,
1665    #[serde(rename = "yaxis")]
1666    y_axis: Option<Axis>,
1667    #[serde(rename = "zaxis")]
1668    z_axis: Option<Axis>,
1669    #[serde(rename = "dragmode")]
1670    drag_mode: Option<DragMode3D>,
1671    #[serde(rename = "hovermode")]
1672    hover_mode: Option<HoverMode>,
1673    annotations: Option<Vec<Annotation>>,
1674    // domain: Domain,
1675    // uirevision: Uirevision,
1676}
1677
1678impl LayoutScene {
1679    pub fn new() -> Self {
1680        Default::default()
1681    }
1682}
1683
1684#[serde_with::skip_serializing_none]
1685#[derive(Serialize, Debug, Clone, FieldSetter)]
1686pub struct Template {
1687    layout: Option<LayoutTemplate>,
1688}
1689
1690impl Template {
1691    pub fn new() -> Self {
1692        Default::default()
1693    }
1694}
1695
1696#[allow(clippy::from_over_into)]
1697impl Into<Cow<'static, Template>> for Template {
1698    fn into(self) -> Cow<'static, Template> {
1699        Cow::Owned(self)
1700    }
1701}
1702
1703#[allow(clippy::from_over_into)]
1704impl Into<Cow<'static, Template>> for &'static Template {
1705    fn into(self) -> Cow<'static, Template> {
1706        Cow::Borrowed(self)
1707    }
1708}
1709
1710// LayoutTemplate matches Layout except it lacks a field for template
1711#[serde_with::skip_serializing_none]
1712#[derive(Serialize, Debug, Clone, FieldSetter)]
1713pub struct LayoutTemplate {
1714    title: Option<Title>,
1715    #[serde(rename = "showlegend")]
1716    show_legend: Option<bool>,
1717    legend: Option<Legend>,
1718    margin: Option<Margin>,
1719    #[serde(rename = "autosize")]
1720    auto_size: Option<bool>,
1721    width: Option<usize>,
1722    height: Option<usize>,
1723    font: Option<Font>,
1724    #[serde(rename = "uniformtext")]
1725    uniform_text: Option<UniformText>,
1726    separators: Option<String>,
1727    #[serde(rename = "paper_bgcolor")]
1728    paper_background_color: Option<Box<dyn Color>>,
1729    #[serde(rename = "plot_bgcolor")]
1730    plot_background_color: Option<Box<dyn Color>>,
1731    #[serde(rename = "colorscale")]
1732    color_scale: Option<LayoutColorScale>,
1733    colorway: Option<Vec<Box<dyn Color>>>,
1734    #[serde(rename = "coloraxis")]
1735    color_axis: Option<ColorAxis>,
1736    #[serde(rename = "modebar")]
1737    mode_bar: Option<ModeBar>,
1738    /// Determines the mode of hover interactions. If "closest", a single
1739    /// hoverlabel will appear for the "closest" point within the
1740    /// `hoverdistance`. If "x" (or "y"), multiple hoverlabels will appear for
1741    /// multiple points at the "closest" x- (or y-) coordinate within the
1742    /// `hoverdistance`, with the caveat that no more than one hoverlabel
1743    /// will appear per trace. If "x unified" (or "y unified"), a single
1744    /// hoverlabel will appear multiple points at the closest x- (or y-)
1745    /// coordinate within the `hoverdistance` with the caveat that no more than
1746    /// one hoverlabel will appear per trace. In this mode, spikelines are
1747    /// enabled by default perpendicular to the specified axis.
1748    /// If false, hover interactions are disabled. If `clickmode` includes the
1749    /// "select" flag, `hovermode` defaults to "closest". If `clickmode`
1750    /// lacks the "select" flag, it defaults to "x" or "y" (depending on the
1751    /// trace's `orientation` value) for plots based on cartesian coordinates.
1752    /// For anything else the default value is "closest".
1753    #[serde(rename = "hovermode")]
1754    hover_mode: Option<HoverMode>,
1755    #[serde(rename = "clickmode")]
1756    click_mode: Option<ClickMode>,
1757    #[serde(rename = "dragmode")]
1758    drag_mode: Option<DragMode>,
1759    #[serde(rename = "selectdirection")]
1760    select_direction: Option<SelectDirection>,
1761    #[serde(rename = "hoverdistance")]
1762    hover_distance: Option<i32>,
1763    #[serde(rename = "spikedistance")]
1764    spike_distance: Option<i32>,
1765    #[serde(rename = "hoverlabel")]
1766    hover_label: Option<Label>,
1767
1768    grid: Option<LayoutGrid>,
1769    calendar: Option<Calendar>,
1770
1771    #[serde(rename = "xaxis")]
1772    x_axis: Option<Box<Axis>>,
1773    #[serde(rename = "yaxis")]
1774    y_axis: Option<Box<Axis>>,
1775    #[serde(rename = "xaxis2")]
1776    x_axis2: Option<Box<Axis>>,
1777    #[serde(rename = "yaxis2")]
1778    y_axis2: Option<Box<Axis>>,
1779    #[serde(rename = "xaxis3")]
1780    x_axis3: Option<Box<Axis>>,
1781    #[serde(rename = "yaxis3")]
1782    y_axis3: Option<Box<Axis>>,
1783    #[serde(rename = "xaxis4")]
1784    x_axis4: Option<Box<Axis>>,
1785    #[serde(rename = "yaxis4")]
1786    y_axis4: Option<Box<Axis>>,
1787    #[serde(rename = "xaxis5")]
1788    x_axis5: Option<Box<Axis>>,
1789    #[serde(rename = "yaxis5")]
1790    y_axis5: Option<Box<Axis>>,
1791    #[serde(rename = "xaxis6")]
1792    x_axis6: Option<Box<Axis>>,
1793    #[serde(rename = "yaxis6")]
1794    y_axis6: Option<Box<Axis>>,
1795    #[serde(rename = "xaxis7")]
1796    x_axis7: Option<Box<Axis>>,
1797    #[serde(rename = "yaxis7")]
1798    y_axis7: Option<Box<Axis>>,
1799    #[serde(rename = "xaxis8")]
1800    x_axis8: Option<Box<Axis>>,
1801    #[serde(rename = "yaxis8")]
1802    y_axis8: Option<Box<Axis>>,
1803
1804    // ternary: Option<LayoutTernary>,
1805    scene: Option<LayoutScene>,
1806    // polar: Option<LayoutPolar>,
1807    annotations: Option<Vec<Annotation>>,
1808    shapes: Option<Vec<Shape>>,
1809    #[serde(rename = "newshape")]
1810    new_shape: Option<NewShape>,
1811    #[serde(rename = "activeshape")]
1812    active_shape: Option<ActiveShape>,
1813
1814    #[serde(rename = "boxmode")]
1815    box_mode: Option<BoxMode>,
1816    #[serde(rename = "boxgap")]
1817    box_gap: Option<f64>,
1818    #[serde(rename = "boxgroupgap")]
1819    box_group_gap: Option<f64>,
1820
1821    #[serde(rename = "barmode")]
1822    bar_mode: Option<BarMode>,
1823    #[serde(rename = "barnorm")]
1824    bar_norm: Option<BarNorm>,
1825    #[serde(rename = "bargap")]
1826    bar_gap: Option<f64>,
1827    #[serde(rename = "bargroupgap")]
1828    bar_group_gap: Option<f64>,
1829
1830    #[serde(rename = "violinmode")]
1831    violin_mode: Option<ViolinMode>,
1832    #[serde(rename = "violingap")]
1833    violin_gap: Option<f64>,
1834    #[serde(rename = "violingroupgap")]
1835    violin_group_gap: Option<f64>,
1836
1837    #[serde(rename = "waterfallmode")]
1838    waterfall_mode: Option<WaterfallMode>,
1839    #[serde(rename = "waterfallgap")]
1840    waterfall_gap: Option<f64>,
1841    #[serde(rename = "waterfallgroupgap")]
1842    waterfall_group_gap: Option<f64>,
1843
1844    #[serde(rename = "piecolorway")]
1845    pie_colorway: Option<Vec<Box<dyn Color>>>,
1846    #[serde(rename = "extendpiecolors")]
1847    extend_pie_colors: Option<bool>,
1848
1849    #[serde(rename = "sunburstcolorway")]
1850    sunburst_colorway: Option<Vec<Box<dyn Color>>>,
1851    #[serde(rename = "extendsunburstcolors")]
1852    extend_sunburst_colors: Option<bool>,
1853}
1854
1855impl LayoutTemplate {
1856    pub fn new() -> Self {
1857        Default::default()
1858    }
1859
1860    pub fn add_annotation(&mut self, annotation: Annotation) {
1861        if self.annotations.is_none() {
1862            self.annotations = Some(Vec::new());
1863        }
1864        self.annotations.as_mut().unwrap().push(annotation);
1865    }
1866
1867    pub fn add_shape(&mut self, shape: Shape) {
1868        if self.shapes.is_none() {
1869            self.shapes = Some(Vec::new());
1870        }
1871        self.shapes.as_mut().unwrap().push(shape);
1872    }
1873}
1874
1875#[serde_with::skip_serializing_none]
1876#[derive(Serialize, Debug, Clone, FieldSetter)]
1877#[field_setter(kind = "layout")]
1878pub struct Layout {
1879    title: Option<Title>,
1880    #[serde(rename = "showlegend")]
1881    show_legend: Option<bool>,
1882    legend: Option<Legend>,
1883    margin: Option<Margin>,
1884    #[serde(rename = "autosize")]
1885    auto_size: Option<bool>,
1886    width: Option<usize>,
1887    height: Option<usize>,
1888    font: Option<Font>,
1889    #[serde(rename = "uniformtext")]
1890    uniform_text: Option<UniformText>,
1891    separators: Option<String>,
1892    #[serde(rename = "paper_bgcolor")]
1893    paper_background_color: Option<Box<dyn Color>>,
1894    #[serde(rename = "plot_bgcolor")]
1895    plot_background_color: Option<Box<dyn Color>>,
1896    #[serde(rename = "colorscale")]
1897    color_scale: Option<LayoutColorScale>,
1898    colorway: Option<Vec<Box<dyn Color>>>,
1899    #[serde(rename = "coloraxis")]
1900    color_axis: Option<ColorAxis>,
1901    #[serde(rename = "modebar")]
1902    mode_bar: Option<ModeBar>,
1903    /// Determines the mode of hover interactions. If "closest", a single
1904    /// hoverlabel will appear for the "closest" point within the
1905    /// `hoverdistance`. If "x" (or "y"), multiple hoverlabels will appear for
1906    /// multiple points at the "closest" x- (or y-) coordinate within the
1907    /// `hoverdistance`, with the caveat that no more than one hoverlabel
1908    /// will appear per trace. If "x unified" (or "y unified"), a single
1909    /// hoverlabel will appear multiple points at the closest x- (or y-)
1910    /// coordinate within the `hoverdistance` with the caveat that no more than
1911    /// one hoverlabel will appear per trace. In this mode, spikelines are
1912    /// enabled by default perpendicular to the specified axis.
1913    /// If false, hover interactions are disabled. If `clickmode` includes the
1914    /// "select" flag, `hovermode` defaults to "closest". If `clickmode`
1915    /// lacks the "select" flag, it defaults to "x" or "y" (depending on the
1916    /// trace's `orientation` value) for plots based on cartesian coordinates.
1917    /// For anything else the default value is "closest".
1918    #[serde(rename = "hovermode")]
1919    hover_mode: Option<HoverMode>,
1920    #[serde(rename = "clickmode")]
1921    click_mode: Option<ClickMode>,
1922    #[serde(rename = "dragmode")]
1923    drag_mode: Option<DragMode>,
1924    #[serde(rename = "selectdirection")]
1925    select_direction: Option<SelectDirection>,
1926    #[serde(rename = "hoverdistance")]
1927    hover_distance: Option<i32>,
1928    #[serde(rename = "spikedistance")]
1929    spike_distance: Option<i32>,
1930    #[serde(rename = "hoverlabel")]
1931    hover_label: Option<Label>,
1932    #[field_setter(skip)]
1933    template: Option<Box<Cow<'static, Template>>>,
1934
1935    grid: Option<LayoutGrid>,
1936    calendar: Option<Calendar>,
1937
1938    #[serde(rename = "xaxis")]
1939    x_axis: Option<Box<Axis>>,
1940    #[serde(rename = "yaxis")]
1941    y_axis: Option<Box<Axis>>,
1942    #[serde(rename = "zaxis")]
1943    z_axis: Option<Box<Axis>>,
1944
1945    #[serde(rename = "xaxis2")]
1946    x_axis2: Option<Box<Axis>>,
1947    #[serde(rename = "yaxis2")]
1948    y_axis2: Option<Box<Axis>>,
1949    #[serde(rename = "zaxis2")]
1950    z_axis2: Option<Box<Axis>>,
1951    #[serde(rename = "xaxis3")]
1952    x_axis3: Option<Box<Axis>>,
1953    #[serde(rename = "yaxis3")]
1954    y_axis3: Option<Box<Axis>>,
1955    #[serde(rename = "zaxis3")]
1956    z_axis3: Option<Box<Axis>>,
1957    #[serde(rename = "xaxis4")]
1958    x_axis4: Option<Box<Axis>>,
1959    #[serde(rename = "yaxis4")]
1960    y_axis4: Option<Box<Axis>>,
1961    #[serde(rename = "zaxis4")]
1962    z_axis4: Option<Box<Axis>>,
1963    #[serde(rename = "xaxis5")]
1964    x_axis5: Option<Box<Axis>>,
1965    #[serde(rename = "yaxis5")]
1966    y_axis5: Option<Box<Axis>>,
1967    #[serde(rename = "zaxis5")]
1968    z_axis5: Option<Box<Axis>>,
1969    #[serde(rename = "xaxis6")]
1970    x_axis6: Option<Box<Axis>>,
1971    #[serde(rename = "yaxis6")]
1972    y_axis6: Option<Box<Axis>>,
1973    #[serde(rename = "zaxis6")]
1974    z_axis6: Option<Box<Axis>>,
1975    #[serde(rename = "xaxis7")]
1976    x_axis7: Option<Box<Axis>>,
1977    #[serde(rename = "yaxis7")]
1978    y_axis7: Option<Box<Axis>>,
1979    #[serde(rename = "zaxis7")]
1980    z_axis7: Option<Box<Axis>>,
1981    #[serde(rename = "xaxis8")]
1982    x_axis8: Option<Box<Axis>>,
1983    #[serde(rename = "yaxis8")]
1984    y_axis8: Option<Box<Axis>>,
1985    #[serde(rename = "zaxis8")]
1986    z_axis8: Option<Box<Axis>>,
1987
1988    // ternary: Option<LayoutTernary>,
1989    scene: Option<LayoutScene>,
1990    // polar: Option<LayoutPolar>,
1991    annotations: Option<Vec<Annotation>>,
1992    shapes: Option<Vec<Shape>>,
1993    #[serde(rename = "newshape")]
1994    new_shape: Option<NewShape>,
1995    #[serde(rename = "activeshape")]
1996    active_shape: Option<ActiveShape>,
1997
1998    #[serde(rename = "boxmode")]
1999    box_mode: Option<BoxMode>,
2000    #[serde(rename = "boxgap")]
2001    box_gap: Option<f64>,
2002    #[serde(rename = "boxgroupgap")]
2003    box_group_gap: Option<f64>,
2004
2005    #[serde(rename = "barmode")]
2006    bar_mode: Option<BarMode>,
2007    #[serde(rename = "barnorm")]
2008    bar_norm: Option<BarNorm>,
2009    #[serde(rename = "bargap")]
2010    bar_gap: Option<f64>,
2011    #[serde(rename = "bargroupgap")]
2012    bar_group_gap: Option<f64>,
2013
2014    #[serde(rename = "violinmode")]
2015    violin_mode: Option<ViolinMode>,
2016    #[serde(rename = "violingap")]
2017    violin_gap: Option<f64>,
2018    #[serde(rename = "violingroupgap")]
2019    violin_group_gap: Option<f64>,
2020
2021    #[serde(rename = "waterfallmode")]
2022    waterfall_mode: Option<WaterfallMode>,
2023    #[serde(rename = "waterfallgap")]
2024    waterfall_gap: Option<f64>,
2025    #[serde(rename = "waterfallgroupgap")]
2026    waterfall_group_gap: Option<f64>,
2027
2028    #[serde(rename = "piecolorway")]
2029    pie_colorway: Option<Vec<Box<dyn Color>>>,
2030    #[serde(rename = "extendpiecolors")]
2031    extend_pie_colors: Option<bool>,
2032
2033    #[serde(rename = "sunburstcolorway")]
2034    sunburst_colorway: Option<Vec<Box<dyn Color>>>,
2035    #[serde(rename = "extendsunburstcolors")]
2036    extend_sunburst_colors: Option<bool>,
2037
2038    mapbox: Option<Mapbox>,
2039
2040    #[serde(rename = "updatemenus")]
2041    update_menus: Option<Vec<UpdateMenu>>,
2042}
2043
2044impl Layout {
2045    pub fn new() -> Self {
2046        Default::default()
2047    }
2048
2049    pub fn to_json(&self) -> String {
2050        serde_json::to_string(self).unwrap()
2051    }
2052
2053    pub fn add_annotation(&mut self, annotation: Annotation) {
2054        if self.annotations.is_none() {
2055            self.annotations = Some(Vec::new());
2056        }
2057        self.annotations.as_mut().unwrap().push(annotation);
2058    }
2059
2060    pub fn add_shape(&mut self, shape: Shape) {
2061        if self.shapes.is_none() {
2062            self.shapes = Some(Vec::new());
2063        }
2064        self.shapes.as_mut().unwrap().push(shape);
2065    }
2066
2067    pub fn template<T>(mut self, template: T) -> Layout
2068    where
2069        T: Into<Cow<'static, Template>>,
2070    {
2071        self.template = Some(Box::new(template.into()));
2072        self
2073    }
2074}
2075
2076#[cfg(test)]
2077mod tests {
2078    use serde_json::{json, to_value};
2079
2080    use super::*;
2081    use crate::common::ColorScalePalette;
2082
2083    #[test]
2084    fn serialize_uniform_text_mode() {
2085        assert_eq!(to_value(UniformTextMode::False).unwrap(), json!(false));
2086        assert_eq!(to_value(UniformTextMode::Hide).unwrap(), json!("hide"));
2087        assert_eq!(to_value(UniformTextMode::Show).unwrap(), json!("show"));
2088    }
2089
2090    #[test]
2091    fn serialize_click_to_show() {
2092        assert_eq!(to_value(ClickToShow::False).unwrap(), json!(false));
2093        assert_eq!(to_value(ClickToShow::OnOff).unwrap(), json!("onoff"));
2094        assert_eq!(to_value(ClickToShow::OnOut).unwrap(), json!("onout"));
2095    }
2096
2097    #[test]
2098    fn serialize_hover_mode() {
2099        assert_eq!(to_value(HoverMode::X).unwrap(), json!("x"));
2100        assert_eq!(to_value(HoverMode::Y).unwrap(), json!("y"));
2101        assert_eq!(to_value(HoverMode::Closest).unwrap(), json!("closest"));
2102        assert_eq!(to_value(HoverMode::False).unwrap(), json!(false));
2103        assert_eq!(to_value(HoverMode::XUnified).unwrap(), json!("x unified"));
2104        assert_eq!(to_value(HoverMode::YUnified).unwrap(), json!("y unified"));
2105    }
2106
2107    #[test]
2108    #[rustfmt::skip]
2109    fn serialize_axis_type() {
2110        assert_eq!(to_value(AxisType::Default).unwrap(), json!("-"));
2111        assert_eq!(to_value(AxisType::Linear).unwrap(), json!("linear"));
2112        assert_eq!(to_value(AxisType::Log).unwrap(), json!("log"));
2113        assert_eq!(to_value(AxisType::Date).unwrap(), json!("date"));
2114        assert_eq!(to_value(AxisType::Category).unwrap(), json!("category"));
2115        assert_eq!(to_value(AxisType::MultiCategory).unwrap(), json!("multicategory"));
2116    }
2117
2118    #[test]
2119    fn serialize_axis_constrain() {
2120        assert_eq!(to_value(AxisConstrain::Range).unwrap(), json!("range"));
2121        assert_eq!(to_value(AxisConstrain::Domain).unwrap(), json!("domain"));
2122    }
2123
2124    #[test]
2125    #[rustfmt::skip]
2126    fn serialize_constrain_direction() {
2127        assert_eq!(to_value(ConstrainDirection::Left).unwrap(), json!("left"));
2128        assert_eq!(to_value(ConstrainDirection::Center).unwrap(), json!("center"));
2129        assert_eq!(to_value(ConstrainDirection::Right).unwrap(), json!("right"));
2130        assert_eq!(to_value(ConstrainDirection::Top).unwrap(), json!("top"));
2131        assert_eq!(to_value(ConstrainDirection::Middle).unwrap(), json!("middle"));
2132        assert_eq!(to_value(ConstrainDirection::Bottom).unwrap(), json!("bottom"));
2133    }
2134
2135    #[test]
2136    #[rustfmt::skip]
2137    fn serialize_range_mode() {
2138        assert_eq!(to_value(RangeMode::Normal).unwrap(), json!("normal"));
2139        assert_eq!(to_value(RangeMode::ToZero).unwrap(), json!("tozero"));
2140        assert_eq!(to_value(RangeMode::NonNegative).unwrap(), json!("nonnegative"));
2141    }
2142
2143    #[test]
2144    fn serialize_ticks_direction() {
2145        assert_eq!(to_value(TicksDirection::Outside).unwrap(), json!("outside"));
2146        assert_eq!(to_value(TicksDirection::Inside).unwrap(), json!("inside"));
2147    }
2148
2149    #[test]
2150    #[rustfmt::skip]
2151    fn serialize_ticks_position() {
2152        assert_eq!(to_value(TicksPosition::Labels).unwrap(), json!("labels"));
2153        assert_eq!(to_value(TicksPosition::Boundaries).unwrap(), json!("boundaries"));
2154    }
2155
2156    #[test]
2157    fn serialize_array_show() {
2158        assert_eq!(to_value(ArrayShow::All).unwrap(), json!("all"));
2159        assert_eq!(to_value(ArrayShow::First).unwrap(), json!("first"));
2160        assert_eq!(to_value(ArrayShow::Last).unwrap(), json!("last"));
2161        assert_eq!(to_value(ArrayShow::None).unwrap(), json!("none"));
2162    }
2163
2164    #[test]
2165    fn serialize_bar_mode() {
2166        assert_eq!(to_value(BarMode::Stack).unwrap(), json!("stack"));
2167        assert_eq!(to_value(BarMode::Group).unwrap(), json!("group"));
2168        assert_eq!(to_value(BarMode::Overlay).unwrap(), json!("overlay"));
2169        assert_eq!(to_value(BarMode::Relative).unwrap(), json!("relative"));
2170    }
2171
2172    #[test]
2173    fn serialize_bar_norm() {
2174        assert_eq!(to_value(BarNorm::Empty).unwrap(), json!(""));
2175        assert_eq!(to_value(BarNorm::Fraction).unwrap(), json!("fraction"));
2176        assert_eq!(to_value(BarNorm::Percent).unwrap(), json!("percent"));
2177    }
2178
2179    #[test]
2180    fn serialize_box_mode() {
2181        assert_eq!(to_value(BoxMode::Group).unwrap(), json!("group"));
2182        assert_eq!(to_value(BoxMode::Overlay).unwrap(), json!("overlay"));
2183    }
2184
2185    #[test]
2186    fn serialize_violin_mode() {
2187        assert_eq!(to_value(ViolinMode::Group).unwrap(), json!("group"));
2188        assert_eq!(to_value(ViolinMode::Overlay).unwrap(), json!("overlay"));
2189    }
2190
2191    #[test]
2192    fn serialize_waterfall_mode() {
2193        assert_eq!(to_value(WaterfallMode::Group).unwrap(), json!("group"));
2194        assert_eq!(to_value(WaterfallMode::Overlay).unwrap(), json!("overlay"));
2195    }
2196
2197    #[test]
2198    #[rustfmt::skip]
2199    fn serialize_trace_order() {
2200        assert_eq!(to_value(TraceOrder::Reversed).unwrap(), json!("reversed"));
2201        assert_eq!(to_value(TraceOrder::Grouped).unwrap(), json!("grouped"));
2202        assert_eq!(to_value(TraceOrder::ReversedGrouped).unwrap(), json!("reversed+grouped"));
2203        assert_eq!(to_value(TraceOrder::Normal).unwrap(), json!("normal"));
2204    }
2205
2206    #[test]
2207    fn serialize_item_sizing() {
2208        assert_eq!(to_value(ItemSizing::Trace).unwrap(), json!("trace"));
2209        assert_eq!(to_value(ItemSizing::Constant).unwrap(), json!("constant"));
2210    }
2211
2212    #[test]
2213    #[rustfmt::skip]
2214    fn serialize_item_click() {
2215        assert_eq!(to_value(ItemClick::Toggle).unwrap(), json!("toggle"));
2216        assert_eq!(to_value(ItemClick::ToggleOthers).unwrap(), json!("toggleothers"));
2217        assert_eq!(to_value(ItemClick::False).unwrap(), json!(false));
2218    }
2219
2220    #[test]
2221    #[rustfmt::skip]
2222    fn serialize_group_click() {
2223        assert_eq!(to_value(GroupClick::ToggleItem).unwrap(), json!("toggleitem"));
2224        assert_eq!(to_value(GroupClick::ToggleGroup).unwrap(), json!("togglegroup"));
2225    }
2226
2227    #[test]
2228    fn serialize_legend() {
2229        let legend = Legend::new()
2230            .background_color("#123123")
2231            .border_color("#321321")
2232            .border_width(500)
2233            .font(Font::new())
2234            .orientation(Orientation::Vertical)
2235            .trace_order(TraceOrder::Normal)
2236            .trace_group_gap(10)
2237            .item_sizing(ItemSizing::Trace)
2238            .item_click(ItemClick::Toggle)
2239            .item_double_click(ItemClick::False)
2240            .x(1.0)
2241            .x_anchor(Anchor::Auto)
2242            .y(2.0)
2243            .y_anchor(Anchor::Left)
2244            .valign(VAlign::Middle)
2245            .title("title")
2246            .group_click(GroupClick::ToggleItem)
2247            .item_width(50);
2248
2249        let expected = json!({
2250            "bgcolor": "#123123",
2251            "bordercolor": "#321321",
2252            "borderwidth": 500,
2253            "font": {},
2254            "orientation": "v",
2255            "traceorder": "normal",
2256            "tracegroupgap": 10,
2257            "itemsizing": "trace",
2258            "itemclick": "toggle",
2259            "itemdoubleclick": false,
2260            "x": 1.0,
2261            "xanchor": "auto",
2262            "y": 2.0,
2263            "yanchor": "left",
2264            "valign": "middle",
2265            "title": {"text": "title"},
2266            "groupclick": "toggleitem",
2267            "itemwidth": 50
2268        });
2269
2270        assert_eq!(to_value(legend).unwrap(), expected)
2271    }
2272
2273    #[test]
2274    fn serialize_valign() {
2275        assert_eq!(to_value(VAlign::Top).unwrap(), json!("top"));
2276        assert_eq!(to_value(VAlign::Middle).unwrap(), json!("middle"));
2277        assert_eq!(to_value(VAlign::Bottom).unwrap(), json!("bottom"));
2278    }
2279
2280    #[test]
2281    fn serialize_halign() {
2282        assert_eq!(to_value(HAlign::Left).unwrap(), json!("left"));
2283        assert_eq!(to_value(HAlign::Center).unwrap(), json!("center"));
2284        assert_eq!(to_value(HAlign::Right).unwrap(), json!("right"));
2285    }
2286
2287    #[test]
2288    fn serialize_margin() {
2289        let margin = Margin::new()
2290            .left(1)
2291            .right(2)
2292            .top(3)
2293            .bottom(4)
2294            .pad(5)
2295            .auto_expand(true);
2296        let expected = json!({
2297            "l": 1,
2298            "r": 2,
2299            "t": 3,
2300            "b": 4,
2301            "pad": 5,
2302            "autoexpand": true,
2303        });
2304
2305        assert_eq!(to_value(margin).unwrap(), expected);
2306    }
2307
2308    #[test]
2309    fn serialize_layout_color_scale() {
2310        let layout_color_scale = LayoutColorScale::new()
2311            .sequential(ColorScale::Palette(ColorScalePalette::Greys))
2312            .sequential_minus(ColorScale::Palette(ColorScalePalette::Blues))
2313            .diverging(ColorScale::Palette(ColorScalePalette::Hot));
2314        let expected = json!({
2315            "sequential": "Greys",
2316            "sequentialminus": "Blues",
2317            "diverging": "Hot"
2318        });
2319
2320        assert_eq!(to_value(layout_color_scale).unwrap(), expected);
2321    }
2322
2323    #[test]
2324    fn serialize_slider_range_mode() {
2325        assert_eq!(to_value(SliderRangeMode::Auto).unwrap(), json!("auto"));
2326        assert_eq!(to_value(SliderRangeMode::Fixed).unwrap(), json!("fixed"));
2327        assert_eq!(to_value(SliderRangeMode::Match).unwrap(), json!("match"));
2328    }
2329
2330    #[test]
2331    fn serialize_range_slider_y_axis() {
2332        let range_slider_y_axis = RangeSliderYAxis::new()
2333            .range_mode(SliderRangeMode::Match)
2334            .range(vec![0.2]);
2335        let expected = json!({
2336            "rangemode": "match",
2337            "range": [0.2]
2338        });
2339
2340        assert_eq!(to_value(range_slider_y_axis).unwrap(), expected);
2341    }
2342
2343    #[test]
2344    fn serialize_range_slider() {
2345        let range_slider = RangeSlider::new()
2346            .background_color("#123ABC")
2347            .border_color("#ABC123")
2348            .border_width(1000)
2349            .auto_range(false)
2350            .range(vec![5_i32])
2351            .thickness(2000.)
2352            .visible(true)
2353            .y_axis(RangeSliderYAxis::new());
2354
2355        let expected = json!({
2356            "bgcolor": "#123ABC",
2357            "bordercolor": "#ABC123",
2358            "borderwidth": 1000,
2359            "autorange": false,
2360            "range": [5],
2361            "thickness": 2000.0,
2362            "visible": true,
2363            "yaxis": {}
2364        });
2365
2366        assert_eq!(to_value(range_slider).unwrap(), expected);
2367    }
2368
2369    #[test]
2370    fn serialize_selector_step() {
2371        assert_eq!(to_value(SelectorStep::Month).unwrap(), json!("month"));
2372        assert_eq!(to_value(SelectorStep::Year).unwrap(), json!("year"));
2373        assert_eq!(to_value(SelectorStep::Day).unwrap(), json!("day"));
2374        assert_eq!(to_value(SelectorStep::Hour).unwrap(), json!("hour"));
2375        assert_eq!(to_value(SelectorStep::Minute).unwrap(), json!("minute"));
2376        assert_eq!(to_value(SelectorStep::Second).unwrap(), json!("second"));
2377        assert_eq!(to_value(SelectorStep::All).unwrap(), json!("all"));
2378    }
2379
2380    #[test]
2381    fn serialize_step_mode() {
2382        assert_eq!(to_value(StepMode::Backward).unwrap(), json!("backward"));
2383        assert_eq!(to_value(StepMode::ToDate).unwrap(), json!("todate"));
2384    }
2385
2386    #[test]
2387    #[rustfmt::skip]
2388    fn serialize_spike_mode() {
2389        assert_eq!(to_value(SpikeMode::ToAxis).unwrap(), json!("toaxis"));
2390        assert_eq!(to_value(SpikeMode::Across).unwrap(), json!("across"));
2391        assert_eq!(to_value(SpikeMode::Marker).unwrap(), json!("marker"));
2392        assert_eq!(to_value(SpikeMode::ToaxisAcross).unwrap(), json!("toaxis+across"));
2393        assert_eq!(to_value(SpikeMode::ToAxisMarker).unwrap(), json!("toaxis+marker"));
2394        assert_eq!(to_value(SpikeMode::AcrossMarker).unwrap(), json!("across+marker"));
2395        assert_eq!(to_value(SpikeMode::ToaxisAcrossMarker).unwrap(), json!("toaxis+across+marker"));
2396    }
2397
2398    #[test]
2399    #[rustfmt::skip]
2400    fn serialize_spike_snap() {
2401        assert_eq!(to_value(SpikeSnap::Data).unwrap(), json!("data"));
2402        assert_eq!(to_value(SpikeSnap::Cursor).unwrap(), json!("cursor"));
2403        assert_eq!(to_value(SpikeSnap::HoveredData).unwrap(), json!("hovered data"));
2404    }
2405
2406    #[test]
2407    #[rustfmt::skip]
2408    fn serialize_category_order() {
2409        assert_eq!(to_value(CategoryOrder::Trace).unwrap(), json!("trace"));
2410        assert_eq!(to_value(CategoryOrder::CategoryAscending).unwrap(), json!("category ascending"));
2411        assert_eq!(to_value(CategoryOrder::CategoryDescending).unwrap(), json!("category descending"));
2412        assert_eq!(to_value(CategoryOrder::Array).unwrap(), json!("array"));
2413        assert_eq!(to_value(CategoryOrder::TotalAscending).unwrap(), json!("total ascending"));
2414        assert_eq!(to_value(CategoryOrder::TotalDescending).unwrap(), json!("total descending"));
2415        assert_eq!(to_value(CategoryOrder::MinAscending).unwrap(), json!("min ascending"));
2416        assert_eq!(to_value(CategoryOrder::MinDescending).unwrap(), json!("min descending"));
2417        assert_eq!(to_value(CategoryOrder::MaxAscending).unwrap(), json!("max ascending"));
2418        assert_eq!(to_value(CategoryOrder::MaxDescending).unwrap(), json!("max descending"));
2419        assert_eq!(to_value(CategoryOrder::SumAscending).unwrap(), json!("sum ascending"));
2420        assert_eq!(to_value(CategoryOrder::SumDescending).unwrap(), json!("sum descending"));
2421        assert_eq!(to_value(CategoryOrder::MeanAscending).unwrap(), json!("mean ascending"));
2422        assert_eq!(to_value(CategoryOrder::MeanDescending).unwrap(), json!("mean descending"));
2423        assert_eq!(to_value(CategoryOrder::GeometricMeanAscending).unwrap(), json!("geometric mean ascending"));
2424        assert_eq!(to_value(CategoryOrder::GeometricMeanDescending).unwrap(), json!("geometric mean descending"));
2425        assert_eq!(to_value(CategoryOrder::MedianAscending).unwrap(), json!("median ascending"));
2426        assert_eq!(to_value(CategoryOrder::MedianDescending).unwrap(), json!("median descending"));
2427    }
2428
2429    #[test]
2430    fn serialize_selector_button() {
2431        let selector_button = SelectorButton::new()
2432            .visible(false)
2433            .step(SelectorStep::Hour)
2434            .step_mode(StepMode::ToDate)
2435            .count(42)
2436            .label("label")
2437            .name("name")
2438            .template_item_name("something");
2439
2440        let expected = json!({
2441            "visible": false,
2442            "step": "hour",
2443            "stepmode": "todate",
2444            "count": 42,
2445            "label": "label",
2446            "name": "name",
2447            "templateitemname": "something",
2448        });
2449
2450        assert_eq!(to_value(selector_button).unwrap(), expected);
2451    }
2452
2453    #[test]
2454    fn serialize_range_selector() {
2455        let range_selector = RangeSelector::new()
2456            .visible(true)
2457            .buttons(vec![SelectorButton::new()])
2458            .x(2.0)
2459            .x_anchor(Anchor::Middle)
2460            .y(4.0)
2461            .y_anchor(Anchor::Top)
2462            .font(Font::new())
2463            .background_color("#123ABC")
2464            .border_color("#ABC123")
2465            .border_width(1000)
2466            .active_color("#888999");
2467
2468        let expected = json!({
2469            "visible": true,
2470            "buttons": [{}],
2471            "x": 2.0,
2472            "xanchor": "middle",
2473            "y": 4.0,
2474            "yanchor": "top",
2475            "font": {},
2476            "bgcolor": "#123ABC",
2477            "bordercolor": "#ABC123",
2478            "borderwidth": 1000,
2479            "activecolor": "#888999",
2480        });
2481
2482        assert_eq!(to_value(range_selector).unwrap(), expected);
2483    }
2484
2485    #[test]
2486    fn serialize_color_axis() {
2487        let color_axis = ColorAxis::new()
2488            .auto_color_scale(false)
2489            .cauto(true)
2490            .cmax(1.0)
2491            .cmid(0.5)
2492            .cmin(0.0)
2493            .color_bar(ColorBar::new())
2494            .color_scale(ColorScale::Palette(ColorScalePalette::Greens))
2495            .reverse_scale(false)
2496            .show_scale(true);
2497
2498        let expected = json!({
2499            "autocolorscale": false,
2500            "cauto": true,
2501            "cmin": 0.0,
2502            "cmid": 0.5,
2503            "cmax": 1.0,
2504            "colorbar": {},
2505            "colorscale": "Greens",
2506            "reversescale": false,
2507            "showscale": true,
2508        });
2509
2510        assert_eq!(to_value(color_axis).unwrap(), expected);
2511    }
2512
2513    #[test]
2514    fn serialize_axis() {
2515        let axis = Axis::new()
2516            .visible(false)
2517            .color("#678123")
2518            .title(Title::with_text("title"))
2519            .type_(AxisType::Date)
2520            .auto_range(false)
2521            .range_mode(RangeMode::NonNegative)
2522            .range(vec![2.0])
2523            .fixed_range(true)
2524            .constrain(AxisConstrain::Range)
2525            .constrain_toward(ConstrainDirection::Middle)
2526            .tick_mode(TickMode::Auto)
2527            .n_ticks(600)
2528            .tick0(5.0)
2529            .dtick(10.0)
2530            .matches("x")
2531            .tick_values(vec![1.0, 2.0])
2532            .tick_text(vec!["one".to_string(), "two".to_string()])
2533            .ticks(TicksDirection::Inside)
2534            .ticks_on(TicksPosition::Boundaries)
2535            .mirror(false)
2536            .tick_length(77)
2537            .tick_width(99)
2538            .tick_color("#101010")
2539            .show_tick_labels(false)
2540            .auto_margin(true)
2541            .show_spikes(false)
2542            .spike_color("#ABABAB")
2543            .spike_thickness(501)
2544            .spike_dash(DashType::DashDot)
2545            .spike_mode(SpikeMode::AcrossMarker)
2546            .spike_snap(SpikeSnap::Data)
2547            .tick_font(Font::new())
2548            .tick_angle(2.1)
2549            .tick_prefix("prefix")
2550            .show_tick_prefix(ArrayShow::Last)
2551            .tick_suffix("suffix")
2552            .show_tick_suffix(ArrayShow::None)
2553            .show_exponent(ArrayShow::All)
2554            .exponent_format(ExponentFormat::SmallE)
2555            .separate_thousands(false)
2556            .tick_format("tickfmt")
2557            .tick_format_stops(vec![TickFormatStop::new()])
2558            .hover_format("hoverfmt")
2559            .show_line(true)
2560            .line_color("#CCCDDD")
2561            .line_width(9)
2562            .show_grid(false)
2563            .grid_color("#fff000")
2564            .grid_width(8)
2565            .zero_line(true)
2566            .zero_line_color("#f0f0f0")
2567            .zero_line_width(7)
2568            .show_dividers(false)
2569            .divider_color("#AFAFAF")
2570            .divider_width(55)
2571            .anchor("anchor")
2572            .side(AxisSide::Right)
2573            .overlaying("overlaying")
2574            .domain(&[0.0, 1.0])
2575            .position(0.6)
2576            .range_slider(RangeSlider::new())
2577            .range_selector(RangeSelector::new())
2578            .calendar(Calendar::Coptic)
2579            .category_order(CategoryOrder::Array)
2580            .category_array(vec!["Category0", "Category1"]);
2581
2582        let expected = json!({
2583            "visible": false,
2584            "color": "#678123",
2585            "title": {"text": "title"},
2586            "type": "date",
2587            "autorange": false,
2588            "rangemode": "nonnegative",
2589            "range": [2.0],
2590            "fixedrange": true,
2591            "constrain": "range",
2592            "constraintoward": "middle",
2593            "tickmode": "auto",
2594            "nticks": 600,
2595            "tick0": 5.0,
2596            "dtick": 10.0,
2597            "matches": "x",
2598            "tickvals": [1.0, 2.0],
2599            "ticktext": ["one", "two"],
2600            "ticks": "inside",
2601            "tickson": "boundaries",
2602            "mirror": false,
2603            "ticklen": 77,
2604            "tickwidth": 99,
2605            "tickcolor": "#101010",
2606            "showticklabels": false,
2607            "automargin": true,
2608            "showspikes": false,
2609            "spikecolor": "#ABABAB",
2610            "spikethickness": 501,
2611            "spikedash": "dashdot",
2612            "spikemode": "across+marker",
2613            "spikesnap": "data",
2614            "tickfont": {},
2615            "tickangle": 2.1,
2616            "tickprefix": "prefix",
2617            "showtickprefix": "last",
2618            "ticksuffix": "suffix",
2619            "showticksuffix": "none",
2620            "showexponent": "all",
2621            "exponentformat": "e",
2622            "separatethousands": false,
2623            "tickformat": "tickfmt",
2624            "tickformatstops": [{"enabled": true}],
2625            "hoverformat": "hoverfmt",
2626            "showline": true,
2627            "linecolor": "#CCCDDD",
2628            "linewidth": 9,
2629            "showgrid": false,
2630            "gridcolor": "#fff000",
2631            "gridwidth": 8,
2632            "zeroline": true,
2633            "zerolinecolor": "#f0f0f0",
2634            "zerolinewidth": 7,
2635            "showdividers": false,
2636            "dividercolor": "#AFAFAF",
2637            "dividerwidth": 55,
2638            "anchor": "anchor",
2639            "side": "right",
2640            "overlaying": "overlaying",
2641            "domain": [0.0, 1.0],
2642            "position": 0.6,
2643            "rangeslider": {},
2644            "rangeselector": {},
2645            "calendar": "coptic",
2646            "categoryorder": "array",
2647            "categoryarray": ["Category0", "Category1"]
2648        });
2649
2650        assert_eq!(to_value(axis).unwrap(), expected);
2651    }
2652
2653    #[test]
2654    #[rustfmt::skip]
2655    fn serialize_row_order() {
2656        assert_eq!(to_value(RowOrder::TopToBottom).unwrap(), json!("top to bottom"));
2657        assert_eq!(to_value(RowOrder::BottomToTop).unwrap(), json!("bottom to top"));
2658    }
2659
2660    #[test]
2661    #[rustfmt::skip]
2662    fn serialize_grid_pattern() {
2663        assert_eq!(to_value(GridPattern::Independent).unwrap(), json!("independent"));
2664        assert_eq!(to_value(GridPattern::Coupled).unwrap(), json!("coupled"));
2665    }
2666
2667    #[test]
2668    #[rustfmt::skip]
2669    fn serialize_grid_x_side() {
2670        assert_eq!(to_value(GridXSide::Bottom).unwrap(), json!("bottom"));
2671        assert_eq!(to_value(GridXSide::BottomPlot).unwrap(), json!("bottom plot"));
2672        assert_eq!(to_value(GridXSide::Top).unwrap(), json!("top"));
2673        assert_eq!(to_value(GridXSide::TopPlot).unwrap(), json!("top plot"));
2674    }
2675
2676    #[test]
2677    #[rustfmt::skip]
2678    fn serialize_grid_y_side() {
2679        assert_eq!(to_value(GridYSide::Left).unwrap(), json!("left"));
2680        assert_eq!(to_value(GridYSide::LeftPlot).unwrap(), json!("left plot"));
2681        assert_eq!(to_value(GridYSide::Right).unwrap(), json!("right"));
2682        assert_eq!(to_value(GridYSide::RightPlot).unwrap(), json!("right plot"));
2683    }
2684
2685    #[test]
2686    fn serialize_grid_domain() {
2687        let grid_domain = GridDomain::new().x(vec![0.0]).y(vec![1.0]);
2688        let expected = json!({
2689            "x": [0.0],
2690            "y": [1.0]
2691        });
2692
2693        assert_eq!(to_value(grid_domain).unwrap(), expected);
2694    }
2695
2696    #[test]
2697    fn serialize_layout_grid() {
2698        let layout_grid = LayoutGrid::new()
2699            .rows(224)
2700            .row_order(RowOrder::BottomToTop)
2701            .columns(501)
2702            .sub_plots(vec!["subplots".to_string()])
2703            .x_axes(vec!["xaxes".to_string()])
2704            .y_axes(vec!["yaxes".to_string()])
2705            .pattern(GridPattern::Coupled)
2706            .x_gap(2.2)
2707            .y_gap(4.4)
2708            .domain(GridDomain::new())
2709            .x_side(GridXSide::Top)
2710            .y_side(GridYSide::Right);
2711
2712        let expected = json!({
2713            "rows": 224,
2714            "roworder": "bottom to top",
2715            "columns": 501,
2716            "subplots": ["subplots"],
2717            "xaxes": ["xaxes"],
2718            "yaxes": ["yaxes"],
2719            "pattern": "coupled",
2720            "xgap": 2.2,
2721            "ygap": 4.4,
2722            "domain": {},
2723            "xside": "top",
2724            "yside": "right",
2725        });
2726
2727        assert_eq!(to_value(layout_grid).unwrap(), expected);
2728    }
2729
2730    #[test]
2731    fn serialize_uniform_text() {
2732        let uniform_text = UniformText::new().mode(UniformTextMode::Hide).min_size(5);
2733        let expected = json!({
2734            "mode": "hide",
2735            "minsize": 5
2736        });
2737
2738        assert_eq!(to_value(uniform_text).unwrap(), expected);
2739    }
2740
2741    #[test]
2742    fn serialize_mode_bar() {
2743        let mode_bar = ModeBar::new()
2744            .orientation(Orientation::Horizontal)
2745            .background_color("#FFF000")
2746            .color("#000FFF")
2747            .active_color("#AAABBB");
2748        let expected = json!({
2749            "orientation": "h",
2750            "bgcolor": "#FFF000",
2751            "color": "#000FFF",
2752            "activecolor": "#AAABBB",
2753        });
2754
2755        assert_eq!(to_value(mode_bar).unwrap(), expected);
2756    }
2757
2758    #[test]
2759    fn serialize_shape_type() {
2760        assert_eq!(to_value(ShapeType::Circle).unwrap(), json!("circle"));
2761        assert_eq!(to_value(ShapeType::Rect).unwrap(), json!("rect"));
2762        assert_eq!(to_value(ShapeType::Path).unwrap(), json!("path"));
2763        assert_eq!(to_value(ShapeType::Line).unwrap(), json!("line"));
2764    }
2765
2766    #[test]
2767    fn serialize_shape_layer() {
2768        assert_eq!(to_value(ShapeLayer::Below).unwrap(), json!("below"));
2769        assert_eq!(to_value(ShapeLayer::Above).unwrap(), json!("above"));
2770    }
2771
2772    #[test]
2773    fn serialize_shape_size_mode() {
2774        assert_eq!(to_value(ShapeSizeMode::Scaled).unwrap(), json!("scaled"));
2775        assert_eq!(to_value(ShapeSizeMode::Pixel).unwrap(), json!("pixel"));
2776    }
2777
2778    #[test]
2779    fn serialize_fill_rule() {
2780        assert_eq!(to_value(FillRule::EvenOdd).unwrap(), json!("evenodd"));
2781        assert_eq!(to_value(FillRule::NonZero).unwrap(), json!("nonzero"));
2782    }
2783
2784    #[test]
2785    fn serialize_shape_line() {
2786        let shape_line = ShapeLine::new()
2787            .color("#000FFF")
2788            .width(100.)
2789            .dash(DashType::LongDashDot);
2790        let expected = json!({
2791            "color": "#000FFF",
2792            "width": 100.0,
2793            "dash": "longdashdot",
2794        });
2795
2796        assert_eq!(to_value(shape_line).unwrap(), expected);
2797    }
2798
2799    #[test]
2800    fn serialize_shape() {
2801        let shape = Shape::new()
2802            .visible(false)
2803            .shape_type(ShapeType::Circle)
2804            .layer(ShapeLayer::Above)
2805            .x_ref("xref")
2806            .x_size_mode(ShapeSizeMode::Pixel)
2807            .x_anchor(5)
2808            .x0(7)
2809            .x1(8)
2810            .y_ref("paper")
2811            .y0(1)
2812            .y1(2)
2813            .y_anchor("yanchor")
2814            .y_size_mode(ShapeSizeMode::Scaled)
2815            .path("path")
2816            .opacity(0.2)
2817            .line(ShapeLine::new())
2818            .fill_color("#FEFEFE")
2819            .fill_rule(FillRule::NonZero)
2820            .editable(true)
2821            .name("name")
2822            .template_item_name("templateitemname");
2823
2824        let expected = json!({
2825            "visible": false,
2826            "type": "circle",
2827            "layer": "above",
2828            "xref": "xref",
2829            "xsizemode": "pixel",
2830            "xanchor": 5,
2831            "x0": 7,
2832            "x1": 8,
2833            "yref": "paper",
2834            "y0": 1,
2835            "y1": 2,
2836            "yanchor": "yanchor",
2837            "ysizemode": "scaled",
2838            "path": "path",
2839            "opacity": 0.2,
2840            "line": {},
2841            "fillcolor": "#FEFEFE",
2842            "fillrule": "nonzero",
2843            "editable": true,
2844            "name": "name",
2845            "templateitemname": "templateitemname"
2846        });
2847
2848        assert_eq!(to_value(shape).unwrap(), expected)
2849    }
2850
2851    #[test]
2852    #[rustfmt::skip]
2853    fn serialize_draw_direction() {
2854        assert_eq!(to_value(DrawDirection::Ortho).unwrap(), json!("ortho"));
2855        assert_eq!(to_value(DrawDirection::Horizontal).unwrap(), json!("horizontal"));
2856        assert_eq!(to_value(DrawDirection::Vertical).unwrap(), json!("vertical"));
2857        assert_eq!(to_value(DrawDirection::Diagonal).unwrap(), json!("diagonal"));
2858    }
2859
2860    #[test]
2861    fn serialize_new_shape() {
2862        let new_shape = NewShape::new()
2863            .line(ShapeLine::new())
2864            .fill_color("#123ABC")
2865            .fill_rule(FillRule::EvenOdd)
2866            .opacity(0.02)
2867            .layer(ShapeLayer::Below)
2868            .draw_direction(DrawDirection::Ortho);
2869
2870        let expected = json!({
2871            "line": {},
2872            "fillcolor": "#123ABC",
2873            "fillrule": "evenodd",
2874            "opacity": 0.02,
2875            "layer": "below",
2876            "drawdirection": "ortho",
2877        });
2878
2879        assert_eq!(to_value(new_shape).unwrap(), expected)
2880    }
2881
2882    #[test]
2883    fn serialize_active_shape() {
2884        let active_shape = ActiveShape::new().fill_color("#123ABC").opacity(0.02);
2885
2886        let expected = json!({
2887            "fillcolor": "#123ABC",
2888            "opacity": 0.02,
2889        });
2890
2891        assert_eq!(to_value(active_shape).unwrap(), expected);
2892    }
2893
2894    #[test]
2895    fn serialize_arrow_side() {
2896        assert_eq!(to_value(ArrowSide::End).unwrap(), json!("end"));
2897        assert_eq!(to_value(ArrowSide::Start).unwrap(), json!("start"));
2898        assert_eq!(to_value(ArrowSide::StartEnd).unwrap(), json!("end+start"));
2899        assert_eq!(to_value(ArrowSide::None).unwrap(), json!("none"));
2900    }
2901
2902    #[test]
2903    fn serialize_annotation() {
2904        let annotation = Annotation::new()
2905            .align(HAlign::Center)
2906            .arrow_color("#464646")
2907            .arrow_head(2)
2908            .arrow_size(123.4)
2909            .arrow_side(ArrowSide::End)
2910            .arrow_width(111.1)
2911            .ax("ax")
2912            .ax_ref("axref")
2913            .ay("ay")
2914            .ay_ref("ayref")
2915            .background_color("#123456")
2916            .border_color("#456789")
2917            .border_pad(500.)
2918            .border_width(1000.)
2919            .capture_events(false)
2920            .click_to_show(ClickToShow::OnOff)
2921            .font(Font::new())
2922            .height(6.)
2923            .hover_label(Label::new())
2924            .hover_text("hovertext")
2925            .name("name")
2926            .opacity(0.01)
2927            .show_arrow(false)
2928            .stand_off(999.9)
2929            .start_arrow_head(0)
2930            .start_stand_off(8.8)
2931            .start_arrow_size(456.7)
2932            .template_item_name("templateitemname")
2933            .text("text")
2934            .text_angle(5.)
2935            .valign(VAlign::Middle)
2936            .visible(true)
2937            .width(4.)
2938            .x_ref("xref")
2939            .x("x")
2940            .x_anchor(Anchor::Auto)
2941            .x_click("xclick")
2942            .x_shift(4.0)
2943            .y_ref("yref")
2944            .y("y")
2945            .y_anchor(Anchor::Bottom)
2946            .y_click("yclick")
2947            .y_shift(6.3);
2948
2949        let expected = json!({
2950            "visible": true,
2951            "text": "text",
2952            "textangle": 5.0,
2953            "font": {},
2954            "width": 4.0,
2955            "height": 6.0,
2956            "opacity": 0.01,
2957            "align": "center",
2958            "valign": "middle",
2959            "bgcolor": "#123456",
2960            "bordercolor": "#456789",
2961            "borderpad": 500.0,
2962            "borderwidth": 1000.0,
2963            "showarrow": false,
2964            "arrowcolor": "#464646",
2965            "arrowhead": 2,
2966            "startarrowhead": 0,
2967            "arrowside": "end",
2968            "arrowsize": 123.4,
2969            "startarrowsize": 456.7,
2970            "arrowwidth": 111.1,
2971            "standoff": 999.9,
2972            "startstandoff": 8.8,
2973            "ax": "ax",
2974            "ay": "ay",
2975            "x": "x",
2976            "y": "y",
2977            "axref": "axref",
2978            "ayref": "ayref",
2979            "xref": "xref",
2980            "yref": "yref",
2981            "xanchor": "auto",
2982            "yanchor": "bottom",
2983            "xshift": 4.0,
2984            "yshift": 6.3,
2985            "clicktoshow": "onoff",
2986            "xclick": "xclick",
2987            "yclick": "yclick",
2988            "hovertext": "hovertext",
2989            "hoverlabel": {},
2990            "captureevents": false,
2991            "name": "name",
2992            "templateitemname": "templateitemname",
2993        });
2994
2995        assert_eq!(to_value(annotation).unwrap(), expected);
2996    }
2997
2998    #[test]
2999    #[rustfmt::skip]
3000    fn serialize_click_mode() {
3001        assert_eq!(to_value(ClickMode::Event).unwrap(), json!("event"));
3002        assert_eq!(to_value(ClickMode::Select).unwrap(), json!("select"));
3003        assert_eq!(to_value(ClickMode::EventAndSelect).unwrap(), json!("event+select"));
3004        assert_eq!(to_value(ClickMode::None).unwrap(), json!("none"));
3005    }
3006
3007    #[test]
3008    #[rustfmt::skip]
3009    fn serialize_drag_mode() {
3010        assert_eq!(to_value(DragMode::Zoom).unwrap(), json!("zoom"));
3011        assert_eq!(to_value(DragMode::Pan).unwrap(), json!("pan"));
3012        assert_eq!(to_value(DragMode::Select).unwrap(), json!("select"));
3013        assert_eq!(to_value(DragMode::Lasso).unwrap(), json!("lasso"));
3014        assert_eq!(to_value(DragMode::DrawClosedPath).unwrap(), json!("drawclosedpath"));
3015        assert_eq!(to_value(DragMode::DrawOpenPath).unwrap(), json!("drawopenpath"));
3016        assert_eq!(to_value(DragMode::DrawLine).unwrap(), json!("drawline"));
3017        assert_eq!(to_value(DragMode::DrawRect).unwrap(), json!("drawrect"));
3018        assert_eq!(to_value(DragMode::DrawCircle).unwrap(), json!("drawcircle"));
3019        assert_eq!(to_value(DragMode::Orbit).unwrap(), json!("orbit"));
3020        assert_eq!(to_value(DragMode::Turntable).unwrap(), json!("turntable"));
3021        assert_eq!(to_value(DragMode::False).unwrap(), json!(false));
3022    }
3023
3024    #[test]
3025    #[rustfmt::skip]
3026    fn serialize_mapbox_style() {
3027        assert_eq!(to_value(MapboxStyle::CartoDarkMatter).unwrap(), json!("carto-darkmatter"));
3028        assert_eq!(to_value(MapboxStyle::CartoPositron).unwrap(), json!("carto-positron"));
3029        assert_eq!(to_value(MapboxStyle::OpenStreetMap).unwrap(), json!("open-street-map"));
3030        assert_eq!(to_value(MapboxStyle::StamenTerrain).unwrap(), json!("stamen-terrain"));
3031        assert_eq!(to_value(MapboxStyle::StamenToner).unwrap(), json!("stamen-toner"));
3032        assert_eq!(to_value(MapboxStyle::StamenWatercolor).unwrap(), json!("stamen-watercolor"));
3033        assert_eq!(to_value(MapboxStyle::WhiteBg).unwrap(), json!("white-bg"));
3034        assert_eq!(to_value(MapboxStyle::Basic).unwrap(), json!("basic"));
3035        assert_eq!(to_value(MapboxStyle::Streets).unwrap(), json!("streets"));
3036        assert_eq!(to_value(MapboxStyle::Outdoors).unwrap(), json!("outdoors"));
3037        assert_eq!(to_value(MapboxStyle::Light).unwrap(), json!("light"));
3038        assert_eq!(to_value(MapboxStyle::Dark).unwrap(), json!("dark"));
3039        assert_eq!(to_value(MapboxStyle::Satellite).unwrap(), json!("satellite"));
3040        assert_eq!(to_value(MapboxStyle::SatelliteStreets).unwrap(), json!("satellite-streets"));
3041    }
3042
3043    #[test]
3044    fn serialize_select_direction() {
3045        assert_eq!(to_value(SelectDirection::Horizontal).unwrap(), json!("h"));
3046        assert_eq!(to_value(SelectDirection::Vertical).unwrap(), json!("v"));
3047        assert_eq!(to_value(SelectDirection::Diagonal).unwrap(), json!("d"));
3048        assert_eq!(to_value(SelectDirection::Any).unwrap(), json!("any"));
3049    }
3050
3051    #[test]
3052    fn serialize_layout_template() {
3053        let layout_template = LayoutTemplate::new()
3054            .title("Title")
3055            .show_legend(false)
3056            .legend(Legend::new())
3057            .margin(Margin::new())
3058            .auto_size(true)
3059            .width(10)
3060            .height(20)
3061            .font(Font::new())
3062            .uniform_text(UniformText::new())
3063            .separators("_")
3064            .paper_background_color("#FFFFFF")
3065            .plot_background_color("#151515")
3066            .color_scale(LayoutColorScale::new())
3067            .colorway(vec!["#123123"])
3068            .color_axis(ColorAxis::new())
3069            .mode_bar(ModeBar::new())
3070            .hover_mode(HoverMode::Closest)
3071            .click_mode(ClickMode::EventAndSelect)
3072            .drag_mode(DragMode::Turntable)
3073            .select_direction(SelectDirection::Diagonal)
3074            .hover_distance(321)
3075            .spike_distance(12)
3076            .hover_label(Label::new())
3077            .grid(LayoutGrid::new())
3078            .calendar(Calendar::Jalali)
3079            .x_axis(Axis::new())
3080            .x_axis2(Axis::new())
3081            .x_axis3(Axis::new())
3082            .x_axis4(Axis::new())
3083            .x_axis5(Axis::new())
3084            .x_axis6(Axis::new())
3085            .x_axis7(Axis::new())
3086            .x_axis8(Axis::new())
3087            .y_axis(Axis::new())
3088            .y_axis2(Axis::new())
3089            .y_axis3(Axis::new())
3090            .y_axis4(Axis::new())
3091            .y_axis5(Axis::new())
3092            .y_axis6(Axis::new())
3093            .y_axis7(Axis::new())
3094            .y_axis8(Axis::new())
3095            .annotations(vec![Annotation::new()])
3096            .shapes(vec![Shape::new()])
3097            .new_shape(NewShape::new())
3098            .active_shape(ActiveShape::new())
3099            .box_mode(BoxMode::Group)
3100            .box_gap(1.)
3101            .box_group_gap(2.)
3102            .bar_mode(BarMode::Overlay)
3103            .bar_norm(BarNorm::Empty)
3104            .bar_gap(3.)
3105            .bar_group_gap(4.)
3106            .violin_mode(ViolinMode::Overlay)
3107            .violin_gap(5.)
3108            .violin_group_gap(6.)
3109            .waterfall_mode(WaterfallMode::Group)
3110            .waterfall_gap(7.)
3111            .waterfall_group_gap(8.)
3112            .pie_colorway(vec!["#789789"])
3113            .extend_pie_colors(true)
3114            .sunburst_colorway(vec!["#654654"])
3115            .extend_sunburst_colors(false);
3116
3117        let expected = json!({
3118            "title": {"text": "Title"},
3119            "showlegend": false,
3120            "legend": {},
3121            "margin": {},
3122            "autosize": true,
3123            "width": 10,
3124            "height": 20,
3125            "font": {},
3126            "uniformtext": {},
3127            "separators": "_",
3128            "paper_bgcolor": "#FFFFFF",
3129            "plot_bgcolor": "#151515",
3130            "colorscale": {},
3131            "colorway": ["#123123"],
3132            "coloraxis": {},
3133            "modebar": {},
3134            "hovermode": "closest",
3135            "clickmode": "event+select",
3136            "dragmode": "turntable",
3137            "selectdirection": "d",
3138            "hoverdistance": 321,
3139            "spikedistance": 12,
3140            "hoverlabel": {},
3141            "grid": {},
3142            "calendar": "jalali",
3143            "xaxis": {},
3144            "xaxis2": {},
3145            "xaxis3": {},
3146            "xaxis4": {},
3147            "xaxis5": {},
3148            "xaxis6": {},
3149            "xaxis7": {},
3150            "xaxis8": {},
3151            "yaxis": {},
3152            "yaxis2": {},
3153            "yaxis3": {},
3154            "yaxis4": {},
3155            "yaxis5": {},
3156            "yaxis6": {},
3157            "yaxis7": {},
3158            "yaxis8": {},
3159            "annotations": [{}],
3160            "shapes": [{}],
3161            "newshape": {},
3162            "activeshape": {},
3163            "boxmode": "group",
3164            "boxgap": 1.0,
3165            "boxgroupgap": 2.0,
3166            "barmode": "overlay",
3167            "barnorm": "",
3168            "bargap": 3.0,
3169            "bargroupgap": 4.0,
3170            "violinmode": "overlay",
3171            "violingap": 5.0,
3172            "violingroupgap": 6.0,
3173            "waterfallmode": "group",
3174            "waterfallgap": 7.0,
3175            "waterfallgroupgap": 8.0,
3176            "piecolorway": ["#789789"],
3177            "extendpiecolors": true,
3178            "sunburstcolorway": ["#654654"],
3179            "extendsunburstcolors": false,
3180        });
3181
3182        assert_eq!(to_value(layout_template).unwrap(), expected);
3183    }
3184
3185    #[test]
3186    fn serialize_template() {
3187        let template = Template::new().layout(LayoutTemplate::new());
3188        let expected = json!({"layout": {}});
3189
3190        assert_eq!(to_value(template).unwrap(), expected);
3191    }
3192
3193    #[test]
3194    fn serialize_layout() {
3195        let layout = Layout::new()
3196            .title("Title")
3197            .title(String::from("Title"))
3198            .title(Title::with_text("Title"))
3199            .show_legend(false)
3200            .legend(Legend::new())
3201            .margin(Margin::new())
3202            .auto_size(true)
3203            .width(10)
3204            .height(20)
3205            .font(Font::new())
3206            .uniform_text(UniformText::new())
3207            .separators("_")
3208            .paper_background_color("#FFFFFF")
3209            .plot_background_color("#151515")
3210            .color_scale(LayoutColorScale::new())
3211            .colorway(vec!["#123123"])
3212            .color_axis(ColorAxis::new())
3213            .mode_bar(ModeBar::new())
3214            .hover_mode(HoverMode::Closest)
3215            .click_mode(ClickMode::EventAndSelect)
3216            .drag_mode(DragMode::Turntable)
3217            .select_direction(SelectDirection::Diagonal)
3218            .hover_distance(321)
3219            .spike_distance(12)
3220            .hover_label(Label::new())
3221            .template(Template::new())
3222            .grid(LayoutGrid::new())
3223            .calendar(Calendar::Jalali)
3224            .x_axis(Axis::new())
3225            .x_axis2(Axis::new())
3226            .x_axis3(Axis::new())
3227            .x_axis4(Axis::new())
3228            .x_axis5(Axis::new())
3229            .x_axis6(Axis::new())
3230            .x_axis7(Axis::new())
3231            .x_axis8(Axis::new())
3232            .y_axis(Axis::new())
3233            .y_axis2(Axis::new())
3234            .y_axis3(Axis::new())
3235            .y_axis4(Axis::new())
3236            .y_axis5(Axis::new())
3237            .y_axis6(Axis::new())
3238            .y_axis7(Axis::new())
3239            .y_axis8(Axis::new())
3240            .annotations(vec![Annotation::new()])
3241            .shapes(vec![Shape::new()])
3242            .new_shape(NewShape::new())
3243            .active_shape(ActiveShape::new())
3244            .box_mode(BoxMode::Group)
3245            .box_gap(1.)
3246            .box_group_gap(2.)
3247            .bar_mode(BarMode::Overlay)
3248            .bar_norm(BarNorm::Empty)
3249            .bar_gap(3.)
3250            .bar_group_gap(4.)
3251            .violin_mode(ViolinMode::Overlay)
3252            .violin_gap(5.)
3253            .violin_group_gap(6.)
3254            .waterfall_mode(WaterfallMode::Group)
3255            .waterfall_gap(7.)
3256            .waterfall_group_gap(8.)
3257            .pie_colorway(vec!["#789789"])
3258            .extend_pie_colors(true)
3259            .sunburst_colorway(vec!["#654654"])
3260            .extend_sunburst_colors(false)
3261            .z_axis(Axis::new())
3262            .scene(LayoutScene::new());
3263
3264        let expected = json!({
3265            "title": {"text": "Title"},
3266            "showlegend": false,
3267            "legend": {},
3268            "margin": {},
3269            "autosize": true,
3270            "width": 10,
3271            "height": 20,
3272            "font": {},
3273            "uniformtext": {},
3274            "separators": "_",
3275            "paper_bgcolor": "#FFFFFF",
3276            "plot_bgcolor": "#151515",
3277            "colorscale": {},
3278            "colorway": ["#123123"],
3279            "coloraxis": {},
3280            "modebar": {},
3281            "hovermode": "closest",
3282            "clickmode": "event+select",
3283            "dragmode": "turntable",
3284            "selectdirection": "d",
3285            "hoverdistance": 321,
3286            "spikedistance": 12,
3287            "hoverlabel": {},
3288            "template": {},
3289            "grid": {},
3290            "calendar": "jalali",
3291            "xaxis": {},
3292            "xaxis2": {},
3293            "xaxis3": {},
3294            "xaxis4": {},
3295            "xaxis5": {},
3296            "xaxis6": {},
3297            "xaxis7": {},
3298            "xaxis8": {},
3299            "yaxis": {},
3300            "yaxis2": {},
3301            "yaxis3": {},
3302            "yaxis4": {},
3303            "yaxis5": {},
3304            "yaxis6": {},
3305            "yaxis7": {},
3306            "yaxis8": {},
3307            "annotations": [{}],
3308            "shapes": [{}],
3309            "newshape": {},
3310            "activeshape": {},
3311            "boxmode": "group",
3312            "boxgap": 1.0,
3313            "boxgroupgap": 2.0,
3314            "barmode": "overlay",
3315            "barnorm": "",
3316            "bargap": 3.0,
3317            "bargroupgap": 4.0,
3318            "violinmode": "overlay",
3319            "violingap": 5.0,
3320            "violingroupgap": 6.0,
3321            "waterfallmode": "group",
3322            "waterfallgap": 7.0,
3323            "waterfallgroupgap": 8.0,
3324            "piecolorway": ["#789789"],
3325            "extendpiecolors": true,
3326            "sunburstcolorway": ["#654654"],
3327            "extendsunburstcolors": false,
3328            "zaxis": {},
3329            "scene": {}
3330        });
3331
3332        assert_eq!(to_value(layout).unwrap(), expected);
3333    }
3334
3335    #[test]
3336    fn serialize_layout_scene() {
3337        let layout = Layout::new().scene(
3338            LayoutScene::new()
3339                .x_axis(Axis::new())
3340                .y_axis(Axis::new())
3341                .z_axis(Axis::new())
3342                .camera(Camera::new())
3343                .aspect_mode(AspectMode::Auto)
3344                .hover_mode(HoverMode::Closest)
3345                .drag_mode(DragMode3D::Turntable)
3346                .background_color("#FFFFFF")
3347                .annotations(vec![Annotation::new()]),
3348        );
3349
3350        let expected = json!({
3351            "scene": {
3352                "xaxis": {},
3353                "yaxis": {},
3354                "zaxis": {},
3355                "camera": {},
3356                "aspectmode": "auto",
3357                "hovermode": "closest",
3358                "dragmode": "turntable",
3359                "bgcolor": "#FFFFFF",
3360                "annotations": [{}],
3361            }
3362        });
3363
3364        assert_eq!(to_value(layout).unwrap(), expected);
3365    }
3366
3367    #[test]
3368    fn serialize_eye() {
3369        let eye = Eye::new();
3370
3371        assert_eq!(
3372            to_value(eye).unwrap(),
3373            json!({
3374                "x": 1.25,
3375                "y": 1.25,
3376                "z": 1.25,
3377            })
3378        );
3379
3380        let eye = Eye::new().x(1f64).y(2f64).z(3f64);
3381
3382        let expected = json!({
3383            "x": 1.0,
3384            "y": 2.0,
3385            "z": 3.0,
3386        });
3387
3388        assert_eq!(to_value(eye).unwrap(), expected);
3389
3390        let eye: Eye = (1f64, 2f64, 3f64).into();
3391
3392        assert_eq!(to_value(eye).unwrap(), expected);
3393    }
3394
3395    #[test]
3396    fn serialize_projection() {
3397        let projection = Projection::new().projection_type(ProjectionType::default());
3398
3399        let expected = json!({
3400            "type": "perspective",
3401        });
3402
3403        assert_eq!(to_value(projection).unwrap(), expected);
3404
3405        let projection = Projection::new().projection_type(ProjectionType::Orthographic);
3406
3407        let expected = json!({
3408            "type": "orthographic",
3409        });
3410
3411        assert_eq!(to_value(projection).unwrap(), expected);
3412
3413        let projection: Projection = ProjectionType::Orthographic.into();
3414
3415        assert_eq!(to_value(projection).unwrap(), expected);
3416    }
3417
3418    #[test]
3419    fn serialize_camera_center() {
3420        let camera_center = CameraCenter::new();
3421
3422        let expected = json!({
3423            "x": 0.0,
3424            "y": 0.0,
3425            "z": 0.0,
3426        });
3427
3428        assert_eq!(to_value(camera_center).unwrap(), expected);
3429
3430        let camera_center = CameraCenter::new().x(1f64).y(2f64).z(3f64);
3431
3432        let expected = json!({
3433            "x": 1.0,
3434            "y": 2.0,
3435            "z": 3.0,
3436        });
3437
3438        assert_eq!(to_value(camera_center).unwrap(), expected);
3439
3440        let camera_center: CameraCenter = (1f64, 2f64, 3f64).into();
3441
3442        assert_eq!(to_value(camera_center).unwrap(), expected);
3443    }
3444
3445    #[test]
3446    fn serialize_aspect_ratio() {
3447        let aspect_ratio = AspectRatio::new();
3448
3449        let expected = json!({
3450            "x": 1.0,
3451            "y": 1.0,
3452            "z": 1.0,
3453        });
3454
3455        assert_eq!(to_value(aspect_ratio).unwrap(), expected);
3456
3457        let aspect_ratio = AspectRatio::new().x(1f64).y(2f64).z(3f64);
3458
3459        let expected = json!({
3460            "x": 1.0,
3461            "y": 2.0,
3462            "z": 3.0,
3463        });
3464
3465        assert_eq!(to_value(aspect_ratio).unwrap(), expected);
3466
3467        let aspect_ratio: AspectRatio = (1f64, 2f64, 3f64).into();
3468
3469        assert_eq!(to_value(aspect_ratio).unwrap(), expected);
3470    }
3471
3472    #[test]
3473    fn serialize_aspect_mode() {
3474        let aspect_mode = AspectMode::default();
3475
3476        assert_eq!(to_value(aspect_mode).unwrap(), json!("auto"));
3477
3478        let aspect_mode = AspectMode::Data;
3479
3480        assert_eq!(to_value(aspect_mode).unwrap(), json!("data"));
3481
3482        let aspect_mode = AspectMode::Cube;
3483
3484        assert_eq!(to_value(aspect_mode).unwrap(), json!("cube"));
3485    }
3486
3487    #[test]
3488    fn serialize_up() {
3489        let up = Up::new();
3490
3491        let expected = json!({
3492            "x": 0.0,
3493            "y": 0.0,
3494            "z": 1.0,
3495        });
3496
3497        assert_eq!(to_value(up).unwrap(), expected);
3498
3499        let up = Up::new().x(1f64).y(2f64).z(3f64);
3500
3501        let expected = json!({
3502            "x": 1.0,
3503            "y": 2.0,
3504            "z": 3.0,
3505        });
3506
3507        assert_eq!(to_value(up).unwrap(), expected);
3508
3509        let up: Up = (1f64, 2f64, 3f64).into();
3510
3511        assert_eq!(to_value(up).unwrap(), expected);
3512    }
3513}