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