flow_plots/plots/
density.rs1use crate::contour::calculate_contours;
2use crate::PlotBytes;
3use crate::density_calc::calculate_plot_pixels;
4use crate::options::{DensityPlotOptions, PlotOptions};
5use crate::plots::traits::Plot;
6use crate::plots::PlotType;
7use crate::render::RenderConfig;
8use crate::render::plotters_backend::{render_contour, render_pixels};
9use crate::scatter_data::ScatterPlotData;
10use anyhow::Result;
11
12pub struct DensityPlot;
37
38impl DensityPlot {
39 pub fn new() -> Self {
41 Self
42 }
43
44 pub fn render_batch(
57 &self,
58 requests: &[(ScatterPlotData, DensityPlotOptions)],
59 render_config: &mut RenderConfig,
60 ) -> Result<Vec<PlotBytes>> {
61 let mut results = Vec::with_capacity(requests.len());
62 for (data, options) in requests.iter() {
63 let bytes = match options.plot_type.canonical() {
64 PlotType::Contour | PlotType::ContourOverlay => {
65 let xy = data.xy();
66 let x_range = (*options.x_axis.range.start(), *options.x_axis.range.end());
67 let y_range = (*options.y_axis.range.start(), *options.y_axis.range.end());
68 let contour_data = calculate_contours(
69 xy,
70 options.contour_level_count,
71 options.contour_smoothing,
72 options.draw_outliers,
73 x_range,
74 y_range,
75 )?;
76 render_contour(contour_data, options, render_config)?
77 }
78 _ => {
79 let base = options.base();
80 let raw_pixels = calculate_plot_pixels(
81 data,
82 base.width as usize,
83 base.height as usize,
84 options,
85 );
86 render_pixels(raw_pixels, options, render_config)?
87 }
88 };
89 results.push(bytes);
90 }
91 Ok(results)
92 }
93}
94
95impl Plot for DensityPlot {
96 type Options = DensityPlotOptions;
97 type Data = ScatterPlotData;
98
99 fn render(
100 &self,
101 data: Self::Data,
102 options: &Self::Options,
103 render_config: &mut RenderConfig,
104 ) -> Result<PlotBytes> {
105 let plot_start = std::time::Instant::now();
106
107 match options.plot_type.canonical() {
108 PlotType::Contour | PlotType::ContourOverlay => {
109 let xy = data.xy();
110 let x_range = (*options.x_axis.range.start(), *options.x_axis.range.end());
111 let y_range = (*options.y_axis.range.start(), *options.y_axis.range.end());
112 let contour_data = calculate_contours(
113 xy,
114 options.contour_level_count,
115 options.contour_smoothing,
116 options.draw_outliers,
117 x_range,
118 y_range,
119 )?;
120 eprintln!(
121 " ├─ Contour calculation: {:?} ({} paths, {} outliers)",
122 plot_start.elapsed(),
123 contour_data.contours.len(),
124 contour_data.outliers.len()
125 );
126 let draw_start = std::time::Instant::now();
127 let result = render_contour(contour_data, options, render_config);
128 eprintln!(" └─ Draw + encode: {:?}", draw_start.elapsed());
129 result
130 }
131 _ => {
132 let base = options.base();
133 let raw_pixels = calculate_plot_pixels(
134 &data,
135 base.width as usize,
136 base.height as usize,
137 options,
138 );
139 eprintln!(
140 " ├─ Plot calculation: {:?} ({} pixels at {}x{})",
141 plot_start.elapsed(),
142 raw_pixels.len(),
143 base.width,
144 base.height
145 );
146 let draw_start = std::time::Instant::now();
147 let result = render_pixels(raw_pixels, options, render_config);
148 eprintln!(" └─ Draw + encode: {:?}", draw_start.elapsed());
149 result
150 }
151 }
152 }
153}