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};