use crate::contour::calculate_contours;
use crate::PlotBytes;
use crate::density_calc::calculate_plot_pixels;
use crate::options::{DensityPlotOptions, PlotOptions};
use crate::plots::traits::Plot;
use crate::plots::PlotType;
use crate::render::RenderConfig;
use crate::render::plotters_backend::{render_contour, render_pixels};
use crate::scatter_data::ScatterPlotData;
use anyhow::Result;
pub struct DensityPlot;
impl DensityPlot {
pub fn new() -> Self {
Self
}
pub fn render_batch(
&self,
requests: &[(ScatterPlotData, DensityPlotOptions)],
render_config: &mut RenderConfig,
) -> Result<Vec<PlotBytes>> {
let mut results = Vec::with_capacity(requests.len());
for (data, options) in requests.iter() {
let bytes = match options.plot_type.canonical() {
PlotType::Contour | PlotType::ContourOverlay => {
let xy = data.xy();
let x_range = (*options.x_axis.range.start(), *options.x_axis.range.end());
let y_range = (*options.y_axis.range.start(), *options.y_axis.range.end());
let contour_data = calculate_contours(
xy,
options.contour_level_count,
options.contour_smoothing,
options.draw_outliers,
x_range,
y_range,
)?;
render_contour(contour_data, options, render_config)?
}
_ => {
let base = options.base();
let raw_pixels = calculate_plot_pixels(
data,
base.width as usize,
base.height as usize,
options,
);
render_pixels(raw_pixels, options, render_config)?
}
};
results.push(bytes);
}
Ok(results)
}
}
impl Plot for DensityPlot {
type Options = DensityPlotOptions;
type Data = ScatterPlotData;
fn render(
&self,
data: Self::Data,
options: &Self::Options,
render_config: &mut RenderConfig,
) -> Result<PlotBytes> {
let plot_start = std::time::Instant::now();
match options.plot_type.canonical() {
PlotType::Contour | PlotType::ContourOverlay => {
let xy = data.xy();
let x_range = (*options.x_axis.range.start(), *options.x_axis.range.end());
let y_range = (*options.y_axis.range.start(), *options.y_axis.range.end());
let contour_data = calculate_contours(
xy,
options.contour_level_count,
options.contour_smoothing,
options.draw_outliers,
x_range,
y_range,
)?;
eprintln!(
" ├─ Contour calculation: {:?} ({} paths, {} outliers)",
plot_start.elapsed(),
contour_data.contours.len(),
contour_data.outliers.len()
);
let draw_start = std::time::Instant::now();
let result = render_contour(contour_data, options, render_config);
eprintln!(" └─ Draw + encode: {:?}", draw_start.elapsed());
result
}
_ => {
let base = options.base();
let raw_pixels = calculate_plot_pixels(
&data,
base.width as usize,
base.height as usize,
options,
);
eprintln!(
" ├─ Plot calculation: {:?} ({} pixels at {}x{})",
plot_start.elapsed(),
raw_pixels.len(),
base.width,
base.height
);
let draw_start = std::time::Instant::now();
let result = render_pixels(raw_pixels, options, render_config);
eprintln!(" └─ Draw + encode: {:?}", draw_start.elapsed());
result
}
}
}
}