Skip to main content

optionstratlib_visualization/visualization/
mod.rs

1//! # Visualization
2//!
3//! # Visualization Library Usage Guide
4//!
5//! This guide explains how to use the visualization layer to create financial charts and other types of visualizations.
6//!
7//! ## Setup
8//!
9//! The chart data builds with no feature; rendering through plotly.rs needs
10//! `plotly`, and PNG/SVG export needs `static_export`:
11//!
12//! ```toml
13//! [dependencies]
14//! optionstratlib-visualization = { version = "0.22.1", features = ["plotly"] }
15//! ```
16//!
17//! ## Core Concepts
18//!
19//! The library follows a domain modeling pattern where it separates:
20//!
21//! 1. **What to visualize** (the data to represent)
22//! 2. **How to visualize it** (styles and configuration)
23//! 3. **Where to display it** (browser, HTML file, PNG image)
24//!
25//! ### Main Trait: `Graph`
26//!
27//! The `Graph` trait is the central component that any object wanting to be visualized must implement:
28//!
29//! ```rust,ignore,no_run
30//! use optionstratlib_visualization::visualization::{GraphConfig, GraphData};
31//!
32//! pub trait Graph {
33//!     fn graph_data(&self) -> GraphData;
34//!     
35//!     fn graph_config(&self) -> GraphConfig {
36//!         GraphConfig::default()
37//!     }
38//!     
39//!     // Rendering methods provided under `plotly` and `static_export`...
40//! }
41//! ```
42//!
43//! To create a chart, you only need to implement:
44//! - `graph_data()`: to provide the data to visualize
45//! - Optionally, `graph_config()`: to customize the appearance
46//!
47//! The trait has this one definition on every feature surface; the backend
48//! features only add provided rendering methods (`to_plot`, `write_html`,
49//! `show`, `render`, `to_interactive_html` under `plotly`, and `write_png`,
50//! `write_svg` under `static_export`), so an implementation written without
51//! a backend compiles unchanged with one.
52//!
53//! ### Data Types
54//!
55//! The library supports these types of visualizations through the `GraphData` enum:
56//!
57//! ```rust
58//! use optionstratlib_visualization::visualization::{MultiSeries2D, Series2D, Surface3D};
59//!
60//! pub enum GraphData {
61//!     Series(Series2D),              // Line or scatter 2D
62//!     MultiSeries(MultiSeries2D),    // Multiple 2D series
63//!     GraphSurface(Surface3D),       // 3D surface
64//! }
65//! ```
66//!
67//! ## Example: Simple Line Chart
68//!
69//! ```rust,no_run
70//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
71//! use std::fs;
72//! use std::path::{Path, PathBuf};
73//! use rust_decimal::Decimal;
74//! use rust_decimal_macros::dec;
75//! use optionstratlib_visualization::visualization::{Graph, GraphData, Series2D, GraphConfig, OutputType};
76//! use optionstratlib_visualization::visualization::{LineStyle, ColorScheme, TraceMode};
77//!
78//! struct MyData {
79//!     x: Vec<Decimal>,
80//!     y: Vec<Decimal>,
81//! }
82//!
83//! impl Graph for MyData {
84//!     fn graph_data(&self) -> GraphData {
85//!         GraphData::Series(Series2D {
86//!             x: self.x.clone(),
87//!             y: self.y.clone(),
88//!             name: "My series".to_string(),
89//!             mode: TraceMode::Lines,
90//!             line_color: Some("#1f77b4".to_string()),
91//!             line_width: Some(2.0),
92//!         })
93//!     }
94//!
95//!     fn graph_config(&self) -> GraphConfig {
96//!         GraphConfig {
97//!             title: "My chart".to_string(),
98//!             width: 800,
99//!             height: 600,
100//!             x_label: Some("X Axis".to_string()),
101//!             y_label: Some("Y Axis".to_string()),
102//!             z_label: None,
103//!             line_style: LineStyle::Solid,
104//!             color_scheme: ColorScheme::Viridis,
105//!             legend: None,
106//!             show_legend: false,
107//!         }
108//!     }
109//! }
110//! #[cfg(feature = "static_export")]
111//! {
112//!     // Using the chart
113//!     let data = MyData {
114//!         x: vec![dec!(1.0), dec!(2.0), dec!(3.0), dec!(4.0), dec!(5.0)],
115//!         y: vec![dec!(2.0), dec!(3.0), dec!(5.0), dec!(7.0), dec!(11.0)],
116//!     };
117//!     // Display in browser
118//!     data.show();
119//!     // Save as PNG
120//!     let filename: PathBuf = PathBuf::from("my_chart.png");
121//!     data.render(OutputType::Png(&filename))?;
122//!     if Path::new(&filename.clone()).exists() {
123//!         fs::remove_file(filename.clone())?;
124//!     }
125//! }
126//! # Ok(())
127//! # }
128//! ```
129//!
130//! ## Example: 3D Surface
131//!
132//! ```rust
133//!
134//! use rust_decimal::Decimal;
135//! use optionstratlib_visualization::visualization::{ColorScheme, Graph, GraphConfig, GraphData, LineStyle, Surface3D};
136//!
137//! struct SurfaceData {
138//!     x: Vec<Decimal>,
139//!     y: Vec<Decimal>,
140//!     z: Vec<Decimal>,
141//! }
142//!
143//! impl Graph for SurfaceData {
144//!     fn graph_data(&self) -> GraphData {
145//!         GraphData::GraphSurface(Surface3D {
146//!             x: self.x.clone(),
147//!             y: self.y.clone(),
148//!             z: self.z.clone(),
149//!             name: "My surface".to_string(),
150//!         })
151//!     }
152//!
153//!     fn graph_config(&self) -> GraphConfig {
154//!         GraphConfig {
155//!             title: "3D Surface".to_string(),
156//!             width: 800,
157//!             height: 600,
158//!             x_label: Some("X".to_string()),
159//!             y_label: Some("Y".to_string()),
160//!             z_label: Some("Z".to_string()),
161//!             line_style: LineStyle::Solid,
162//!             color_scheme: ColorScheme::Plasma,
163//!             legend: None,
164//!             show_legend: false,
165//!          }
166//!     }
167//! }
168//! ```
169//!
170//! ## Color Schemes
171//!
172//! The library provides several predefined color schemes:
173//!
174//! - `ColorScheme::Default`: Uses plotly's default colors
175//! - `ColorScheme::Viridis`: A color palette ranging from violet to yellow
176//! - `ColorScheme::Plasma`: A color palette ranging from dark blue to yellow
177//! - `ColorScheme::Custom(Vec<String>)`: Define your own colors as hexadecimal strings
178//!
179//! ## Line Styles
180//!
181//! You can customize lines with:
182//!
183//! - `LineStyle::Solid`: Continuous line
184//! - `LineStyle::Dotted`: Dotted line
185//! - `LineStyle::Dashed`: Dashed line
186//!
187//! ## Display Modes
188//!
189//! For 2D series, you can choose how to display points:
190//!
191//! - `TraceMode::Lines`: Lines only
192//! - `TraceMode::Markers`: Markers (points) only
193//! - `TraceMode::LinesMarkers`: Both lines and markers
194//!
195//! ## Error Handling
196//!
197//! The library provides a `GraphError` type that encapsulates graph-specific errors and I/O errors. All methods that can fail return `Result<(), GraphError>`.
198//!
199//! ## Advanced Tips
200//!
201//! ### Serialization and Deserialization
202//!
203//! All main types implement `serde::Serialize` and `serde::Deserialize`, allowing you to save and load chart configurations in JSON or other compatible formats.
204//!
205//! ### Multiple Series
206//!
207//! For charts with multiple series, use the `GraphData::MultiSeries` type:
208//!
209//! ```rust
210//! use rust_decimal_macros::dec;
211//! use optionstratlib_visualization::visualization::{GraphData, Series2D, TraceMode};
212//! let series1 = Series2D {
213//!     x: vec![dec!(1.0), dec!(2.0), dec!(3.0)],
214//!     y: vec![dec!(4.0), dec!(5.0), dec!(6.0)],
215//!     name: "Series 1".to_string(),
216//!     mode: TraceMode::Lines,
217//!     line_color: Some("#1f77b4".to_string()),
218//!     line_width: Some(2.0),
219//! };
220//!
221//! let series2 = Series2D {
222//!     x: vec![dec!(1.0), dec!(2.0), dec!(3.0)],
223//!     y: vec![dec!(7.0), dec!(8.0), dec!(9.0)],
224//!     name: "Series 2".to_string(),
225//!     mode: TraceMode::Markers,
226//!     line_color: Some("#ff7f0e".to_string()),
227//!     line_width: Some(2.0),
228//! };
229//!
230//! let graph_data = GraphData::MultiSeries(vec![series1, series2]);
231//! ```
232//!
233//! ### Interactive HTML Generation
234//!
235//! If you need interactive HTML with advanced hover and tooltip functions, use the `to_interactive_html` method:
236//!
237//! ```rust
238//! use optionstratlib_visualization::visualization::{Graph, GraphData, Series2D, TraceMode, GraphConfig};
239//! use optionstratlib_visualization::error::GraphError;
240//! use std::path::PathBuf;
241//! use tracing::info;
242//! use rust_decimal_macros::dec;
243//! struct SimpleChart {
244//!     series: Series2D
245//! }
246//!
247//! impl Graph for SimpleChart {
248//!     fn graph_data(&self) -> GraphData {
249//!         GraphData::Series(self.series.clone())
250//!     }
251//!     
252//!     fn graph_config(&self) -> GraphConfig {
253//!         GraphConfig {
254//!             title: "Interactive Chart Example".into(),
255//!             width: 800,
256//!             height: 600,
257//!             x_label: Some("X Axis".into()),
258//!             y_label: Some("Y Axis".into()),
259//!             ..GraphConfig::default()
260//!         }
261//!     }
262//! }
263//!
264//! fn main() -> Result<(), GraphError> {
265//!     use std::fs;
266//! use std::path::Path;
267//! let series = Series2D {
268//!         x: vec![dec!(1.0), dec!(2.0), dec!(3.0)],
269//!         y: vec![dec!(4.0), dec!(5.0), dec!(6.0)],
270//!         name: "Series 1".to_string(),
271//!         mode: TraceMode::Lines,
272//!         line_color: Some("#1f77b4".to_string()),
273//!         line_width: Some(2.0),
274//!     };
275//!     
276//!     #[cfg(feature = "static_export")]
277//!     {
278//!     let chart = SimpleChart { series };
279//!     let filename: PathBuf = PathBuf::from("interactive_chart.html");
280//!     chart.to_interactive_html(&filename)?;
281//!     info!("Interactive HTML chart created successfully!");
282//!     if Path::new(&filename.clone()).exists() {
283//!             fs::remove_file(filename.clone())?;
284//!         }
285//!     }
286//!     Ok(())
287//! }
288//! ```
289//!
290//! ## Complete Examples
291//!
292//! Check the `examples/` directory for practical examples, including:
293//! - Stock price charts with moving averages
294//! - Volatility surfaces for options
295//! - Scatter plots with multiple series
296//!
297//! ## Adaptation to Your Needs
298//!
299//! `GraphData` is a closed enum, so a downstream crate cannot add variants to
300//! it. To chart a new type, implement `Graph` for it: build one of the
301//! existing `GraphData` variants in `graph_data()` and style it through
302//! `graph_config()`. A new kind of chart (a variant, or a change to `to_plot`)
303//! is a change to this crate.
304//!
305//! Enjoy visualizing your financial data!
306
307mod config;
308/// `impl Graph` and `impl Plottable` for `Curve` and `Vec<Curve>`.
309mod curves;
310/// Filesystem preparation for chart export. Owned by `visualization`:
311/// writing a rendered chart to disk is the only production use of it.
312mod file;
313/// The `Graph` contract, one definition on every feature surface.
314mod graph;
315mod interface;
316mod model;
317mod model_impls;
318/// The native PNG and SVG export behind `static_export`.
319#[cfg(feature = "static_export")]
320mod native;
321/// `Plottable` trait and `PlotBuilder`.
322mod plot_builder;
323mod simulation;
324mod strategies;
325mod styles;
326/// `impl Graph` and `impl Plottable` for `Surface`.
327mod surfaces;
328/// Terminal tables for chain and simulation reports: the explicit adapter
329/// that writes them to stdout (M6-05).
330pub mod terminal;
331mod tests;
332/// Colour helpers, and the Plotly trace builders behind `plotly`.
333mod utils;
334
335pub use config::GraphConfig;
336pub use file::prepare_file_path;
337pub use graph::Graph;
338pub use interface::GraphType;
339pub use model::{
340    GraphData, Label2D, Label3D, MultiSeries2D, OutputType, Series2D, Surface3D, VisPoint2D,
341    VisPoint3D,
342};
343pub use plot_builder::{PlotBuilder, Plottable};
344pub use styles::{ColorScheme, LineStyle, PlotType, TraceMode};
345pub use utils::get_color_from_scheme;
346#[cfg(feature = "plotly")]
347pub use utils::{make_scatter, make_surface, pick_color, to_plotly_mode};