1pub mod core;
10pub mod data;
11
12pub mod plots;
14
15pub mod export;
17
18#[cfg(feature = "gui")]
20pub mod gui;
21
22#[cfg(feature = "jupyter")]
24pub mod jupyter;
25
26pub mod styling;
28
29pub use plots::*;
33
34#[cfg(feature = "gui")]
36pub use gui::{PlotWindow, WindowConfig};
37
38#[cfg(feature = "gui")]
40pub use gui::{is_window_available, show_plot_sequential};
41
42#[cfg(feature = "gui")]
44pub use gui::{
45 get_gui_manager, health_check_global, initialize_gui_manager, is_main_thread,
46 register_main_thread, show_plot_global, GuiErrorCode, GuiOperationResult, GuiThreadManager,
47};
48
49pub use export::*;
51
52#[derive(Debug, Clone)]
56pub struct PlotOptions {
57 pub width: u32,
58 pub height: u32,
59 pub dpi: f32,
60 pub background_color: [f32; 4],
61}
62
63impl Default for PlotOptions {
64 fn default() -> Self {
65 Self {
66 width: 800,
67 height: 600,
68 dpi: 96.0,
69 background_color: [0.0, 0.0, 0.0, 1.0], }
71 }
72}
73
74pub fn show_plot_unified(
79 figure: plots::Figure,
80 output_path: Option<&str>,
81) -> Result<String, String> {
82 match output_path {
83 Some(path) => {
84 render_figure_to_file(figure, path)
86 }
87 None => {
88 #[cfg(feature = "gui")]
90 {
91 show_plot_sequential(figure)
92 }
93 #[cfg(not(feature = "gui"))]
94 {
95 Err(
96 "GUI feature not enabled. Build with --features gui for interactive plotting."
97 .to_string(),
98 )
99 }
100 }
101 }
102}
103
104fn render_figure_to_file(figure: plots::Figure, path: &str) -> Result<String, String> {
106 #[cfg(feature = "gui")]
109 {
110 show_plot_sequential(figure)?;
112 Ok(format!("Plot displayed interactively. Static export to {path} not yet implemented - please screenshot the window."))
113 }
114 #[cfg(not(feature = "gui"))]
115 {
116 Err("GUI feature not enabled. Cannot render plots without GUI.".to_string())
117 }
118}
119
120pub fn plot_line(xs: &[f64], ys: &[f64], path: &str, _options: PlotOptions) -> Result<(), String> {
125 if xs.len() != ys.len() {
126 return Err("input length mismatch".into());
127 }
128
129 let line_plot = plots::LinePlot::new(xs.to_vec(), ys.to_vec())
130 .map_err(|e| format!("Failed to create line plot: {e}"))?
131 .with_label("Data")
132 .with_style(
133 glam::Vec4::new(0.0, 0.4, 0.8, 1.0), 2.0,
135 plots::LineStyle::Solid,
136 );
137
138 let mut figure = plots::Figure::new()
139 .with_title("Line Plot")
140 .with_labels("X", "Y")
141 .with_grid(true);
142
143 figure.add_line_plot(line_plot);
144
145 show_plot_unified(figure, Some(path))?;
146 Ok(())
147}
148
149pub fn plot_scatter(
151 xs: &[f64],
152 ys: &[f64],
153 path: &str,
154 _options: PlotOptions,
155) -> Result<(), String> {
156 if xs.len() != ys.len() {
157 return Err("input length mismatch".into());
158 }
159
160 let scatter_plot = plots::ScatterPlot::new(xs.to_vec(), ys.to_vec())
161 .map_err(|e| format!("Failed to create scatter plot: {e}"))?
162 .with_label("Data")
163 .with_style(
164 glam::Vec4::new(0.8, 0.2, 0.2, 1.0), 5.0,
166 plots::MarkerStyle::Circle,
167 );
168
169 let mut figure = plots::Figure::new()
170 .with_title("Scatter Plot")
171 .with_labels("X", "Y")
172 .with_grid(true);
173
174 figure.add_scatter_plot(scatter_plot);
175
176 show_plot_unified(figure, Some(path))?;
177 Ok(())
178}
179
180pub fn plot_bar(
182 labels: &[String],
183 values: &[f64],
184 path: &str,
185 _options: PlotOptions,
186) -> Result<(), String> {
187 if labels.len() != values.len() {
188 return Err("labels and values length mismatch".into());
189 }
190
191 let bar_chart = plots::BarChart::new(labels.to_vec(), values.to_vec())
192 .map_err(|e| format!("Failed to create bar chart: {e}"))?
193 .with_label("Values")
194 .with_style(glam::Vec4::new(0.2, 0.6, 0.3, 1.0), 0.8); let mut figure = plots::Figure::new()
197 .with_title("Bar Chart")
198 .with_labels("Categories", "Values")
199 .with_grid(true);
200
201 figure.add_bar_chart(bar_chart);
202
203 show_plot_unified(figure, Some(path))?;
204 Ok(())
205}
206
207pub fn plot_histogram(
209 data: &[f64],
210 bins: usize,
211 path: &str,
212 _options: PlotOptions,
213) -> Result<(), String> {
214 let histogram = plots::Histogram::new(data.to_vec(), bins)
215 .map_err(|e| format!("Failed to create histogram: {e}"))?
216 .with_label("Frequency")
217 .with_style(glam::Vec4::new(0.6, 0.3, 0.7, 1.0), false); let mut figure = plots::Figure::new()
220 .with_title("Histogram")
221 .with_labels("Values", "Frequency")
222 .with_grid(true);
223
224 figure.add_histogram(histogram);
225
226 show_plot_unified(figure, Some(path))?;
227 Ok(())
228}
229
230pub fn show_interactive_platform_optimal(figure: plots::Figure) -> Result<String, String> {
235 show_plot_unified(figure, None)
236}