Skip to main content

plotly/common/
mod.rs

1pub mod color;
2
3use plotly_derive::FieldSetter;
4use serde::{Serialize, Serializer};
5
6use crate::{
7    color::{Color, ColorArray},
8    private,
9};
10
11#[derive(Serialize, Clone, Debug)]
12#[serde(untagged)]
13pub enum Direction {
14    Increasing { line: Line },
15    Decreasing { line: Line },
16}
17
18#[derive(Clone, Debug)]
19pub enum Visible {
20    True,
21    False,
22    LegendOnly,
23}
24
25impl Serialize for Visible {
26    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
27    where
28        S: Serializer,
29    {
30        match *self {
31            Self::True => serializer.serialize_bool(true),
32            Self::False => serializer.serialize_bool(false),
33            Self::LegendOnly => serializer.serialize_str("legendonly"),
34        }
35    }
36}
37
38#[derive(Serialize, Clone, Debug)]
39#[serde(rename_all = "lowercase")]
40pub enum HoverInfo {
41    X,
42    Y,
43    Z,
44    #[serde(rename = "x+y")]
45    XAndY,
46    #[serde(rename = "x+z")]
47    XAndZ,
48    #[serde(rename = "y+z")]
49    YAndZ,
50    #[serde(rename = "x+y+z")]
51    XAndYAndZ,
52    Text,
53    Name,
54    All,
55    None,
56    Skip,
57}
58
59#[serde_with::skip_serializing_none]
60#[derive(Serialize, Clone, Debug, FieldSetter)]
61pub struct LegendGroupTitle {
62    text: Option<String>,
63    font: Option<Font>,
64}
65
66impl From<&str> for LegendGroupTitle {
67    fn from(title: &str) -> Self {
68        LegendGroupTitle::with_text(title)
69    }
70}
71
72impl From<String> for LegendGroupTitle {
73    fn from(value: String) -> Self {
74        LegendGroupTitle::with_text(value)
75    }
76}
77
78impl From<&String> for LegendGroupTitle {
79    fn from(value: &String) -> Self {
80        LegendGroupTitle::with_text(value)
81    }
82}
83
84impl LegendGroupTitle {
85    pub fn new() -> Self {
86        Default::default()
87    }
88
89    pub fn with_text<S: Into<String>>(text: S) -> Self {
90        LegendGroupTitle {
91            text: Some(text.into()),
92            ..Default::default()
93        }
94    }
95}
96
97#[serde_with::skip_serializing_none]
98#[derive(Serialize, Clone, Debug, Default)]
99pub struct Domain {
100    column: Option<usize>,
101    row: Option<usize>,
102    x: Option<[f64; 2]>,
103    y: Option<[f64; 2]>,
104}
105
106impl Domain {
107    pub fn new() -> Self {
108        Default::default()
109    }
110
111    pub fn column(mut self, column: usize) -> Self {
112        self.column = Some(column);
113        self
114    }
115
116    pub fn row(mut self, row: usize) -> Self {
117        self.row = Some(row);
118        self
119    }
120
121    pub fn x(mut self, x: &[f64; 2]) -> Self {
122        self.x = Some(x.to_owned());
123        self
124    }
125
126    pub fn y(mut self, y: &[f64; 2]) -> Self {
127        self.y = Some(y.to_owned());
128        self
129    }
130}
131
132#[derive(Serialize, Clone, Debug)]
133#[serde(rename_all = "lowercase")]
134pub enum TextPosition {
135    Inside,
136    Outside,
137    Auto,
138    None,
139}
140
141#[derive(Serialize, Clone, Debug)]
142#[serde(rename_all = "lowercase")]
143pub enum ConstrainText {
144    Inside,
145    Outside,
146    Both,
147    None,
148}
149
150#[derive(Serialize, Clone, Debug)]
151pub enum Orientation {
152    #[serde(rename = "a")]
153    Auto,
154    #[serde(rename = "v")]
155    Vertical,
156    #[serde(rename = "h")]
157    Horizontal,
158    #[serde(rename = "r")]
159    Radial,
160    #[serde(rename = "t")]
161    Tangential,
162}
163
164#[derive(Serialize, Clone, Debug)]
165#[serde(rename_all = "lowercase")]
166pub enum Fill {
167    ToZeroY,
168    ToZeroX,
169    ToNextY,
170    ToNextX,
171    ToSelf,
172    ToNext,
173    None,
174}
175
176#[derive(Serialize, Clone, Debug)]
177#[serde(rename_all = "lowercase")]
178pub enum Calendar {
179    Gregorian,
180    Chinese,
181    Coptic,
182    DiscWorld,
183    Ethiopian,
184    Hebrew,
185    Islamic,
186    Julian,
187    Mayan,
188    Nanakshahi,
189    Nepali,
190    Persian,
191    Jalali,
192    Taiwan,
193    Thai,
194    Ummalqura,
195}
196
197#[derive(Serialize, Clone, Debug)]
198#[serde(untagged)]
199pub enum Dim<T>
200where
201    T: Serialize,
202{
203    Scalar(T),
204    Vector(Vec<T>),
205    Matrix(Vec<Vec<T>>),
206}
207
208#[derive(Serialize, Clone, Debug, PartialEq, Eq)]
209#[serde(rename_all = "lowercase")]
210pub enum PlotType {
211    Scatter,
212    ScatterGL,
213    Scatter3D,
214    ScatterMapbox,
215    ScatterGeo,
216    ScatterPolar,
217    ScatterPolarGL,
218    Bar,
219    Box,
220    Candlestick,
221    Contour,
222    HeatMap,
223    Histogram,
224    Histogram2dContour,
225    Image,
226    Mesh3D,
227    Ohlc,
228    Sankey,
229    Surface,
230    DensityMapbox,
231    Table,
232    Pie,
233}
234
235#[derive(Serialize, Clone, Debug)]
236#[serde(rename_all = "lowercase")]
237pub enum Mode {
238    Lines,
239    Markers,
240    Text,
241    #[serde(rename = "lines+markers")]
242    LinesMarkers,
243    #[serde(rename = "lines+text")]
244    LinesText,
245    #[serde(rename = "markers+text")]
246    MarkersText,
247    #[serde(rename = "lines+markers+text")]
248    LinesMarkersText,
249    None,
250}
251
252#[derive(Serialize, Clone, Debug)]
253#[serde(rename_all = "lowercase")]
254pub enum Ticks {
255    Outside,
256    Inside,
257    #[serde(rename = "")]
258    None,
259}
260
261#[derive(Serialize, Clone, Debug)]
262pub enum Position {
263    #[serde(rename = "top left")]
264    TopLeft,
265    #[serde(rename = "top center")]
266    TopCenter,
267    #[serde(rename = "top right")]
268    TopRight,
269    #[serde(rename = "middle left")]
270    MiddleLeft,
271    #[serde(rename = "middle center")]
272    MiddleCenter,
273    #[serde(rename = "middle right")]
274    MiddleRight,
275    #[serde(rename = "bottom left")]
276    BottomLeft,
277    #[serde(rename = "bottom center")]
278    BottomCenter,
279    #[serde(rename = "bottom right")]
280    BottomRight,
281    #[serde(rename = "inside")]
282    Inside,
283    #[serde(rename = "outside")]
284    Outside,
285}
286
287#[derive(Serialize, Clone, Debug)]
288#[serde(rename_all = "kebab-case")]
289pub enum MarkerSymbol {
290    Circle,
291    CircleOpen,
292    CircleDot,
293    CircleOpenDot,
294    Square,
295    SquareOpen,
296    SquareDot,
297    SquareOpenDot,
298    Diamond,
299    DiamondOpen,
300    DiamondDot,
301    DiamondOpenDot,
302    Cross,
303    CrossOpen,
304    CrossDot,
305    CrossOpenDot,
306    X,
307    XOpen,
308    XDot,
309    XOpenDot,
310    TriangleUp,
311    TriangleUpOpen,
312    TriangleUpDot,
313    TriangleUpOpenDot,
314    TriangleDown,
315    TriangleDownOpen,
316    TriangleDownDot,
317    TriangleDownOpenDot,
318    TriangleLeft,
319    TriangleLeftOpen,
320    TriangleLeftDot,
321    TriangleLeftOpenDot,
322    TriangleRight,
323    TriangleRightOpen,
324    TriangleRightDot,
325    TriangleRightOpenDot,
326    #[serde(rename = "triangle-ne")]
327    TriangleNE,
328    #[serde(rename = "triangle-ne-open")]
329    TriangleNEOpen,
330    #[serde(rename = "triangle-ne-dot")]
331    TriangleNEDot,
332    #[serde(rename = "triangle-ne-open-dot")]
333    TriangleNEOpenDot,
334    #[serde(rename = "triangle-se")]
335    TriangleSE,
336    #[serde(rename = "triangle-se-open")]
337    TriangleSEOpen,
338    #[serde(rename = "triangle-se-dot")]
339    TriangleSEDot,
340    #[serde(rename = "triangle-se-open-dot")]
341    TriangleSEOpenDot,
342    #[serde(rename = "triangle-sw")]
343    TriangleSW,
344    #[serde(rename = "triangle-sw-open")]
345    TriangleSWOpen,
346    #[serde(rename = "triangle-sw-dot")]
347    TriangleSWDot,
348    #[serde(rename = "triangle-sw-open-dot")]
349    TriangleSWOpenDot,
350    #[serde(rename = "triangle-nw")]
351    TriangleNW,
352    #[serde(rename = "triangle-nw-open")]
353    TriangleNWOpen,
354    #[serde(rename = "triangle-nw-dot")]
355    TriangleNWDot,
356    #[serde(rename = "triangle-nw-open-dot")]
357    TriangleNWOpenDot,
358    Pentagon,
359    PentagonOpen,
360    PentagonDot,
361    PentagonOpenDot,
362    Hexagon,
363    HexagonOpen,
364    HexagonDot,
365    HexagonOpenDot,
366    Hexagon2,
367    Hexagon2Open,
368    Hexagon2Dot,
369    Hexagon2OpenDot,
370    Octagon,
371    OctagonOpen,
372    OctagonDot,
373    OctagonOpenDot,
374    Star,
375    StarOpen,
376    StarDot,
377    StarOpenDot,
378    Hexagram,
379    HexagramOpen,
380    HexagramDot,
381    HexagramOpenDot,
382    StarTriangleUp,
383    StarTriangleUpOpen,
384    StarTriangleUpDot,
385    StarTriangleUpOpenDot,
386    StarTriangleDown,
387    StarTriangleDownOpen,
388    StarTriangleDownDot,
389    StarTriangleDownOpenDot,
390    StarSquare,
391    StarSquareOpen,
392    StarSquareDot,
393    StarSquareOpenDot,
394    StarDiamond,
395    StarDiamondOpen,
396    StarDiamondDot,
397    StarDiamondOpenDot,
398    DiamondTall,
399    DiamondTallOpen,
400    DiamondTallDot,
401    DiamondTallOpenDot,
402    DiamondWide,
403    DiamondWideOpen,
404    DiamondWideDot,
405    DiamondWideOpenDot,
406    Hourglass,
407    HourglassOpen,
408    #[serde(rename = "bowtie")]
409    BowTie,
410    #[serde(rename = "bowtie-open")]
411    BowTieOpen,
412    CircleCross,
413    CircleCrossOpen,
414    CircleX,
415    CircleXOpen,
416    SquareCross,
417    SquareCrossOpen,
418    SquareX,
419    SquareXOpen,
420    DiamondCross,
421    DiamondCrossOpen,
422    DiamondX,
423    DiamondXOpen,
424    CrossThin,
425    CrossThinOpen,
426    XThin,
427    XThinOpen,
428    Asterisk,
429    AsteriskOpen,
430    Hash,
431    HashOpen,
432    HashDot,
433    HashOpenDot,
434    YUp,
435    YUpOpen,
436    YDown,
437    YDownOpen,
438    YLeft,
439    YLeftOpen,
440    YRight,
441    YRightOpen,
442    #[serde(rename = "line-ew")]
443    LineEW,
444    #[serde(rename = "line-ew-open")]
445    LineEWOpen,
446    #[serde(rename = "line-ns")]
447    LineNS,
448    #[serde(rename = "line-ns-open")]
449    LineNSOpen,
450    #[serde(rename = "line-ne")]
451    LineNE,
452    #[serde(rename = "line-ne-open")]
453    LineNEOpen,
454    #[serde(rename = "line-nw")]
455    LineNW,
456    #[serde(rename = "line-nw-open")]
457    LineNWOpen,
458}
459
460#[derive(Serialize, Clone, Debug)]
461#[serde(rename_all = "lowercase")]
462pub enum TickMode {
463    Auto,
464    Linear,
465    Array,
466}
467
468#[derive(Serialize, Clone, Debug)]
469#[serde(rename_all = "lowercase")]
470pub enum DashType {
471    Solid,
472    Dot,
473    Dash,
474    LongDash,
475    DashDot,
476    LongDashDot,
477}
478
479#[derive(Serialize, Clone, Debug)]
480pub struct ColorScaleElement(pub f64, pub String);
481
482#[derive(Serialize, Clone, Debug)]
483pub enum ColorScalePalette {
484    Greys,
485    YlGnBu,
486    Greens,
487    YlOrRd,
488    Bluered,
489    RdBu,
490    Reds,
491    Blues,
492    Picnic,
493    Rainbow,
494    Portland,
495    Jet,
496    Hot,
497    Blackbody,
498    Earth,
499    Electric,
500    Viridis,
501    Cividis,
502}
503
504#[derive(Serialize, Clone, Debug)]
505#[serde(untagged)]
506pub enum ColorScale {
507    Palette(ColorScalePalette),
508    Vector(Vec<ColorScaleElement>),
509}
510
511impl From<ColorScalePalette> for ColorScale {
512    fn from(src: ColorScalePalette) -> Self {
513        ColorScale::Palette(src)
514    }
515}
516
517#[derive(Serialize, Clone, Debug)]
518#[serde(rename_all = "lowercase")]
519pub enum LineShape {
520    Linear,
521    Spline,
522    Hv,
523    Vh,
524    Hvh,
525    Vhv,
526}
527
528#[serde_with::skip_serializing_none]
529#[derive(Serialize, Clone, Debug, FieldSetter)]
530pub struct Line {
531    width: Option<f64>,
532    shape: Option<LineShape>,
533    smoothing: Option<f64>,
534    dash: Option<DashType>,
535    simplify: Option<bool>,
536    color: Option<Box<dyn Color>>,
537    cauto: Option<bool>,
538    cmin: Option<f64>,
539    cmax: Option<f64>,
540    cmid: Option<f64>,
541    #[serde(rename = "colorscale")]
542    color_scale: Option<ColorScale>,
543    #[serde(rename = "autocolorscale")]
544    auto_color_scale: Option<bool>,
545    #[serde(rename = "reversescale")]
546    reverse_scale: Option<bool>,
547    #[serde(rename = "outliercolor")]
548    outlier_color: Option<Box<dyn Color>>,
549    #[serde(rename = "outlierwidth")]
550    outlier_width: Option<usize>,
551}
552
553impl Line {
554    pub fn new() -> Self {
555        Default::default()
556    }
557}
558
559#[derive(Serialize, Clone, Debug)]
560#[serde(rename_all = "lowercase")]
561pub enum GradientType {
562    Radial,
563    Horizontal,
564    Vertical,
565    None,
566}
567
568#[derive(Serialize, Clone, Debug)]
569#[serde(rename_all = "lowercase")]
570pub enum SizeMode {
571    Diameter,
572    Area,
573}
574
575#[derive(Serialize, Clone, Debug)]
576#[serde(rename_all = "lowercase")]
577pub enum ThicknessMode {
578    Fraction,
579    Pixels,
580}
581
582#[derive(Serialize, Clone, Debug)]
583#[serde(rename_all = "lowercase")]
584pub enum Anchor {
585    Auto,
586    Left,
587    Center,
588    Right,
589    Top,
590    Middle,
591    Bottom,
592}
593
594#[derive(Serialize, Clone, Debug)]
595#[serde(rename_all = "lowercase")]
596pub enum TextAnchor {
597    Start,
598    Middle,
599    End,
600}
601
602#[derive(Serialize, Clone, Debug)]
603#[serde(rename_all = "lowercase")]
604pub enum ExponentFormat {
605    None,
606    #[serde(rename = "e")]
607    SmallE,
608    #[serde(rename = "E")]
609    CapitalE,
610    Power,
611    #[serde(rename = "SI")]
612    SI,
613    #[serde(rename = "B")]
614    B,
615}
616
617#[derive(Serialize, Clone, Debug)]
618pub struct Gradient {
619    r#type: GradientType,
620    color: Dim<Box<dyn Color>>,
621}
622
623impl Gradient {
624    pub fn new<C: Color>(gradient_type: GradientType, color: C) -> Self {
625        Gradient {
626            r#type: gradient_type,
627            color: Dim::Scalar(Box::new(color)),
628        }
629    }
630
631    pub fn new_array<C: Color>(gradient_type: GradientType, colors: Vec<C>) -> Self {
632        Gradient {
633            r#type: gradient_type,
634            color: Dim::Vector(ColorArray(colors).into()),
635        }
636    }
637}
638
639#[serde_with::skip_serializing_none]
640#[derive(Serialize, Clone, Debug, FieldSetter)]
641pub struct TickFormatStop {
642    #[field_setter(default = "true")]
643    enabled: bool,
644    #[serde(rename = "dtickrange")]
645    dtick_range: Option<private::NumOrStringCollection>,
646    value: Option<String>,
647    name: Option<String>,
648    #[serde(rename = "templateitemname")]
649    template_item_name: Option<String>,
650}
651
652impl TickFormatStop {
653    pub fn new() -> Self {
654        TickFormatStop {
655            enabled: true,
656            ..Default::default()
657        }
658    }
659
660    pub fn enabled(mut self, enabled: bool) -> Self {
661        self.enabled = enabled;
662        self
663    }
664}
665
666#[derive(Serialize, Debug, Clone)]
667#[serde(rename_all = "lowercase")]
668pub enum Show {
669    All,
670    First,
671    Last,
672    None,
673}
674
675#[serde_with::skip_serializing_none]
676#[derive(Serialize, Clone, Debug, FieldSetter)]
677pub struct ColorBar {
678    #[serde(rename = "bgcolor")]
679    background_color: Option<Box<dyn Color>>,
680    #[serde(rename = "bordercolor")]
681    border_color: Option<Box<dyn Color>>,
682    #[serde(rename = "borderwidth")]
683    border_width: Option<usize>,
684    dtick: Option<f64>,
685    #[serde(rename = "exponentformat")]
686    exponent_format: Option<ExponentFormat>,
687    len: Option<usize>,
688    #[serde(rename = "lenmode")]
689    len_mode: Option<ThicknessMode>,
690    #[serde(rename = "nticks")]
691    n_ticks: Option<usize>,
692    orientation: Option<Orientation>,
693    #[serde(rename = "outlinecolor")]
694    outline_color: Option<Box<dyn Color>>,
695    #[serde(rename = "outlinewidth")]
696    outline_width: Option<usize>,
697    #[serde(rename = "separatethousands")]
698    separate_thousands: Option<bool>,
699    #[serde(rename = "showexponent")]
700    show_exponent: Option<Show>,
701    #[serde(rename = "showticklabels")]
702    show_tick_labels: Option<bool>,
703    #[serde(rename = "showtickprefix")]
704    show_tick_prefix: Option<Show>,
705    #[serde(rename = "showticksuffix")]
706    show_tick_suffix: Option<Show>,
707    thickness: Option<usize>,
708    #[serde(rename = "thicknessmode")]
709    thickness_mode: Option<ThicknessMode>,
710    #[serde(rename = "tickangle")]
711    tick_angle: Option<f64>,
712    #[serde(rename = "tickcolor")]
713    tick_color: Option<Box<dyn Color>>,
714    #[serde(rename = "tickfont")]
715    tick_font: Option<Font>,
716    #[serde(rename = "tickformat")]
717    tick_format: Option<String>,
718    #[serde(rename = "tickformatstops")]
719    tick_format_stops: Option<Vec<TickFormatStop>>,
720    #[serde(rename = "ticklen")]
721    tick_len: Option<usize>,
722    #[serde(rename = "tickmode")]
723    tick_mode: Option<TickMode>,
724    #[serde(rename = "tickprefix")]
725    tick_prefix: Option<String>,
726    #[serde(rename = "ticksuffix")]
727    tick_suffix: Option<String>,
728    #[serde(rename = "ticktext")]
729    tick_text: Option<Vec<String>>,
730    #[serde(rename = "tickvals")]
731    tick_vals: Option<Vec<f64>>,
732    #[serde(rename = "tickwidth")]
733    tick_width: Option<usize>,
734    tick0: Option<f64>,
735    ticks: Option<Ticks>,
736    title: Option<Title>,
737    x: Option<f64>,
738    #[serde(rename = "xanchor")]
739    x_anchor: Option<Anchor>,
740    #[serde(rename = "xpad")]
741    x_pad: Option<f64>,
742    y: Option<f64>,
743    #[serde(rename = "yanchor")]
744    y_anchor: Option<Anchor>,
745    #[serde(rename = "ypad")]
746    y_pad: Option<f64>,
747}
748
749impl ColorBar {
750    pub fn new() -> Self {
751        Default::default()
752    }
753}
754
755#[derive(Serialize, Debug, Clone)]
756#[serde(rename_all = "lowercase")]
757pub enum AxisSide {
758    Top,
759    Bottom,
760    Left,
761    Right,
762}
763
764#[derive(Serialize, Debug, Clone)]
765pub enum PatternShape {
766    #[serde(rename = "")]
767    None,
768    #[serde(rename = "-")]
769    HorizontalLine,
770    #[serde(rename = "|")]
771    VerticalLine,
772    #[serde(rename = "/")]
773    RightDiagonalLine,
774    #[serde(rename = "\\")]
775    LeftDiagonalLine,
776    #[serde(rename = "+")]
777    Cross,
778    #[serde(rename = "x")]
779    DiagonalCross,
780    #[serde(rename = ".")]
781    Dot,
782}
783
784#[derive(Serialize, Debug, Clone)]
785#[serde(rename_all = "lowercase")]
786pub enum PatternFillMode {
787    Replace,
788    Overlay,
789}
790
791#[serde_with::skip_serializing_none]
792#[derive(Serialize, Clone, Debug, FieldSetter)]
793pub struct Pattern {
794    shape: Option<Dim<PatternShape>>,
795    #[serde(rename = "fillmode")]
796    fill_mode: Option<PatternFillMode>,
797    #[serde(rename = "bgcolor")]
798    background_color: Option<Dim<Box<dyn Color>>>,
799    #[serde(rename = "fgcolor")]
800    foreground_color: Option<Dim<Box<dyn Color>>>,
801    #[serde(rename = "fgopacity")]
802    foreground_opacity: Option<f64>,
803    size: Option<Dim<f64>>,
804    solidity: Option<Dim<f64>>,
805}
806
807impl Pattern {
808    pub fn new() -> Self {
809        Default::default()
810    }
811}
812
813#[serde_with::skip_serializing_none]
814#[derive(Serialize, Clone, Debug, FieldSetter)]
815pub struct Marker {
816    symbol: Option<MarkerSymbol>,
817    opacity: Option<f64>,
818    size: Option<Dim<usize>>,
819    #[serde(rename = "maxdisplayed")]
820    max_displayed: Option<usize>,
821    #[serde(rename = "sizeref")]
822    size_ref: Option<usize>,
823    #[serde(rename = "sizemin")]
824    size_min: Option<usize>,
825    #[serde(rename = "sizemode")]
826    size_mode: Option<SizeMode>,
827    line: Option<Line>,
828    gradient: Option<Gradient>,
829    /// Marker option specific for Scatter and other common traces
830    color: Option<Dim<Box<dyn Color>>>,
831    /// Marker option specific for Pie charts to set the colors of the sectors
832    #[field_setter(skip)]
833    colors: Option<Vec<Box<dyn Color>>>,
834    cauto: Option<bool>,
835    cmin: Option<f64>,
836    cmax: Option<f64>,
837    cmid: Option<f64>,
838    #[serde(rename = "colorscale")]
839    color_scale: Option<ColorScale>,
840    #[serde(rename = "autocolorscale")]
841    auto_color_scale: Option<bool>,
842    #[serde(rename = "reversescale")]
843    reverse_scale: Option<bool>,
844    #[serde(rename = "showscale")]
845    show_scale: Option<bool>,
846    #[serde(rename = "colorbar")]
847    color_bar: Option<ColorBar>,
848    #[serde(rename = "outliercolor")]
849    outlier_color: Option<Box<dyn Color>>,
850    pattern: Option<Pattern>,
851}
852
853impl Marker {
854    pub fn new() -> Self {
855        Default::default()
856    }
857
858    pub fn colors<C: Color>(mut self, colors: Vec<C>) -> Self {
859        self.colors = Some(ColorArray(colors).into());
860        self
861    }
862}
863
864#[serde_with::skip_serializing_none]
865#[derive(Serialize, Clone, Debug, FieldSetter)]
866pub struct Font {
867    family: Option<String>,
868    size: Option<usize>,
869    color: Option<Box<dyn Color>>,
870}
871
872impl Font {
873    pub fn new() -> Self {
874        Default::default()
875    }
876}
877
878#[derive(Serialize, Clone, Debug)]
879#[serde(rename_all = "lowercase")]
880pub enum Side {
881    Right,
882    Top,
883    Bottom,
884    Left,
885    #[serde(rename = "top left")]
886    TopLeft,
887}
888
889#[derive(Serialize, Clone, Debug)]
890#[serde(rename_all = "lowercase")]
891pub enum Reference {
892    Container,
893    Paper,
894}
895
896#[derive(Serialize, Clone, Debug)]
897pub struct Pad {
898    t: usize,
899    b: usize,
900    l: usize,
901}
902
903impl Pad {
904    pub fn new(t: usize, b: usize, l: usize) -> Self {
905        Pad { t, b, l }
906    }
907}
908
909#[serde_with::skip_serializing_none]
910#[derive(Serialize, Clone, Debug, FieldSetter)]
911pub struct Title {
912    text: Option<String>,
913    font: Option<Font>,
914    side: Option<Side>,
915    #[serde(rename = "xref")]
916    x_ref: Option<Reference>,
917    #[serde(rename = "yref")]
918    y_ref: Option<Reference>,
919    x: Option<f64>,
920    y: Option<f64>,
921    #[serde(rename = "xanchor")]
922    x_anchor: Option<Anchor>,
923    #[serde(rename = "yanchor")]
924    y_anchor: Option<Anchor>,
925    pad: Option<Pad>,
926}
927
928impl From<&str> for Title {
929    fn from(title: &str) -> Self {
930        Title::with_text(title)
931    }
932}
933
934impl From<String> for Title {
935    fn from(value: String) -> Self {
936        Title::with_text(value)
937    }
938}
939
940impl From<&String> for Title {
941    fn from(value: &String) -> Self {
942        Title::with_text(value)
943    }
944}
945
946impl Title {
947    pub fn new() -> Self {
948        Default::default()
949    }
950
951    pub fn with_text<S: Into<String>>(text: S) -> Self {
952        Title {
953            text: Some(text.into()),
954            ..Default::default()
955        }
956    }
957}
958
959#[serde_with::skip_serializing_none]
960#[derive(Serialize, Clone, Debug, FieldSetter)]
961pub struct Label {
962    #[serde(rename = "bgcolor")]
963    background_color: Option<Box<dyn Color>>,
964    #[serde(rename = "bordercolor")]
965    border_color: Option<Box<dyn Color>>,
966    font: Option<Font>,
967    align: Option<String>,
968    #[serde(rename = "namelength")]
969    name_length: Option<Dim<i32>>,
970}
971
972impl Label {
973    pub fn new() -> Self {
974        Default::default()
975    }
976}
977
978#[derive(Serialize, Clone, Debug, Default)]
979#[serde(rename_all = "lowercase")]
980pub enum ErrorType {
981    #[default]
982    Percent,
983    Constant,
984    #[serde(rename = "sqrt")]
985    SquareRoot,
986    Data,
987}
988
989#[serde_with::skip_serializing_none]
990#[derive(Serialize, Clone, Debug, FieldSetter)]
991pub struct ErrorData {
992    #[field_setter(default = "ErrorType::Percent")]
993    r#type: ErrorType,
994    array: Option<Vec<f64>>,
995    visible: Option<bool>,
996    symmetric: Option<bool>,
997    #[serde(rename = "arrayminus")]
998    array_minus: Option<Vec<f64>>,
999    value: Option<f64>,
1000    #[serde(rename = "valueminus")]
1001    value_minus: Option<f64>,
1002    #[serde(rename = "traceref")]
1003    trace_ref: Option<usize>,
1004    #[serde(rename = "tracerefminus")]
1005    trace_ref_minus: Option<usize>,
1006    copy_ystyle: Option<bool>,
1007    color: Option<Box<dyn Color>>,
1008    thickness: Option<f64>,
1009    width: Option<usize>,
1010}
1011
1012impl ErrorData {
1013    pub fn new(error_type: ErrorType) -> Self {
1014        ErrorData {
1015            r#type: error_type,
1016            ..Default::default()
1017        }
1018    }
1019}
1020
1021#[derive(Serialize, Clone, Debug)]
1022#[serde(rename_all = "lowercase")]
1023pub enum HoverOn {
1024    Points,
1025    Fills,
1026    #[serde(rename = "points+fills")]
1027    PointsAndFills,
1028}
1029
1030#[cfg(test)]
1031mod tests {
1032    use serde_json::{json, to_value};
1033
1034    use super::*;
1035    use crate::color::NamedColor;
1036
1037    #[test]
1038    fn serialize_domain() {
1039        let domain = Domain::new().column(0).row(0).x(&[0., 1.]).y(&[0., 1.]);
1040        let expected = json!({
1041            "column": 0,
1042            "row": 0,
1043            "x": [0.0, 1.0],
1044            "y": [0.0, 1.0],
1045        });
1046
1047        assert_eq!(to_value(domain).unwrap(), expected);
1048    }
1049
1050    #[test]
1051    fn serialize_direction() {
1052        // TODO: I think `Direction` would be better as a struct, with `fillcolor` and
1053        // `line` attributes
1054        let inc = Direction::Increasing { line: Line::new() };
1055        let expected = json!({"line": {}});
1056        assert_eq!(to_value(inc).unwrap(), expected);
1057
1058        let dec = Direction::Decreasing { line: Line::new() };
1059        let expected = json!({"line": {}});
1060        assert_eq!(to_value(dec).unwrap(), expected);
1061    }
1062
1063    #[test]
1064    fn serialize_hover_info() {
1065        assert_eq!(to_value(HoverInfo::X).unwrap(), json!("x"));
1066        assert_eq!(to_value(HoverInfo::Y).unwrap(), json!("y"));
1067        assert_eq!(to_value(HoverInfo::Z).unwrap(), json!("z"));
1068        assert_eq!(to_value(HoverInfo::XAndY).unwrap(), json!("x+y"));
1069        assert_eq!(to_value(HoverInfo::XAndZ).unwrap(), json!("x+z"));
1070        assert_eq!(to_value(HoverInfo::YAndZ).unwrap(), json!("y+z"));
1071        assert_eq!(to_value(HoverInfo::XAndYAndZ).unwrap(), json!("x+y+z"));
1072        assert_eq!(to_value(HoverInfo::Text).unwrap(), json!("text"));
1073        assert_eq!(to_value(HoverInfo::Name).unwrap(), json!("name"));
1074        assert_eq!(to_value(HoverInfo::All).unwrap(), json!("all"));
1075        assert_eq!(to_value(HoverInfo::None).unwrap(), json!("none"));
1076        assert_eq!(to_value(HoverInfo::Skip).unwrap(), json!("skip"));
1077    }
1078
1079    #[test]
1080    fn serialize_text_position() {
1081        assert_eq!(to_value(TextPosition::Inside).unwrap(), json!("inside"));
1082        assert_eq!(to_value(TextPosition::Outside).unwrap(), json!("outside"));
1083        assert_eq!(to_value(TextPosition::Auto).unwrap(), json!("auto"));
1084        assert_eq!(to_value(TextPosition::None).unwrap(), json!("none"));
1085    }
1086
1087    #[test]
1088    fn serialize_constrain_text() {
1089        assert_eq!(to_value(ConstrainText::Inside).unwrap(), json!("inside"));
1090        assert_eq!(to_value(ConstrainText::Outside).unwrap(), json!("outside"));
1091        assert_eq!(to_value(ConstrainText::Both).unwrap(), json!("both"));
1092        assert_eq!(to_value(ConstrainText::None).unwrap(), json!("none"));
1093    }
1094
1095    #[test]
1096    #[rustfmt::skip]
1097    fn serialize_orientation() {
1098        assert_eq!(to_value(Orientation::Vertical).unwrap(), json!("v"));
1099        assert_eq!(to_value(Orientation::Horizontal).unwrap(), json!("h"));
1100    }
1101
1102    #[test]
1103    fn serialize_fill() {
1104        assert_eq!(to_value(Fill::ToZeroY).unwrap(), json!("tozeroy"));
1105        assert_eq!(to_value(Fill::ToZeroX).unwrap(), json!("tozerox"));
1106        assert_eq!(to_value(Fill::ToNextY).unwrap(), json!("tonexty"));
1107        assert_eq!(to_value(Fill::ToNextX).unwrap(), json!("tonextx"));
1108        assert_eq!(to_value(Fill::ToSelf).unwrap(), json!("toself"));
1109        assert_eq!(to_value(Fill::ToNext).unwrap(), json!("tonext"));
1110        assert_eq!(to_value(Fill::None).unwrap(), json!("none"));
1111    }
1112
1113    #[test]
1114    fn serialize_calendar() {
1115        assert_eq!(to_value(Calendar::Gregorian).unwrap(), json!("gregorian"));
1116        assert_eq!(to_value(Calendar::Chinese).unwrap(), json!("chinese"));
1117        assert_eq!(to_value(Calendar::Coptic).unwrap(), json!("coptic"));
1118        assert_eq!(to_value(Calendar::DiscWorld).unwrap(), json!("discworld"));
1119        assert_eq!(to_value(Calendar::Ethiopian).unwrap(), json!("ethiopian"));
1120        assert_eq!(to_value(Calendar::Hebrew).unwrap(), json!("hebrew"));
1121        assert_eq!(to_value(Calendar::Islamic).unwrap(), json!("islamic"));
1122        assert_eq!(to_value(Calendar::Julian).unwrap(), json!("julian"));
1123        assert_eq!(to_value(Calendar::Mayan).unwrap(), json!("mayan"));
1124        assert_eq!(to_value(Calendar::Nanakshahi).unwrap(), json!("nanakshahi"));
1125        assert_eq!(to_value(Calendar::Nepali).unwrap(), json!("nepali"));
1126        assert_eq!(to_value(Calendar::Persian).unwrap(), json!("persian"));
1127        assert_eq!(to_value(Calendar::Jalali).unwrap(), json!("jalali"));
1128        assert_eq!(to_value(Calendar::Taiwan).unwrap(), json!("taiwan"));
1129        assert_eq!(to_value(Calendar::Thai).unwrap(), json!("thai"));
1130        assert_eq!(to_value(Calendar::Ummalqura).unwrap(), json!("ummalqura"));
1131    }
1132
1133    #[test]
1134    fn serialize_dim() {
1135        assert_eq!(to_value(Dim::Scalar(0)).unwrap(), json!(0));
1136        assert_eq!(to_value(Dim::Vector(vec![0])).unwrap(), json!([0]));
1137    }
1138
1139    #[test]
1140    #[rustfmt::skip]
1141    fn serialize_plot_type() {
1142        assert_eq!(to_value(PlotType::Scatter).unwrap(), json!("scatter"));
1143        assert_eq!(to_value(PlotType::ScatterGL).unwrap(), json!("scattergl"));
1144        assert_eq!(to_value(PlotType::Scatter3D).unwrap(), json!("scatter3d"));
1145        assert_eq!(to_value(PlotType::ScatterGeo).unwrap(), json!("scattergeo"));
1146        assert_eq!(to_value(PlotType::ScatterPolar).unwrap(), json!("scatterpolar"));
1147        assert_eq!(to_value(PlotType::ScatterPolarGL).unwrap(), json!("scatterpolargl"));
1148        assert_eq!(to_value(PlotType::Bar).unwrap(), json!("bar"));
1149        assert_eq!(to_value(PlotType::Box).unwrap(), json!("box"));
1150        assert_eq!(to_value(PlotType::Candlestick).unwrap(), json!("candlestick"));
1151        assert_eq!(to_value(PlotType::Contour).unwrap(), json!("contour"));
1152        assert_eq!(to_value(PlotType::HeatMap).unwrap(), json!("heatmap"));
1153        assert_eq!(to_value(PlotType::Histogram).unwrap(), json!("histogram"));
1154        assert_eq!(to_value(PlotType::Histogram2dContour).unwrap(), json!("histogram2dcontour"));
1155        assert_eq!(to_value(PlotType::Ohlc).unwrap(), json!("ohlc"));
1156        assert_eq!(to_value(PlotType::Sankey).unwrap(), json!("sankey"));
1157        assert_eq!(to_value(PlotType::Surface).unwrap(), json!("surface"));
1158    }
1159
1160    #[test]
1161    #[rustfmt::skip]
1162    fn serialize_mode() {
1163        assert_eq!(to_value(Mode::Lines).unwrap(), json!("lines"));
1164        assert_eq!(to_value(Mode::Markers).unwrap(), json!("markers"));
1165        assert_eq!(to_value(Mode::Text).unwrap(), json!("text"));
1166        assert_eq!(to_value(Mode::LinesMarkers).unwrap(), json!("lines+markers"));
1167        assert_eq!(to_value(Mode::LinesText).unwrap(), json!("lines+text"));
1168        assert_eq!(to_value(Mode::MarkersText).unwrap(), json!("markers+text"));
1169        assert_eq!(to_value(Mode::LinesMarkersText).unwrap(), json!("lines+markers+text"));
1170        assert_eq!(to_value(Mode::None).unwrap(), json!("none"));
1171    }
1172
1173    #[test]
1174    #[rustfmt::skip]
1175    fn serialize_axis_side() {
1176        assert_eq!(to_value(AxisSide::Left).unwrap(), json!("left"));
1177        assert_eq!(to_value(AxisSide::Top).unwrap(), json!("top"));
1178        assert_eq!(to_value(AxisSide::Right).unwrap(), json!("right"));
1179        assert_eq!(to_value(AxisSide::Bottom).unwrap(), json!("bottom"));
1180    }
1181
1182    #[test]
1183    #[rustfmt::skip]
1184    fn serialize_position() {
1185        assert_eq!(to_value(Position::TopLeft).unwrap(), json!("top left"));
1186        assert_eq!(to_value(Position::TopCenter).unwrap(), json!("top center"));
1187        assert_eq!(to_value(Position::TopRight).unwrap(), json!("top right"));
1188        assert_eq!(to_value(Position::MiddleLeft).unwrap(), json!("middle left"));
1189        assert_eq!(to_value(Position::MiddleCenter).unwrap(), json!("middle center"));
1190        assert_eq!(to_value(Position::MiddleRight).unwrap(), json!("middle right"));
1191        assert_eq!(to_value(Position::BottomLeft).unwrap(), json!("bottom left"));
1192        assert_eq!(to_value(Position::BottomCenter).unwrap(), json!("bottom center"));
1193        assert_eq!(to_value(Position::BottomRight).unwrap(), json!("bottom right"));
1194    }
1195
1196    #[test]
1197    fn serialize_ticks() {
1198        assert_eq!(to_value(Ticks::Outside).unwrap(), json!("outside"));
1199        assert_eq!(to_value(Ticks::Inside).unwrap(), json!("inside"));
1200        assert_eq!(to_value(Ticks::None).unwrap(), json!(""));
1201    }
1202
1203    #[test]
1204    fn serialize_show() {
1205        assert_eq!(to_value(Show::All).unwrap(), json!("all"));
1206        assert_eq!(to_value(Show::First).unwrap(), json!("first"));
1207        assert_eq!(to_value(Show::Last).unwrap(), json!("last"));
1208        assert_eq!(to_value(Show::None).unwrap(), json!("none"));
1209    }
1210
1211    #[test]
1212    fn serialize_default_color_bar() {
1213        let color_bar = ColorBar::new();
1214        let expected = json!({});
1215
1216        assert_eq!(to_value(color_bar).unwrap(), expected);
1217    }
1218
1219    #[test]
1220    fn serialize_color_bar() {
1221        let color_bar = ColorBar::new()
1222            .background_color("#123456")
1223            .border_color("#123456")
1224            .border_width(19)
1225            .dtick(1.0)
1226            .exponent_format(ExponentFormat::CapitalE)
1227            .len(99)
1228            .len_mode(ThicknessMode::Pixels)
1229            .n_ticks(500)
1230            .orientation(Orientation::Horizontal)
1231            .outline_color("#789456")
1232            .outline_width(7)
1233            .separate_thousands(true)
1234            .show_exponent(Show::All)
1235            .show_tick_labels(true)
1236            .show_tick_prefix(Show::First)
1237            .show_tick_suffix(Show::Last)
1238            .thickness(5)
1239            .thickness_mode(ThicknessMode::Fraction)
1240            .tick_angle(90.0)
1241            .tick_color("#777999")
1242            .tick_font(Font::new())
1243            .tick_format("tick_format")
1244            .tick_format_stops(vec![TickFormatStop::new()])
1245            .tick_len(1)
1246            .tick_mode(TickMode::Auto)
1247            .tick_prefix("prefix")
1248            .tick_suffix("suffix")
1249            .tick_text(vec!["txt"])
1250            .tick_vals(vec![1.0, 2.0])
1251            .tick_width(55)
1252            .tick0(0.0)
1253            .ticks(Ticks::Outside)
1254            .title(Title::new())
1255            .x(5.0)
1256            .x_anchor(Anchor::Bottom)
1257            .x_pad(2.2)
1258            .y(1.0)
1259            .y_anchor(Anchor::Auto)
1260            .y_pad(8.8);
1261
1262        let expected = json!({
1263            "bgcolor": "#123456",
1264            "bordercolor": "#123456",
1265            "borderwidth": 19,
1266            "dtick": 1.0,
1267            "exponentformat": "E",
1268            "len": 99,
1269            "lenmode": "pixels",
1270            "nticks": 500,
1271            "orientation": "h",
1272            "outlinecolor": "#789456",
1273            "outlinewidth": 7,
1274            "separatethousands": true,
1275            "showexponent": "all",
1276            "showticklabels": true,
1277            "showtickprefix": "first",
1278            "showticksuffix": "last",
1279            "thickness": 5,
1280            "thicknessmode": "fraction",
1281            "tickangle": 90.0,
1282            "tickcolor": "#777999",
1283            "tickfont": {},
1284            "tickformat": "tick_format",
1285            "tickformatstops": [{"enabled": true}],
1286            "ticklen": 1,
1287            "tickmode": "auto",
1288            "tickprefix": "prefix",
1289            "ticksuffix": "suffix",
1290            "ticktext": ["txt"],
1291            "tickvals": [1.0, 2.0],
1292            "tickwidth": 55,
1293            "tick0": 0.0,
1294            "ticks": "outside",
1295            "title": {},
1296            "x": 5.0,
1297            "xanchor": "bottom",
1298            "xpad": 2.2,
1299            "y": 1.0,
1300            "yanchor": "auto",
1301            "ypad": 8.8
1302        });
1303
1304        assert_eq!(to_value(color_bar).unwrap(), expected);
1305    }
1306
1307    #[test]
1308    #[rustfmt::skip]
1309    fn serialize_marker_symbol() {
1310        assert_eq!(to_value(MarkerSymbol::Circle).unwrap(), json!("circle"));
1311        assert_eq!(to_value(MarkerSymbol::CircleOpen).unwrap(), json!("circle-open"));
1312        assert_eq!(to_value(MarkerSymbol::CircleDot).unwrap(), json!("circle-dot"));
1313        assert_eq!(to_value(MarkerSymbol::CircleOpenDot).unwrap(), json!("circle-open-dot"));
1314        assert_eq!(to_value(MarkerSymbol::Square).unwrap(), json!("square"));
1315        assert_eq!(to_value(MarkerSymbol::SquareOpen).unwrap(), json!("square-open"));
1316        assert_eq!(to_value(MarkerSymbol::SquareDot).unwrap(), json!("square-dot"));
1317        assert_eq!(to_value(MarkerSymbol::SquareOpenDot).unwrap(), json!("square-open-dot"));
1318        assert_eq!(to_value(MarkerSymbol::Diamond).unwrap(), json!("diamond"));
1319        assert_eq!(to_value(MarkerSymbol::DiamondOpen).unwrap(), json!("diamond-open"));
1320        assert_eq!(to_value(MarkerSymbol::DiamondDot).unwrap(), json!("diamond-dot"));
1321        assert_eq!(to_value(MarkerSymbol::DiamondOpenDot).unwrap(), json!("diamond-open-dot"));
1322        assert_eq!(to_value(MarkerSymbol::Cross).unwrap(), json!("cross"));
1323        assert_eq!(to_value(MarkerSymbol::CrossOpen).unwrap(), json!("cross-open"));
1324        assert_eq!(to_value(MarkerSymbol::CrossDot).unwrap(), json!("cross-dot"));
1325        assert_eq!(to_value(MarkerSymbol::CrossOpenDot).unwrap(), json!("cross-open-dot"));
1326        assert_eq!(to_value(MarkerSymbol::X).unwrap(), json!("x"));
1327        assert_eq!(to_value(MarkerSymbol::XOpen).unwrap(), json!("x-open"));
1328        assert_eq!(to_value(MarkerSymbol::XDot).unwrap(), json!("x-dot"));
1329        assert_eq!(to_value(MarkerSymbol::XOpenDot).unwrap(), json!("x-open-dot"));
1330        assert_eq!(to_value(MarkerSymbol::TriangleUp).unwrap(), json!("triangle-up"));
1331        assert_eq!(to_value(MarkerSymbol::TriangleUpOpen).unwrap(), json!("triangle-up-open"));
1332        assert_eq!(to_value(MarkerSymbol::TriangleUpDot).unwrap(), json!("triangle-up-dot"));
1333        assert_eq!(to_value(MarkerSymbol::TriangleUpOpenDot).unwrap(), json!("triangle-up-open-dot"));
1334        assert_eq!(to_value(MarkerSymbol::TriangleDown).unwrap(), json!("triangle-down"));
1335        assert_eq!(to_value(MarkerSymbol::TriangleDownOpen).unwrap(), json!("triangle-down-open"));
1336        assert_eq!(to_value(MarkerSymbol::TriangleDownDot).unwrap(), json!("triangle-down-dot"));
1337        assert_eq!(to_value(MarkerSymbol::TriangleDownOpenDot).unwrap(), json!("triangle-down-open-dot"));
1338        assert_eq!(to_value(MarkerSymbol::TriangleLeft).unwrap(), json!("triangle-left"));
1339        assert_eq!(to_value(MarkerSymbol::TriangleLeftOpen).unwrap(), json!("triangle-left-open"));
1340        assert_eq!(to_value(MarkerSymbol::TriangleLeftDot).unwrap(), json!("triangle-left-dot"));
1341        assert_eq!(to_value(MarkerSymbol::TriangleLeftOpenDot).unwrap(), json!("triangle-left-open-dot"));
1342        assert_eq!(to_value(MarkerSymbol::TriangleRight).unwrap(), json!("triangle-right"));
1343        assert_eq!(to_value(MarkerSymbol::TriangleRightOpen).unwrap(), json!("triangle-right-open"));
1344        assert_eq!(to_value(MarkerSymbol::TriangleRightDot).unwrap(), json!("triangle-right-dot"));
1345        assert_eq!(to_value(MarkerSymbol::TriangleRightOpenDot).unwrap(), json!("triangle-right-open-dot"));
1346        assert_eq!(to_value(MarkerSymbol::TriangleNE).unwrap(), json!("triangle-ne"));
1347        assert_eq!(to_value(MarkerSymbol::TriangleNEOpen).unwrap(), json!("triangle-ne-open"));
1348        assert_eq!(to_value(MarkerSymbol::TriangleNEDot).unwrap(), json!("triangle-ne-dot"));
1349        assert_eq!(to_value(MarkerSymbol::TriangleNEOpenDot).unwrap(), json!("triangle-ne-open-dot"));
1350        assert_eq!(to_value(MarkerSymbol::TriangleSE).unwrap(), json!("triangle-se"));
1351        assert_eq!(to_value(MarkerSymbol::TriangleSEOpen).unwrap(), json!("triangle-se-open"));
1352        assert_eq!(to_value(MarkerSymbol::TriangleSEDot).unwrap(), json!("triangle-se-dot"));
1353        assert_eq!(to_value(MarkerSymbol::TriangleSEOpenDot).unwrap(), json!("triangle-se-open-dot"));
1354        assert_eq!(to_value(MarkerSymbol::TriangleSW).unwrap(), json!("triangle-sw"));
1355        assert_eq!(to_value(MarkerSymbol::TriangleSWOpen).unwrap(), json!("triangle-sw-open"));
1356        assert_eq!(to_value(MarkerSymbol::TriangleSWDot).unwrap(), json!("triangle-sw-dot"));
1357        assert_eq!(to_value(MarkerSymbol::TriangleSWOpenDot).unwrap(), json!("triangle-sw-open-dot"));
1358        assert_eq!(to_value(MarkerSymbol::TriangleNW).unwrap(), json!("triangle-nw"));
1359        assert_eq!(to_value(MarkerSymbol::TriangleNWOpen).unwrap(), json!("triangle-nw-open"));
1360        assert_eq!(to_value(MarkerSymbol::TriangleNWDot).unwrap(), json!("triangle-nw-dot"));
1361        assert_eq!(to_value(MarkerSymbol::TriangleNWOpenDot).unwrap(), json!("triangle-nw-open-dot"));
1362        assert_eq!(to_value(MarkerSymbol::Pentagon).unwrap(), json!("pentagon"));
1363        assert_eq!(to_value(MarkerSymbol::PentagonOpen).unwrap(), json!("pentagon-open"));
1364        assert_eq!(to_value(MarkerSymbol::PentagonDot).unwrap(), json!("pentagon-dot"));
1365        assert_eq!(to_value(MarkerSymbol::PentagonOpenDot).unwrap(), json!("pentagon-open-dot"));
1366        assert_eq!(to_value(MarkerSymbol::Hexagon).unwrap(), json!("hexagon"));
1367        assert_eq!(to_value(MarkerSymbol::HexagonOpen).unwrap(), json!("hexagon-open"));
1368        assert_eq!(to_value(MarkerSymbol::HexagonDot).unwrap(), json!("hexagon-dot"));
1369        assert_eq!(to_value(MarkerSymbol::HexagonOpenDot).unwrap(), json!("hexagon-open-dot"));
1370        assert_eq!(to_value(MarkerSymbol::Hexagon2).unwrap(), json!("hexagon2"));
1371        assert_eq!(to_value(MarkerSymbol::Hexagon2Open).unwrap(), json!("hexagon2-open"));
1372        assert_eq!(to_value(MarkerSymbol::Hexagon2Dot).unwrap(), json!("hexagon2-dot"));
1373        assert_eq!(to_value(MarkerSymbol::Hexagon2OpenDot).unwrap(), json!("hexagon2-open-dot"));
1374        assert_eq!(to_value(MarkerSymbol::Octagon).unwrap(), json!("octagon"));
1375        assert_eq!(to_value(MarkerSymbol::OctagonOpen).unwrap(), json!("octagon-open"));
1376        assert_eq!(to_value(MarkerSymbol::OctagonDot).unwrap(), json!("octagon-dot"));
1377        assert_eq!(to_value(MarkerSymbol::OctagonOpenDot).unwrap(), json!("octagon-open-dot"));
1378        assert_eq!(to_value(MarkerSymbol::Star).unwrap(), json!("star"));
1379        assert_eq!(to_value(MarkerSymbol::StarOpen).unwrap(), json!("star-open"));
1380        assert_eq!(to_value(MarkerSymbol::StarDot).unwrap(), json!("star-dot"));
1381        assert_eq!(to_value(MarkerSymbol::StarOpenDot).unwrap(), json!("star-open-dot"));
1382        assert_eq!(to_value(MarkerSymbol::Hexagram).unwrap(), json!("hexagram"));
1383        assert_eq!(to_value(MarkerSymbol::HexagramOpen).unwrap(), json!("hexagram-open"));
1384        assert_eq!(to_value(MarkerSymbol::HexagramDot).unwrap(), json!("hexagram-dot"));
1385        assert_eq!(to_value(MarkerSymbol::HexagramOpenDot).unwrap(), json!("hexagram-open-dot"));
1386        assert_eq!(to_value(MarkerSymbol::StarTriangleUp).unwrap(), json!("star-triangle-up"));
1387        assert_eq!(to_value(MarkerSymbol::StarTriangleUpOpen).unwrap(), json!("star-triangle-up-open"));
1388        assert_eq!(to_value(MarkerSymbol::StarTriangleUpDot).unwrap(), json!("star-triangle-up-dot"));
1389        assert_eq!(to_value(MarkerSymbol::StarTriangleUpOpenDot).unwrap(), json!("star-triangle-up-open-dot"));
1390        assert_eq!(to_value(MarkerSymbol::StarTriangleDown).unwrap(), json!("star-triangle-down"));
1391        assert_eq!(to_value(MarkerSymbol::StarTriangleDownOpen).unwrap(), json!("star-triangle-down-open"));
1392        assert_eq!(to_value(MarkerSymbol::StarTriangleDownDot).unwrap(), json!("star-triangle-down-dot"));
1393        assert_eq!(to_value(MarkerSymbol::StarTriangleDownOpenDot).unwrap(), json!("star-triangle-down-open-dot"));
1394        assert_eq!(to_value(MarkerSymbol::StarSquare).unwrap(), json!("star-square"));
1395        assert_eq!(to_value(MarkerSymbol::StarSquareOpen).unwrap(), json!("star-square-open"));
1396        assert_eq!(to_value(MarkerSymbol::StarSquareDot).unwrap(), json!("star-square-dot"));
1397        assert_eq!(to_value(MarkerSymbol::StarSquareOpenDot).unwrap(), json!("star-square-open-dot"));
1398        assert_eq!(to_value(MarkerSymbol::StarDiamond).unwrap(), json!("star-diamond"));
1399        assert_eq!(to_value(MarkerSymbol::StarDiamondOpen).unwrap(), json!("star-diamond-open"));
1400        assert_eq!(to_value(MarkerSymbol::StarDiamondDot).unwrap(), json!("star-diamond-dot"));
1401        assert_eq!(to_value(MarkerSymbol::StarDiamondOpenDot).unwrap(), json!("star-diamond-open-dot"));
1402        assert_eq!(to_value(MarkerSymbol::DiamondTall).unwrap(), json!("diamond-tall"));
1403        assert_eq!(to_value(MarkerSymbol::DiamondTallOpen).unwrap(), json!("diamond-tall-open"));
1404        assert_eq!(to_value(MarkerSymbol::DiamondTallDot).unwrap(), json!("diamond-tall-dot"));
1405        assert_eq!(to_value(MarkerSymbol::DiamondTallOpenDot).unwrap(), json!("diamond-tall-open-dot"));
1406        assert_eq!(to_value(MarkerSymbol::DiamondWide).unwrap(), json!("diamond-wide"));
1407        assert_eq!(to_value(MarkerSymbol::DiamondWideOpen).unwrap(), json!("diamond-wide-open"));
1408        assert_eq!(to_value(MarkerSymbol::DiamondWideDot).unwrap(), json!("diamond-wide-dot"));
1409        assert_eq!(to_value(MarkerSymbol::DiamondWideOpenDot).unwrap(), json!("diamond-wide-open-dot"));
1410        assert_eq!(to_value(MarkerSymbol::Hourglass).unwrap(), json!("hourglass"));
1411        assert_eq!(to_value(MarkerSymbol::HourglassOpen).unwrap(), json!("hourglass-open"));
1412        assert_eq!(to_value(MarkerSymbol::BowTie).unwrap(), json!("bowtie"));
1413        assert_eq!(to_value(MarkerSymbol::BowTieOpen).unwrap(), json!("bowtie-open"));
1414        assert_eq!(to_value(MarkerSymbol::CircleCross).unwrap(), json!("circle-cross"));
1415        assert_eq!(to_value(MarkerSymbol::CircleCrossOpen).unwrap(), json!("circle-cross-open"));
1416        assert_eq!(to_value(MarkerSymbol::CircleX).unwrap(), json!("circle-x"));
1417        assert_eq!(to_value(MarkerSymbol::CircleXOpen).unwrap(), json!("circle-x-open"));
1418        assert_eq!(to_value(MarkerSymbol::SquareCross).unwrap(), json!("square-cross"));
1419        assert_eq!(to_value(MarkerSymbol::SquareCrossOpen).unwrap(), json!("square-cross-open"));
1420        assert_eq!(to_value(MarkerSymbol::SquareX).unwrap(), json!("square-x"));
1421        assert_eq!(to_value(MarkerSymbol::SquareXOpen).unwrap(), json!("square-x-open"));
1422        assert_eq!(to_value(MarkerSymbol::DiamondCross).unwrap(), json!("diamond-cross"));
1423        assert_eq!(to_value(MarkerSymbol::DiamondCrossOpen).unwrap(), json!("diamond-cross-open"));
1424        assert_eq!(to_value(MarkerSymbol::DiamondX).unwrap(), json!("diamond-x"));
1425        assert_eq!(to_value(MarkerSymbol::DiamondXOpen).unwrap(), json!("diamond-x-open"));
1426        assert_eq!(to_value(MarkerSymbol::CrossThin).unwrap(), json!("cross-thin"));
1427        assert_eq!(to_value(MarkerSymbol::CrossThinOpen).unwrap(), json!("cross-thin-open"));
1428        assert_eq!(to_value(MarkerSymbol::XThin).unwrap(), json!("x-thin"));
1429        assert_eq!(to_value(MarkerSymbol::XThinOpen).unwrap(), json!("x-thin-open"));
1430        assert_eq!(to_value(MarkerSymbol::Asterisk).unwrap(), json!("asterisk"));
1431        assert_eq!(to_value(MarkerSymbol::AsteriskOpen).unwrap(), json!("asterisk-open"));
1432        assert_eq!(to_value(MarkerSymbol::Hash).unwrap(), json!("hash"));
1433        assert_eq!(to_value(MarkerSymbol::HashOpen).unwrap(), json!("hash-open"));
1434        assert_eq!(to_value(MarkerSymbol::HashDot).unwrap(), json!("hash-dot"));
1435        assert_eq!(to_value(MarkerSymbol::HashOpenDot).unwrap(), json!("hash-open-dot"));
1436        assert_eq!(to_value(MarkerSymbol::YUp).unwrap(), json!("y-up"));
1437        assert_eq!(to_value(MarkerSymbol::YUpOpen).unwrap(), json!("y-up-open"));
1438        assert_eq!(to_value(MarkerSymbol::YDown).unwrap(), json!("y-down"));
1439        assert_eq!(to_value(MarkerSymbol::YDownOpen).unwrap(), json!("y-down-open"));
1440        assert_eq!(to_value(MarkerSymbol::YLeft).unwrap(), json!("y-left"));
1441        assert_eq!(to_value(MarkerSymbol::YLeftOpen).unwrap(), json!("y-left-open"));
1442        assert_eq!(to_value(MarkerSymbol::YRight).unwrap(), json!("y-right"));
1443        assert_eq!(to_value(MarkerSymbol::YRightOpen).unwrap(), json!("y-right-open"));
1444        assert_eq!(to_value(MarkerSymbol::LineEW).unwrap(), json!("line-ew"));
1445        assert_eq!(to_value(MarkerSymbol::LineEWOpen).unwrap(), json!("line-ew-open"));
1446        assert_eq!(to_value(MarkerSymbol::LineNS).unwrap(), json!("line-ns"));
1447        assert_eq!(to_value(MarkerSymbol::LineNSOpen).unwrap(), json!("line-ns-open"));
1448        assert_eq!(to_value(MarkerSymbol::LineNE).unwrap(), json!("line-ne"));
1449        assert_eq!(to_value(MarkerSymbol::LineNEOpen).unwrap(), json!("line-ne-open"));
1450        assert_eq!(to_value(MarkerSymbol::LineNW).unwrap(), json!("line-nw"));
1451        assert_eq!(to_value(MarkerSymbol::LineNWOpen).unwrap(), json!("line-nw-open"));
1452    }
1453
1454    #[test]
1455    fn serialize_tick_mode() {
1456        assert_eq!(to_value(TickMode::Auto).unwrap(), json!("auto"));
1457        assert_eq!(to_value(TickMode::Linear).unwrap(), json!("linear"));
1458        assert_eq!(to_value(TickMode::Array).unwrap(), json!("array"));
1459    }
1460
1461    #[test]
1462    #[rustfmt::skip]
1463    fn serialize_dash_type() {
1464        assert_eq!(to_value(DashType::Solid).unwrap(), json!("solid"));
1465        assert_eq!(to_value(DashType::Dot).unwrap(), json!("dot"));
1466        assert_eq!(to_value(DashType::Dash).unwrap(), json!("dash"));
1467        assert_eq!(to_value(DashType::LongDash).unwrap(), json!("longdash"));
1468        assert_eq!(to_value(DashType::DashDot).unwrap(), json!("dashdot"));
1469        assert_eq!(to_value(DashType::LongDashDot).unwrap(), json!("longdashdot"));
1470    }
1471
1472    #[test]
1473    #[rustfmt::skip]
1474    fn serialize_color_scale_element() {
1475        assert_eq!(to_value(ColorScaleElement(0., "red".to_string())).unwrap(), json!([0.0, "red"]));
1476    }
1477
1478    #[test]
1479    #[rustfmt::skip]
1480    fn serialize_color_scale_palette() {
1481        assert_eq!(to_value(ColorScalePalette::Greys).unwrap(), json!("Greys"));
1482        assert_eq!(to_value(ColorScalePalette::YlGnBu).unwrap(), json!("YlGnBu"));
1483        assert_eq!(to_value(ColorScalePalette::Greens).unwrap(), json!("Greens"));
1484        assert_eq!(to_value(ColorScalePalette::YlOrRd).unwrap(), json!("YlOrRd"));
1485        assert_eq!(to_value(ColorScalePalette::Bluered).unwrap(), json!("Bluered"));
1486        assert_eq!(to_value(ColorScalePalette::RdBu).unwrap(), json!("RdBu"));
1487        assert_eq!(to_value(ColorScalePalette::Reds).unwrap(), json!("Reds"));
1488        assert_eq!(to_value(ColorScalePalette::Blues).unwrap(), json!("Blues"));
1489        assert_eq!(to_value(ColorScalePalette::Picnic).unwrap(), json!("Picnic"));
1490        assert_eq!(to_value(ColorScalePalette::Rainbow).unwrap(), json!("Rainbow"));
1491        assert_eq!(to_value(ColorScalePalette::Portland).unwrap(), json!("Portland"));
1492        assert_eq!(to_value(ColorScalePalette::Jet).unwrap(), json!("Jet"));
1493        assert_eq!(to_value(ColorScalePalette::Hot).unwrap(), json!("Hot"));
1494        assert_eq!(to_value(ColorScalePalette::Blackbody).unwrap(), json!("Blackbody"));
1495        assert_eq!(to_value(ColorScalePalette::Earth).unwrap(), json!("Earth"));
1496        assert_eq!(to_value(ColorScalePalette::Electric).unwrap(), json!("Electric"));
1497        assert_eq!(to_value(ColorScalePalette::Viridis).unwrap(), json!("Viridis"));
1498        assert_eq!(to_value(ColorScalePalette::Cividis).unwrap(), json!("Cividis"));
1499    }
1500
1501    #[test]
1502    fn serialize_color_scale() {
1503        assert_eq!(
1504            to_value(ColorScale::Palette(ColorScalePalette::Greys)).unwrap(),
1505            json!("Greys")
1506        );
1507        assert_eq!(
1508            to_value(ColorScale::Vector(vec![ColorScaleElement(
1509                0.0,
1510                "red".to_string()
1511            )]))
1512            .unwrap(),
1513            json!([[0.0, "red"]])
1514        );
1515    }
1516
1517    #[test]
1518    fn serialize_line_shape() {
1519        assert_eq!(to_value(LineShape::Linear).unwrap(), json!("linear"));
1520        assert_eq!(to_value(LineShape::Spline).unwrap(), json!("spline"));
1521        assert_eq!(to_value(LineShape::Hv).unwrap(), json!("hv"));
1522        assert_eq!(to_value(LineShape::Vh).unwrap(), json!("vh"));
1523        assert_eq!(to_value(LineShape::Hvh).unwrap(), json!("hvh"));
1524        assert_eq!(to_value(LineShape::Vhv).unwrap(), json!("vhv"));
1525    }
1526
1527    #[test]
1528    fn serialize_line() {
1529        let line = Line::new()
1530            .width(0.1)
1531            .shape(LineShape::Linear)
1532            .smoothing(1.0)
1533            .dash(DashType::Dash)
1534            .simplify(true)
1535            .color("#FFFFFF")
1536            .cauto(true)
1537            .cmin(0.0)
1538            .cmax(1.0)
1539            .cmid(0.5)
1540            .color_scale(ColorScale::Palette(ColorScalePalette::Greys))
1541            .auto_color_scale(true)
1542            .reverse_scale(true)
1543            .outlier_color("#111111")
1544            .outlier_width(1);
1545
1546        let expected = json!({
1547            "width": 0.1,
1548            "shape": "linear",
1549            "smoothing": 1.0,
1550            "dash": "dash",
1551            "simplify": true,
1552            "color": "#FFFFFF",
1553            "cauto": true,
1554            "cmin": 0.0,
1555            "cmax": 1.0,
1556            "cmid": 0.5,
1557            "colorscale": "Greys",
1558            "autocolorscale": true,
1559            "reversescale": true,
1560            "outliercolor": "#111111",
1561            "outlierwidth": 1
1562        });
1563
1564        assert_eq!(to_value(line).unwrap(), expected);
1565    }
1566
1567    #[test]
1568    #[rustfmt::skip]
1569    fn serialize_gradient_type() {
1570        assert_eq!(to_value(GradientType::Radial).unwrap(), json!("radial"));
1571        assert_eq!(to_value(GradientType::Horizontal).unwrap(), json!("horizontal"));
1572        assert_eq!(to_value(GradientType::Vertical).unwrap(), json!("vertical"));
1573        assert_eq!(to_value(GradientType::None).unwrap(), json!("none"));
1574    }
1575
1576    #[test]
1577    fn serialize_size_mode() {
1578        assert_eq!(to_value(SizeMode::Diameter).unwrap(), json!("diameter"));
1579        assert_eq!(to_value(SizeMode::Area).unwrap(), json!("area"));
1580    }
1581
1582    #[test]
1583    #[rustfmt::skip]
1584    fn serialize_thickness_mode() {
1585        assert_eq!(to_value(ThicknessMode::Fraction).unwrap(), json!("fraction"));
1586        assert_eq!(to_value(ThicknessMode::Pixels).unwrap(), json!("pixels"));
1587    }
1588
1589    #[test]
1590    fn serialize_anchor() {
1591        assert_eq!(to_value(Anchor::Auto).unwrap(), json!("auto"));
1592        assert_eq!(to_value(Anchor::Left).unwrap(), json!("left"));
1593        assert_eq!(to_value(Anchor::Center).unwrap(), json!("center"));
1594        assert_eq!(to_value(Anchor::Right).unwrap(), json!("right"));
1595        assert_eq!(to_value(Anchor::Top).unwrap(), json!("top"));
1596        assert_eq!(to_value(Anchor::Middle).unwrap(), json!("middle"));
1597        assert_eq!(to_value(Anchor::Bottom).unwrap(), json!("bottom"));
1598    }
1599
1600    #[test]
1601    fn serialize_text_anchor() {
1602        assert_eq!(to_value(TextAnchor::Start).unwrap(), json!("start"));
1603        assert_eq!(to_value(TextAnchor::Middle).unwrap(), json!("middle"));
1604        assert_eq!(to_value(TextAnchor::End).unwrap(), json!("end"));
1605    }
1606
1607    #[test]
1608    fn serialize_exponent_format() {
1609        assert_eq!(to_value(ExponentFormat::None).unwrap(), json!("none"));
1610        assert_eq!(to_value(ExponentFormat::SmallE).unwrap(), json!("e"));
1611        assert_eq!(to_value(ExponentFormat::CapitalE).unwrap(), json!("E"));
1612        assert_eq!(to_value(ExponentFormat::Power).unwrap(), json!("power"));
1613        assert_eq!(to_value(ExponentFormat::SI).unwrap(), json!("SI"));
1614        assert_eq!(to_value(ExponentFormat::B).unwrap(), json!("B"));
1615    }
1616
1617    #[test]
1618    #[rustfmt::skip]
1619    fn serialize_gradient() {
1620        let gradient = Gradient::new(GradientType::Horizontal, "#FFFFFF");
1621        let expected = json!({"color": "#FFFFFF", "type": "horizontal"});
1622        assert_eq!(to_value(gradient).unwrap(), expected);
1623
1624        let gradient = Gradient::new_array(GradientType::Horizontal, vec!["#FFFFFF"]);
1625        let expected = json!({"color": ["#FFFFFF"], "type": "horizontal"});
1626        assert_eq!(to_value(gradient).unwrap(), expected);
1627    }
1628
1629    #[test]
1630    fn serialize_tick_format_stop_default() {
1631        let tick_format_stop = TickFormatStop::new();
1632        let expected = json!({"enabled": true});
1633        assert_eq!(to_value(tick_format_stop).unwrap(), expected);
1634    }
1635
1636    #[test]
1637    fn serialize_tick_format_stop() {
1638        let tick_format_stop = TickFormatStop::new()
1639            .enabled(false)
1640            .dtick_range(vec![0.0, 1.0])
1641            .value("value")
1642            .name("name")
1643            .template_item_name("template_item_name");
1644        let expected = json!({
1645            "enabled": false,
1646            "dtickrange": [0.0, 1.0],
1647            "value": "value",
1648            "name": "name",
1649            "templateitemname": "template_item_name"
1650        });
1651        assert_eq!(to_value(tick_format_stop).unwrap(), expected);
1652    }
1653
1654    #[test]
1655    fn serialize_pattern_shape() {
1656        assert_eq!(to_value(PatternShape::None).unwrap(), json!(""));
1657        assert_eq!(to_value(PatternShape::HorizontalLine).unwrap(), json!("-"));
1658        assert_eq!(to_value(PatternShape::VerticalLine).unwrap(), json!("|"));
1659        assert_eq!(
1660            to_value(PatternShape::RightDiagonalLine).unwrap(),
1661            json!("/")
1662        );
1663        assert_eq!(
1664            to_value(PatternShape::LeftDiagonalLine).unwrap(),
1665            json!("\\")
1666        );
1667        assert_eq!(to_value(PatternShape::Cross).unwrap(), json!("+"));
1668        assert_eq!(to_value(PatternShape::DiagonalCross).unwrap(), json!("x"));
1669        assert_eq!(to_value(PatternShape::Dot).unwrap(), json!("."));
1670    }
1671
1672    #[test]
1673    fn serialize_pattern_fill_mode() {
1674        assert_eq!(
1675            to_value(PatternFillMode::Replace).unwrap(),
1676            json!("replace")
1677        );
1678        assert_eq!(
1679            to_value(PatternFillMode::Overlay).unwrap(),
1680            json!("overlay")
1681        );
1682    }
1683
1684    #[test]
1685    fn serialize_pattern() {
1686        let pattern = Pattern::new()
1687            .shape_array(vec![
1688                PatternShape::HorizontalLine,
1689                PatternShape::VerticalLine,
1690            ])
1691            .fill_mode(PatternFillMode::Overlay)
1692            .background_color_array(vec![NamedColor::Black, NamedColor::Blue])
1693            .foreground_color_array(vec![NamedColor::Red, NamedColor::Green])
1694            .foreground_opacity(0.9)
1695            .size_array(vec![10.0, 20.0])
1696            .solidity_array(vec![0.1, 0.2]);
1697
1698        let expected = json!({
1699            "shape": ["-", "|"],
1700            "fillmode": "overlay",
1701            "bgcolor": ["black", "blue"],
1702            "fgcolor": ["red", "green"],
1703            "fgopacity": 0.9,
1704            "size": [10.0, 20.0],
1705            "solidity": [0.1, 0.2]
1706        });
1707
1708        assert_eq!(to_value(pattern).unwrap(), expected);
1709    }
1710
1711    #[test]
1712    fn serialize_marker() {
1713        let marker = Marker::new()
1714            .symbol(MarkerSymbol::Circle)
1715            .opacity(0.1)
1716            .size(1)
1717            .max_displayed(5)
1718            .size_ref(5)
1719            .size_min(1)
1720            .size_mode(SizeMode::Area)
1721            .line(Line::new())
1722            .gradient(Gradient::new(GradientType::Radial, "#FFFFFF"))
1723            .color(NamedColor::Blue)
1724            .colors(vec![NamedColor::Black, NamedColor::Blue])
1725            .color_array(vec![NamedColor::Black, NamedColor::Blue])
1726            .cauto(true)
1727            .cmin(0.0)
1728            .cmax(1.0)
1729            .cmid(0.5)
1730            .color_scale(ColorScale::Palette(ColorScalePalette::Earth))
1731            .auto_color_scale(true)
1732            .reverse_scale(true)
1733            .show_scale(true)
1734            .color_bar(ColorBar::new())
1735            .outlier_color("#FFFFFF")
1736            .pattern(
1737                Pattern::new()
1738                    .shape(PatternShape::Cross)
1739                    .foreground_color(NamedColor::Red)
1740                    .size(10.0),
1741            );
1742
1743        let expected = json!({
1744            "symbol": "circle",
1745            "opacity": 0.1,
1746            "size": 1,
1747            "maxdisplayed": 5,
1748            "sizeref": 5,
1749            "sizemin": 1,
1750            "sizemode": "area",
1751            "line": {},
1752            "gradient": {"type": "radial", "color": "#FFFFFF"},
1753            "color": ["black", "blue"],
1754            "colors": ["black", "blue"],
1755            "colorbar": {},
1756            "cauto": true,
1757            "cmin": 0.0,
1758            "cmax": 1.0,
1759            "cmid": 0.5,
1760            "colorscale": "Earth",
1761            "autocolorscale": true,
1762            "reversescale": true,
1763            "showscale": true,
1764            "outliercolor": "#FFFFFF",
1765            "pattern": {
1766                "shape": "+",
1767                "fgcolor": "red",
1768                "size": 10.0
1769            }
1770        });
1771
1772        assert_eq!(to_value(marker).unwrap(), expected);
1773    }
1774
1775    #[test]
1776    fn serialize_font() {
1777        let font = Font::new().family("family").size(100).color("#FFFFFF");
1778        let expected = json!({
1779            "family": "family",
1780            "size": 100,
1781            "color": "#FFFFFF"
1782        });
1783
1784        assert_eq!(to_value(font).unwrap(), expected);
1785    }
1786
1787    #[test]
1788    fn serialize_side() {
1789        assert_eq!(to_value(Side::Right).unwrap(), json!("right"));
1790        assert_eq!(to_value(Side::Top).unwrap(), json!("top"));
1791        assert_eq!(to_value(Side::Bottom).unwrap(), json!("bottom"));
1792        assert_eq!(to_value(Side::Left).unwrap(), json!("left"));
1793        assert_eq!(to_value(Side::TopLeft).unwrap(), json!("top left"));
1794    }
1795
1796    #[test]
1797    fn serialize_reference() {
1798        assert_eq!(to_value(Reference::Container).unwrap(), json!("container"));
1799        assert_eq!(to_value(Reference::Paper).unwrap(), json!("paper"));
1800    }
1801
1802    #[test]
1803    #[rustfmt::skip]
1804    fn serialize_legend_group_title() {
1805        assert_eq!(to_value(LegendGroupTitle::new()).unwrap(), json!({}));
1806        assert_eq!(to_value(LegendGroupTitle::with_text("title_str").font(Font::default())).unwrap(), json!({"font": {}, "text": "title_str"}));
1807        assert_eq!(to_value(LegendGroupTitle::from(String::from("title_string"))).unwrap(), json!({"text" : "title_string"}));
1808        assert_eq!(to_value(LegendGroupTitle::from(&String::from("title_string"))).unwrap(), json!({"text" : "title_string"}));
1809    }
1810
1811    #[test]
1812    fn serialize_pad() {
1813        let pad = Pad::new(1, 2, 3);
1814        let expected = json!({
1815            "t": 1,
1816            "b": 2,
1817            "l": 3
1818        });
1819
1820        assert_eq!(to_value(pad).unwrap(), expected);
1821    }
1822
1823    #[test]
1824    fn serialize_title() {
1825        let title = Title::with_text("title")
1826            .font(Font::new())
1827            .side(Side::Top)
1828            .x_ref(Reference::Paper)
1829            .y_ref(Reference::Paper)
1830            .x(0.5)
1831            .y(0.5)
1832            .x_anchor(Anchor::Auto)
1833            .y_anchor(Anchor::Auto)
1834            .pad(Pad::new(0, 0, 0));
1835        let expected = json!({
1836            "text": "title",
1837            "font": {},
1838            "side": "top",
1839            "xref": "paper",
1840            "yref": "paper",
1841            "x": 0.5,
1842            "y": 0.5,
1843            "xanchor": "auto",
1844            "yanchor": "auto",
1845            "pad": {"t": 0, "b": 0, "l": 0}
1846        });
1847
1848        assert_eq!(to_value(title).unwrap(), expected);
1849    }
1850
1851    #[test]
1852    fn serialize_title_from_str() {
1853        let title = Title::from("from");
1854        let expected = json!({"text": "from"});
1855
1856        assert_eq!(to_value(title).unwrap(), expected);
1857
1858        let title: Title = "into".into();
1859        let expected = json!({"text": "into"});
1860
1861        assert_eq!(to_value(title).unwrap(), expected);
1862    }
1863
1864    #[test]
1865    fn serialize_label() {
1866        let label = Label::new()
1867            .background_color("#FFFFFF")
1868            .border_color("#000000")
1869            .font(Font::new())
1870            .align("something")
1871            .name_length_array(vec![5, 10])
1872            .name_length(6);
1873        let expected = json!({
1874            "bgcolor": "#FFFFFF",
1875            "bordercolor": "#000000",
1876            "font": {},
1877            "align": "something",
1878            "namelength": 6,
1879        });
1880
1881        assert_eq!(to_value(label).unwrap(), expected);
1882    }
1883
1884    #[test]
1885    fn serialize_error_type() {
1886        assert_eq!(to_value(ErrorType::Percent).unwrap(), json!("percent"));
1887        assert_eq!(to_value(ErrorType::Constant).unwrap(), json!("constant"));
1888        assert_eq!(to_value(ErrorType::SquareRoot).unwrap(), json!("sqrt"));
1889        assert_eq!(to_value(ErrorType::Data).unwrap(), json!("data"));
1890    }
1891
1892    #[test]
1893    fn serialize_error_type_default() {
1894        assert_eq!(to_value(ErrorType::default()).unwrap(), json!("percent"));
1895    }
1896
1897    #[test]
1898    fn serialize_error_data() {
1899        let error_data = ErrorData::new(ErrorType::Constant)
1900            .array(vec![0.1, 0.2])
1901            .visible(true)
1902            .symmetric(false)
1903            .array_minus(vec![0.05, 0.1])
1904            .value(5.0)
1905            .value_minus(2.5)
1906            .trace_ref(1)
1907            .trace_ref_minus(1)
1908            .copy_ystyle(true)
1909            .color("#AAAAAA")
1910            .thickness(2.0)
1911            .width(5);
1912        let expected = json!({
1913            "type": "constant",
1914            "array": [0.1, 0.2],
1915            "visible": true,
1916            "symmetric": false,
1917            "arrayminus": [0.05, 0.1],
1918            "value": 5.0,
1919            "valueminus": 2.5,
1920            "traceref": 1,
1921            "tracerefminus": 1,
1922            "copy_ystyle": true,
1923            "color": "#AAAAAA",
1924            "thickness": 2.0,
1925            "width": 5,
1926        });
1927
1928        assert_eq!(to_value(error_data).unwrap(), expected)
1929    }
1930
1931    #[test]
1932    fn serialize_visible() {
1933        assert_eq!(to_value(Visible::True).unwrap(), json!(true));
1934        assert_eq!(to_value(Visible::False).unwrap(), json!(false));
1935        assert_eq!(to_value(Visible::LegendOnly).unwrap(), json!("legendonly"));
1936    }
1937
1938    #[test]
1939    #[rustfmt::skip]
1940    fn serialize_hover_on() {
1941        assert_eq!(to_value(HoverOn::Points).unwrap(), json!("points"));
1942        assert_eq!(to_value(HoverOn::Fills).unwrap(), json!("fills"));
1943        assert_eq!(to_value(HoverOn::PointsAndFills).unwrap(), json!("points+fills"));
1944
1945    }
1946
1947    #[test]
1948    fn serialize_slider_anchor() {
1949        assert_eq!(to_value(Anchor::Auto).unwrap(), json!("auto"));
1950        assert_eq!(to_value(Anchor::Left).unwrap(), json!("left"));
1951        assert_eq!(to_value(Anchor::Center).unwrap(), json!("center"));
1952        assert_eq!(to_value(Anchor::Right).unwrap(), json!("right"));
1953        assert_eq!(to_value(Anchor::Top).unwrap(), json!("top"));
1954        assert_eq!(to_value(Anchor::Middle).unwrap(), json!("middle"));
1955        assert_eq!(to_value(Anchor::Bottom).unwrap(), json!("bottom"));
1956    }
1957
1958    #[test]
1959    #[allow(clippy::needless_borrows_for_generic_args)]
1960    fn title_method_can_take_string() {
1961        ColorBar::new().title("Title");
1962        ColorBar::new().title(String::from("Title"));
1963        ColorBar::new().title(&String::from("Title"));
1964        ColorBar::new().title(Title::with_text("Title"));
1965    }
1966}