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