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