mdbook_plotly/preprocessor/handlers/code_handler/
plot_obj_parser.rs1pub use super::until;
2use super::until::Map;
3use crate::translate;
4use anyhow::{Result, anyhow};
5use plotly::{
6 Configuration, Layout, Plot, Trace,
7 common::color::Rgb,
8 layout::{Legend, Margin},
9};
10use serde_json::Value;
11
12pub mod bar_parser;
13pub mod density_mapbox_parser;
14pub mod histogram_parser;
15pub mod image_parser;
16pub mod pie_parser;
17pub mod scatter_geo_parser;
18pub mod scatter_mapbox_parser;
19pub mod scatter_parser;
20
21pub fn parse(plot_obj: &mut Value) -> Result<Plot> {
22 let mut plot = Plot::new();
23
24 let map = if let Some(map_obj) = plot_obj.get_mut("map") {
25 serde_json::from_value::<Map>(map_obj.take())?
26 } else {
27 Map::new()
28 };
29
30 if let Some(config_obj) = plot_obj.get_mut("config")
31 && config_obj.is_object()
32 {
33 let config = parse_config_obj(config_obj, &map)?;
34 plot.set_configuration(config);
35 }
36
37 if let Some(layout_obj) = plot_obj.get_mut("layout")
38 && layout_obj.is_object()
39 {
40 let layout = parse_layout_obj(layout_obj, &map)?;
41 plot.set_layout(layout);
42 }
43
44 if let Some(data_list) = plot_obj.get_mut("data")
45 && data_list.is_array()
46 {
47 for data in data_list.as_array_mut().unwrap_or_else(|| unreachable!()) {
48 let trace = parse_data_obj(data, &map)?;
49 plot.add_trace(trace);
50 }
51 }
52
53 Ok(plot)
54}
55
56fn parse_config_obj(config_obj: &mut Value, map: &Map) -> Result<Configuration> {
57 let config = translate! {
58 Configuration::new(),
59 config_obj,
60 map,
61 (static_plot, bool),
62 (typeset_math, bool),
63 (editable, bool),
64 (autosizable, bool),
65 (responsive, bool),
69 (fill_frame, bool),
70 (frame_margins, f64),
71 (scroll_zoom, bool),
72 (show_axis_drag_handles, bool),
73 (show_axis_range_entry_boxes, bool),
74 (show_tips, bool),
75 (show_link, bool),
76 (send_data, bool),
77 }?;
78
79 Ok(config)
80}
81
82fn parse_layout_obj(layout_obj: &mut Value, map: &Map) -> Result<Layout> {
83 let layout = translate! {
84 Layout::new(),
85 layout_obj,
86 map,
87 (title, String),
88 (show_legend, bool),
89 (height, usize),
90 (width, usize),
91 (colorway, Vec<Rgb>),
92 (plot_background_color, Rgb),
93 (separators, String),
94 }?;
95
96 let layout = if let Some(legend_obj) = layout_obj.get_mut("legend")
97 && legend_obj.is_object()
98 {
99 let legend = translate! {
100 Legend::new(),
101 legend_obj,
102 map,
103 (background_color, Rgb),
104 (border_color, Rgb),
105 (border_width, usize),
106 (x, f64),
107 (y, f64),
108 (trace_group_gap, usize),
109 (title, String),
110 }?;
111 layout.legend(legend)
112 } else {
113 layout
114 };
115
116 let layout = if let Some(margin_obj) = layout_obj.get_mut("margin")
117 && margin_obj.is_object()
118 {
119 let margin = translate! {
120 Margin::new(),
121 margin_obj,
122 map,
123 (left, usize),
124 (right, usize),
125 (top, usize),
126 (bottom, usize),
127 (pad, usize),
128 (auto_expand, bool)
129 }?;
130 layout.margin(margin)
131 } else {
132 layout
133 };
134
135 Ok(layout)
136}
137
138pub fn parse_data_obj(data_obj: &mut Value, map: &Map) -> Result<Box<dyn Trace>> {
139 let data_type = data_obj
140 .get("type")
141 .and_then(|v| v.as_str())
142 .ok_or_else(|| anyhow!("`type` must be a string"))?;
143 match data_type {
144 "bar" => bar_parser::parse_bar_data(data_obj, map).map(|v| v as Box<dyn Trace>),
145 "density_mapbox" => density_mapbox_parser::parse_density_mapbox_data(data_obj, map)
146 .map(|v| v as Box<dyn Trace>),
147 "histogram" => {
148 histogram_parser::parse_histogram_data(data_obj, map).map(|v| v as Box<dyn Trace>)
149 }
150 "image" => image_parser::parse_image_data(data_obj, map).map(|v| v as Box<dyn Trace>),
151 "pie" => pie_parser::parse_pie_data(data_obj, map).map(|v| v as Box<dyn Trace>),
152 "scatter" => scatter_parser::parse_scatter_data(data_obj, map).map(|v| v as Box<dyn Trace>),
153 "scatter_geo" => {
154 scatter_geo_parser::parse_scatter_geo_data(data_obj, map).map(|v| v as Box<dyn Trace>)
155 }
156 "scatter_mapbox" => scatter_mapbox_parser::parse_scatter_mapbox_data(data_obj, map)
157 .map(|v| v as Box<dyn Trace>),
158 unexpected => Err(anyhow!("{} isn't a type", unexpected)),
159 }
160}