pub mod area;
pub mod bar;
pub mod bin2d;
pub mod blank;
pub mod boxplot;
pub mod bracket;
pub mod candlestick;
pub mod col;
pub mod contour;
pub mod count;
pub mod crossbar;
pub mod curve;
pub mod density;
pub mod density2d;
pub mod dotplot;
pub mod errorbar;
pub mod freqpoly;
pub mod hex;
pub mod histogram;
pub mod jitter;
pub mod line;
pub mod linerange;
pub mod path;
pub mod point;
pub mod pointrange;
pub mod polygon;
pub mod qq;
pub mod raster;
pub mod rect;
pub mod refline;
pub mod ribbon;
pub mod rug;
pub mod segment;
#[cfg(feature = "sf")]
pub mod sf;
pub mod smooth;
pub mod spoke;
pub mod step;
pub mod text;
pub mod tile;
pub mod violin;
use std::collections::HashMap;
use crate::aes::Aesthetic;
use crate::coord::Coord;
use crate::data::DataFrame;
use crate::position::Position;
use crate::render::backend::DrawBackend;
use crate::render::RenderError;
use crate::scale::ScaleSet;
use crate::stat::Stat;
use crate::theme::Theme;
#[derive(Clone, Debug, Default)]
pub struct GeomParams {
pub values: HashMap<String, f64>,
pub color: Option<(u8, u8, u8)>,
pub fill: Option<(u8, u8, u8)>,
pub alpha: Option<f64>,
}
pub trait Geom: Send + Sync {
fn draw(
&self,
data: &DataFrame,
coord: &dyn Coord,
scales: &ScaleSet,
theme: &Theme,
backend: &mut dyn DrawBackend,
) -> Result<(), RenderError>;
fn required_aes(&self) -> Vec<Aesthetic>;
fn default_stat(&self) -> Box<dyn Stat>;
fn default_position(&self) -> Box<dyn Position>;
fn default_params(&self) -> GeomParams;
fn name(&self) -> &str;
fn set_series_color(&mut self, _color: (u8, u8, u8)) {}
fn include_zero_baseline(&self) -> bool {
false
}
fn allows_infinite(&self) -> bool {
false
}
fn setup_data(&self, _data: &mut DataFrame) {}
}
pub(crate) fn tip_value(v: &crate::data::Value) -> String {
crate::format::format_value(v)
}
pub(crate) fn continuous_bar_half_width(
mapped_xs: impl Iterator<Item = f64>,
width: f64,
fallback: f64,
) -> f64 {
let mut xs: Vec<f64> = mapped_xs.filter(|x| x.is_finite()).collect();
xs.sort_by(|a, b| a.total_cmp(b));
xs.dedup_by(|a, b| (*a - *b).abs() < 1e-12);
let gap = xs
.windows(2)
.map(|w| w[1] - w[0])
.fold(f64::INFINITY, f64::min);
if gap.is_finite() && gap > 0.0 {
gap * width / 2.0
} else {
fallback
}
}
pub(crate) fn raw_value(v: &crate::data::Value) -> Option<String> {
use crate::data::Value;
match v {
Value::Float(f) if f.is_finite() => Some(format!("{f}")),
Value::Float(_) | Value::Na => None,
Value::Integer(i) => Some(i.to_string()),
Value::DateTime(s) => Some(s.to_string()),
Value::Str(s) => Some(s.clone()),
Value::Bool(b) => Some(b.to_string()),
}
}
pub(crate) fn series_key(data: &DataFrame, i: usize) -> Option<String> {
["color", "fill", "group"].iter().find_map(|c| {
data.column(c)
.and_then(|col| col.get(i))
.filter(|v| !v.is_na())
.map(tip_value)
.filter(|s| !s.is_empty())
})
}
pub(crate) fn measured_value(data: &DataFrame, i: usize) -> Option<String> {
data.column(crate::position::RAW_Y_COL)
.or_else(|| data.column("y"))
.and_then(|c| c.get(i))
.and_then(raw_value)
}
pub(crate) fn set_mark(
backend: &mut dyn DrawBackend,
tooltip: Option<String>,
x: Option<String>,
series: Option<String>,
value: Option<String>,
) {
backend.set_tooltip(tooltip);
backend.set_mark_axis(x);
backend.set_mark_series(series);
backend.set_mark_value(value);
}
pub(crate) fn clear_mark(backend: &mut dyn DrawBackend) {
set_mark(backend, None, None, None, None);
}