pub(super) const COLORBAR_MARGIN_PX: f32 = 10.0;
pub(super) const COLORBAR_WIDTH_PX: f32 = 20.0;
#[derive(Clone, Copy)]
pub(super) enum ErrorValuesRef<'a> {
Symmetric(&'a [f64]),
Asymmetric(&'a [f64], &'a [f64]),
}
impl ErrorValuesRef<'_> {
fn bounds_at(self, index: usize) -> Option<(f64, f64)> {
match self {
Self::Symmetric(errors) => errors.get(index).map(|&error| (error, error)),
Self::Asymmetric(lower, upper) => match (lower.get(index), upper.get(index)) {
(Some(&lower), Some(&upper)) => Some((lower, upper)),
_ => None,
},
}
}
}
impl<'a> From<&'a ErrorValues> for ErrorValuesRef<'a> {
fn from(values: &'a ErrorValues) -> Self {
match values {
ErrorValues::Symmetric(errors) => Self::Symmetric(errors),
ErrorValues::Asymmetric(lower, upper) => Self::Asymmetric(lower, upper),
}
}
}
fn effective_error_values<'a>(
configured: Option<&'a ErrorValues>,
resolved: &'a [f64],
) -> ErrorValuesRef<'a> {
configured
.map(ErrorValuesRef::from)
.unwrap_or(ErrorValuesRef::Symmetric(resolved))
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(super) enum RenderExecutionMode {
Reference,
Optimized,
}
impl RenderExecutionMode {
pub(super) fn allows_auto_datashader(self) -> bool {
matches!(self, Self::Optimized)
}
pub(super) fn allows_raster_line_reduction(self) -> bool {
true
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
#[doc(hidden)]
pub struct RenderDiagnostics {
pub render_mode: &'static str,
pub used_parallel: bool,
pub used_auto_datashader: bool,
pub used_exact_line_canonicalization: bool,
pub used_raster_line_reduction: bool,
pub used_marker_path_cache: bool,
pub used_marker_sprite_cache: bool,
pub used_marker_sprite_compositor: bool,
pub used_marker_sprite_fallback: bool,
pub used_marker_scanline_blit: bool,
pub used_direct_rect_fill: bool,
pub used_pixel_aligned_rect_fill: bool,
pub used_prepared_geometry_cache: bool,
pub rebuilt_prepared_geometry_cache: bool,
}
impl RenderDiagnostics {
pub const fn actual_backend(&self) -> BackendType {
if self.used_parallel {
BackendType::Parallel
} else if self.used_auto_datashader {
BackendType::DataShader
} else {
BackendType::Skia
}
}
pub const fn actual_backend_name(&self) -> &'static str {
self.actual_backend().as_str()
}
}
macro_rules! impl_series_continuation_methods {
($self_:ident.$finalize:ident()) => {
pub fn line<X, Y>(
$self_,
x_data: &X,
y_data: &Y,
) -> $crate::core::plot::PlotBuilder<$crate::plots::basic::LineConfig>
where
X: $crate::data::NumericData1D,
Y: $crate::data::NumericData1D,
{
$self_.$finalize().line(x_data, y_data)
}
pub fn line_source<X, Y>(
$self_,
x_data: X,
y_data: Y,
) -> $crate::core::plot::PlotBuilder<$crate::plots::basic::LineConfig>
where
X: $crate::core::plot::IntoPlotData,
Y: $crate::core::plot::IntoPlotData,
{
$self_.$finalize().line_source(x_data, y_data)
}
pub fn scatter<X, Y>(
$self_,
x_data: &X,
y_data: &Y,
) -> $crate::core::plot::PlotBuilder<$crate::plots::basic::ScatterConfig>
where
X: $crate::data::NumericData1D,
Y: $crate::data::NumericData1D,
{
$self_.$finalize().scatter(x_data, y_data)
}
pub fn scatter_source<X, Y>(
$self_,
x_data: X,
y_data: Y,
) -> $crate::core::plot::PlotBuilder<$crate::plots::basic::ScatterConfig>
where
X: $crate::core::plot::IntoPlotData,
Y: $crate::core::plot::IntoPlotData,
{
$self_.$finalize().scatter_source(x_data, y_data)
}
pub fn bar<S, V>(
$self_,
categories: &[S],
values: &V,
) -> $crate::core::plot::PlotBuilder<$crate::plots::basic::BarConfig>
where
S: ToString,
V: $crate::data::NumericData1D,
{
$self_.$finalize().bar(categories, values)
}
pub fn bar_source<S, V>(
$self_,
categories: &[S],
values: V,
) -> $crate::core::plot::PlotBuilder<$crate::plots::basic::BarConfig>
where
S: ToString,
V: $crate::core::plot::IntoPlotData,
{
$self_.$finalize().bar_source(categories, values)
}
pub fn group<F>($self_, f: F) -> $crate::core::plot::Plot
where
F: FnOnce(
$crate::core::plot::SeriesGroupBuilder,
) -> $crate::core::plot::SeriesGroupBuilder,
{
$self_.$finalize().group(f)
}
pub fn histogram<D: $crate::data::NumericData1D>(
$self_,
data: &D,
) -> $crate::core::plot::PlotBuilder<$crate::plots::HistogramConfig> {
$self_.$finalize().histogram(data)
}
pub fn histogram_with<D: $crate::data::NumericData1D>(
$self_,
data: &D,
config: $crate::plots::HistogramConfig,
) -> $crate::core::plot::PlotBuilder<$crate::plots::HistogramConfig> {
$self_.$finalize().histogram_with(data, config)
}
pub fn histogram_source<D: $crate::core::plot::IntoPlotData>(
$self_,
data: D,
) -> $crate::core::plot::PlotBuilder<$crate::plots::HistogramConfig> {
$self_.$finalize().histogram_source(data)
}
pub fn histogram_source_with<D: $crate::core::plot::IntoPlotData>(
$self_,
data: D,
config: $crate::plots::HistogramConfig,
) -> $crate::core::plot::PlotBuilder<$crate::plots::HistogramConfig> {
$self_.$finalize().histogram_source_with(data, config)
}
pub fn boxplot<D: $crate::data::NumericData1D>(
$self_,
data: &D,
) -> $crate::core::plot::PlotBuilder<$crate::plots::BoxPlotConfig> {
$self_.$finalize().boxplot(data)
}
pub fn boxplot_with<D: $crate::data::NumericData1D>(
$self_,
data: &D,
config: $crate::plots::BoxPlotConfig,
) -> $crate::core::plot::PlotBuilder<$crate::plots::BoxPlotConfig> {
$self_.$finalize().boxplot_with(data, config)
}
pub fn boxplot_source<D: $crate::core::plot::IntoPlotData>(
$self_,
data: D,
) -> $crate::core::plot::PlotBuilder<$crate::plots::BoxPlotConfig> {
$self_.$finalize().boxplot_source(data)
}
pub fn boxplot_source_with<D: $crate::core::plot::IntoPlotData>(
$self_,
data: D,
config: $crate::plots::BoxPlotConfig,
) -> $crate::core::plot::PlotBuilder<$crate::plots::BoxPlotConfig> {
$self_.$finalize().boxplot_source_with(data, config)
}
pub fn heatmap<D>(
$self_,
data: &D,
) -> $crate::core::plot::PlotBuilder<$crate::plots::heatmap::HeatmapConfig>
where
D: $crate::data::NumericData2D + ?Sized,
{
$self_.$finalize().heatmap(data)
}
pub fn heatmap_with<D>(
$self_,
data: &D,
config: $crate::plots::heatmap::HeatmapConfig,
) -> $crate::core::plot::PlotBuilder<$crate::plots::heatmap::HeatmapConfig>
where
D: $crate::data::NumericData2D + ?Sized,
{
$self_.$finalize().heatmap_with(data, config)
}
pub fn kde<T, D: $crate::data::Data1D<T>>(
$self_,
data: &D,
) -> $crate::core::plot::PlotBuilder<$crate::plots::KdeConfig>
where
T: Into<f64> + Copy,
{
$self_.$finalize().kde(data)
}
pub fn ecdf<T, D: $crate::data::Data1D<T>>(
$self_,
data: &D,
) -> $crate::core::plot::PlotBuilder<$crate::plots::EcdfConfig>
where
T: Into<f64> + Copy,
{
$self_.$finalize().ecdf(data)
}
pub fn contour<X, Y, Z>(
$self_,
x: &X,
y: &Y,
z: &Z,
) -> $crate::core::plot::PlotBuilder<$crate::plots::ContourConfig>
where
X: $crate::data::Data1D<f64>,
Y: $crate::data::Data1D<f64>,
Z: $crate::data::Data1D<f64>,
{
$self_.$finalize().contour(x, y, z)
}
pub fn pie<V>(
$self_,
values: &V,
) -> $crate::core::plot::PlotBuilder<$crate::plots::PieConfig>
where
V: $crate::data::Data1D<f64>,
{
$self_.$finalize().pie(values)
}
pub fn radar<S: AsRef<str>>(
$self_,
labels: &[S],
) -> $crate::core::plot::PlotBuilder<$crate::plots::RadarConfig> {
$self_.$finalize().radar(labels)
}
pub fn polar_line<R, T>(
$self_,
r: &R,
theta: &T,
) -> $crate::core::plot::PlotBuilder<$crate::plots::PolarPlotConfig>
where
R: $crate::data::Data1D<f64>,
T: $crate::data::Data1D<f64>,
{
$self_.$finalize().polar_line(r, theta)
}
pub fn violin<T, D: $crate::data::Data1D<T>>(
$self_,
data: &D,
) -> $crate::core::plot::PlotBuilder<$crate::plots::ViolinConfig>
where
T: Into<f64> + Copy,
{
$self_.$finalize().violin(data)
}
pub fn boxen<T, D: $crate::data::Data1D<T>>(
$self_,
data: &D,
) -> $crate::core::plot::PlotBuilder<$crate::plots::BoxenConfig>
where
T: Into<f64> + Copy,
{
$self_.$finalize().boxen(data)
}
pub fn quiver<X, Y, U, V>(
$self_,
x_data: &X,
y_data: &Y,
u_data: &U,
v_data: &V,
) -> $crate::core::plot::PlotBuilder<$crate::plots::QuiverConfig>
where
X: $crate::data::NumericData1D,
Y: $crate::data::NumericData1D,
U: $crate::data::NumericData1D,
V: $crate::data::NumericData1D,
{
$self_.$finalize().quiver(x_data, y_data, u_data, v_data)
}
pub fn rug<T, D: $crate::data::Data1D<T>>(
$self_,
data: &D,
) -> $crate::core::plot::PlotBuilder<$crate::plots::distribution::RugConfig>
where
T: Into<f64> + Copy,
{
$self_.$finalize().rug(data)
}
pub fn strip<S: AsRef<str>, D: $crate::data::NumericData1D>(
$self_,
categories: &[S],
values: &D,
) -> $crate::core::plot::PlotBuilder<$crate::plots::categorical::StripConfig> {
$self_.$finalize().strip(categories, values)
}
pub fn swarm<S: AsRef<str>, D: $crate::data::NumericData1D>(
$self_,
categories: &[S],
values: &D,
) -> $crate::core::plot::PlotBuilder<$crate::plots::categorical::SwarmConfig> {
$self_.$finalize().swarm(categories, values)
}
pub fn hexbin<X, Y>(
$self_,
x: &X,
y: &Y,
) -> $crate::core::plot::PlotBuilder<$crate::plots::continuous::hexbin::HexbinConfig>
where
X: $crate::data::NumericData1D,
Y: $crate::data::NumericData1D,
{
$self_.$finalize().hexbin(x, y)
}
pub fn dendrogram(
$self_,
linkage: &$crate::stats::clustering::Linkage,
) -> $crate::core::plot::PlotBuilder<$crate::plots::hierarchical::DendrogramConfig> {
$self_.$finalize().dendrogram(linkage)
}
pub fn grouped_bar<C, S, V>(
$self_,
categories: &[C],
series: &[(S, V)],
) -> $crate::core::plot::PlotBuilder<$crate::plots::categorical::GroupedBarConfig>
where
C: ToString,
S: ToString,
V: $crate::data::NumericData1D,
{
$self_.$finalize().grouped_bar(categories, series)
}
pub fn stacked_bar<C, S, V>(
$self_,
categories: &[C],
series: &[(S, V)],
) -> $crate::core::plot::PlotBuilder<$crate::plots::categorical::StackedBarConfig>
where
C: ToString,
S: ToString,
V: $crate::data::NumericData1D,
{
$self_.$finalize().stacked_bar(categories, series)
}
pub fn stacked_area<X, S, V>(
$self_,
x: &X,
series: &[(S, V)],
) -> $crate::core::plot::PlotBuilder<$crate::plots::continuous::StackPlotConfig>
where
X: $crate::data::NumericData1D,
S: ToString,
V: $crate::data::NumericData1D,
{
$self_.$finalize().stacked_area(x, series)
}
pub fn line_streaming(
$self_,
stream: &$crate::data::StreamingXY,
) -> $crate::core::plot::PlotBuilder<$crate::plots::basic::LineConfig> {
$self_.$finalize().line_streaming(stream)
}
pub fn scatter_streaming(
$self_,
stream: &$crate::data::StreamingXY,
) -> $crate::core::plot::PlotBuilder<$crate::plots::basic::ScatterConfig> {
$self_.$finalize().scatter_streaming(stream)
}
pub fn error_bars<X, Y, E>(
$self_,
x_data: &X,
y_data: &Y,
y_errors: &E,
) -> $crate::core::plot::PlotBuilder<$crate::plots::error::ErrorBarConfig>
where
X: $crate::data::NumericData1D,
Y: $crate::data::NumericData1D,
E: $crate::data::NumericData1D,
{
$self_.$finalize().error_bars(x_data, y_data, y_errors)
}
pub fn error_bars_source<X, Y, E>(
$self_,
x_data: X,
y_data: Y,
y_errors: E,
) -> $crate::core::plot::PlotBuilder<$crate::plots::error::ErrorBarConfig>
where
X: $crate::core::plot::IntoPlotData,
Y: $crate::core::plot::IntoPlotData,
E: $crate::core::plot::IntoPlotData,
{
$self_.$finalize().error_bars_source(x_data, y_data, y_errors)
}
pub fn error_bars_xy<X, Y, EX, EY>(
$self_,
x_data: &X,
y_data: &Y,
x_errors: &EX,
y_errors: &EY,
) -> $crate::core::plot::PlotBuilder<$crate::plots::error::ErrorBarConfig>
where
X: $crate::data::NumericData1D,
Y: $crate::data::NumericData1D,
EX: $crate::data::NumericData1D,
EY: $crate::data::NumericData1D,
{
$self_.$finalize().error_bars_xy(x_data, y_data, x_errors, y_errors)
}
pub fn error_bars_xy_source<X, Y, EX, EY>(
$self_,
x_data: X,
y_data: Y,
x_errors: EX,
y_errors: EY,
) -> $crate::core::plot::PlotBuilder<$crate::plots::error::ErrorBarConfig>
where
X: $crate::core::plot::IntoPlotData,
Y: $crate::core::plot::IntoPlotData,
EX: $crate::core::plot::IntoPlotData,
EY: $crate::core::plot::IntoPlotData,
{
$self_
.$finalize()
.error_bars_xy_source(x_data, y_data, x_errors, y_errors)
}
};
}
mod annotations;
mod bounds;
mod builder;
mod config;
mod configuration;
mod construction;
pub mod data;
mod error_bars;
mod image;
mod interactive_session;
mod layout_manager;
mod mixed_render;
mod prepared;
mod raster_batches;
mod raster_fast_path;
mod render;
mod render_pipeline;
mod series_api;
mod series_builders;
mod series_internal;
mod series_manager;
#[cfg(test)]
#[allow(deprecated)]
mod tests;
mod types;
pub use builder::{BuilderWhen, IntoPlot, PlotBuilder};
pub(crate) use builder::{PlotInput, SeriesStyle};
pub use config::{
BackendFallbackReason, BackendOperation, BackendResolution, BackendType, GridMode,
TickDirection, TickSides,
};
pub use configuration::{PlotConfiguration, TextEngineMode};
pub use data::{IntoPlotData, PlotData, PlotSource, PlotText, ReactiveValue};
pub(crate) use image::convert_rgba_alpha_mode;
pub use image::{AlphaMode, Image, source_over_straight_rgba};
pub use interactive_session::{
AnnotationId, DirtyDomain, DirtyDomains, FramePacing, FrameStats, HitResult, ImageTarget,
InteractiveChangeRevision, InteractiveChangeSubscription, InteractiveFrame,
InteractiveFrameWithGeneration, InteractivePlotSession, InteractiveRenderStamp,
InteractiveViewBoundsSnapshot, InteractiveViewportSnapshot, LayerRenderState, PlotInputEvent,
QualityPolicy, RenderTargetKind, StampedInteractiveFrame, SurfaceCapability, SurfaceTarget,
ViewportPoint, ViewportRect,
};
pub use layout_manager::LayoutManager;
pub use prepared::{PreparedPlot, ReactiveSubscription};
pub use render_pipeline::RenderPipeline;
pub use series_builders::SeriesGroupBuilder;
pub use series_manager::SeriesManager;
pub use types::{InsetAnchor, InsetLayout, Plot};
use crate::{
axes::AxisScale,
core::{
Annotation, ArrowStyle, FillStyle, GridStyle, LayoutCalculator, LayoutConfig,
LayoutMeasurements, Legend, LegendItem, LegendItemType, LegendOccupancy, LegendPosition,
MarginConfig, MeasuredDimensions, PlotConfig, PlotContent, PlotLayout, PlotStyle,
PlottingError, REFERENCE_DPI, RenderScale, ResolvedLayout, Result, ShapeStyle,
StyleResolver, TextStyle, pt_to_px,
},
data::{
Data1D, DataShader, NullPolicy, NumericData1D, NumericData2D, StreamingXY,
collect_numeric_data_1d, collect_numeric_data_2d,
},
plots::boxplot::BoxPlotConfig,
plots::error::errorbar::{ErrorBarConfig, ErrorValues},
plots::histogram::HistogramConfig,
plots::traits::PlotRender,
render::skia::{
SkiaRenderer, calculate_plot_area_config, calculate_plot_area_dpi, generate_ticks,
map_data_to_pixels, try_map_data_to_pixels_scaled,
},
render::{Color, LineStyle, MarkerStyle, Theme},
};
use std::{
borrow::Cow,
collections::{HashMap, HashSet},
fmt,
path::Path,
sync::Arc,
};
use self::data::{ReactiveTeardown, SharedReactiveCallback};
pub(crate) use self::types::{
LegendConfig, PendingIngestionError, PlotSeries, ResolvedData, ResolvedFrame, ResolvedSeries,
ResolvedSeriesStyle, ResolvedStreamingPair, ResolvedStyle, SeriesGroupMeta, SeriesStyleProps,
SeriesType, TickConfig,
};
#[cfg(feature = "gpu")]
use crate::render::gpu::GpuRenderer;