optionstratlib/visualization/model.rs
1//! Centralised Graph trait powered by `plotly.rs`
2//!
3//! This supersedes the old `plotters` spaghetti and now offers:
4//!
5//! * **Single‑series 2‑D** (`Series2D`)
6//! * **Multi‑series 2‑D** (`MultiSeries2D`)
7//! * **3‑D surfaces** (`Surface3D`)
8//!
9//! Out of the box you get PNG export, HTML export, inline browser view,
10//! sensible error handling and a growing bag of style knobs (titles,
11//! axis labels, colour schemes, line styles, …).
12//!
13//! Domain objects only describe *what* to plot; *how* lives here.
14
15use crate::curves::Curve;
16use crate::surfaces::Surface;
17use crate::visualization::interface::GraphType;
18use crate::visualization::styles::{PlotType, TraceMode};
19use crate::visualization::{ColorScheme, get_color_from_scheme};
20use rust_decimal::Decimal;
21use serde::{Deserialize, Serialize};
22use std::path::PathBuf;
23
24/// A 2D point representation for plotting in a 2D coordinate system.
25///
26/// This structure represents a point in a 2D space with additional styling properties
27/// for visualization purposes.
28#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
29pub struct VisPoint2D {
30 /// The x-coordinate of the point.
31 pub x: Decimal,
32
33 /// The y-coordinate of the point.
34 pub y: Decimal,
35
36 /// Name of the data series, used for legends and identification.
37 pub name: String,
38
39 /// Visual mode of the trace (lines, markers, or both).
40 pub mode: TraceMode,
41
42 /// Optional color for the point, specified as a hex string (e.g., "#FF0000").
43 pub color: Option<String>,
44
45 /// Optional width/size of the point when rendered.
46 pub width: Option<f64>,
47}
48
49/// A 3D point representation for plotting in a 3D coordinate system.
50///
51/// This structure represents a point in a 3D space with additional styling properties
52/// for visualization purposes.
53#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
54pub struct VisPoint3D {
55 /// The x-coordinate of the point.
56 pub x: Decimal,
57
58 /// The y-coordinate of the point.
59 pub y: Decimal,
60
61 /// The z-coordinate of the point.
62 pub z: Decimal,
63
64 /// Name of the data series, used for legends and identification.
65 pub name: String,
66
67 /// Visual mode of the trace (lines, markers, or both).
68 pub mode: TraceMode,
69
70 /// Optional color for the point, specified as a hex string (e.g., "#FF0000").
71 pub color: Option<String>,
72
73 /// Optional width/size of the point when rendered.
74 pub width: Option<f64>,
75}
76
77/// A text label attached to a 2D point for displaying information on a 2D plot.
78///
79/// This structure combines a 2D point with a text label, allowing text to be
80/// positioned at specific coordinates on a 2D plot.
81#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
82pub struct Label2D {
83 /// The 2D point where the label should be positioned.
84 pub point: VisPoint2D,
85
86 /// The text content of the label.
87 pub label: String,
88}
89
90/// A text label attached to a 3D point for displaying information on a 3D plot.
91///
92/// This structure combines a 3D point with a text label, allowing text to be
93/// positioned at specific coordinates on a 3D plot.
94#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
95pub struct Label3D {
96 /// The 3D point where the label should be positioned.
97 pub point: VisPoint3D,
98
99 /// The text content of the label.
100 pub label: String,
101}
102
103/// Represents a two-dimensional data series for plotting.
104///
105/// This struct contains the X and Y coordinates of data points, along with
106/// styling information to control how the series appears in a plot.
107#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
108pub struct Series2D {
109 /// X-coordinates of the data points.
110 pub x: Vec<Decimal>,
111
112 /// Y-coordinates of the data points.
113 pub y: Vec<Decimal>,
114
115 /// Name of the data series, used for legends and identification.
116 pub name: String,
117
118 /// Visual mode of the trace (lines, markers, or both).
119 pub mode: TraceMode,
120
121 /// Optional color for the line in hex format (e.g., "#FF0000" for red).
122 /// If None, a default color will be used.
123 pub line_color: Option<String>,
124
125 /// Optional width of the line in pixels.
126 /// If None, a default width will be used.
127 pub line_width: Option<f64>,
128}
129
130impl Default for Series2D {
131 fn default() -> Self {
132 Self {
133 x: vec![],
134 y: vec![],
135 name: "Series".into(),
136 mode: TraceMode::Lines,
137 line_color: None,
138 line_width: None,
139 }
140 }
141}
142
143/// A type alias representing a collection of 2D series.
144///
145/// `MultiSeries2D` is a type alias for a `Vec<Series2D>`, where each `Series2D`
146/// represents a single two-dimensional data series. This alias is used to
147/// simplify the representation of multiple 2D series in a single collection.
148///
149pub type MultiSeries2D = Vec<Series2D>;
150
151/// A struct representing a 3D surface plot.
152///
153/// This structure holds the 3D coordinates data (x, y, z) as vectors of Decimal values,
154/// along with a name to identify the surface in plots.
155#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Default)]
156pub struct Surface3D {
157 /// The x-coordinates of the points in the 3D surface
158 pub x: Vec<Decimal>,
159
160 /// The y-coordinates of the points in the 3D surface
161 pub y: Vec<Decimal>,
162
163 /// The z-coordinates of the points in the 3D surface
164 pub z: Vec<Decimal>,
165
166 /// A descriptive name for the 3D surface
167 pub name: String,
168}
169
170/// Represents different types of graph data for visualization.
171///
172/// This enum encapsulates various data structures that can be used for
173/// rendering different types of charts and plots.
174#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
175pub enum GraphData {
176 /// A single 2D data series containing x and y coordinates.
177 /// Typically used for line, scatter, or bar charts with a single dataset.
178 Series(Series2D),
179
180 /// Multiple 2D data series for comparison in the same visualization.
181 /// Useful for charts that need to display multiple datasets simultaneously.
182 MultiSeries(MultiSeries2D),
183
184 /// A 3D surface representation with x, y, and z coordinates.
185 /// Used for creating 3D surface plots and visualizations.
186 GraphSurface(Surface3D),
187}
188
189impl From<Curve> for GraphData {
190 fn from(curve: Curve) -> Self {
191 GraphData::Series(Series2D {
192 x: curve.points.iter().map(|p| p.x).collect(),
193 y: curve.points.iter().map(|p| p.y).collect(),
194 name: "Curve".to_string(),
195 mode: TraceMode::Lines,
196 line_color: Some("#1f77b4".to_string()),
197 line_width: Some(2.0),
198 })
199 }
200}
201
202impl From<Vec<Curve>> for GraphData {
203 fn from(curves: Vec<Curve>) -> Self {
204 let color_scheme = ColorScheme::Plasma;
205
206 let series: Vec<Series2D> = curves
207 .into_iter()
208 .enumerate()
209 .map(|(idx, c)| {
210 let color = get_color_from_scheme(&color_scheme, idx)
211 .unwrap_or_else(|| "#1f77b4".to_string());
212
213 Series2D {
214 x: c.points.iter().map(|p| p.x).collect(),
215 y: c.points.iter().map(|p| p.y).collect(),
216 name: format!("Curve {}", idx + 1),
217 mode: TraceMode::Lines,
218 line_color: Some(color),
219 line_width: Some(2.0),
220 }
221 })
222 .collect();
223
224 GraphData::MultiSeries(series)
225 }
226}
227
228impl From<Surface> for GraphData {
229 fn from(surface: Surface) -> Self {
230 GraphData::GraphSurface(Surface3D {
231 x: surface.points.iter().map(|p| p.x).collect(),
232 y: surface.points.iter().map(|p| p.y).collect(),
233 z: surface.points.iter().map(|p| p.z).collect(),
234 name: "Surface".to_string(),
235 })
236 }
237}
238
239/// Represents the different output types for saving or displaying plots.
240///
241/// This enum allows specifying whether the output should be saved to a file
242/// in a specific format (PNG, HTML, SVG) or displayed directly in a browser.
243#[derive(Clone, Copy, Debug, PartialEq, Serialize)]
244pub enum OutputType<'a> {
245 /// PNG image output with a reference to the file path where it should be saved.
246 #[cfg(feature = "plotly")]
247 Png(&'a PathBuf),
248
249 /// HTML document output with a reference to the file path where it should be saved.
250 Html(&'a PathBuf),
251
252 /// SVG image output with a reference to the file path where it should be saved.
253 #[cfg(feature = "plotly")]
254 Svg(&'a PathBuf),
255
256 /// Output directly to the default web browser without saving to a file.
257 Browser,
258}
259
260impl GraphType for Series2D {
261 fn plot_type() -> PlotType {
262 PlotType::Line2D
263 }
264}
265
266impl GraphType for Surface3D {
267 fn plot_type() -> PlotType {
268 PlotType::Surface3D
269 }
270}