1#[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
2use plotters::prelude::IntoDrawingArea;
3
4use crate::aes::Aes;
5use crate::annotate::Annotation;
6use crate::build::PlotBuilder;
7use crate::coord::cartesian::CoordCartesian;
8use crate::coord::fixed::CoordFixed;
9use crate::coord::flip::CoordFlip;
10use crate::coord::polar::CoordPolar;
11use crate::coord::Coord;
12use crate::data::{DataFrame, GGData, Value};
13use crate::facet::{Facet, FacetLabeller, FacetScales, FacetSpace};
14use crate::geom::area::GeomArea;
15use crate::geom::bar::GeomBar;
16use crate::geom::bin2d::GeomBin2d;
17use crate::geom::blank::GeomBlank;
18use crate::geom::boxplot::GeomBoxplot;
19use crate::geom::col::GeomCol;
20use crate::geom::contour::GeomContour;
21use crate::geom::count::GeomCount;
22use crate::geom::crossbar::GeomCrossbar;
23use crate::geom::curve::GeomCurve;
24use crate::geom::density::GeomDensity;
25use crate::geom::density2d::GeomDensity2d;
26use crate::geom::dotplot::GeomDotplot;
27use crate::geom::errorbar::GeomErrorbar;
28use crate::geom::freqpoly::GeomFreqpoly;
29use crate::geom::hex::GeomHex;
30use crate::geom::histogram::GeomHistogram;
31use crate::geom::jitter::GeomJitter;
32use crate::geom::line::GeomLine;
33use crate::geom::linerange::GeomLinerange;
34use crate::geom::path::GeomPath;
35use crate::geom::point::GeomPoint;
36use crate::geom::pointrange::GeomPointrange;
37use crate::geom::polygon::GeomPolygon;
38use crate::geom::qq::{GeomQQ, GeomQQLine};
39use crate::geom::rect::GeomRect;
40use crate::geom::refline::{GeomAbline, GeomHline, GeomVline};
41use crate::geom::ribbon::GeomRibbon;
42use crate::geom::rug::GeomRug;
43use crate::geom::segment::GeomSegment;
44use crate::geom::smooth::GeomSmooth;
45use crate::geom::spoke::GeomSpoke;
46use crate::geom::step::GeomStep;
47use crate::geom::text::{GeomLabel, GeomText};
48use crate::geom::tile::GeomTile;
49use crate::geom::violin::GeomViolin;
50use crate::geom::{Geom, GeomParams};
51use crate::position::Position;
52use crate::render::layout::PlotLayout;
53#[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
54use crate::render::plotters_backend::PlottersAdapter;
55use crate::render::renderer::PlotRenderer;
56use crate::render::RenderError;
57use crate::scale::continuous::ScaleContinuous;
58use crate::scale::transform::ScaleTransform;
59use crate::scale::Scale;
60use crate::stat::Stat;
61use crate::theme::Theme;
62
63mod stat_layers;
66
67#[derive(Clone, Debug, Default)]
69pub struct Labels {
70 pub title: Option<String>,
71 pub subtitle: Option<String>,
72 pub x: Option<String>,
73 pub y: Option<String>,
74 pub caption: Option<String>,
75 pub tag: Option<String>,
77}
78
79pub struct Layer {
81 pub data: Option<DataFrame>,
82 pub mapping: Aes,
83 pub geom: Box<dyn Geom>,
84 pub stat: Box<dyn Stat>,
85 pub position: Box<dyn Position>,
86 pub params: GeomParams,
87 pub show_legend: Option<bool>,
88 pub explicit_style: bool,
91}
92
93pub struct GGPlot {
95 pub(crate) data: DataFrame,
96 pub(crate) mapping: Aes,
97 pub(crate) layers: Vec<Layer>,
98 pub(crate) scales: Vec<Box<dyn Scale>>,
99 pub(crate) coord: Box<dyn Coord>,
100 pub(crate) theme: Theme,
101 pub(crate) labels: Labels,
102 pub(crate) facet: Facet,
103 pub(crate) annotations: Vec<Annotation>,
104 pub(crate) guide_legend: crate::guide::config::GuideLegend,
105 pub(crate) warnings: Vec<String>,
108 pub(crate) default_aspect_ratio: Option<f64>,
111 pub(crate) locale: Option<crate::locale::Locale>,
113}
114
115impl GGPlot {
116 pub fn new(data: impl GGData) -> Self {
123 GGPlot {
124 data: data.into_dataframe(),
125 mapping: Aes::default(),
126 layers: Vec::new(),
127 scales: Vec::new(),
128 coord: Box::new(CoordCartesian::new()),
129 theme: Theme::default(),
130 labels: Labels::default(),
131 facet: Facet::default(),
132 annotations: Vec::new(),
133 guide_legend: crate::guide::config::GuideLegend::default(),
134 warnings: Vec::new(),
135 default_aspect_ratio: None,
136 locale: None,
137 }
138 }
139
140 pub fn aes(mut self, mapping: Aes) -> Self {
142 self.mapping = mapping;
143 self
144 }
145
146 pub fn geom_point(self) -> Self {
149 self.add_geom(GeomPoint::default())
150 }
151
152 pub fn geom_point_with(self, geom: GeomPoint) -> Self {
153 self.add_geom_with(geom)
154 }
155
156 pub fn geom_line(self) -> Self {
157 self.add_geom(GeomLine::default())
158 }
159
160 pub fn geom_line_with(self, geom: GeomLine) -> Self {
161 self.add_geom_with(geom)
162 }
163
164 pub fn geom_bar(self) -> Self {
165 self.add_geom(GeomBar::default())
166 }
167
168 pub fn geom_bar_with(self, geom: GeomBar) -> Self {
169 self.add_geom_with(geom)
170 }
171
172 pub fn geom_histogram(self) -> Self {
173 self.add_geom(GeomHistogram::default())
174 }
175
176 pub fn geom_histogram_with(self, geom: GeomHistogram) -> Self {
177 self.add_geom_with(geom)
178 }
179
180 pub fn geom_boxplot(self) -> Self {
181 self.add_geom(GeomBoxplot::default())
182 }
183
184 pub fn geom_boxplot_with(self, geom: GeomBoxplot) -> Self {
185 self.add_geom_with(geom)
186 }
187
188 pub fn geom_smooth(self) -> Self {
189 self.add_geom(GeomSmooth::default())
190 }
191
192 pub fn geom_smooth_with(self, geom: GeomSmooth) -> Self {
193 self.add_geom_with(geom)
194 }
195
196 pub fn geom_col(self) -> Self {
197 self.add_geom(GeomCol::default())
198 }
199
200 pub fn geom_col_with(self, geom: GeomCol) -> Self {
201 self.add_geom_with(geom)
202 }
203
204 pub fn geom_hline(self, yintercept: f64) -> Self {
208 self.add_refline(
209 GeomHline::new(yintercept),
210 false,
211 &[("yintercept", yintercept)],
212 )
213 }
214
215 pub fn geom_hline_with(self, geom: GeomHline) -> Self {
217 let y = geom.yintercept;
218 self.add_refline(geom, true, &[("yintercept", y)])
219 }
220
221 pub fn geom_hline_aes(self, mapping: Aes) -> Self {
245 self.add_geom(GeomHline::mapped()).layer_aes(mapping)
246 }
247
248 pub fn geom_hline_aes_with(self, geom: GeomHline, mapping: Aes) -> Self {
250 self.add_geom_with(geom).layer_aes(mapping)
251 }
252
253 pub fn geom_vline(self, xintercept: f64) -> Self {
256 self.add_refline(
257 GeomVline::new(xintercept),
258 false,
259 &[("xintercept", xintercept)],
260 )
261 }
262
263 pub fn geom_vline_with(self, geom: GeomVline) -> Self {
265 let x = geom.xintercept;
266 self.add_refline(geom, true, &[("xintercept", x)])
267 }
268
269 pub fn geom_vline_aes(self, mapping: Aes) -> Self {
272 self.add_geom(GeomVline::mapped()).layer_aes(mapping)
273 }
274
275 pub fn geom_vline_aes_with(self, geom: GeomVline, mapping: Aes) -> Self {
277 self.add_geom_with(geom).layer_aes(mapping)
278 }
279
280 pub fn geom_abline(self, slope: f64, intercept: f64) -> Self {
283 self.add_refline(
284 GeomAbline::new(slope, intercept),
285 false,
286 &[("slope", slope), ("intercept", intercept)],
287 )
288 }
289
290 pub fn geom_abline_with(self, geom: GeomAbline) -> Self {
292 let (b, a) = (geom.slope, geom.intercept);
293 self.add_refline(geom, true, &[("slope", b), ("intercept", a)])
294 }
295
296 pub fn geom_abline_aes(self, mapping: Aes) -> Self {
299 self.add_geom(GeomAbline::mapped()).layer_aes(mapping)
300 }
301
302 pub fn geom_abline_aes_with(self, geom: GeomAbline, mapping: Aes) -> Self {
304 self.add_geom_with(geom).layer_aes(mapping)
305 }
306
307 fn add_refline(
310 self,
311 geom: impl Geom + 'static,
312 explicit: bool,
313 values: &[(&str, f64)],
314 ) -> Self {
315 let mut data = DataFrame::new();
316 let mut mapping = Aes::new();
317 for (col, v) in values {
318 data.add_column(col.to_string(), vec![Value::Float(*v)]);
319 mapping = match *col {
320 "xintercept" => mapping.xintercept(col),
321 "yintercept" => mapping.yintercept(col),
322 "slope" => mapping.slope(col),
323 _ => mapping.intercept(col),
324 };
325 }
326 let plot = if explicit {
327 self.add_geom_with(geom)
328 } else {
329 self.add_geom(geom)
330 };
331 plot.layer_aes(mapping).layer_data(data)
332 }
333
334 pub fn geom_text(self) -> Self {
335 self.add_geom(GeomText::default())
336 }
337
338 pub fn geom_text_with(self, geom: GeomText) -> Self {
339 self.add_geom_with(geom)
340 }
341
342 #[cfg(feature = "ggpubr")]
347 pub fn stat_cor(self) -> Self {
348 self.geom_text().stat(crate::stat::cor::StatCor::default())
349 }
350
351 #[cfg(feature = "ggpubr")]
354 pub fn stat_cor_with(self, stat: crate::stat::cor::StatCor) -> Self {
355 self.geom_text().stat(stat)
356 }
357
358 #[cfg(feature = "ggpubr")]
363 pub fn stat_compare_means(self) -> Self {
364 self.geom_text()
365 .stat(crate::stat::compare_means::StatCompareMeans::default())
366 }
367
368 #[cfg(feature = "ggpubr")]
371 pub fn stat_compare_means_with(
372 self,
373 stat: crate::stat::compare_means::StatCompareMeans,
374 ) -> Self {
375 self.geom_text().stat(stat)
376 }
377
378 #[cfg(feature = "ggpubr")]
384 pub fn stat_compare_means_pairwise(self, comparisons: &[(&str, &str)]) -> Self {
385 self.stat_compare_means_pairwise_with(
386 crate::stat::compare_means::CompareMethod::Auto,
387 comparisons,
388 )
389 }
390
391 #[cfg(feature = "ggpubr")]
394 pub fn stat_compare_means_pairwise_with(
395 self,
396 method: crate::stat::compare_means::CompareMethod,
397 comparisons: &[(&str, &str)],
398 ) -> Self {
399 let col_for = |a: crate::aes::Aesthetic| {
401 self.mapping
402 .mappings
403 .iter()
404 .find(|m| m.aesthetic == a)
405 .map(|m| m.column.clone())
406 };
407 let (xcol, ycol) = match (
408 col_for(crate::aes::Aesthetic::X),
409 col_for(crate::aes::Aesthetic::Y),
410 ) {
411 (Some(x), Some(y)) => (x, y),
412 _ => return self,
413 };
414 let (xc, yc) = match (self.data.column(&xcol), self.data.column(&ycol)) {
415 (Some(x), Some(y)) => (x, y),
416 _ => return self,
417 };
418
419 let mut groups: Vec<(String, Vec<f64>)> = Vec::new();
421 let mut ymax = f64::NEG_INFINITY;
422 let mut ymin = f64::INFINITY;
423 for (xv, yv) in xc.iter().zip(yc.iter()) {
424 let y = match yv.as_f64() {
425 Some(y) if y.is_finite() => y,
426 _ => continue,
427 };
428 ymax = ymax.max(y);
429 ymin = ymin.min(y);
430 let key = xv.to_group_key();
431 if let Some(g) = groups.iter_mut().find(|(k, _)| *k == key) {
432 g.1.push(y);
433 } else {
434 groups.push((key, vec![y]));
435 }
436 }
437 if groups.len() < 2 {
438 return self;
439 }
440 let step = if ymax > ymin {
441 (ymax - ymin) * 0.12
442 } else {
443 1.0
444 };
445
446 let (mut xmin_v, mut xmax_v, mut y_v, mut label_v) =
448 (Vec::new(), Vec::new(), Vec::new(), Vec::new());
449 let mut placed = 0usize;
450 for (a, b) in comparisons {
451 let ga = groups.iter().find(|(k, _)| k == a).map(|g| &g.1);
452 let gb = groups.iter().find(|(k, _)| k == b).map(|g| &g.1);
453 let (ga, gb) = match (ga, gb) {
454 (Some(x), Some(y)) if x.len() >= 2 && y.len() >= 2 => (x, y),
455 _ => continue,
456 };
457 let p = match crate::stat::compare_means::pairwise_p(method, ga, gb) {
458 Some(p) => p,
459 None => continue,
460 };
461 xmin_v.push(Value::Str((*a).to_string()));
462 xmax_v.push(Value::Str((*b).to_string()));
463 y_v.push(Value::Float(ymax + step * (placed as f64 + 1.0)));
464 label_v.push(Value::Str(crate::stat::cor::format_p_value(p)));
465 placed += 1;
466 }
467 if xmin_v.is_empty() {
468 return self;
469 }
470
471 let data = vec![
472 ("xmin".to_string(), xmin_v),
473 ("xmax".to_string(), xmax_v),
474 ("y".to_string(), y_v),
475 ("label".to_string(), label_v),
476 ];
477 self.add_geom(crate::geom::bracket::GeomBracket::default())
478 .layer_data(data)
479 .layer_aes(Aes::new().xmin("xmin").xmax("xmax").y("y").label("label"))
480 }
481
482 pub fn geom_bracket(self, xmin: &str, xmax: &str, y: f64, label: &str) -> Self {
487 self.geom_bracket_many(
488 crate::geom::bracket::GeomBracket::default(),
489 &[(xmin, xmax, y, label)],
490 )
491 }
492
493 pub fn geom_bracket_many(
497 self,
498 geom: crate::geom::bracket::GeomBracket,
499 brackets: &[(&str, &str, f64, &str)],
500 ) -> Self {
501 let xmin = brackets
502 .iter()
503 .map(|b| Value::Str(b.0.to_string()))
504 .collect::<Vec<_>>();
505 let xmax = brackets
506 .iter()
507 .map(|b| Value::Str(b.1.to_string()))
508 .collect::<Vec<_>>();
509 let y = brackets
510 .iter()
511 .map(|b| Value::Float(b.2))
512 .collect::<Vec<_>>();
513 let label = brackets
514 .iter()
515 .map(|b| Value::Str(b.3.to_string()))
516 .collect::<Vec<_>>();
517 let data = vec![
518 ("xmin".to_string(), xmin),
519 ("xmax".to_string(), xmax),
520 ("y".to_string(), y),
521 ("label".to_string(), label),
522 ];
523 self.add_geom(geom)
524 .layer_data(data)
525 .layer_aes(Aes::new().xmin("xmin").xmax("xmax").y("y").label("label"))
526 }
527
528 pub fn geom_bracket_table(
537 mut self,
538 table: impl GGData,
539 spec: crate::geom::bracket::BracketTable,
540 ) -> Self {
541 let table = table.into_dataframe();
542 let col_for = |a: crate::aes::Aesthetic| {
543 self.mapping
544 .mappings
545 .iter()
546 .find(|m| m.aesthetic == a)
547 .map(|m| m.column.clone())
548 };
549 let x_levels: Vec<String> = col_for(crate::aes::Aesthetic::X)
552 .and_then(|c| self.data.column(&c))
553 .filter(|col| col.iter().any(|v| matches!(v, Value::Str(_))))
554 .map(|col| {
555 let mut seen = std::collections::HashSet::new();
556 col.iter()
557 .filter(|v| !v.is_na())
558 .map(|v| v.to_group_key())
559 .filter(|k| seen.insert(k.clone()))
560 .collect()
561 })
562 .unwrap_or_default();
563 let y_range = col_for(crate::aes::Aesthetic::Y)
564 .and_then(|c| self.data.column(&c))
565 .and_then(|col| {
566 let (lo, hi) = col
567 .iter()
568 .filter_map(|v| v.as_f64())
569 .filter(|v| v.is_finite())
570 .fold((f64::INFINITY, f64::NEG_INFINITY), |(lo, hi), v| {
571 (lo.min(v), hi.max(v))
572 });
573 (lo <= hi).then_some((lo, hi))
574 });
575 let mut warnings = Vec::new();
576 let resolved = spec.resolve(&table, &x_levels, y_range, &mut warnings);
577 self.warnings.extend(warnings);
578 match resolved {
579 Some(data) => self
580 .add_geom(crate::geom::bracket::GeomBracket::from(spec.geom))
581 .layer_data(data)
582 .layer_aes(Aes::new().xmin("xmin").xmax("xmax").y("y").label("label")),
583 None => self,
584 }
585 }
586
587 pub fn geom_text_repel(self) -> Self {
592 self.add_geom(crate::geom::repel::GeomTextRepel::default())
593 }
594
595 pub fn geom_text_repel_with(self, geom: crate::geom::repel::GeomTextRepel) -> Self {
598 self.add_geom_with(geom)
599 }
600
601 pub fn geom_label_repel(self) -> Self {
604 self.add_geom(crate::geom::repel::GeomLabelRepel::default())
605 }
606
607 pub fn geom_label_repel_with(self, geom: crate::geom::repel::GeomLabelRepel) -> Self {
609 self.add_geom_with(geom)
610 }
611
612 pub fn geom_label(self) -> Self {
613 self.add_geom(GeomLabel::default())
614 }
615
616 pub fn geom_label_with(self, geom: GeomLabel) -> Self {
617 self.add_geom_with(geom)
618 }
619
620 pub fn geom_area(self) -> Self {
621 self.add_geom(GeomArea::default())
622 }
623
624 pub fn geom_area_with(self, geom: GeomArea) -> Self {
625 self.add_geom_with(geom)
626 }
627
628 pub fn geom_ribbon(self) -> Self {
629 self.add_geom(GeomRibbon::default())
630 }
631
632 pub fn geom_ribbon_with(self, geom: GeomRibbon) -> Self {
633 self.add_geom_with(geom)
634 }
635
636 pub fn geom_errorbar(self) -> Self {
637 self.add_geom(GeomErrorbar::default())
638 }
639
640 pub fn geom_errorbar_with(self, geom: GeomErrorbar) -> Self {
641 self.add_geom_with(geom)
642 }
643
644 pub fn geom_segment(self) -> Self {
645 self.add_geom(GeomSegment::default())
646 }
647
648 pub fn geom_segment_with(self, geom: GeomSegment) -> Self {
649 self.add_geom_with(geom)
650 }
651
652 pub fn geom_density(self) -> Self {
653 self.add_geom(GeomDensity::default())
654 }
655
656 pub fn geom_density_with(self, geom: GeomDensity) -> Self {
657 self.add_geom_with(geom)
658 }
659
660 pub fn geom_rug(self) -> Self {
661 self.add_geom(GeomRug::default())
662 }
663
664 pub fn geom_rug_with(self, geom: GeomRug) -> Self {
665 self.add_geom_with(geom)
666 }
667
668 pub fn geom_jitter(self) -> Self {
669 self.add_geom(GeomJitter::default())
670 }
671
672 pub fn geom_jitter_with(self, geom: GeomJitter) -> Self {
673 self.add_geom_with(geom)
674 }
675
676 pub fn geom_path(self) -> Self {
677 self.add_geom(GeomPath::default())
678 }
679
680 pub fn geom_path_with(self, geom: GeomPath) -> Self {
681 self.add_geom_with(geom)
682 }
683
684 pub fn stat_ellipse(self) -> Self {
686 self.geom_path()
687 .stat(crate::stat::ellipse::StatEllipse::default())
688 }
689
690 pub fn stat_ellipse_level(self, level: f64) -> Self {
692 self.geom_path()
693 .stat(crate::stat::ellipse::StatEllipse::new(level))
694 }
695
696 #[cfg(feature = "regression")]
699 pub fn stat_quantile(mut self, taus: &[f64]) -> Self {
700 for &tau in taus {
701 self = self
702 .geom_path()
703 .stat(crate::stat::quantile::StatQuantile::new(tau));
704 }
705 self
706 }
707
708 #[cfg(feature = "regression")]
710 pub fn geom_quantile(self) -> Self {
711 self.stat_quantile(&[0.25, 0.5, 0.75])
712 }
713
714 pub fn geom_step(self) -> Self {
715 self.add_geom(GeomStep::default())
716 }
717
718 pub fn geom_step_with(self, geom: GeomStep) -> Self {
719 self.add_geom_with(geom)
720 }
721
722 pub fn geom_freqpoly(self) -> Self {
723 self.add_geom(GeomFreqpoly::default())
724 }
725
726 pub fn geom_freqpoly_with(self, geom: GeomFreqpoly) -> Self {
727 self.add_geom_with(geom)
728 }
729
730 pub fn geom_linerange(self) -> Self {
731 self.add_geom(GeomLinerange::default())
732 }
733
734 pub fn geom_linerange_with(self, geom: GeomLinerange) -> Self {
735 self.add_geom_with(geom)
736 }
737
738 pub fn geom_pointrange(self) -> Self {
739 self.add_geom(GeomPointrange::default())
740 }
741
742 pub fn geom_pointrange_with(self, geom: GeomPointrange) -> Self {
743 self.add_geom_with(geom)
744 }
745
746 pub fn geom_crossbar(self) -> Self {
747 self.add_geom(GeomCrossbar::default())
748 }
749
750 pub fn geom_crossbar_with(self, geom: GeomCrossbar) -> Self {
751 self.add_geom_with(geom)
752 }
753
754 pub fn geom_spoke(self) -> Self {
755 self.add_geom(GeomSpoke::default())
756 }
757
758 pub fn geom_spoke_with(self, geom: GeomSpoke) -> Self {
759 self.add_geom_with(geom)
760 }
761
762 pub fn geom_rect(self) -> Self {
763 self.add_geom(GeomRect::default())
764 }
765
766 pub fn geom_rect_with(self, geom: GeomRect) -> Self {
767 self.add_geom_with(geom)
768 }
769
770 pub fn geom_tile(self) -> Self {
771 self.add_geom(GeomTile::default())
772 }
773
774 pub fn geom_tile_with(self, geom: GeomTile) -> Self {
775 self.add_geom_with(geom)
776 }
777
778 pub fn geom_raster(self) -> Self {
780 self.add_geom(crate::geom::raster::GeomRaster::default())
781 }
782
783 pub fn geom_raster_with(self, geom: crate::geom::raster::GeomRaster) -> Self {
784 self.add_geom_with(geom)
785 }
786
787 pub fn geom_polygon(self) -> Self {
788 self.add_geom(GeomPolygon::default())
789 }
790
791 pub fn geom_polygon_with(self, geom: GeomPolygon) -> Self {
792 self.add_geom_with(geom)
793 }
794
795 #[cfg(feature = "sf")]
797 pub fn geom_sf(self) -> Self {
798 self.add_geom(crate::geom::sf::GeomSf::default())
799 }
800
801 #[cfg(feature = "sf")]
802 pub fn geom_sf_with(self, geom: crate::geom::sf::GeomSf) -> Self {
803 self.add_geom_with(geom)
804 }
805
806 pub fn geom_curve(self) -> Self {
807 self.add_geom(GeomCurve::default())
808 }
809
810 pub fn geom_curve_with(self, geom: GeomCurve) -> Self {
811 self.add_geom_with(geom)
812 }
813
814 pub fn geom_violin(self) -> Self {
815 self.add_geom(GeomViolin::default())
816 }
817
818 pub fn geom_violin_with(self, geom: GeomViolin) -> Self {
819 self.add_geom_with(geom)
820 }
821
822 pub fn geom_dotplot(self) -> Self {
823 self.add_geom(GeomDotplot::default())
824 }
825
826 pub fn geom_dotplot_with(self, geom: GeomDotplot) -> Self {
827 self.add_geom_with(geom)
828 }
829
830 pub fn geom_qq(self) -> Self {
831 self.add_geom(GeomQQ::default())
832 }
833
834 pub fn geom_qq_with(self, geom: GeomQQ) -> Self {
835 self.add_geom_with(geom)
836 }
837
838 pub fn geom_qq_line(self) -> Self {
839 self.add_geom(GeomQQLine::default())
840 }
841
842 pub fn geom_qq_line_with(self, geom: GeomQQLine) -> Self {
843 self.add_geom_with(geom)
844 }
845
846 pub fn geom_bin2d(self) -> Self {
847 self.add_geom(GeomBin2d::default())
848 }
849
850 pub fn geom_bin2d_with(self, geom: GeomBin2d) -> Self {
851 self.add_geom_with(geom)
852 }
853
854 pub fn geom_hex(self) -> Self {
855 self.add_geom(GeomHex::default())
856 }
857
858 pub fn geom_hex_with(self, geom: GeomHex) -> Self {
859 self.add_geom_with(geom)
860 }
861
862 pub fn geom_count(self) -> Self {
863 self.add_geom(GeomCount::default())
864 }
865
866 pub fn geom_count_with(self, geom: GeomCount) -> Self {
867 self.add_geom_with(geom)
868 }
869
870 pub fn geom_contour(self) -> Self {
871 self.add_geom(GeomContour::default())
872 }
873
874 pub fn geom_contour_with(self, geom: GeomContour) -> Self {
875 self.add_geom_with(geom)
876 }
877
878 pub fn geom_contour_filled(self) -> Self {
881 self.add_geom(GeomPolygon {
882 line_width: 0.0,
883 alpha: 1.0,
884 ..GeomPolygon::default()
885 })
886 .stat(crate::stat::contour_filled::StatContourFilled::default())
887 }
888
889 pub fn geom_density2d(self) -> Self {
890 self.add_geom(GeomDensity2d::default())
891 }
892
893 pub fn geom_density2d_with(self, geom: GeomDensity2d) -> Self {
894 self.add_geom_with(geom)
895 }
896
897 pub fn geom_candlestick(self) -> Self {
900 self.add_geom(crate::geom::candlestick::GeomCandlestick::default())
901 }
902
903 pub fn geom_candlestick_with(self, geom: crate::geom::candlestick::GeomCandlestick) -> Self {
904 self.add_geom_with(geom)
905 }
906
907 pub fn geom_ohlc(self) -> Self {
910 self.add_geom(crate::geom::candlestick::GeomOhlc::default())
911 }
912
913 pub fn geom_ohlc_with(self, geom: crate::geom::candlestick::GeomOhlc) -> Self {
914 self.add_geom_with(geom)
915 }
916
917 pub fn geom_calendar(self) -> Self {
928 self.geom_calendar_with(
929 GeomTile {
930 color: (255, 255, 255),
931 line_width: 1.5,
932 ..Default::default()
933 },
934 false,
935 )
936 }
937
938 pub fn geom_calendar_with(mut self, tile: GeomTile, monday_first: bool) -> Self {
941 use crate::stat::calendar::{
942 day_number, month_boundaries, month_breaks, CalendarGrid, StatCalendar,
943 MAX_CALENDAR_YEARS,
944 };
945 let grid = self
946 .mapping
947 .get_mapping(&crate::aes::Aesthetic::X)
948 .and_then(|c| self.data.column(c))
949 .and_then(|col| {
950 CalendarGrid::from_days(col.iter().filter_map(day_number), monday_first)
951 });
952 let Some((grid, clipped)) = grid else {
953 return self.add_geom_with(tile).stat(StatCalendar {
955 grid: None,
956 monday_first,
957 });
958 };
959 if clipped {
960 self.warnings.push(format!(
961 "geom_calendar: dates more than {MAX_CALENDAR_YEARS} years before the newest were dropped"
962 ));
963 }
964 let (xb, xl) = month_breaks(&grid);
965 let (yb, yl) = if monday_first {
967 (vec![6.0, 4.0, 2.0], ["Mon", "Wed", "Fri"])
968 } else {
969 (vec![5.0, 3.0, 1.0], ["Mon", "Wed", "Fri"])
970 };
971 let segs = month_boundaries(&grid);
972 let col = |f: fn(&(f64, f64, f64, f64)) -> f64| -> Vec<Value> {
973 segs.iter().map(|s| Value::Float(f(s))).collect()
974 };
975 let boundaries = vec![
976 ("x".to_string(), col(|s| s.0)),
977 ("y".to_string(), col(|s| s.1)),
978 ("xend".to_string(), col(|s| s.2)),
979 ("yend".to_string(), col(|s| s.3)),
980 ];
981 self.default_aspect_ratio = Some(7.0 / grid.n_weeks().max(1) as f64);
982 let plot = self
983 .add_geom_with(tile)
984 .stat(StatCalendar {
985 grid: Some(grid),
986 monday_first,
987 })
988 .scale_x_continuous(
989 ScaleContinuous::new()
990 .with_breaks(xb)
991 .with_labels(xl)
992 .with_expand(0.0, 0.0),
993 )
994 .scale_y_continuous(
995 ScaleContinuous::new()
996 .with_breaks(yb)
997 .with_labels(yl.iter().map(|s| s.to_string()).collect())
998 .with_expand(0.0, 0.0),
999 );
1000 if segs.is_empty() {
1001 return plot;
1002 }
1003 plot.geom_segment_with(GeomSegment {
1004 color: (120, 128, 140),
1005 width: 1.2,
1006 alpha: 1.0,
1007 })
1008 .layer_data(boundaries)
1009 .layer_aes(Aes::new().x("x").y("y").xend("xend").yend("yend"))
1010 .show_legend(false)
1011 }
1012
1013 pub fn geom_blank(self) -> Self {
1014 self.add_geom(GeomBlank)
1015 }
1016
1017 fn add_geom_with(self, geom: impl Geom + 'static) -> Self {
1020 let mut plot = self.add_geom(geom);
1021 if let Some(layer) = plot.layers.last_mut() {
1022 layer.explicit_style = true;
1023 }
1024 plot
1025 }
1026
1027 fn add_geom(mut self, geom: impl Geom + 'static) -> Self {
1028 let stat = geom.default_stat();
1029 let position = geom.default_position();
1030 let params = geom.default_params();
1031 self.layers.push(Layer {
1032 data: None,
1033 mapping: Aes::default(),
1034 geom: Box::new(geom),
1035 stat,
1036 position,
1037 params,
1038 show_legend: None,
1039 explicit_style: false,
1040 });
1041 self
1042 }
1043
1044 pub fn stat(mut self, stat: impl Stat + 'static) -> Self {
1048 if let Some(layer) = self.layers.last_mut() {
1049 layer.stat = Box::new(stat);
1050 }
1051 self
1052 }
1053
1054 pub fn position(mut self, pos: impl Position + 'static) -> Self {
1056 if let Some(layer) = self.layers.last_mut() {
1057 layer.position = Box::new(pos);
1058 }
1059 self
1060 }
1061
1062 pub fn layer_data(mut self, data: impl GGData) -> Self {
1064 if let Some(layer) = self.layers.last_mut() {
1065 layer.data = Some(data.into_dataframe());
1066 }
1067 self
1068 }
1069
1070 pub fn layer_aes(mut self, mapping: Aes) -> Self {
1072 if let Some(layer) = self.layers.last_mut() {
1073 layer.mapping = mapping;
1074 }
1075 self
1076 }
1077
1078 pub fn show_legend(mut self, show: bool) -> Self {
1081 if let Some(layer) = self.layers.last_mut() {
1082 layer.show_legend = Some(show);
1083 }
1084 self
1085 }
1086
1087 pub fn scale_x_continuous(mut self, s: ScaleContinuous) -> Self {
1090 let s = s.for_aesthetic(crate::aes::Aesthetic::X);
1091 self.scales.push(Box::new(s));
1092 self
1093 }
1094
1095 pub fn scale_y_continuous(mut self, s: ScaleContinuous) -> Self {
1096 let s = s.for_aesthetic(crate::aes::Aesthetic::Y);
1097 self.scales.push(Box::new(s));
1098 self
1099 }
1100
1101 pub fn scale_x_discrete(mut self, s: crate::scale::discrete::ScaleDiscrete) -> Self {
1102 let s = s.for_aesthetic(crate::aes::Aesthetic::X);
1103 self.scales.push(Box::new(s));
1104 self
1105 }
1106
1107 pub fn scale_y_discrete(mut self, s: crate::scale::discrete::ScaleDiscrete) -> Self {
1108 let s = s.for_aesthetic(crate::aes::Aesthetic::Y);
1109 self.scales.push(Box::new(s));
1110 self
1111 }
1112
1113 pub fn scale_color(mut self, s: impl Scale + 'static) -> Self {
1114 self.scales.push(Box::new(s));
1115 self
1116 }
1117
1118 pub fn scale_fill(mut self, s: impl Scale + 'static) -> Self {
1119 self.scales.push(Box::new(s));
1120 self
1121 }
1122
1123 pub fn scale_color_manual(self, values: Vec<(&str, crate::scale::color::RGBAColor)>) -> Self {
1124 let s = crate::scale::manual::ScaleManual::new(crate::aes::Aesthetic::Color, values);
1125 self.scale_color(s)
1126 }
1127
1128 pub fn scale_fill_manual(self, values: Vec<(&str, crate::scale::color::RGBAColor)>) -> Self {
1129 let s = crate::scale::manual::ScaleManual::new(crate::aes::Aesthetic::Fill, values);
1130 self.scale_fill(s)
1131 }
1132
1133 pub fn scale_color_viridis(self) -> Self {
1134 use crate::scale::color::ScaleColorDiscrete;
1135 use crate::scale::palettes::PaletteName;
1136 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Color)
1137 .with_named_palette(&PaletteName::Viridis);
1138 self.scale_color(s)
1139 }
1140
1141 pub fn scale_color_brewer(self, name: crate::scale::palettes::PaletteName) -> Self {
1142 use crate::scale::color::ScaleColorDiscrete;
1143 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Color).with_named_palette(&name);
1144 self.scale_color(s)
1145 }
1146
1147 pub fn scale_color_gradient(
1148 self,
1149 low: crate::scale::color::RGBAColor,
1150 high: crate::scale::color::RGBAColor,
1151 ) -> Self {
1152 use crate::scale::color::ScaleColorContinuous;
1153 let s = ScaleColorContinuous::new(crate::aes::Aesthetic::Color).with_colors(low, high);
1154 self.scale_color(s)
1155 }
1156
1157 pub fn scale_fill_gradient(
1158 self,
1159 low: crate::scale::color::RGBAColor,
1160 high: crate::scale::color::RGBAColor,
1161 ) -> Self {
1162 use crate::scale::color::ScaleColorContinuous;
1163 let s = ScaleColorContinuous::new(crate::aes::Aesthetic::Fill).with_colors(low, high);
1164 self.scale_fill(s)
1165 }
1166
1167 pub fn scale_color_gradient2(
1168 self,
1169 low: crate::scale::color::RGBAColor,
1170 mid: crate::scale::color::RGBAColor,
1171 high: crate::scale::color::RGBAColor,
1172 ) -> Self {
1173 use crate::scale::gradient::ScaleColorGradient2;
1174 let s = ScaleColorGradient2::new(crate::aes::Aesthetic::Color).with_colors(low, mid, high);
1175 self.scale_color(s)
1176 }
1177
1178 pub fn scale_fill_gradient2(
1179 self,
1180 low: crate::scale::color::RGBAColor,
1181 mid: crate::scale::color::RGBAColor,
1182 high: crate::scale::color::RGBAColor,
1183 ) -> Self {
1184 use crate::scale::gradient::ScaleColorGradient2;
1185 let s = ScaleColorGradient2::new(crate::aes::Aesthetic::Fill).with_colors(low, mid, high);
1186 self.scale_fill(s)
1187 }
1188
1189 pub fn scale_fill_viridis(self) -> Self {
1190 use crate::scale::color::ScaleColorDiscrete;
1191 use crate::scale::palettes::PaletteName;
1192 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill)
1193 .with_named_palette(&PaletteName::Viridis);
1194 self.scale_fill(s)
1195 }
1196
1197 pub fn scale_color_viridis_c(self) -> Self {
1199 use crate::scale::gradient_n::ScaleColorGradientN;
1200 let s = ScaleColorGradientN::viridis(crate::aes::Aesthetic::Color);
1201 self.scale_color(s)
1202 }
1203
1204 pub fn scale_fill_viridis_c(self) -> Self {
1206 use crate::scale::gradient_n::ScaleColorGradientN;
1207 let s = ScaleColorGradientN::viridis(crate::aes::Aesthetic::Fill);
1208 self.scale_fill(s)
1209 }
1210
1211 pub fn scale_color_gradientn(self, stops: Vec<(f64, crate::scale::color::RGBAColor)>) -> Self {
1213 use crate::scale::gradient_n::ScaleColorGradientN;
1214 let s = ScaleColorGradientN::new(crate::aes::Aesthetic::Color, stops);
1215 self.scale_color(s)
1216 }
1217
1218 pub fn scale_fill_gradientn(self, stops: Vec<(f64, crate::scale::color::RGBAColor)>) -> Self {
1220 use crate::scale::gradient_n::ScaleColorGradientN;
1221 let s = ScaleColorGradientN::new(crate::aes::Aesthetic::Fill, stops);
1222 self.scale_fill(s)
1223 }
1224
1225 pub fn scale_color_steps(
1228 self,
1229 low: crate::scale::color::RGBAColor,
1230 high: crate::scale::color::RGBAColor,
1231 n_bins: usize,
1232 ) -> Self {
1233 let s = crate::scale::steps::ScaleColorSteps::two(
1234 crate::aes::Aesthetic::Color,
1235 (low.r, low.g, low.b),
1236 (high.r, high.g, high.b),
1237 n_bins,
1238 );
1239 self.scale_color(s)
1240 }
1241
1242 pub fn scale_color_stepsn(
1244 self,
1245 stops: Vec<crate::scale::color::RGBAColor>,
1246 n_bins: usize,
1247 ) -> Self {
1248 let s = crate::scale::steps::ScaleColorSteps::new(
1249 crate::aes::Aesthetic::Color,
1250 stops.iter().map(|c| (c.r, c.g, c.b)).collect(),
1251 n_bins,
1252 );
1253 self.scale_color(s)
1254 }
1255
1256 pub fn scale_color_fermenter(
1258 self,
1259 name: crate::scale::palettes::PaletteName,
1260 n_bins: usize,
1261 ) -> Self {
1262 let stops = crate::scale::palettes::palette(&name)
1263 .iter()
1264 .map(|c| (c.r, c.g, c.b))
1265 .collect();
1266 let s =
1267 crate::scale::steps::ScaleColorSteps::new(crate::aes::Aesthetic::Color, stops, n_bins);
1268 self.scale_color(s)
1269 }
1270
1271 pub fn scale_fill_steps(
1273 self,
1274 low: crate::scale::color::RGBAColor,
1275 high: crate::scale::color::RGBAColor,
1276 n_bins: usize,
1277 ) -> Self {
1278 let s = crate::scale::steps::ScaleColorSteps::two(
1279 crate::aes::Aesthetic::Fill,
1280 (low.r, low.g, low.b),
1281 (high.r, high.g, high.b),
1282 n_bins,
1283 );
1284 self.scale_fill(s)
1285 }
1286
1287 pub fn scale_fill_fermenter(
1289 self,
1290 name: crate::scale::palettes::PaletteName,
1291 n_bins: usize,
1292 ) -> Self {
1293 let stops = crate::scale::palettes::palette(&name)
1294 .iter()
1295 .map(|c| (c.r, c.g, c.b))
1296 .collect();
1297 let s =
1298 crate::scale::steps::ScaleColorSteps::new(crate::aes::Aesthetic::Fill, stops, n_bins);
1299 self.scale_fill(s)
1300 }
1301
1302 pub fn scale_fill_discrete_sorted(self) -> Self {
1307 use crate::scale::color::ScaleColorDiscrete;
1308 self.scale_fill(ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill).sorted())
1309 }
1310
1311 pub fn scale_color_discrete_sorted(self) -> Self {
1314 use crate::scale::color::ScaleColorDiscrete;
1315 self.scale_color(ScaleColorDiscrete::new(crate::aes::Aesthetic::Color).sorted())
1316 }
1317
1318 pub fn scale_fill_brewer(self, name: crate::scale::palettes::PaletteName) -> Self {
1319 use crate::scale::color::ScaleColorDiscrete;
1320 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill).with_named_palette(&name);
1321 self.scale_fill(s)
1322 }
1323
1324 pub fn scale_linetype_manual(
1325 self,
1326 values: Vec<(&str, crate::render::backend::Linetype)>,
1327 ) -> Self {
1328 let s = crate::scale::linetype_manual::ScaleLinetypeManual::new(values);
1329 self.scale_color(s)
1330 }
1331
1332 pub fn scale_shape_manual(
1333 self,
1334 values: Vec<(&str, crate::render::backend::PointShape)>,
1335 ) -> Self {
1336 let s = crate::scale::shape_manual::ScaleShapeManual::new(values);
1337 self.scale_color(s)
1338 }
1339
1340 pub fn scale_color_grey(self) -> Self {
1341 let s = crate::scale::grey::ScaleColorGrey::new(crate::aes::Aesthetic::Color);
1342 self.scale_color(s)
1343 }
1344
1345 pub fn scale_fill_grey(self) -> Self {
1346 let s = crate::scale::grey::ScaleColorGrey::new(crate::aes::Aesthetic::Fill);
1347 self.scale_fill(s)
1348 }
1349
1350 pub fn scale_color_grey_with(self, s: crate::scale::grey::ScaleColorGrey) -> Self {
1351 self.scale_color(s)
1352 }
1353
1354 pub fn scale_fill_grey_with(self, s: crate::scale::grey::ScaleColorGrey) -> Self {
1355 self.scale_fill(s)
1356 }
1357
1358 pub fn scale_x_reverse(self) -> Self {
1359 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reverse))
1360 }
1361
1362 pub fn scale_y_reverse(self) -> Self {
1363 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reverse))
1364 }
1365
1366 pub fn scale_x_datetime(mut self, s: crate::scale::datetime::ScaleDateTime) -> Self {
1367 let s = s.for_aesthetic(crate::aes::Aesthetic::X);
1368 self.scales.push(Box::new(s));
1369 self
1370 }
1371
1372 pub fn scale_y_datetime(mut self, s: crate::scale::datetime::ScaleDateTime) -> Self {
1373 let s = s.for_aesthetic(crate::aes::Aesthetic::Y);
1374 self.scales.push(Box::new(s));
1375 self
1376 }
1377
1378 pub fn scale_size(mut self, s: crate::scale::size::ScaleSizeContinuous) -> Self {
1379 self.scales.push(Box::new(s));
1380 self
1381 }
1382
1383 pub fn scale_alpha(mut self, s: crate::scale::alpha::ScaleAlphaContinuous) -> Self {
1384 self.scales.push(Box::new(s));
1385 self
1386 }
1387
1388 pub fn xlim(self, min: f64, max: f64) -> Self {
1389 self.scale_x_continuous(ScaleContinuous::new().with_limits(min, max))
1390 }
1391
1392 pub fn ylim(self, min: f64, max: f64) -> Self {
1393 self.scale_y_continuous(ScaleContinuous::new().with_limits(min, max))
1394 }
1395
1396 pub fn scale_x_log10(self) -> Self {
1397 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log10))
1398 }
1399
1400 pub fn scale_y_log10(self) -> Self {
1401 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log10))
1402 }
1403
1404 pub fn scale_x_sqrt(self) -> Self {
1405 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Sqrt))
1406 }
1407
1408 pub fn scale_y_sqrt(self) -> Self {
1409 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Sqrt))
1410 }
1411
1412 pub fn scale_x_log2(self) -> Self {
1413 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log2))
1414 }
1415
1416 pub fn scale_y_log2(self) -> Self {
1417 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log2))
1418 }
1419
1420 pub fn scale_x_ln(self) -> Self {
1421 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Ln))
1422 }
1423
1424 pub fn scale_y_ln(self) -> Self {
1425 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Ln))
1426 }
1427
1428 pub fn scale_x_logit(self) -> Self {
1430 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Logit))
1431 }
1432
1433 pub fn scale_y_logit(self) -> Self {
1434 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Logit))
1435 }
1436
1437 pub fn scale_x_probit(self) -> Self {
1439 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Probit))
1440 }
1441
1442 pub fn scale_y_probit(self) -> Self {
1443 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Probit))
1444 }
1445
1446 pub fn scale_x_pseudo_log(self) -> Self {
1448 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::PseudoLog))
1449 }
1450
1451 pub fn scale_y_pseudo_log(self) -> Self {
1452 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::PseudoLog))
1453 }
1454
1455 pub fn scale_x_reciprocal(self) -> Self {
1457 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reciprocal))
1458 }
1459
1460 pub fn scale_y_reciprocal(self) -> Self {
1461 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reciprocal))
1462 }
1463
1464 pub fn scale_x_exp(self) -> Self {
1466 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Exp))
1467 }
1468
1469 pub fn scale_y_exp(self) -> Self {
1470 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Exp))
1471 }
1472
1473 pub fn scale_x_boxcox(self, lambda: f64) -> Self {
1475 self.scale_x_continuous(
1476 ScaleContinuous::new().with_transform(ScaleTransform::BoxCox(lambda)),
1477 )
1478 }
1479
1480 pub fn scale_y_boxcox(self, lambda: f64) -> Self {
1481 self.scale_y_continuous(
1482 ScaleContinuous::new().with_transform(ScaleTransform::BoxCox(lambda)),
1483 )
1484 }
1485
1486 pub fn facet_wrap(mut self, var: &str, ncol: Option<usize>) -> Self {
1489 self.facet = Facet::Wrap {
1490 var: var.to_string(),
1491 ncol,
1492 scales: FacetScales::Fixed,
1493 labeller: FacetLabeller::default(),
1494 };
1495 self
1496 }
1497
1498 pub fn facet_wrap_free(mut self, var: &str, ncol: Option<usize>, scales: FacetScales) -> Self {
1499 self.facet = Facet::Wrap {
1500 var: var.to_string(),
1501 ncol,
1502 scales,
1503 labeller: FacetLabeller::default(),
1504 };
1505 self
1506 }
1507
1508 pub fn facet_wrap_labeller(
1509 mut self,
1510 var: &str,
1511 ncol: Option<usize>,
1512 labeller: FacetLabeller,
1513 ) -> Self {
1514 self.facet = Facet::Wrap {
1515 var: var.to_string(),
1516 ncol,
1517 scales: FacetScales::Fixed,
1518 labeller,
1519 };
1520 self
1521 }
1522
1523 pub fn facet_grid(mut self, row: Option<&str>, col: Option<&str>) -> Self {
1524 self.facet = Facet::Grid {
1525 row_var: row.map(String::from),
1526 col_var: col.map(String::from),
1527 scales: FacetScales::Fixed,
1528 labeller: FacetLabeller::default(),
1529 space: FacetSpace::Fixed,
1530 };
1531 self
1532 }
1533
1534 pub fn facet_grid_free(
1535 mut self,
1536 row: Option<&str>,
1537 col: Option<&str>,
1538 scales: FacetScales,
1539 ) -> Self {
1540 self.facet = Facet::Grid {
1541 row_var: row.map(String::from),
1542 col_var: col.map(String::from),
1543 scales,
1544 labeller: FacetLabeller::default(),
1545 space: FacetSpace::Fixed,
1546 };
1547 self
1548 }
1549
1550 pub fn facet_grid_multi(
1554 mut self,
1555 row: Option<&str>,
1556 cols: &[&str],
1557 scales: FacetScales,
1558 space: FacetSpace,
1559 ) -> Self {
1560 let col_var = if cols.len() > 1 {
1561 let n = self.data.nrows();
1563 let mut combined = Vec::with_capacity(n);
1564 for i in 0..n {
1565 let parts: Vec<String> = cols
1566 .iter()
1567 .map(|c| {
1568 self.data
1569 .column(c)
1570 .and_then(|col| col.get(i))
1571 .map(|v| v.to_group_key())
1572 .unwrap_or_default()
1573 })
1574 .collect();
1575 combined.push(crate::data::Value::Str(parts.join(" . ")));
1576 }
1577 let name = "__facet_cols__".to_string();
1578 self.data.add_column(name.clone(), combined);
1579 Some(name)
1580 } else {
1581 cols.first().map(|s| s.to_string())
1582 };
1583 self.facet = Facet::Grid {
1584 row_var: row.map(String::from),
1585 col_var,
1586 scales,
1587 labeller: FacetLabeller::default(),
1588 space,
1589 };
1590 self
1591 }
1592
1593 pub fn facet_grid_space(
1596 mut self,
1597 row: Option<&str>,
1598 col: Option<&str>,
1599 scales: FacetScales,
1600 space: FacetSpace,
1601 ) -> Self {
1602 self.facet = Facet::Grid {
1603 row_var: row.map(String::from),
1604 col_var: col.map(String::from),
1605 scales,
1606 labeller: FacetLabeller::default(),
1607 space,
1608 };
1609 self
1610 }
1611
1612 pub fn facet_grid_labeller(
1613 mut self,
1614 row: Option<&str>,
1615 col: Option<&str>,
1616 labeller: FacetLabeller,
1617 ) -> Self {
1618 self.facet = Facet::Grid {
1619 row_var: row.map(String::from),
1620 col_var: col.map(String::from),
1621 scales: FacetScales::Fixed,
1622 labeller,
1623 space: FacetSpace::Fixed,
1624 };
1625 self
1626 }
1627
1628 pub fn coord_flip(mut self) -> Self {
1631 self.coord = Box::new(CoordFlip);
1632 self
1633 }
1634
1635 pub fn coord_fixed(mut self, ratio: f64) -> Self {
1636 self.coord = Box::new(CoordFixed::new(ratio));
1637 self
1638 }
1639
1640 #[cfg(feature = "sf")]
1644 pub fn coord_sf(mut self) -> Self {
1645 self.coord = Box::new(crate::coord::sf::CoordSf::new());
1646 self
1647 }
1648
1649 pub fn coord_trans(mut self, x: Option<ScaleTransform>, y: Option<ScaleTransform>) -> Self {
1654 self.coord = Box::new(crate::coord::trans::CoordTrans::new(x, y));
1655 self
1656 }
1657
1658 pub fn coord_trans_y(self, y: ScaleTransform) -> Self {
1660 self.coord_trans(None, Some(y))
1661 }
1662
1663 pub fn coord_trans_x(self, x: ScaleTransform) -> Self {
1665 self.coord_trans(Some(x), None)
1666 }
1667
1668 pub fn coord_cartesian_zoom(
1670 mut self,
1671 xlim: Option<(f64, f64)>,
1672 ylim: Option<(f64, f64)>,
1673 ) -> Self {
1674 let mut c = CoordCartesian::new();
1675 if let Some((min, max)) = xlim {
1676 c = c.xlim(min, max);
1677 }
1678 if let Some((min, max)) = ylim {
1679 c = c.ylim(min, max);
1680 }
1681 self.coord = Box::new(c);
1682 self
1683 }
1684
1685 pub fn coord_polar(mut self) -> Self {
1686 self.coord = Box::new(CoordPolar::new());
1687 self
1688 }
1689
1690 pub fn coord_radar(mut self) -> Self {
1694 self.coord = Box::new(crate::coord::radar::CoordRadar::new());
1695 self
1696 }
1697
1698 pub fn coord_radar_with(mut self, coord: crate::coord::radar::CoordRadar) -> Self {
1699 self.coord = Box::new(coord);
1700 self
1701 }
1702
1703 pub fn coord_polar_with(mut self, coord: CoordPolar) -> Self {
1704 self.coord = Box::new(coord);
1705 self
1706 }
1707
1708 pub fn theme(mut self, theme: Theme) -> Self {
1713 self.apply_preset(theme);
1714 self
1715 }
1716
1717 fn apply_preset(&mut self, theme: Theme) {
1718 let primary = self.theme.primary;
1719 self.theme = theme;
1720 if self.theme.primary.is_none() {
1721 self.theme.primary = primary;
1722 }
1723 }
1724
1725 pub fn axis_text_x_angle(mut self, degrees: f64) -> Self {
1729 self.theme.axis_text_x.angle = degrees;
1730 self
1731 }
1732
1733 pub fn axis_text_y_angle(mut self, degrees: f64) -> Self {
1735 self.theme.axis_text_y.angle = degrees;
1736 self
1737 }
1738
1739 pub fn axis_text_x_dodge(mut self, n: usize) -> Self {
1742 self.theme.axis_text_x_dodge = n.max(1);
1743 self
1744 }
1745
1746 pub fn aspect_ratio(mut self, ratio: f64) -> Self {
1749 self.theme.aspect_ratio = Some(ratio);
1750 self
1751 }
1752
1753 pub fn panel_ontop(mut self) -> Self {
1755 self.theme.panel_ontop = true;
1756 self
1757 }
1758
1759 pub fn axis_minor_ticks(mut self) -> Self {
1761 self.theme.axis_minor_ticks = true;
1762 self
1763 }
1764
1765 pub fn title_position(mut self, pos: crate::theme::TitlePosition) -> Self {
1768 self.theme.title_position = pos;
1769 self
1770 }
1771
1772 pub fn tag_position(mut self, pos: crate::theme::TagPosition) -> Self {
1774 self.theme.tag_position = pos;
1775 self
1776 }
1777
1778 pub fn legend_direction(mut self, dir: crate::theme::LegendDirection) -> Self {
1780 self.theme.legend_direction = Some(dir);
1781 self
1782 }
1783
1784 pub fn legend_position_inside(mut self, x: f64, y: f64) -> Self {
1791 self.theme.legend_position = crate::theme::LegendPosition::Inside(x, y);
1792 self
1793 }
1794
1795 pub fn legend_position(mut self, pos: crate::theme::LegendPosition) -> Self {
1797 self.theme.legend_position = pos;
1798 self
1799 }
1800
1801 pub fn primary_color(mut self, color: (u8, u8, u8)) -> Self {
1802 self.theme.primary = Some(color);
1803 self
1804 }
1805
1806 pub fn theme_minimal(mut self) -> Self {
1807 self.apply_preset(crate::theme::presets::theme_minimal());
1808 self
1809 }
1810
1811 pub fn theme_bw(mut self) -> Self {
1812 self.apply_preset(crate::theme::presets::theme_bw());
1813 self
1814 }
1815
1816 pub fn theme_gray(mut self) -> Self {
1817 self.apply_preset(crate::theme::presets::theme_gray());
1818 self
1819 }
1820
1821 pub fn theme_classic(mut self) -> Self {
1822 self.apply_preset(crate::theme::presets::theme_classic());
1823 self
1824 }
1825
1826 pub fn theme_pubr(mut self) -> Self {
1828 self.apply_preset(crate::theme::presets::theme_pubr());
1829 self
1830 }
1831
1832 pub fn theme_linedraw(mut self) -> Self {
1833 self.apply_preset(crate::theme::presets::theme_linedraw());
1834 self
1835 }
1836
1837 pub fn theme_light(mut self) -> Self {
1838 self.apply_preset(crate::theme::presets::theme_light());
1839 self
1840 }
1841
1842 pub fn theme_dark(mut self) -> Self {
1843 self.apply_preset(crate::theme::presets::theme_dark());
1844 self
1845 }
1846
1847 pub fn theme_void(mut self) -> Self {
1848 self.apply_preset(crate::theme::presets::theme_void());
1849 self
1850 }
1851
1852 pub fn theme_update(mut self, update: crate::theme::ThemeUpdate) -> Self {
1855 self.theme = self.theme.update(update);
1856 self
1857 }
1858
1859 pub fn guides(mut self, guide: crate::guide::config::GuideLegend) -> Self {
1863 self.guide_legend = guide;
1864 self
1865 }
1866
1867 pub fn labs(mut self, labels: Labels) -> Self {
1870 if labels.title.is_some() {
1871 self.labels.title = labels.title;
1872 }
1873 if labels.subtitle.is_some() {
1874 self.labels.subtitle = labels.subtitle;
1875 }
1876 if labels.x.is_some() {
1877 self.labels.x = labels.x;
1878 }
1879 if labels.y.is_some() {
1880 self.labels.y = labels.y;
1881 }
1882 if labels.caption.is_some() {
1883 self.labels.caption = labels.caption;
1884 }
1885 if labels.tag.is_some() {
1886 self.labels.tag = labels.tag;
1887 }
1888 self
1889 }
1890
1891 pub fn title(mut self, title: &str) -> Self {
1892 self.labels.title = Some(title.to_string());
1893 self
1894 }
1895
1896 pub fn tag(mut self, tag: &str) -> Self {
1899 self.labels.tag = Some(tag.to_string());
1900 self
1901 }
1902
1903 pub fn subtitle(mut self, subtitle: &str) -> Self {
1904 self.labels.subtitle = Some(subtitle.to_string());
1905 self
1906 }
1907
1908 pub fn xlab(mut self, label: &str) -> Self {
1909 self.labels.x = Some(label.to_string());
1910 self
1911 }
1912
1913 pub fn ylab(mut self, label: &str) -> Self {
1914 self.labels.y = Some(label.to_string());
1915 self
1916 }
1917
1918 pub fn caption(mut self, caption: &str) -> Self {
1919 self.labels.caption = Some(caption.to_string());
1920 self
1921 }
1922
1923 pub fn annotate(mut self, annotation: Annotation) -> Self {
1927 self.annotations.push(annotation);
1928 self
1929 }
1930
1931 pub fn annotate_text(self, label: &str, x: f64, y: f64) -> Self {
1933 self.annotate(Annotation::text(label, x, y))
1934 }
1935
1936 pub fn annotate_rect(self, xmin: f64, xmax: f64, ymin: f64, ymax: f64) -> Self {
1938 self.annotate(Annotation::rect(xmin, xmax, ymin, ymax))
1939 }
1940
1941 pub fn annotate_segment(self, x: f64, y: f64, xend: f64, yend: f64) -> Self {
1943 self.annotate(Annotation::segment(x, y, xend, yend))
1944 }
1945
1946 pub fn locale(mut self, locale: crate::locale::Locale) -> Self {
1969 self.locale = Some(locale);
1970 self
1971 }
1972
1973 pub fn try_build(self) -> Result<crate::build::BuiltPlot, GGError> {
1977 PlotBuilder::build(self)
1978 }
1979
1980 pub fn build(self) -> crate::build::BuiltPlot {
1984 self.try_build().expect("plot build failed")
1985 }
1986
1987 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
1991 pub fn save(self, path: &str) -> Result<(), GGError> {
1992 self.save_with_size(path, 800, 600)
1993 }
1994
1995 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
1997 pub fn save_with_size(self, path: &str, w: u32, h: u32) -> Result<(), GGError> {
1998 let (built, layout) = self.prepare(w, h)?;
1999
2000 let ext = path.rsplit('.').next().unwrap_or("svg").to_lowercase();
2002
2003 match ext.as_str() {
2004 "svg" => {
2005 let backend = plotters::prelude::SVGBackend::new(path, (w, h));
2006 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
2007 }
2008 "png" | "bmp" | "gif" | "jpeg" | "jpg" | "tiff" => {
2009 let backend = plotters::prelude::BitMapBackend::new(path, (w, h));
2010 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
2011 }
2012 _ => {
2013 return Err(GGError::UnsupportedFormat(ext));
2014 }
2015 }
2016
2017 Ok(())
2018 }
2019
2020 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
2026 pub fn render_svg(self) -> Result<String, GGError> {
2027 self.render_svg_with_size(800, 600)
2028 }
2029
2030 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
2034 pub fn render_svg_with_size(self, w: u32, h: u32) -> Result<String, GGError> {
2035 let (built, layout) = self.prepare(w, h)?;
2036 let mut buf = String::new();
2037 {
2038 let backend = plotters::prelude::SVGBackend::with_string(&mut buf, (w, h));
2039 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
2040 }
2041 Ok(buf)
2042 }
2043
2044 pub fn render_svg_native(self) -> Result<String, GGError> {
2048 self.render_svg_native_with_size(800, 600)
2049 }
2050
2051 pub fn render_svg_native_with_size(self, w: u32, h: u32) -> Result<String, GGError> {
2059 Ok(self.render_native(w, h)?.0.finish())
2060 }
2061
2062 pub fn render_svg_native_with_warnings(
2067 self,
2068 w: u32,
2069 h: u32,
2070 ) -> Result<(String, Vec<String>), GGError> {
2071 let (backend, warnings, _) = self.render_native(w, h)?;
2072 Ok((backend.finish(), warnings))
2073 }
2074
2075 pub fn render_svg_native_at(self, x: f64, y: f64, w: u32, h: u32) -> Result<String, GGError> {
2087 Ok(self.render_native(w, h)?.0.finish_fragment(x, y))
2088 }
2089
2090 pub fn render_svg_area_with_size(self, w: u32, h: u32) -> Result<(String, [f64; 4]), GGError> {
2094 let (backend, _, pa) = self.render_native(w, h)?;
2095 Ok((backend.finish(), [pa.x, pa.y, pa.width, pa.height]))
2096 }
2097
2098 fn render_native(
2102 self,
2103 w: u32,
2104 h: u32,
2105 ) -> Result<
2106 (
2107 crate::render::svg_backend::SvgBackend,
2108 Vec<String>,
2109 crate::render::Rect,
2110 ),
2111 GGError,
2112 > {
2113 let (built, layout) = self.prepare(w, h)?;
2114 let pa = layout.plot_area.clone();
2115 let mut backend = crate::render::svg_backend::SvgBackend::new(w, h, pa.clone());
2116 backend.set_root_attrs(crate::render::svg_backend::root_data_attrs(&built));
2117 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
2118 let mut warnings = built.warnings;
2119 warnings.extend(backend.take_warnings());
2120 Ok((backend, warnings, pa))
2121 }
2122
2123 #[cfg(feature = "canvas")]
2128 pub fn render_rgba_with_size(self, w: u32, h: u32) -> Result<(u32, u32, Vec<u8>), GGError> {
2129 let (built, layout) = self.prepare(w, h)?;
2130 let mut backend =
2131 crate::render::pixel_backend::PixelBackend::new(w, h, layout.plot_area.clone());
2132 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
2133 let (ow, oh) = backend.dimensions();
2134 Ok((ow, oh, backend.into_rgba()))
2135 }
2136
2137 #[cfg(feature = "canvas")]
2141 pub fn render_rgba_area_with_size(
2142 self,
2143 w: u32,
2144 h: u32,
2145 ) -> Result<(Vec<u8>, [f64; 4]), GGError> {
2146 let (built, layout) = self.prepare(w, h)?;
2147 let pa = layout.plot_area.clone();
2148 let mut backend = crate::render::pixel_backend::PixelBackend::new(w, h, pa.clone());
2149 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
2150 Ok((backend.into_rgba(), [pa.x, pa.y, pa.width, pa.height]))
2151 }
2152
2153 #[cfg(feature = "canvas")]
2157 pub fn render_png_raster_with_size(self, w: u32, h: u32) -> Result<Vec<u8>, GGError> {
2158 let (built, layout) = self.prepare(w, h)?;
2159 let mut backend =
2160 crate::render::pixel_backend::PixelBackend::new(w, h, layout.plot_area.clone());
2161 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
2162 backend.into_png().map_err(GGError::Render)
2163 }
2164
2165 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
2172 pub fn render_png(self) -> Result<Vec<u8>, GGError> {
2173 self.render_png_with_size(800, 600)
2174 }
2175
2176 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
2179 pub fn render_png_with_size(self, w: u32, h: u32) -> Result<Vec<u8>, GGError> {
2180 let (built, layout) = self.prepare(w, h)?;
2181
2182 let mut rgb = vec![0u8; (w as usize) * (h as usize) * 3];
2185 {
2186 let backend = plotters::prelude::BitMapBackend::with_buffer(&mut rgb, (w, h));
2187 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
2188 }
2189
2190 let img = image::RgbImage::from_raw(w, h, rgb).ok_or_else(|| {
2191 GGError::Render(RenderError::BackendError(
2192 "PNG buffer size mismatch".to_string(),
2193 ))
2194 })?;
2195 let mut out = std::io::Cursor::new(Vec::new());
2196 img.write_to(&mut out, image::ImageOutputFormat::Png)
2197 .map_err(|e| GGError::Render(RenderError::BackendError(format!("{:?}", e))))?;
2198 Ok(out.into_inner())
2199 }
2200
2201 pub(crate) fn prepare(
2203 self,
2204 w: u32,
2205 h: u32,
2206 ) -> Result<(crate::build::BuiltPlot, PlotLayout), GGError> {
2207 let (mut built, meta) = self.build_for_render()?;
2208 let layout = Self::layout_built(&mut built, &meta, w, h);
2209 Ok((built, layout))
2210 }
2211
2212 pub(crate) fn build_for_render(self) -> Result<(crate::build::BuiltPlot, RenderMeta), GGError> {
2215 let plot = self;
2216
2217 let has_title = plot.labels.title.is_some();
2218 let has_subtitle = plot.labels.subtitle.is_some();
2219 let has_caption = plot.labels.caption.is_some();
2220 let has_legend = plot.has_legend_mapping();
2221 let x_label = plot.labels.x.clone();
2222 let y_label = plot.labels.y.clone();
2223
2224 let mut built = PlotBuilder::build(plot)?;
2225
2226 built.theme.resolve_inheritance();
2228
2229 if let Some(ref label) = x_label {
2231 if let Some(s) = built.scales.get_mut(&crate::aes::Aesthetic::X) {
2232 s.set_name(label);
2233 }
2234 }
2235 if let Some(ref label) = y_label {
2236 if let Some(s) = built.scales.get_mut(&crate::aes::Aesthetic::Y) {
2237 s.set_name(label);
2238 }
2239 }
2240
2241 Ok((
2242 built,
2243 RenderMeta {
2244 has_title,
2245 has_subtitle,
2246 has_caption,
2247 has_legend,
2248 },
2249 ))
2250 }
2251
2252 pub(crate) fn layout_built(
2255 built: &mut crate::build::BuiltPlot,
2256 meta: &RenderMeta,
2257 w: u32,
2258 h: u32,
2259 ) -> PlotLayout {
2260 let RenderMeta {
2261 has_title,
2262 has_subtitle,
2263 has_caption,
2264 has_legend,
2265 } = *meta;
2266 let x_axis_top = built
2267 .scales
2268 .get(&crate::aes::Aesthetic::X)
2269 .map(|s| s.axis_position_opposite())
2270 .unwrap_or(false);
2271
2272 let flipped = built.coord.is_flipped();
2276 let h_aes = if flipped {
2277 crate::aes::Aesthetic::Y
2278 } else {
2279 crate::aes::Aesthetic::X
2280 };
2281 let v_aes = if flipped {
2282 crate::aes::Aesthetic::X
2283 } else {
2284 crate::aes::Aesthetic::Y
2285 };
2286
2287 let x_rot: Option<(f64, f64)> =
2291 if built.theme.axis_text_x.visible && built.theme.axis_text_x.angle.abs() < 1.0 {
2292 built.scales.get(&h_aes).and_then(|hs| {
2293 if !hs.is_discrete() {
2294 return None;
2295 }
2296 let breaks = hs.breaks();
2297 let n = breaks.len().max(1) as f64;
2298 let max_ch = breaks
2299 .iter()
2300 .map(|(_, l)| l.chars().count())
2301 .max()
2302 .unwrap_or(0) as f64;
2303 let font = built.theme.axis_text_x.size;
2304 let label_w = max_ch * font * 0.6; let spacing = 0.9 * w as f64 / n; if label_w <= spacing {
2307 return None; }
2309 let vertical = label_w * 0.707 > spacing;
2313 let angle = if vertical { 270.0 } else { 45.0 };
2314 let drop = if vertical { label_w } else { label_w * 0.707 };
2315 Some((angle, drop + font + 4.0))
2316 })
2317 } else {
2318 None
2319 };
2320 let x_label_height = x_rot.map(|(_, drop)| drop);
2321 if let Some((angle, _)) = x_rot {
2322 built.theme.axis_text_x.angle = angle;
2323 }
2324
2325 let y_label_width = if built.theme.axis_text_y.visible {
2329 built.scales.get(&v_aes).map(|vs| {
2330 let max_ch = vs
2331 .breaks()
2332 .iter()
2333 .map(|(_, l)| l.chars().count())
2334 .max()
2335 .unwrap_or(0);
2336 let measured = max_ch as f64 * built.theme.axis_text_y.size * 0.6 + 4.0;
2337 let default = built.theme.axis_text_y.size * 3.5 + 4.0;
2338 measured.max(default).min(0.35 * w as f64)
2339 })
2340 } else {
2341 None
2342 };
2343
2344 PlotLayout::compute_full(
2345 w as f64,
2346 h as f64,
2347 &built.theme,
2348 has_title,
2349 has_subtitle,
2350 has_caption,
2351 has_legend,
2352 x_axis_top,
2353 y_label_width,
2354 x_label_height,
2355 )
2356 }
2357
2358 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
2361 fn render_into<DB>(
2362 area: plotters::drawing::DrawingArea<DB, plotters::coord::Shift>,
2363 built: &crate::build::BuiltPlot,
2364 layout: &PlotLayout,
2365 ) -> Result<(), GGError>
2366 where
2367 DB: plotters::prelude::DrawingBackend,
2368 DB::ErrorType: 'static,
2369 {
2370 area.fill(&plotters::prelude::WHITE)
2371 .map_err(|e| GGError::Render(RenderError::BackendError(format!("{:?}", e))))?;
2372 let mut adapter = PlottersAdapter::new(&area, layout.plot_area.clone());
2373 PlotRenderer::render(built, &mut adapter).map_err(GGError::Render)?;
2374 area.present()
2375 .map_err(|e| GGError::Render(RenderError::BackendError(format!("{:?}", e))))?;
2376 Ok(())
2377 }
2378
2379 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
2382 pub fn ggsave(
2383 self,
2384 path: &str,
2385 width_inches: f64,
2386 height_inches: f64,
2387 dpi: f64,
2388 ) -> Result<(), GGError> {
2389 let w = (width_inches * dpi) as u32;
2390 let h = (height_inches * dpi) as u32;
2391 self.save_with_size(path, w, h)
2392 }
2393
2394 fn has_legend_mapping(&self) -> bool {
2395 self.mapping.mappings.iter().any(|m| {
2396 matches!(
2397 m.aesthetic,
2398 crate::aes::Aesthetic::Color
2399 | crate::aes::Aesthetic::Fill
2400 | crate::aes::Aesthetic::Shape
2401 | crate::aes::Aesthetic::Linetype
2402 | crate::aes::Aesthetic::Size
2403 | crate::aes::Aesthetic::Alpha
2404 )
2405 })
2406 }
2407}
2408
2409#[derive(Clone, Copy, Debug)]
2411pub(crate) struct RenderMeta {
2412 pub(crate) has_title: bool,
2413 pub(crate) has_subtitle: bool,
2414 pub(crate) has_caption: bool,
2415 pub(crate) has_legend: bool,
2416}
2417
2418#[derive(Debug)]
2420pub enum GGError {
2421 Render(RenderError),
2422 UnsupportedFormat(String),
2423 Io(std::io::Error),
2424 ValidationError(String),
2425}
2426
2427impl std::fmt::Display for GGError {
2428 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2429 match self {
2430 GGError::Render(e) => write!(f, "Render error: {e}"),
2431 GGError::UnsupportedFormat(ext) => write!(f, "Unsupported output format: {ext}"),
2432 GGError::Io(e) => write!(f, "IO error: {e}"),
2433 GGError::ValidationError(msg) => write!(f, "Validation error: {msg}"),
2434 }
2435 }
2436}
2437
2438impl std::error::Error for GGError {}