use esoc_gfx::color::Color;
use esoc_gfx::style::DashPattern;
use crate::axis::AxisConfig;
use crate::chart::{
BarSeries, BoxPlotSeries, ErrorBarSeries, HeatmapSeries, HistogramSeries, LineSeries,
ScatterSeries,
};
use crate::legend::LegendPosition;
use crate::series::SeriesRenderer;
#[derive(Default)]
pub struct Axes {
pub title: Option<String>,
pub x_config: AxisConfig,
pub y_config: AxisConfig,
pub(crate) series: Vec<Box<dyn SeriesRenderer>>,
pub legend_position: LegendPosition,
pub show_legend: bool,
}
impl Axes {
pub fn new() -> Self {
Self {
show_legend: true,
..Self::default()
}
}
pub fn title(&mut self, title: impl Into<String>) -> &mut Self {
self.title = Some(title.into());
self
}
pub fn x_label(&mut self, label: impl Into<String>) -> &mut Self {
self.x_config.label = Some(label.into());
self
}
pub fn y_label(&mut self, label: impl Into<String>) -> &mut Self {
self.y_config.label = Some(label.into());
self
}
pub fn x_range(&mut self, min: f64, max: f64) -> &mut Self {
self.x_config.range = Some((min, max));
self
}
pub fn y_range(&mut self, min: f64, max: f64) -> &mut Self {
self.y_config.range = Some((min, max));
self
}
pub fn x_axis(&mut self, config: AxisConfig) -> &mut Self {
self.x_config = config;
self
}
pub fn y_axis(&mut self, config: AxisConfig) -> &mut Self {
self.y_config = config;
self
}
pub fn legend(&mut self, position: LegendPosition) -> &mut Self {
self.legend_position = position;
self
}
pub fn line(&mut self, x: &[f64], y: &[f64]) -> LineBuilder<'_> {
LineBuilder {
axes: self,
series: Some(LineSeries::new(x, y)),
}
}
pub fn scatter(&mut self, x: &[f64], y: &[f64]) -> ScatterBuilder<'_> {
ScatterBuilder {
axes: self,
series: Some(ScatterSeries::new(x, y)),
}
}
pub fn bar(&mut self, x: &[f64], heights: &[f64]) -> BarBuilder<'_> {
BarBuilder {
axes: self,
series: Some(BarSeries::new(x, heights)),
}
}
pub fn histogram(&mut self, data: &[f64]) -> HistogramBuilder<'_> {
HistogramBuilder {
axes: self,
series: Some(HistogramSeries::new(data)),
}
}
pub fn boxplot(&mut self, datasets: Vec<Vec<f64>>) -> BoxPlotBuilder<'_> {
BoxPlotBuilder {
axes: self,
series: Some(BoxPlotSeries::new(datasets)),
}
}
pub fn heatmap(&mut self, data: Vec<Vec<f64>>) -> HeatmapBuilder<'_> {
HeatmapBuilder {
axes: self,
series: Some(HeatmapSeries::new(data)),
}
}
pub fn errorbar(&mut self, x: &[f64], y: &[f64], err: &[f64]) -> ErrorBarBuilder<'_> {
ErrorBarBuilder {
axes: self,
series: Some(ErrorBarSeries::new(x, y, err)),
}
}
pub fn add_series(&mut self, series: Box<dyn SeriesRenderer>) -> &mut Self {
self.series.push(series);
self
}
}
pub struct LineBuilder<'a> {
axes: &'a mut Axes,
series: Option<LineSeries>,
}
impl<'a> LineBuilder<'a> {
pub fn label(mut self, label: impl Into<String>) -> Self {
if let Some(s) = &mut self.series {
s.label = Some(label.into());
}
self
}
pub fn color(mut self, color: Color) -> Self {
if let Some(s) = &mut self.series {
s.color = Some(color);
}
self
}
pub fn width(mut self, width: f64) -> Self {
if let Some(s) = &mut self.series {
s.width = Some(width);
}
self
}
pub fn dash(mut self, dashes: &[f64]) -> Self {
if let Some(s) = &mut self.series {
s.dash = Some(DashPattern::new(dashes));
}
self
}
pub fn done(mut self) -> &'a mut Axes {
if let Some(s) = self.series.take() {
self.axes.series.push(Box::new(s));
}
self.axes
}
}
pub struct ScatterBuilder<'a> {
axes: &'a mut Axes,
series: Option<ScatterSeries>,
}
impl<'a> ScatterBuilder<'a> {
pub fn label(mut self, label: impl Into<String>) -> Self {
if let Some(s) = &mut self.series {
s.label = Some(label.into());
}
self
}
pub fn color(mut self, color: Color) -> Self {
if let Some(s) = &mut self.series {
s.color = Some(color);
}
self
}
pub fn radius(mut self, r: f64) -> Self {
if let Some(s) = &mut self.series {
s.radius = Some(r);
}
self
}
pub fn done(mut self) -> &'a mut Axes {
if let Some(s) = self.series.take() {
self.axes.series.push(Box::new(s));
}
self.axes
}
}
pub struct BarBuilder<'a> {
axes: &'a mut Axes,
series: Option<BarSeries>,
}
impl<'a> BarBuilder<'a> {
pub fn label(mut self, label: impl Into<String>) -> Self {
if let Some(s) = &mut self.series {
s.label = Some(label.into());
}
self
}
pub fn color(mut self, color: Color) -> Self {
if let Some(s) = &mut self.series {
s.color = Some(color);
}
self
}
pub fn bar_width(mut self, width: f64) -> Self {
if let Some(s) = &mut self.series {
s.bar_width = width;
}
self
}
pub fn horizontal(mut self) -> Self {
if let Some(s) = &mut self.series {
s.horizontal = true;
}
self
}
pub fn done(mut self) -> &'a mut Axes {
if let Some(s) = self.series.take() {
self.axes.series.push(Box::new(s));
}
self.axes
}
}
pub struct HistogramBuilder<'a> {
axes: &'a mut Axes,
series: Option<HistogramSeries>,
}
impl<'a> HistogramBuilder<'a> {
pub fn label(mut self, label: impl Into<String>) -> Self {
if let Some(s) = &mut self.series {
s.label = Some(label.into());
}
self
}
pub fn color(mut self, color: Color) -> Self {
if let Some(s) = &mut self.series {
s.color = Some(color);
}
self
}
pub fn bins(mut self, bins: usize) -> Self {
if let Some(s) = &mut self.series {
s.bin_count = Some(bins);
}
self
}
pub fn done(mut self) -> &'a mut Axes {
if let Some(s) = self.series.take() {
self.axes.series.push(Box::new(s));
}
self.axes
}
}
pub struct BoxPlotBuilder<'a> {
axes: &'a mut Axes,
series: Option<BoxPlotSeries>,
}
impl<'a> BoxPlotBuilder<'a> {
pub fn label(mut self, label: impl Into<String>) -> Self {
if let Some(s) = &mut self.series {
s.label = Some(label.into());
}
self
}
pub fn labels(mut self, labels: Vec<String>) -> Self {
if let Some(s) = &mut self.series {
s.labels = Some(labels);
}
self
}
pub fn done(mut self) -> &'a mut Axes {
if let Some(s) = self.series.take() {
self.axes.series.push(Box::new(s));
}
self.axes
}
}
pub struct HeatmapBuilder<'a> {
axes: &'a mut Axes,
series: Option<HeatmapSeries>,
}
impl<'a> HeatmapBuilder<'a> {
pub fn label(mut self, label: impl Into<String>) -> Self {
if let Some(s) = &mut self.series {
s.label = Some(label.into());
}
self
}
pub fn annotate(mut self) -> Self {
if let Some(s) = &mut self.series {
s.annotate = true;
}
self
}
pub fn row_labels(mut self, labels: Vec<String>) -> Self {
if let Some(s) = &mut self.series {
s.row_labels = Some(labels);
}
self
}
pub fn col_labels(mut self, labels: Vec<String>) -> Self {
if let Some(s) = &mut self.series {
s.col_labels = Some(labels);
}
self
}
pub fn done(mut self) -> &'a mut Axes {
if let Some(s) = self.series.take() {
self.axes.series.push(Box::new(s));
}
self.axes
}
}
pub struct ErrorBarBuilder<'a> {
axes: &'a mut Axes,
series: Option<ErrorBarSeries>,
}
impl<'a> ErrorBarBuilder<'a> {
pub fn label(mut self, label: impl Into<String>) -> Self {
if let Some(s) = &mut self.series {
s.label = Some(label.into());
}
self
}
pub fn color(mut self, color: Color) -> Self {
if let Some(s) = &mut self.series {
s.color = Some(color);
}
self
}
pub fn done(mut self) -> &'a mut Axes {
if let Some(s) = self.series.take() {
self.axes.series.push(Box::new(s));
}
self.axes
}
}