ironlab_ir/axes.rs
1//! Axes, their coordinate axes, projection and legend.
2
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6use crate::artist::Artist;
7use crate::ids::NodeId;
8use crate::text::Text;
9
10/// A plotting region placed in one or more cells of the figure's tile layout.
11#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
12pub struct Axes {
13 /// The node identifier of the axes, unique within the figure.
14 pub id: NodeId,
15 /// The cells of the figure's tile layout that the axes occupies.
16 pub cell: Cell,
17 /// Whether the axes is two- or three-dimensional, with its 3D view.
18 pub projection: Projection,
19 /// The title drawn above the axes.
20 pub title: Option<Text>,
21 /// The horizontal axis in 2D, or the first horizontal axis in 3D.
22 pub x: Axis,
23 /// The vertical axis in 2D, or the second horizontal axis in 3D.
24 pub y: Axis,
25 /// The vertical axis in 3D; ignored by 2D axes.
26 pub z: Axis,
27 /// Whether the full outline of the plot box is drawn, rather than only the
28 /// edges that carry tick labels.
29 #[serde(rename = "box")]
30 pub box_: bool,
31 /// The colormap used by colormapped artists in this axes.
32 pub colormap: ColormapName,
33 /// The data values mapped to the first and last colours of the colormap.
34 pub clim: Limits,
35 /// The legend, or `null` when no legend is shown.
36 pub legend: Option<Legend>,
37 /// The artists drawn in this axes, in drawing order.
38 pub artists: Vec<Artist>,
39}
40
41impl Default for Axes {
42 fn default() -> Self {
43 Self {
44 id: NodeId::default(),
45 cell: Cell::default(),
46 projection: Projection::TwoD,
47 title: None,
48 x: Axis::default(),
49 y: Axis::default(),
50 z: Axis::default(),
51 box_: true,
52 colormap: ColormapName::Viridis,
53 clim: Limits::Auto,
54 legend: None,
55 artists: Vec::new(),
56 }
57 }
58}
59
60/// A rectangular block of cells in the figure's tile layout.
61///
62/// Rows and columns are numbered from zero, starting at the top-left cell.
63#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
64pub struct Cell {
65 /// The zero-based index of the top row occupied.
66 pub row: u32,
67 /// The zero-based index of the leftmost column occupied.
68 pub col: u32,
69 /// The number of rows occupied; at least one.
70 pub row_span: u32,
71 /// The number of columns occupied; at least one.
72 pub col_span: u32,
73}
74
75impl Default for Cell {
76 fn default() -> Self {
77 Self {
78 row: 0,
79 col: 0,
80 row_span: 1,
81 col_span: 1,
82 }
83 }
84}
85
86/// The projection of an axes.
87#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
88#[serde(tag = "type", rename_all = "snake_case")]
89pub enum Projection {
90 /// A two-dimensional Cartesian axes.
91 #[default]
92 TwoD,
93 /// A three-dimensional Cartesian axes viewed through an orthographic camera.
94 ThreeD {
95 /// The camera view.
96 view3d: View3d,
97 },
98}
99
100/// The orthographic camera view of a three-dimensional axes.
101#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, JsonSchema)]
102pub struct View3d {
103 /// The rotation about the vertical axis in degrees, measured counterclockwise
104 /// from the negative y axis when viewed from above.
105 pub azimuth_deg: f64,
106 /// The angle of the view direction above the x-y plane in degrees, from -90 to 90.
107 pub elevation_deg: f64,
108 /// The magnification of the projected box, where 1 fits the box to the plot area.
109 pub zoom: f64,
110 /// The horizontal offset of the projected box as a fraction of the plot area's
111 /// width, increasing to the right.
112 pub pan_x: f64,
113 /// The vertical offset of the projected box as a fraction of the plot area's
114 /// height, increasing downwards.
115 pub pan_y: f64,
116}
117
118impl Default for View3d {
119 fn default() -> Self {
120 Self {
121 azimuth_deg: -37.5,
122 elevation_deg: 30.0,
123 zoom: 1.0,
124 pan_x: 0.0,
125 pan_y: 0.0,
126 }
127 }
128}
129
130/// One coordinate axis of an axes.
131#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
132pub struct Axis {
133 /// The axis label.
134 pub label: Option<Text>,
135 /// The mapping from data values to positions along the axis.
136 pub scale: Scale,
137 /// The range of data values shown along the axis.
138 pub limits: Limits,
139 /// Whether grid lines are drawn at the major ticks of this axis.
140 pub grid: bool,
141}
142
143/// The mapping from data values to positions along an axis.
144#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
145#[serde(rename_all = "snake_case")]
146pub enum Scale {
147 /// Positions are proportional to values.
148 #[default]
149 Linear,
150 /// Positions are proportional to the base-10 logarithm of values; non-positive
151 /// values are not drawn.
152 Log,
153}
154
155/// A range of data values.
156#[derive(Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
157#[serde(tag = "type", rename_all = "snake_case")]
158pub enum Limits {
159 /// The range is computed from the data. Axis limits are rounded outwards to ticks, except where only the grid of a
160 /// contour or surface sets the x or y range, which then ends exactly at the grid.
161 #[default]
162 Auto,
163 /// The range is fixed.
164 Manual {
165 /// The lower bound of the range.
166 min: f64,
167 /// The upper bound of the range.
168 max: f64,
169 },
170}
171
172/// The name of a colormap.
173#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
174#[serde(rename_all = "snake_case")]
175pub enum ColormapName {
176 /// The perceptually uniform blue–green–yellow colormap.
177 #[default]
178 Viridis,
179 /// The perceptually uniform blue–yellow colormap designed for colour-vision
180 /// deficiency.
181 Cividis,
182 /// The perceptually uniform black–purple–cream colormap.
183 Magma,
184 /// The perceptually uniform black–red–yellow colormap.
185 Inferno,
186 /// The perceptually uniform blue–purple–yellow colormap.
187 Plasma,
188 /// The diverging blue–white–red colormap.
189 Coolwarm,
190 /// The linear black–white colormap.
191 Gray,
192}
193
194/// A legend listing the artists of an axes that have a display name.
195#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
196pub struct Legend {
197 /// Where the legend is placed inside the plot area.
198 pub location: LegendLocation,
199 /// Whether the legend is drawn with a background and outline.
200 pub boxed: bool,
201}
202
203impl Default for Legend {
204 fn default() -> Self {
205 Self {
206 location: LegendLocation::NorthEast,
207 boxed: true,
208 }
209 }
210}
211
212/// The placement of a legend inside the plot area.
213#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
214#[serde(rename_all = "snake_case")]
215pub enum LegendLocation {
216 /// The top-right corner.
217 #[default]
218 NorthEast,
219 /// The top-left corner.
220 NorthWest,
221 /// The bottom-right corner.
222 SouthEast,
223 /// The bottom-left corner.
224 SouthWest,
225 /// The centre of the top edge.
226 North,
227 /// The centre of the bottom edge.
228 South,
229 /// The centre of the right edge.
230 East,
231 /// The centre of the left edge.
232 West,
233 /// The corner that overlaps the least data.
234 Best,
235}