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 pub tooltip_template: Option<String>,
94}
95
96pub struct GGPlot {
98 pub(crate) data: DataFrame,
99 pub(crate) mapping: Aes,
100 pub(crate) layers: Vec<Layer>,
101 pub(crate) scales: Vec<Box<dyn Scale>>,
102 pub(crate) coord: Box<dyn Coord>,
103 pub(crate) theme: Theme,
104 pub(crate) labels: Labels,
105 pub(crate) facet: Facet,
106 pub(crate) annotations: Vec<Annotation>,
107 pub(crate) guide_legend: crate::guide::config::GuideLegend,
108 pub(crate) warnings: Vec<String>,
111 pub(crate) default_aspect_ratio: Option<f64>,
114 pub(crate) locale: Option<crate::locale::Locale>,
116 pub(crate) svg_root_data: bool,
121 pub(crate) root_attrs: Vec<(String, String)>,
124 pub(crate) svg_warnings_attr: bool,
128 pub(crate) svg_formatted_values: bool,
132 pub(crate) layer_svg_attrs: Vec<(usize, String, String)>,
136}
137
138impl GGPlot {
139 pub fn new(data: impl GGData) -> Self {
146 GGPlot {
147 data: data.into_dataframe(),
148 mapping: Aes::default(),
149 layers: Vec::new(),
150 scales: Vec::new(),
151 coord: Box::new(CoordCartesian::new()),
152 theme: Theme::default(),
153 labels: Labels::default(),
154 facet: Facet::default(),
155 annotations: Vec::new(),
156 guide_legend: crate::guide::config::GuideLegend::default(),
157 warnings: Vec::new(),
158 default_aspect_ratio: None,
159 locale: None,
160 svg_root_data: true,
161 root_attrs: Vec::new(),
162 svg_warnings_attr: false,
163 svg_formatted_values: false,
164 layer_svg_attrs: Vec::new(),
165 }
166 }
167
168 pub fn aes(mut self, mapping: Aes) -> Self {
170 self.warnings.extend(mapping.warnings.iter().cloned());
171 self.mapping = mapping;
172 self
173 }
174
175 pub fn geom_point(self) -> Self {
178 self.add_geom(GeomPoint::default())
179 }
180
181 pub fn geom_point_with(self, geom: GeomPoint) -> Self {
182 self.add_geom_with(geom)
183 }
184
185 pub fn geom_line(self) -> Self {
186 self.add_geom(GeomLine::default())
187 }
188
189 pub fn geom_line_with(self, geom: GeomLine) -> Self {
190 self.add_geom_with(geom)
191 }
192
193 pub fn geom_bar(self) -> Self {
194 self.add_geom(GeomBar::default())
195 }
196
197 pub fn geom_bar_with(self, geom: GeomBar) -> Self {
198 self.add_geom_with(geom)
199 }
200
201 pub fn geom_histogram(self) -> Self {
202 self.add_geom(GeomHistogram::default())
203 }
204
205 pub fn geom_histogram_with(self, geom: GeomHistogram) -> Self {
206 self.add_geom_with(geom)
207 }
208
209 pub fn geom_boxplot(self) -> Self {
210 self.add_geom(GeomBoxplot::default())
211 }
212
213 pub fn geom_boxplot_with(self, geom: GeomBoxplot) -> Self {
214 self.add_geom_with(geom)
215 }
216
217 pub fn geom_smooth(self) -> Self {
218 self.add_geom(GeomSmooth::default())
219 }
220
221 pub fn geom_smooth_with(self, geom: GeomSmooth) -> Self {
222 self.add_geom_with(geom)
223 }
224
225 pub fn geom_col(self) -> Self {
226 self.add_geom(GeomCol::default())
227 }
228
229 pub fn geom_col_with(self, geom: GeomCol) -> Self {
230 self.add_geom_with(geom)
231 }
232
233 pub fn geom_hline(self, yintercept: f64) -> Self {
237 self.add_refline(
238 GeomHline::new(yintercept),
239 false,
240 &[("yintercept", yintercept)],
241 )
242 }
243
244 pub fn geom_hline_with(self, geom: GeomHline) -> Self {
246 let y = geom.yintercept;
247 self.add_refline(geom, true, &[("yintercept", y)])
248 }
249
250 pub fn geom_hline_aes(self, mapping: Aes) -> Self {
274 self.add_geom(GeomHline::mapped()).layer_aes(mapping)
275 }
276
277 pub fn geom_hline_aes_with(self, geom: GeomHline, mapping: Aes) -> Self {
279 self.add_geom_with(geom).layer_aes(mapping)
280 }
281
282 pub fn geom_vline(self, xintercept: f64) -> Self {
285 self.add_refline(
286 GeomVline::new(xintercept),
287 false,
288 &[("xintercept", xintercept)],
289 )
290 }
291
292 pub fn geom_vline_with(self, geom: GeomVline) -> Self {
294 let x = geom.xintercept;
295 self.add_refline(geom, true, &[("xintercept", x)])
296 }
297
298 pub fn geom_vline_aes(self, mapping: Aes) -> Self {
301 self.add_geom(GeomVline::mapped()).layer_aes(mapping)
302 }
303
304 pub fn geom_vline_aes_with(self, geom: GeomVline, mapping: Aes) -> Self {
306 self.add_geom_with(geom).layer_aes(mapping)
307 }
308
309 pub fn geom_abline(self, slope: f64, intercept: f64) -> Self {
312 self.add_refline(
313 GeomAbline::new(slope, intercept),
314 false,
315 &[("slope", slope), ("intercept", intercept)],
316 )
317 }
318
319 pub fn geom_abline_with(self, geom: GeomAbline) -> Self {
321 let (b, a) = (geom.slope, geom.intercept);
322 self.add_refline(geom, true, &[("slope", b), ("intercept", a)])
323 }
324
325 pub fn geom_abline_aes(self, mapping: Aes) -> Self {
328 self.add_geom(GeomAbline::mapped()).layer_aes(mapping)
329 }
330
331 pub fn geom_abline_aes_with(self, geom: GeomAbline, mapping: Aes) -> Self {
333 self.add_geom_with(geom).layer_aes(mapping)
334 }
335
336 fn add_refline(
339 self,
340 geom: impl Geom + 'static,
341 explicit: bool,
342 values: &[(&str, f64)],
343 ) -> Self {
344 let mut data = DataFrame::new();
345 let mut mapping = Aes::new();
346 for (col, v) in values {
347 data.add_column(col.to_string(), vec![Value::Float(*v)]);
348 mapping = match *col {
349 "xintercept" => mapping.xintercept(col),
350 "yintercept" => mapping.yintercept(col),
351 "slope" => mapping.slope(col),
352 _ => mapping.intercept(col),
353 };
354 }
355 let plot = if explicit {
356 self.add_geom_with(geom)
357 } else {
358 self.add_geom(geom)
359 };
360 plot.layer_aes(mapping).layer_data(data)
361 }
362
363 pub fn geom_text(self) -> Self {
364 self.add_geom(GeomText::default())
365 }
366
367 pub fn geom_text_with(self, geom: GeomText) -> Self {
368 self.add_geom_with(geom)
369 }
370
371 #[cfg(feature = "ggpubr")]
376 pub fn stat_cor(self) -> Self {
377 self.geom_text().stat(crate::stat::cor::StatCor::default())
378 }
379
380 #[cfg(feature = "ggpubr")]
383 pub fn stat_cor_with(self, stat: crate::stat::cor::StatCor) -> Self {
384 self.geom_text().stat(stat)
385 }
386
387 #[cfg(feature = "ggpubr")]
392 pub fn stat_compare_means(self) -> Self {
393 self.geom_text()
394 .stat(crate::stat::compare_means::StatCompareMeans::default())
395 }
396
397 #[cfg(feature = "ggpubr")]
400 pub fn stat_compare_means_with(
401 self,
402 stat: crate::stat::compare_means::StatCompareMeans,
403 ) -> Self {
404 self.geom_text().stat(stat)
405 }
406
407 #[cfg(feature = "ggpubr")]
413 pub fn stat_compare_means_pairwise(self, comparisons: &[(&str, &str)]) -> Self {
414 self.stat_compare_means_pairwise_with(
415 crate::stat::compare_means::CompareMethod::Auto,
416 comparisons,
417 )
418 }
419
420 #[cfg(feature = "ggpubr")]
423 pub fn stat_compare_means_pairwise_with(
424 self,
425 method: crate::stat::compare_means::CompareMethod,
426 comparisons: &[(&str, &str)],
427 ) -> Self {
428 let col_for = |a: crate::aes::Aesthetic| {
430 self.mapping
431 .mappings
432 .iter()
433 .find(|m| m.aesthetic == a)
434 .map(|m| m.column.clone())
435 };
436 let (xcol, ycol) = match (
437 col_for(crate::aes::Aesthetic::X),
438 col_for(crate::aes::Aesthetic::Y),
439 ) {
440 (Some(x), Some(y)) => (x, y),
441 _ => return self,
442 };
443 let (xc, yc) = match (self.data.column(&xcol), self.data.column(&ycol)) {
444 (Some(x), Some(y)) => (x, y),
445 _ => return self,
446 };
447
448 let mut groups: Vec<(String, Vec<f64>)> = Vec::new();
450 let mut ymax = f64::NEG_INFINITY;
451 let mut ymin = f64::INFINITY;
452 for (xv, yv) in xc.iter().zip(yc.iter()) {
453 let y = match yv.as_f64() {
454 Some(y) if y.is_finite() => y,
455 _ => continue,
456 };
457 ymax = ymax.max(y);
458 ymin = ymin.min(y);
459 let key = xv.to_group_key();
460 if let Some(g) = groups.iter_mut().find(|(k, _)| *k == key) {
461 g.1.push(y);
462 } else {
463 groups.push((key, vec![y]));
464 }
465 }
466 if groups.len() < 2 {
467 return self;
468 }
469 let step = if ymax > ymin {
470 (ymax - ymin) * 0.12
471 } else {
472 1.0
473 };
474
475 let (mut xmin_v, mut xmax_v, mut y_v, mut label_v) =
477 (Vec::new(), Vec::new(), Vec::new(), Vec::new());
478 let mut placed = 0usize;
479 for (a, b) in comparisons {
480 let ga = groups.iter().find(|(k, _)| k == a).map(|g| &g.1);
481 let gb = groups.iter().find(|(k, _)| k == b).map(|g| &g.1);
482 let (ga, gb) = match (ga, gb) {
483 (Some(x), Some(y)) if x.len() >= 2 && y.len() >= 2 => (x, y),
484 _ => continue,
485 };
486 let p = match crate::stat::compare_means::pairwise_p(method, ga, gb) {
487 Some(p) => p,
488 None => continue,
489 };
490 xmin_v.push(Value::Str((*a).to_string()));
491 xmax_v.push(Value::Str((*b).to_string()));
492 y_v.push(Value::Float(ymax + step * (placed as f64 + 1.0)));
493 label_v.push(Value::Str(crate::stat::cor::format_p_value(p)));
494 placed += 1;
495 }
496 if xmin_v.is_empty() {
497 return self;
498 }
499
500 let data = vec![
501 ("xmin".to_string(), xmin_v),
502 ("xmax".to_string(), xmax_v),
503 ("y".to_string(), y_v),
504 ("label".to_string(), label_v),
505 ];
506 self.add_geom(crate::geom::bracket::GeomBracket::default())
507 .layer_data(data)
508 .layer_aes(Aes::new().xmin("xmin").xmax("xmax").y("y").label("label"))
509 }
510
511 pub fn geom_bracket(self, xmin: &str, xmax: &str, y: f64, label: &str) -> Self {
516 self.geom_bracket_many(
517 crate::geom::bracket::GeomBracket::default(),
518 &[(xmin, xmax, y, label)],
519 )
520 }
521
522 pub fn geom_bracket_many(
526 self,
527 geom: crate::geom::bracket::GeomBracket,
528 brackets: &[(&str, &str, f64, &str)],
529 ) -> Self {
530 let xmin = brackets
531 .iter()
532 .map(|b| Value::Str(b.0.to_string()))
533 .collect::<Vec<_>>();
534 let xmax = brackets
535 .iter()
536 .map(|b| Value::Str(b.1.to_string()))
537 .collect::<Vec<_>>();
538 let y = brackets
539 .iter()
540 .map(|b| Value::Float(b.2))
541 .collect::<Vec<_>>();
542 let label = brackets
543 .iter()
544 .map(|b| Value::Str(b.3.to_string()))
545 .collect::<Vec<_>>();
546 let data = vec![
547 ("xmin".to_string(), xmin),
548 ("xmax".to_string(), xmax),
549 ("y".to_string(), y),
550 ("label".to_string(), label),
551 ];
552 self.add_geom(geom)
553 .layer_data(data)
554 .layer_aes(Aes::new().xmin("xmin").xmax("xmax").y("y").label("label"))
555 }
556
557 pub fn geom_bracket_table(
566 mut self,
567 table: impl GGData,
568 spec: crate::geom::bracket::BracketTable,
569 ) -> Self {
570 let table = table.into_dataframe();
571 let col_for = |a: crate::aes::Aesthetic| {
572 self.mapping
573 .mappings
574 .iter()
575 .find(|m| m.aesthetic == a)
576 .map(|m| m.column.clone())
577 };
578 let x_levels: Vec<String> = col_for(crate::aes::Aesthetic::X)
581 .and_then(|c| self.data.column(&c))
582 .filter(|col| col.iter().any(|v| matches!(v, Value::Str(_))))
583 .map(|col| {
584 let mut seen = std::collections::HashSet::new();
585 col.iter()
586 .filter(|v| !v.is_na())
587 .map(|v| v.to_group_key())
588 .filter(|k| seen.insert(k.clone()))
589 .collect()
590 })
591 .unwrap_or_default();
592 let y_range = col_for(crate::aes::Aesthetic::Y)
593 .and_then(|c| self.data.column(&c))
594 .and_then(|col| {
595 let (lo, hi) = col
596 .iter()
597 .filter_map(|v| v.as_f64())
598 .filter(|v| v.is_finite())
599 .fold((f64::INFINITY, f64::NEG_INFINITY), |(lo, hi), v| {
600 (lo.min(v), hi.max(v))
601 });
602 (lo <= hi).then_some((lo, hi))
603 });
604 let mut warnings = Vec::new();
605 let resolved = spec.resolve(&table, &x_levels, y_range, &mut warnings);
606 self.warnings.extend(warnings);
607 match resolved {
608 Some(data) => self
609 .add_geom(crate::geom::bracket::GeomBracket::from(spec.geom))
610 .layer_data(data)
611 .layer_aes(Aes::new().xmin("xmin").xmax("xmax").y("y").label("label")),
612 None => self,
613 }
614 }
615
616 pub fn geom_text_repel(self) -> Self {
621 self.add_geom(crate::geom::repel::GeomTextRepel::default())
622 }
623
624 pub fn geom_text_repel_with(self, geom: crate::geom::repel::GeomTextRepel) -> Self {
627 self.add_geom_with(geom)
628 }
629
630 pub fn geom_label_repel(self) -> Self {
633 self.add_geom(crate::geom::repel::GeomLabelRepel::default())
634 }
635
636 pub fn geom_label_repel_with(self, geom: crate::geom::repel::GeomLabelRepel) -> Self {
638 self.add_geom_with(geom)
639 }
640
641 pub fn geom_label(self) -> Self {
642 self.add_geom(GeomLabel::default())
643 }
644
645 pub fn geom_label_with(self, geom: GeomLabel) -> Self {
646 self.add_geom_with(geom)
647 }
648
649 pub fn geom_area(self) -> Self {
650 self.add_geom(GeomArea::default())
651 }
652
653 pub fn geom_area_with(self, geom: GeomArea) -> Self {
654 self.add_geom_with(geom)
655 }
656
657 pub fn geom_ribbon(self) -> Self {
658 self.add_geom(GeomRibbon::default())
659 }
660
661 pub fn geom_ribbon_with(self, geom: GeomRibbon) -> Self {
662 self.add_geom_with(geom)
663 }
664
665 pub fn geom_errorbar(self) -> Self {
666 self.add_geom(GeomErrorbar::default())
667 }
668
669 pub fn geom_errorbar_with(self, geom: GeomErrorbar) -> Self {
670 self.add_geom_with(geom)
671 }
672
673 pub fn geom_segment(self) -> Self {
674 self.add_geom(GeomSegment::default())
675 }
676
677 pub fn geom_segment_with(self, geom: GeomSegment) -> Self {
678 self.add_geom_with(geom)
679 }
680
681 pub fn geom_density(self) -> Self {
682 self.add_geom(GeomDensity::default())
683 }
684
685 pub fn geom_density_with(self, geom: GeomDensity) -> Self {
686 self.add_geom_with(geom)
687 }
688
689 pub fn geom_rug(self) -> Self {
690 self.add_geom(GeomRug::default())
691 }
692
693 pub fn geom_rug_with(self, geom: GeomRug) -> Self {
694 self.add_geom_with(geom)
695 }
696
697 pub fn geom_jitter(self) -> Self {
698 self.add_geom(GeomJitter::default())
699 }
700
701 pub fn geom_jitter_with(self, geom: GeomJitter) -> Self {
702 self.add_geom_with(geom)
703 }
704
705 pub fn geom_path(self) -> Self {
706 self.add_geom(GeomPath::default())
707 }
708
709 pub fn geom_path_with(self, geom: GeomPath) -> Self {
710 self.add_geom_with(geom)
711 }
712
713 pub fn stat_ellipse(self) -> Self {
715 self.geom_path()
716 .stat(crate::stat::ellipse::StatEllipse::default())
717 }
718
719 pub fn stat_ellipse_level(self, level: f64) -> Self {
721 self.geom_path()
722 .stat(crate::stat::ellipse::StatEllipse::new(level))
723 }
724
725 #[cfg(feature = "regression")]
728 pub fn stat_quantile(mut self, taus: &[f64]) -> Self {
729 for &tau in taus {
730 self = self
731 .geom_path()
732 .stat(crate::stat::quantile::StatQuantile::new(tau));
733 }
734 self
735 }
736
737 #[cfg(feature = "regression")]
739 pub fn geom_quantile(self) -> Self {
740 self.stat_quantile(&[0.25, 0.5, 0.75])
741 }
742
743 pub fn geom_step(self) -> Self {
744 self.add_geom(GeomStep::default())
745 }
746
747 pub fn geom_step_with(self, geom: GeomStep) -> Self {
748 self.add_geom_with(geom)
749 }
750
751 pub fn geom_freqpoly(self) -> Self {
752 self.add_geom(GeomFreqpoly::default())
753 }
754
755 pub fn geom_freqpoly_with(self, geom: GeomFreqpoly) -> Self {
756 self.add_geom_with(geom)
757 }
758
759 pub fn geom_linerange(self) -> Self {
760 self.add_geom(GeomLinerange::default())
761 }
762
763 pub fn geom_linerange_with(self, geom: GeomLinerange) -> Self {
764 self.add_geom_with(geom)
765 }
766
767 pub fn geom_pointrange(self) -> Self {
768 self.add_geom(GeomPointrange::default())
769 }
770
771 pub fn geom_pointrange_with(self, geom: GeomPointrange) -> Self {
772 self.add_geom_with(geom)
773 }
774
775 pub fn geom_crossbar(self) -> Self {
776 self.add_geom(GeomCrossbar::default())
777 }
778
779 pub fn geom_crossbar_with(self, geom: GeomCrossbar) -> Self {
780 self.add_geom_with(geom)
781 }
782
783 pub fn geom_spoke(self) -> Self {
784 self.add_geom(GeomSpoke::default())
785 }
786
787 pub fn geom_spoke_with(self, geom: GeomSpoke) -> Self {
788 self.add_geom_with(geom)
789 }
790
791 pub fn geom_rect(self) -> Self {
792 self.add_geom(GeomRect::default())
793 }
794
795 pub fn geom_rect_with(self, geom: GeomRect) -> Self {
796 self.add_geom_with(geom)
797 }
798
799 pub fn geom_tile(self) -> Self {
800 self.add_geom(GeomTile::default())
801 }
802
803 pub fn geom_tile_with(self, geom: GeomTile) -> Self {
804 self.add_geom_with(geom)
805 }
806
807 pub fn geom_raster(self) -> Self {
809 self.add_geom(crate::geom::raster::GeomRaster::default())
810 }
811
812 pub fn geom_raster_with(self, geom: crate::geom::raster::GeomRaster) -> Self {
813 self.add_geom_with(geom)
814 }
815
816 pub fn geom_polygon(self) -> Self {
817 self.add_geom(GeomPolygon::default())
818 }
819
820 pub fn geom_polygon_with(self, geom: GeomPolygon) -> Self {
821 self.add_geom_with(geom)
822 }
823
824 #[cfg(feature = "sf")]
826 pub fn geom_sf(self) -> Self {
827 self.add_geom(crate::geom::sf::GeomSf::default())
828 }
829
830 #[cfg(feature = "sf")]
831 pub fn geom_sf_with(self, geom: crate::geom::sf::GeomSf) -> Self {
832 self.add_geom_with(geom)
833 }
834
835 #[cfg(feature = "sf")]
838 pub fn geom_sf_text(self) -> Self {
839 self.add_geom(crate::geom::sf_text::GeomSfText::default())
840 }
841
842 #[cfg(feature = "sf")]
843 pub fn geom_sf_text_with(self, geom: crate::geom::sf_text::GeomSfText) -> Self {
844 self.add_geom_with(geom)
845 }
846
847 #[cfg(feature = "sf")]
850 pub fn geom_sf_label(self) -> Self {
851 self.add_geom(crate::geom::sf_text::GeomSfLabel::default())
852 }
853
854 #[cfg(feature = "sf")]
855 pub fn geom_sf_label_with(self, geom: crate::geom::sf_text::GeomSfLabel) -> Self {
856 self.add_geom_with(geom)
857 }
858
859 #[cfg(feature = "sf")]
863 pub fn annotation_scale(self) -> Self {
864 self.add_geom(crate::geom::annotation_scale::GeomAnnotationScale::default())
865 }
866
867 #[cfg(feature = "sf")]
868 pub fn annotation_scale_with(
869 self,
870 geom: crate::geom::annotation_scale::GeomAnnotationScale,
871 ) -> Self {
872 self.add_geom_with(geom)
873 }
874
875 #[cfg(feature = "sf")]
878 pub fn annotation_attribution(self, text: impl Into<String>) -> Self {
879 self.add_geom(crate::geom::annotation_scale::GeomAttribution::new(text))
880 }
881
882 #[cfg(feature = "sf")]
883 pub fn annotation_attribution_with(
884 self,
885 geom: crate::geom::annotation_scale::GeomAttribution,
886 ) -> Self {
887 self.add_geom_with(geom)
888 }
889
890 #[cfg(feature = "sf")]
898 pub fn bivariate_legend(
899 self,
900 geom: crate::geom::bivariate_legend::GeomBivariateLegend,
901 ) -> Self {
902 self.add_geom(geom)
903 }
904
905 pub fn geom_curve(self) -> Self {
906 self.add_geom(GeomCurve::default())
907 }
908
909 pub fn geom_curve_with(self, geom: GeomCurve) -> Self {
910 self.add_geom_with(geom)
911 }
912
913 pub fn geom_violin(self) -> Self {
914 self.add_geom(GeomViolin::default())
915 }
916
917 pub fn geom_violin_with(self, geom: GeomViolin) -> Self {
918 self.add_geom_with(geom)
919 }
920
921 pub fn geom_dotplot(self) -> Self {
922 self.add_geom(GeomDotplot::default())
923 }
924
925 pub fn geom_dotplot_with(self, geom: GeomDotplot) -> Self {
926 self.add_geom_with(geom)
927 }
928
929 pub fn geom_qq(self) -> Self {
930 self.add_geom(GeomQQ::default())
931 }
932
933 pub fn geom_qq_with(self, geom: GeomQQ) -> Self {
934 self.add_geom_with(geom)
935 }
936
937 pub fn geom_qq_line(self) -> Self {
938 self.add_geom(GeomQQLine::default())
939 }
940
941 pub fn geom_qq_line_with(self, geom: GeomQQLine) -> Self {
942 self.add_geom_with(geom)
943 }
944
945 pub fn geom_bin2d(self) -> Self {
946 self.add_geom(GeomBin2d::default())
947 }
948
949 pub fn geom_bin2d_with(self, geom: GeomBin2d) -> Self {
950 self.add_geom_with(geom)
951 }
952
953 pub fn geom_hex(self) -> Self {
954 self.add_geom(GeomHex::default())
955 }
956
957 pub fn geom_hex_with(self, geom: GeomHex) -> Self {
958 self.add_geom_with(geom)
959 }
960
961 pub fn geom_count(self) -> Self {
962 self.add_geom(GeomCount::default())
963 }
964
965 pub fn geom_count_with(self, geom: GeomCount) -> Self {
966 self.add_geom_with(geom)
967 }
968
969 pub fn geom_contour(self) -> Self {
970 self.add_geom(GeomContour::default())
971 }
972
973 pub fn geom_contour_with(self, geom: GeomContour) -> Self {
974 self.add_geom_with(geom)
975 }
976
977 pub fn geom_contour_filled(self) -> Self {
980 self.add_geom(GeomPolygon {
981 line_width: 0.0,
982 alpha: 1.0,
983 ..GeomPolygon::default()
984 })
985 .stat(crate::stat::contour_filled::StatContourFilled::default())
986 }
987
988 pub fn geom_density2d(self) -> Self {
989 self.add_geom(GeomDensity2d::default())
990 }
991
992 pub fn geom_density2d_with(self, geom: GeomDensity2d) -> Self {
993 self.add_geom_with(geom)
994 }
995
996 pub fn geom_candlestick(self) -> Self {
999 self.add_geom(crate::geom::candlestick::GeomCandlestick::default())
1000 }
1001
1002 pub fn geom_candlestick_with(self, geom: crate::geom::candlestick::GeomCandlestick) -> Self {
1003 self.add_geom_with(geom)
1004 }
1005
1006 pub fn geom_ohlc(self) -> Self {
1009 self.add_geom(crate::geom::candlestick::GeomOhlc::default())
1010 }
1011
1012 pub fn geom_ohlc_with(self, geom: crate::geom::candlestick::GeomOhlc) -> Self {
1013 self.add_geom_with(geom)
1014 }
1015
1016 pub fn geom_calendar(self) -> Self {
1027 self.geom_calendar_with(
1028 GeomTile {
1029 color: (255, 255, 255),
1030 line_width: 1.5,
1031 ..Default::default()
1032 },
1033 false,
1034 )
1035 }
1036
1037 pub fn geom_calendar_with(mut self, tile: GeomTile, monday_first: bool) -> Self {
1040 use crate::stat::calendar::{
1041 day_number, month_boundaries, month_breaks, month_breaks_localized, weekday_labels,
1042 CalendarGrid, StatCalendar, MAX_CALENDAR_YEARS,
1043 };
1044 let grid = self
1045 .mapping
1046 .get_mapping(&crate::aes::Aesthetic::X)
1047 .and_then(|c| self.data.column(c))
1048 .and_then(|col| {
1049 CalendarGrid::from_days(col.iter().filter_map(day_number), monday_first)
1050 });
1051 let Some((grid, clipped)) = grid else {
1052 return self.add_geom_with(tile).stat(StatCalendar {
1054 grid: None,
1055 monday_first,
1056 });
1057 };
1058 if clipped {
1059 self.warnings.push(format!(
1060 "geom_calendar: dates more than {MAX_CALENDAR_YEARS} years before the newest were dropped"
1061 ));
1062 }
1063 let (xb, _) = month_breaks(&grid);
1064 let yb = if monday_first {
1066 vec![6.0, 4.0, 2.0]
1067 } else {
1068 vec![5.0, 3.0, 1.0]
1069 };
1070 let segs = month_boundaries(&grid);
1071 let col = |f: fn(&(f64, f64, f64, f64)) -> f64| -> Vec<Value> {
1072 segs.iter().map(|s| Value::Float(f(s))).collect()
1073 };
1074 let boundaries = vec![
1075 ("x".to_string(), col(|s| s.0)),
1076 ("y".to_string(), col(|s| s.1)),
1077 ("xend".to_string(), col(|s| s.2)),
1078 ("yend".to_string(), col(|s| s.3)),
1079 ];
1080 self.default_aspect_ratio = Some(7.0 / grid.n_weeks().max(1) as f64);
1081 let plot = self
1082 .add_geom_with(tile)
1083 .stat(StatCalendar {
1084 grid: Some(grid),
1085 monday_first,
1086 })
1087 .scale_x_continuous(
1088 ScaleContinuous::new()
1089 .with_breaks(xb)
1090 .with_localized_labels(move |l| month_breaks_localized(&grid, l).1)
1092 .with_expand(0.0, 0.0),
1093 )
1094 .scale_y_continuous(
1095 ScaleContinuous::new()
1096 .with_breaks(yb)
1097 .with_localized_labels(weekday_labels)
1098 .with_expand(0.0, 0.0),
1099 );
1100 if segs.is_empty() {
1101 return plot;
1102 }
1103 plot.add_geom_with(crate::geom::segment::GeomCalendarBorder)
1105 .layer_data(boundaries)
1106 .layer_aes(Aes::new().x("x").y("y").xend("xend").yend("yend"))
1107 .show_legend(false)
1108 }
1109
1110 pub fn geom_blank(self) -> Self {
1111 self.add_geom(GeomBlank)
1112 }
1113
1114 fn add_geom_with(self, geom: impl Geom + 'static) -> Self {
1117 let mut plot = self.add_geom(geom);
1118 if let Some(layer) = plot.layers.last_mut() {
1119 layer.explicit_style = true;
1120 }
1121 plot
1122 }
1123
1124 fn add_geom(mut self, geom: impl Geom + 'static) -> Self {
1125 let stat = geom.default_stat();
1126 let position = geom.default_position();
1127 let params = geom.default_params();
1128 self.layers.push(Layer {
1129 data: None,
1130 mapping: Aes::default(),
1131 geom: Box::new(geom),
1132 stat,
1133 position,
1134 params,
1135 show_legend: None,
1136 explicit_style: false,
1137 tooltip_template: None,
1138 });
1139 self
1140 }
1141
1142 pub fn stat(mut self, stat: impl Stat + 'static) -> Self {
1146 if let Some(layer) = self.layers.last_mut() {
1147 layer.stat = Box::new(stat);
1148 }
1149 self
1150 }
1151
1152 pub fn position(mut self, pos: impl Position + 'static) -> Self {
1154 if let Some(layer) = self.layers.last_mut() {
1155 layer.position = Box::new(pos);
1156 }
1157 self
1158 }
1159
1160 pub fn layer_data(mut self, data: impl GGData) -> Self {
1162 if let Some(layer) = self.layers.last_mut() {
1163 layer.data = Some(data.into_dataframe());
1164 }
1165 self
1166 }
1167
1168 pub fn layer_aes(mut self, mapping: Aes) -> Self {
1170 self.warnings.extend(mapping.warnings.iter().cloned());
1171 if let Some(layer) = self.layers.last_mut() {
1172 layer.mapping = mapping;
1173 }
1174 self
1175 }
1176
1177 pub fn tooltip(mut self, template: &str) -> Self {
1188 if let Some(layer) = self.layers.last_mut() {
1189 layer.tooltip_template = Some(template.to_string());
1190 }
1191 self
1192 }
1193
1194 pub fn show_legend(mut self, show: bool) -> Self {
1197 if let Some(layer) = self.layers.last_mut() {
1198 layer.show_legend = Some(show);
1199 }
1200 self
1201 }
1202
1203 pub fn decorative(mut self) -> Self {
1230 if let Some(layer) = self.layers.last_mut() {
1231 let geom = std::mem::replace(&mut layer.geom, Box::new(GeomBlank));
1232 layer.geom = Box::new(crate::geom::decorative::Decorative(geom));
1233 if layer.show_legend.is_none() {
1234 layer.show_legend = Some(false);
1235 }
1236 }
1237 self
1238 }
1239
1240 pub fn layer_svg_attr(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
1274 let (name, value) = (name.into(), value.into());
1275 let Some(idx) = self.layers.len().checked_sub(1) else {
1276 self.warnings.push(format!(
1277 "layer_svg_attr(\"{name}\") called before any layer was added — ignored"
1278 ));
1279 return self;
1280 };
1281 if let Some((n, v)) =
1282 crate::render::svg_backend::validate_layer_svg_attr(&name, &value, &mut self.warnings)
1283 {
1284 self.layer_svg_attrs
1285 .retain(|(i, k, _)| !(*i == idx && *k == n));
1286 self.layer_svg_attrs.push((idx, n, v));
1287 }
1288 self
1289 }
1290
1291 pub fn layer_svg_attrs<N: Into<String>, V: Into<String>>(
1293 self,
1294 attrs: impl IntoIterator<Item = (N, V)>,
1295 ) -> Self {
1296 attrs
1297 .into_iter()
1298 .fold(self, |p, (n, v)| p.layer_svg_attr(n, v))
1299 }
1300
1301 pub fn scale_x_continuous(mut self, s: ScaleContinuous) -> Self {
1304 let s = s.for_aesthetic(crate::aes::Aesthetic::X);
1305 self.scales.push(Box::new(s));
1306 self
1307 }
1308
1309 pub fn scale_y_continuous(mut self, s: ScaleContinuous) -> Self {
1310 let s = s.for_aesthetic(crate::aes::Aesthetic::Y);
1311 self.scales.push(Box::new(s));
1312 self
1313 }
1314
1315 pub fn scale_x_discrete(mut self, s: crate::scale::discrete::ScaleDiscrete) -> Self {
1316 let s = s.for_aesthetic(crate::aes::Aesthetic::X);
1317 self.scales.push(Box::new(s));
1318 self
1319 }
1320
1321 pub fn scale_y_discrete(mut self, s: crate::scale::discrete::ScaleDiscrete) -> Self {
1322 let s = s.for_aesthetic(crate::aes::Aesthetic::Y);
1323 self.scales.push(Box::new(s));
1324 self
1325 }
1326
1327 pub fn scale_color(mut self, s: impl Scale + 'static) -> Self {
1328 self.scales.push(Box::new(s));
1329 self
1330 }
1331
1332 pub fn scale_fill(mut self, s: impl Scale + 'static) -> Self {
1333 self.scales.push(Box::new(s));
1334 self
1335 }
1336
1337 pub fn scale_color_manual(self, values: Vec<(&str, crate::scale::color::RGBAColor)>) -> Self {
1338 let s = crate::scale::manual::ScaleManual::new(crate::aes::Aesthetic::Color, values);
1339 self.scale_color(s)
1340 }
1341
1342 pub fn scale_fill_manual(self, values: Vec<(&str, crate::scale::color::RGBAColor)>) -> Self {
1343 let s = crate::scale::manual::ScaleManual::new(crate::aes::Aesthetic::Fill, values);
1344 self.scale_fill(s)
1345 }
1346
1347 pub fn scale_colour_identity(self) -> Self {
1350 let s = crate::scale::identity::ScaleColorIdentity::new(crate::aes::Aesthetic::Color);
1351 self.scale_color(s)
1352 }
1353
1354 pub fn scale_color_identity(self) -> Self {
1356 self.scale_colour_identity()
1357 }
1358
1359 pub fn scale_fill_identity(self) -> Self {
1362 let s = crate::scale::identity::ScaleColorIdentity::new(crate::aes::Aesthetic::Fill);
1363 self.scale_fill(s)
1364 }
1365
1366 pub fn scale_color_viridis(self) -> Self {
1367 use crate::scale::color::ScaleColorDiscrete;
1368 use crate::scale::palettes::PaletteName;
1369 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Color)
1370 .with_named_palette(&PaletteName::Viridis);
1371 self.scale_color(s)
1372 }
1373
1374 pub fn scale_color_brewer(self, name: crate::scale::palettes::PaletteName) -> Self {
1375 use crate::scale::color::ScaleColorDiscrete;
1376 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Color).with_named_palette(&name);
1377 self.scale_color(s)
1378 }
1379
1380 pub fn scale_color_gradient(
1381 self,
1382 low: crate::scale::color::RGBAColor,
1383 high: crate::scale::color::RGBAColor,
1384 ) -> Self {
1385 use crate::scale::color::ScaleColorContinuous;
1386 let s = ScaleColorContinuous::new(crate::aes::Aesthetic::Color).with_colors(low, high);
1387 self.scale_color(s)
1388 }
1389
1390 pub fn scale_fill_gradient(
1391 self,
1392 low: crate::scale::color::RGBAColor,
1393 high: crate::scale::color::RGBAColor,
1394 ) -> Self {
1395 use crate::scale::color::ScaleColorContinuous;
1396 let s = ScaleColorContinuous::new(crate::aes::Aesthetic::Fill).with_colors(low, high);
1397 self.scale_fill(s)
1398 }
1399
1400 pub fn scale_color_gradient2(
1401 self,
1402 low: crate::scale::color::RGBAColor,
1403 mid: crate::scale::color::RGBAColor,
1404 high: crate::scale::color::RGBAColor,
1405 ) -> Self {
1406 use crate::scale::gradient::ScaleColorGradient2;
1407 let s = ScaleColorGradient2::new(crate::aes::Aesthetic::Color).with_colors(low, mid, high);
1408 self.scale_color(s)
1409 }
1410
1411 pub fn scale_fill_gradient2(
1412 self,
1413 low: crate::scale::color::RGBAColor,
1414 mid: crate::scale::color::RGBAColor,
1415 high: crate::scale::color::RGBAColor,
1416 ) -> Self {
1417 use crate::scale::gradient::ScaleColorGradient2;
1418 let s = ScaleColorGradient2::new(crate::aes::Aesthetic::Fill).with_colors(low, mid, high);
1419 self.scale_fill(s)
1420 }
1421
1422 pub fn scale_fill_viridis(self) -> Self {
1423 use crate::scale::color::ScaleColorDiscrete;
1424 use crate::scale::palettes::PaletteName;
1425 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill)
1426 .with_named_palette(&PaletteName::Viridis);
1427 self.scale_fill(s)
1428 }
1429
1430 pub fn scale_color_viridis_c(self) -> Self {
1432 use crate::scale::gradient_n::ScaleColorGradientN;
1433 let s = ScaleColorGradientN::viridis(crate::aes::Aesthetic::Color);
1434 self.scale_color(s)
1435 }
1436
1437 pub fn scale_fill_viridis_c(self) -> Self {
1439 use crate::scale::gradient_n::ScaleColorGradientN;
1440 let s = ScaleColorGradientN::viridis(crate::aes::Aesthetic::Fill);
1441 self.scale_fill(s)
1442 }
1443
1444 pub fn scale_color_gradientn(self, stops: Vec<(f64, crate::scale::color::RGBAColor)>) -> Self {
1446 use crate::scale::gradient_n::ScaleColorGradientN;
1447 let s = ScaleColorGradientN::new(crate::aes::Aesthetic::Color, stops);
1448 self.scale_color(s)
1449 }
1450
1451 pub fn scale_fill_gradientn(self, stops: Vec<(f64, crate::scale::color::RGBAColor)>) -> Self {
1453 use crate::scale::gradient_n::ScaleColorGradientN;
1454 let s = ScaleColorGradientN::new(crate::aes::Aesthetic::Fill, stops);
1455 self.scale_fill(s)
1456 }
1457
1458 pub fn scale_color_steps(
1461 self,
1462 low: crate::scale::color::RGBAColor,
1463 high: crate::scale::color::RGBAColor,
1464 n_bins: usize,
1465 ) -> Self {
1466 let s = crate::scale::steps::ScaleColorSteps::two(
1467 crate::aes::Aesthetic::Color,
1468 (low.r, low.g, low.b),
1469 (high.r, high.g, high.b),
1470 n_bins,
1471 );
1472 self.scale_color(s)
1473 }
1474
1475 pub fn scale_color_stepsn(
1477 self,
1478 stops: Vec<crate::scale::color::RGBAColor>,
1479 n_bins: usize,
1480 ) -> Self {
1481 let s = crate::scale::steps::ScaleColorSteps::new(
1482 crate::aes::Aesthetic::Color,
1483 stops.iter().map(|c| (c.r, c.g, c.b)).collect(),
1484 n_bins,
1485 );
1486 self.scale_color(s)
1487 }
1488
1489 pub fn scale_color_fermenter(
1491 self,
1492 name: crate::scale::palettes::PaletteName,
1493 n_bins: usize,
1494 ) -> Self {
1495 let stops = crate::scale::palettes::palette(&name)
1496 .iter()
1497 .map(|c| (c.r, c.g, c.b))
1498 .collect();
1499 let s =
1500 crate::scale::steps::ScaleColorSteps::new(crate::aes::Aesthetic::Color, stops, n_bins);
1501 self.scale_color(s)
1502 }
1503
1504 pub fn scale_fill_steps(
1506 self,
1507 low: crate::scale::color::RGBAColor,
1508 high: crate::scale::color::RGBAColor,
1509 n_bins: usize,
1510 ) -> Self {
1511 let s = crate::scale::steps::ScaleColorSteps::two(
1512 crate::aes::Aesthetic::Fill,
1513 (low.r, low.g, low.b),
1514 (high.r, high.g, high.b),
1515 n_bins,
1516 );
1517 self.scale_fill(s)
1518 }
1519
1520 pub fn scale_fill_binned(
1531 self,
1532 breaks: Vec<f64>,
1533 low: crate::scale::color::RGBAColor,
1534 high: crate::scale::color::RGBAColor,
1535 ) -> Self {
1536 let s = crate::scale::binned::ScaleFillBinned::two(
1537 crate::aes::Aesthetic::Fill,
1538 breaks,
1539 (low.r, low.g, low.b),
1540 (high.r, high.g, high.b),
1541 );
1542 self.scale_fill(s)
1543 }
1544
1545 pub fn scale_fill_binned_with(
1549 self,
1550 breaks: Vec<f64>,
1551 colors: Vec<crate::scale::color::RGBAColor>,
1552 ) -> Self {
1553 let s = crate::scale::binned::ScaleFillBinned::new(
1554 crate::aes::Aesthetic::Fill,
1555 breaks,
1556 colors.iter().map(|c| (c.r, c.g, c.b)).collect(),
1557 );
1558 self.scale_fill(s)
1559 }
1560
1561 pub fn scale_fill_fermenter(
1563 self,
1564 name: crate::scale::palettes::PaletteName,
1565 n_bins: usize,
1566 ) -> Self {
1567 let stops = crate::scale::palettes::palette(&name)
1568 .iter()
1569 .map(|c| (c.r, c.g, c.b))
1570 .collect();
1571 let s =
1572 crate::scale::steps::ScaleColorSteps::new(crate::aes::Aesthetic::Fill, stops, n_bins);
1573 self.scale_fill(s)
1574 }
1575
1576 pub fn scale_fill_discrete_sorted(self) -> Self {
1581 use crate::scale::color::ScaleColorDiscrete;
1582 self.scale_fill(ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill).sorted())
1583 }
1584
1585 pub fn scale_color_discrete_sorted(self) -> Self {
1588 use crate::scale::color::ScaleColorDiscrete;
1589 self.scale_color(ScaleColorDiscrete::new(crate::aes::Aesthetic::Color).sorted())
1590 }
1591
1592 pub fn scale_fill_brewer(self, name: crate::scale::palettes::PaletteName) -> Self {
1593 use crate::scale::color::ScaleColorDiscrete;
1594 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill).with_named_palette(&name);
1595 self.scale_fill(s)
1596 }
1597
1598 pub fn scale_linetype_manual(
1599 self,
1600 values: Vec<(&str, crate::render::backend::Linetype)>,
1601 ) -> Self {
1602 let s = crate::scale::linetype_manual::ScaleLinetypeManual::new(values);
1603 self.scale_color(s)
1604 }
1605
1606 pub fn scale_shape_manual(
1607 self,
1608 values: Vec<(&str, crate::render::backend::PointShape)>,
1609 ) -> Self {
1610 let s = crate::scale::shape_manual::ScaleShapeManual::new(values);
1611 self.scale_color(s)
1612 }
1613
1614 pub fn scale_color_grey(self) -> Self {
1615 let s = crate::scale::grey::ScaleColorGrey::new(crate::aes::Aesthetic::Color);
1616 self.scale_color(s)
1617 }
1618
1619 pub fn scale_fill_grey(self) -> Self {
1620 let s = crate::scale::grey::ScaleColorGrey::new(crate::aes::Aesthetic::Fill);
1621 self.scale_fill(s)
1622 }
1623
1624 pub fn scale_color_grey_with(self, s: crate::scale::grey::ScaleColorGrey) -> Self {
1625 self.scale_color(s)
1626 }
1627
1628 pub fn scale_fill_grey_with(self, s: crate::scale::grey::ScaleColorGrey) -> Self {
1629 self.scale_fill(s)
1630 }
1631
1632 pub fn scale_x_reverse(self) -> Self {
1633 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reverse))
1634 }
1635
1636 pub fn scale_y_reverse(self) -> Self {
1637 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reverse))
1638 }
1639
1640 pub fn scale_x_datetime(mut self, s: crate::scale::datetime::ScaleDateTime) -> Self {
1641 let s = s.for_aesthetic(crate::aes::Aesthetic::X);
1642 self.scales.push(Box::new(s));
1643 self
1644 }
1645
1646 pub fn scale_y_datetime(mut self, s: crate::scale::datetime::ScaleDateTime) -> Self {
1647 let s = s.for_aesthetic(crate::aes::Aesthetic::Y);
1648 self.scales.push(Box::new(s));
1649 self
1650 }
1651
1652 pub fn scale_size(mut self, s: crate::scale::size::ScaleSizeContinuous) -> Self {
1653 self.scales.push(Box::new(s));
1654 self
1655 }
1656
1657 pub fn scale_size_area(mut self, max_size: f64) -> Self {
1661 self.scales.push(Box::new(
1662 crate::scale::size::ScaleSizeContinuous::new().area(max_size),
1663 ));
1664 self
1665 }
1666
1667 pub fn scale_alpha(mut self, s: crate::scale::alpha::ScaleAlphaContinuous) -> Self {
1668 self.scales.push(Box::new(s));
1669 self
1670 }
1671
1672 pub fn scale_linewidth(mut self, s: crate::scale::linewidth::ScaleLinewidthContinuous) -> Self {
1676 self.scales.push(Box::new(s));
1677 self
1678 }
1679
1680 pub fn xlim(self, min: f64, max: f64) -> Self {
1681 self.scale_x_continuous(ScaleContinuous::new().with_limits(min, max))
1682 }
1683
1684 pub fn ylim(self, min: f64, max: f64) -> Self {
1685 self.scale_y_continuous(ScaleContinuous::new().with_limits(min, max))
1686 }
1687
1688 pub fn scale_x_log10(self) -> Self {
1689 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log10))
1690 }
1691
1692 pub fn scale_y_log10(self) -> Self {
1693 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log10))
1694 }
1695
1696 pub fn scale_x_sqrt(self) -> Self {
1697 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Sqrt))
1698 }
1699
1700 pub fn scale_y_sqrt(self) -> Self {
1701 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Sqrt))
1702 }
1703
1704 pub fn scale_x_log2(self) -> Self {
1705 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log2))
1706 }
1707
1708 pub fn scale_y_log2(self) -> Self {
1709 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log2))
1710 }
1711
1712 pub fn scale_x_ln(self) -> Self {
1713 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Ln))
1714 }
1715
1716 pub fn scale_y_ln(self) -> Self {
1717 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Ln))
1718 }
1719
1720 pub fn scale_x_logit(self) -> Self {
1722 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Logit))
1723 }
1724
1725 pub fn scale_y_logit(self) -> Self {
1726 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Logit))
1727 }
1728
1729 pub fn scale_x_probit(self) -> Self {
1731 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Probit))
1732 }
1733
1734 pub fn scale_y_probit(self) -> Self {
1735 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Probit))
1736 }
1737
1738 pub fn scale_x_pseudo_log(self) -> Self {
1740 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::PseudoLog))
1741 }
1742
1743 pub fn scale_y_pseudo_log(self) -> Self {
1744 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::PseudoLog))
1745 }
1746
1747 pub fn scale_x_reciprocal(self) -> Self {
1749 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reciprocal))
1750 }
1751
1752 pub fn scale_y_reciprocal(self) -> Self {
1753 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reciprocal))
1754 }
1755
1756 pub fn scale_x_exp(self) -> Self {
1758 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Exp))
1759 }
1760
1761 pub fn scale_y_exp(self) -> Self {
1762 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Exp))
1763 }
1764
1765 pub fn scale_x_boxcox(self, lambda: f64) -> Self {
1767 self.scale_x_continuous(
1768 ScaleContinuous::new().with_transform(ScaleTransform::BoxCox(lambda)),
1769 )
1770 }
1771
1772 pub fn scale_y_boxcox(self, lambda: f64) -> Self {
1773 self.scale_y_continuous(
1774 ScaleContinuous::new().with_transform(ScaleTransform::BoxCox(lambda)),
1775 )
1776 }
1777
1778 pub fn facet_wrap(mut self, var: &str, ncol: Option<usize>) -> Self {
1781 self.facet = Facet::Wrap {
1782 var: var.to_string(),
1783 ncol,
1784 scales: FacetScales::Fixed,
1785 labeller: FacetLabeller::default(),
1786 };
1787 self
1788 }
1789
1790 pub fn facet_wrap_free(mut self, var: &str, ncol: Option<usize>, scales: FacetScales) -> Self {
1791 self.facet = Facet::Wrap {
1792 var: var.to_string(),
1793 ncol,
1794 scales,
1795 labeller: FacetLabeller::default(),
1796 };
1797 self
1798 }
1799
1800 pub fn facet_wrap_labeller(
1801 mut self,
1802 var: &str,
1803 ncol: Option<usize>,
1804 labeller: FacetLabeller,
1805 ) -> Self {
1806 self.facet = Facet::Wrap {
1807 var: var.to_string(),
1808 ncol,
1809 scales: FacetScales::Fixed,
1810 labeller,
1811 };
1812 self
1813 }
1814
1815 pub fn facet_grid(mut self, row: Option<&str>, col: Option<&str>) -> Self {
1816 self.facet = Facet::Grid {
1817 row_var: row.map(String::from),
1818 col_var: col.map(String::from),
1819 scales: FacetScales::Fixed,
1820 labeller: FacetLabeller::default(),
1821 space: FacetSpace::Fixed,
1822 };
1823 self
1824 }
1825
1826 pub fn facet_grid_free(
1827 mut self,
1828 row: Option<&str>,
1829 col: Option<&str>,
1830 scales: FacetScales,
1831 ) -> Self {
1832 self.facet = Facet::Grid {
1833 row_var: row.map(String::from),
1834 col_var: col.map(String::from),
1835 scales,
1836 labeller: FacetLabeller::default(),
1837 space: FacetSpace::Fixed,
1838 };
1839 self
1840 }
1841
1842 pub fn facet_grid_multi(
1846 mut self,
1847 row: Option<&str>,
1848 cols: &[&str],
1849 scales: FacetScales,
1850 space: FacetSpace,
1851 ) -> Self {
1852 let col_var = if cols.len() > 1 {
1853 let n = self.data.nrows();
1855 let mut combined = Vec::with_capacity(n);
1856 for i in 0..n {
1857 let parts: Vec<String> = cols
1858 .iter()
1859 .map(|c| {
1860 self.data
1861 .column(c)
1862 .and_then(|col| col.get(i))
1863 .map(|v| v.to_group_key())
1864 .unwrap_or_default()
1865 })
1866 .collect();
1867 combined.push(crate::data::Value::Str(parts.join(" . ")));
1868 }
1869 let name = "__facet_cols__".to_string();
1870 self.data.add_column(name.clone(), combined);
1871 Some(name)
1872 } else {
1873 cols.first().map(|s| s.to_string())
1874 };
1875 self.facet = Facet::Grid {
1876 row_var: row.map(String::from),
1877 col_var,
1878 scales,
1879 labeller: FacetLabeller::default(),
1880 space,
1881 };
1882 self
1883 }
1884
1885 pub fn facet_grid_space(
1888 mut self,
1889 row: Option<&str>,
1890 col: Option<&str>,
1891 scales: FacetScales,
1892 space: FacetSpace,
1893 ) -> Self {
1894 self.facet = Facet::Grid {
1895 row_var: row.map(String::from),
1896 col_var: col.map(String::from),
1897 scales,
1898 labeller: FacetLabeller::default(),
1899 space,
1900 };
1901 self
1902 }
1903
1904 pub fn facet_grid_labeller(
1905 mut self,
1906 row: Option<&str>,
1907 col: Option<&str>,
1908 labeller: FacetLabeller,
1909 ) -> Self {
1910 self.facet = Facet::Grid {
1911 row_var: row.map(String::from),
1912 col_var: col.map(String::from),
1913 scales: FacetScales::Fixed,
1914 labeller,
1915 space: FacetSpace::Fixed,
1916 };
1917 self
1918 }
1919
1920 pub fn coord_flip(mut self) -> Self {
1923 self.coord = Box::new(CoordFlip);
1924 self
1925 }
1926
1927 pub fn coord_fixed(mut self, ratio: f64) -> Self {
1928 self.coord = Box::new(CoordFixed::new(ratio));
1929 self
1930 }
1931
1932 #[cfg(feature = "sf")]
1936 pub fn coord_sf(mut self) -> Self {
1937 self.coord = Box::new(crate::coord::sf::CoordSf::new());
1938 self
1939 }
1940
1941 #[cfg(feature = "sf")]
1946 pub fn coord_sf_with(mut self, coord: crate::coord::sf::CoordSf) -> Self {
1947 self.coord = Box::new(coord);
1948 self
1949 }
1950
1951 pub fn svg_root_data(mut self, on: bool) -> Self {
1958 self.svg_root_data = on;
1959 self
1960 }
1961
1962 pub fn svg_attr(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
1972 self.root_attrs.push((name.into(), value.into()));
1973 self
1974 }
1975
1976 pub fn svg_attrs(mut self, attrs: impl IntoIterator<Item = (String, String)>) -> Self {
1978 self.root_attrs.extend(attrs);
1979 self
1980 }
1981
1982 pub fn svg_warnings_attr(mut self, on: bool) -> Self {
1987 self.svg_warnings_attr = on;
1988 self
1989 }
1990
1991 pub fn svg_formatted_values(mut self, on: bool) -> Self {
2000 self.svg_formatted_values = on;
2001 self
2002 }
2003
2004 pub fn coord_trans(mut self, x: Option<ScaleTransform>, y: Option<ScaleTransform>) -> Self {
2009 self.coord = Box::new(crate::coord::trans::CoordTrans::new(x, y));
2010 self
2011 }
2012
2013 pub fn coord_trans_y(self, y: ScaleTransform) -> Self {
2015 self.coord_trans(None, Some(y))
2016 }
2017
2018 pub fn coord_trans_x(self, x: ScaleTransform) -> Self {
2020 self.coord_trans(Some(x), None)
2021 }
2022
2023 pub fn coord_cartesian_zoom(
2025 mut self,
2026 xlim: Option<(f64, f64)>,
2027 ylim: Option<(f64, f64)>,
2028 ) -> Self {
2029 let mut c = CoordCartesian::new();
2030 if let Some((min, max)) = xlim {
2031 c = c.xlim(min, max);
2032 }
2033 if let Some((min, max)) = ylim {
2034 c = c.ylim(min, max);
2035 }
2036 self.coord = Box::new(c);
2037 self
2038 }
2039
2040 pub fn coord_polar(mut self) -> Self {
2041 self.coord = Box::new(CoordPolar::new());
2042 self
2043 }
2044
2045 pub fn coord_radar(mut self) -> Self {
2049 self.coord = Box::new(crate::coord::radar::CoordRadar::new());
2050 self
2051 }
2052
2053 pub fn coord_radar_with(mut self, coord: crate::coord::radar::CoordRadar) -> Self {
2054 self.coord = Box::new(coord);
2055 self
2056 }
2057
2058 pub fn coord_polar_with(mut self, coord: CoordPolar) -> Self {
2059 self.coord = Box::new(coord);
2060 self
2061 }
2062
2063 pub fn theme(mut self, theme: Theme) -> Self {
2068 self.apply_preset(theme);
2069 self
2070 }
2071
2072 fn apply_preset(&mut self, theme: Theme) {
2073 let primary = self.theme.primary;
2074 self.theme = theme;
2075 if self.theme.primary.is_none() {
2076 self.theme.primary = primary;
2077 }
2078 }
2079
2080 pub fn axis_text_x_angle(mut self, degrees: f64) -> Self {
2084 self.theme.axis_text_x.angle = degrees;
2085 self
2086 }
2087
2088 pub fn axis_text_y_angle(mut self, degrees: f64) -> Self {
2090 self.theme.axis_text_y.angle = degrees;
2091 self
2092 }
2093
2094 pub fn axis_text_x_dodge(mut self, n: usize) -> Self {
2097 self.theme.axis_text_x_dodge = n.max(1);
2098 self
2099 }
2100
2101 pub fn aspect_ratio(mut self, ratio: f64) -> Self {
2104 self.theme.aspect_ratio = Some(ratio);
2105 self
2106 }
2107
2108 pub fn panel_ontop(mut self) -> Self {
2110 self.theme.panel_ontop = true;
2111 self
2112 }
2113
2114 pub fn axis_minor_ticks(mut self) -> Self {
2116 self.theme.axis_minor_ticks = true;
2117 self
2118 }
2119
2120 pub fn axis_text_x_fit(mut self, fit: crate::theme::AxisLabelFit) -> Self {
2125 self.theme.axis_text_x_fit = fit;
2126 self
2127 }
2128
2129 pub fn axis_text_x_check_overlap(mut self, on: bool) -> Self {
2132 self.theme.axis_text_x_check_overlap = on;
2133 self
2134 }
2135
2136 pub fn title_position(mut self, pos: crate::theme::TitlePosition) -> Self {
2139 self.theme.title_position = pos;
2140 self
2141 }
2142
2143 pub fn tag_position(mut self, pos: crate::theme::TagPosition) -> Self {
2145 self.theme.tag_position = pos;
2146 self
2147 }
2148
2149 pub fn legend_direction(mut self, dir: crate::theme::LegendDirection) -> Self {
2151 self.theme.legend_direction = Some(dir);
2152 self
2153 }
2154
2155 pub fn legend_position_inside(mut self, x: f64, y: f64) -> Self {
2162 self.theme.legend_position = crate::theme::LegendPosition::Inside(x, y);
2163 self
2164 }
2165
2166 pub fn legend_position(mut self, pos: crate::theme::LegendPosition) -> Self {
2168 self.theme.legend_position = pos;
2169 self
2170 }
2171
2172 pub fn primary_color(mut self, color: (u8, u8, u8)) -> Self {
2173 self.theme.primary = Some(color);
2174 self
2175 }
2176
2177 pub fn theme_minimal(mut self) -> Self {
2178 self.apply_preset(crate::theme::presets::theme_minimal());
2179 self
2180 }
2181
2182 pub fn theme_bw(mut self) -> Self {
2183 self.apply_preset(crate::theme::presets::theme_bw());
2184 self
2185 }
2186
2187 pub fn theme_gray(mut self) -> Self {
2188 self.apply_preset(crate::theme::presets::theme_gray());
2189 self
2190 }
2191
2192 pub fn theme_classic(mut self) -> Self {
2193 self.apply_preset(crate::theme::presets::theme_classic());
2194 self
2195 }
2196
2197 pub fn theme_pubr(mut self) -> Self {
2199 self.apply_preset(crate::theme::presets::theme_pubr());
2200 self
2201 }
2202
2203 pub fn theme_linedraw(mut self) -> Self {
2204 self.apply_preset(crate::theme::presets::theme_linedraw());
2205 self
2206 }
2207
2208 pub fn theme_light(mut self) -> Self {
2209 self.apply_preset(crate::theme::presets::theme_light());
2210 self
2211 }
2212
2213 pub fn theme_dark(mut self) -> Self {
2214 self.apply_preset(crate::theme::presets::theme_dark());
2215 self
2216 }
2217
2218 pub fn theme_void(mut self) -> Self {
2219 self.apply_preset(crate::theme::presets::theme_void());
2220 self
2221 }
2222
2223 pub fn theme_update(mut self, update: crate::theme::ThemeUpdate) -> Self {
2226 self.theme = self.theme.update(update);
2227 self
2228 }
2229
2230 pub fn guides(mut self, guide: crate::guide::config::GuideLegend) -> Self {
2234 self.guide_legend = guide;
2235 self
2236 }
2237
2238 pub fn labs(mut self, labels: Labels) -> Self {
2241 if labels.title.is_some() {
2242 self.labels.title = labels.title;
2243 }
2244 if labels.subtitle.is_some() {
2245 self.labels.subtitle = labels.subtitle;
2246 }
2247 if labels.x.is_some() {
2248 self.labels.x = labels.x;
2249 }
2250 if labels.y.is_some() {
2251 self.labels.y = labels.y;
2252 }
2253 if labels.caption.is_some() {
2254 self.labels.caption = labels.caption;
2255 }
2256 if labels.tag.is_some() {
2257 self.labels.tag = labels.tag;
2258 }
2259 self
2260 }
2261
2262 pub fn title(mut self, title: &str) -> Self {
2263 self.labels.title = Some(title.to_string());
2264 self
2265 }
2266
2267 pub fn tag(mut self, tag: &str) -> Self {
2270 self.labels.tag = Some(tag.to_string());
2271 self
2272 }
2273
2274 pub fn subtitle(mut self, subtitle: &str) -> Self {
2275 self.labels.subtitle = Some(subtitle.to_string());
2276 self
2277 }
2278
2279 pub fn xlab(mut self, label: &str) -> Self {
2280 self.labels.x = Some(label.to_string());
2281 self
2282 }
2283
2284 pub fn ylab(mut self, label: &str) -> Self {
2285 self.labels.y = Some(label.to_string());
2286 self
2287 }
2288
2289 pub fn caption(mut self, caption: &str) -> Self {
2290 self.labels.caption = Some(caption.to_string());
2291 self
2292 }
2293
2294 pub fn annotate(mut self, annotation: Annotation) -> Self {
2298 self.annotations.push(annotation);
2299 self
2300 }
2301
2302 pub fn annotate_text(self, label: &str, x: f64, y: f64) -> Self {
2304 self.annotate(Annotation::text(label, x, y))
2305 }
2306
2307 pub fn annotate_rect(self, xmin: f64, xmax: f64, ymin: f64, ymax: f64) -> Self {
2309 self.annotate(Annotation::rect(xmin, xmax, ymin, ymax))
2310 }
2311
2312 pub fn annotate_segment(self, x: f64, y: f64, xend: f64, yend: f64) -> Self {
2314 self.annotate(Annotation::segment(x, y, xend, yend))
2315 }
2316
2317 pub fn locale(mut self, locale: crate::locale::Locale) -> Self {
2340 self.locale = Some(locale);
2341 self
2342 }
2343
2344 pub fn try_build(self) -> Result<crate::build::BuiltPlot, GGError> {
2348 PlotBuilder::build(self)
2349 }
2350
2351 pub fn build(self) -> crate::build::BuiltPlot {
2355 self.try_build().expect("plot build failed")
2356 }
2357
2358 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
2362 pub fn save(self, path: &str) -> Result<(), GGError> {
2363 self.save_with_size(path, 800, 600)
2364 }
2365
2366 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
2368 pub fn save_with_size(self, path: &str, w: u32, h: u32) -> Result<(), GGError> {
2369 let (built, layout) = self.prepare(w, h)?;
2370
2371 let ext = path.rsplit('.').next().unwrap_or("svg").to_lowercase();
2373
2374 match ext.as_str() {
2375 "svg" => {
2376 let backend = plotters::prelude::SVGBackend::new(path, (w, h));
2377 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
2378 }
2379 "png" | "bmp" | "gif" | "jpeg" | "jpg" | "tiff" => {
2380 let backend = plotters::prelude::BitMapBackend::new(path, (w, h));
2381 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
2382 }
2383 _ => {
2384 return Err(GGError::UnsupportedFormat(ext));
2385 }
2386 }
2387
2388 Ok(())
2389 }
2390
2391 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
2397 pub fn render_svg(self) -> Result<String, GGError> {
2398 self.render_svg_with_size(800, 600)
2399 }
2400
2401 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
2405 pub fn render_svg_with_size(self, w: u32, h: u32) -> Result<String, GGError> {
2406 let (built, layout) = self.prepare(w, h)?;
2407 let mut buf = String::new();
2408 {
2409 let backend = plotters::prelude::SVGBackend::with_string(&mut buf, (w, h));
2410 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
2411 }
2412 Ok(buf)
2413 }
2414
2415 pub fn render_svg_native(self) -> Result<String, GGError> {
2419 self.render_svg_native_with_size(800, 600)
2420 }
2421
2422 pub fn render_svg_native_with_size(self, w: u32, h: u32) -> Result<String, GGError> {
2430 Ok(self.render_native(w, h)?.0.finish())
2431 }
2432
2433 pub fn render_svg_native_with_warnings(
2438 self,
2439 w: u32,
2440 h: u32,
2441 ) -> Result<(String, Vec<String>), GGError> {
2442 let (backend, warnings, _) = self.render_native(w, h)?;
2443 Ok((backend.finish(), warnings))
2444 }
2445
2446 pub fn render_svg_native_at(self, x: f64, y: f64, w: u32, h: u32) -> Result<String, GGError> {
2458 Ok(self.render_native(w, h)?.0.finish_fragment(x, y))
2459 }
2460
2461 pub fn render_svg_area_with_size(self, w: u32, h: u32) -> Result<(String, [f64; 4]), GGError> {
2465 let (backend, _, pa) = self.render_native(w, h)?;
2466 Ok((backend.finish(), [pa.x, pa.y, pa.width, pa.height]))
2467 }
2468
2469 fn render_native(
2473 self,
2474 w: u32,
2475 h: u32,
2476 ) -> Result<
2477 (
2478 crate::render::svg_backend::SvgBackend,
2479 Vec<String>,
2480 crate::render::Rect,
2481 ),
2482 GGError,
2483 > {
2484 let svg_root_data = self.svg_root_data;
2485 let root_attrs = self.root_attrs.clone();
2486 let svg_warnings_attr = self.svg_warnings_attr;
2487 let svg_formatted_values = self.svg_formatted_values;
2488 let (built, layout) = self.prepare(w, h)?;
2489 let pa = layout.plot_area.clone();
2490 let mut backend = crate::render::svg_backend::SvgBackend::new(w, h, pa.clone());
2491 backend.set_formatted_values(svg_formatted_values);
2492 let existing_root_attrs = if svg_root_data {
2493 let attrs = crate::render::svg_backend::root_data_attrs(&built);
2494 backend.set_root_attrs(attrs.clone());
2495 let mut reserved = attrs;
2499 reserved.push(("data-plot".to_string(), String::new()));
2500 reserved
2501 } else {
2502 backend.without_plot_attr();
2503 Vec::new()
2504 };
2505 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
2506 let mut warnings = built.warnings;
2507 warnings.extend(backend.take_warnings());
2508
2509 let mut reserved = existing_root_attrs;
2510 if svg_warnings_attr {
2511 reserved.push(("data-warnings".to_string(), String::new()));
2512 }
2513 let extra = crate::render::svg_backend::validate_root_attrs(
2514 &root_attrs,
2515 &reserved,
2516 "plot",
2517 &mut warnings,
2518 );
2519 backend.extend_root_attrs(extra);
2520 if svg_warnings_attr {
2521 backend.extend_root_attrs(vec![(
2522 "data-warnings".to_string(),
2523 crate::render::svg_backend::warnings_json(&warnings),
2524 )]);
2525 }
2526 Ok((backend, warnings, pa))
2527 }
2528
2529 #[cfg(feature = "canvas")]
2534 pub fn render_rgba_with_size(self, w: u32, h: u32) -> Result<(u32, u32, Vec<u8>), GGError> {
2535 let (built, layout) = self.prepare(w, h)?;
2536 let mut backend =
2537 crate::render::pixel_backend::PixelBackend::new(w, h, layout.plot_area.clone());
2538 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
2539 let (ow, oh) = backend.dimensions();
2540 Ok((ow, oh, backend.into_rgba()))
2541 }
2542
2543 #[cfg(feature = "canvas")]
2547 pub fn render_rgba_area_with_size(
2548 self,
2549 w: u32,
2550 h: u32,
2551 ) -> Result<(Vec<u8>, [f64; 4]), GGError> {
2552 let (built, layout) = self.prepare(w, h)?;
2553 let pa = layout.plot_area.clone();
2554 let mut backend = crate::render::pixel_backend::PixelBackend::new(w, h, pa.clone());
2555 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
2556 Ok((backend.into_rgba(), [pa.x, pa.y, pa.width, pa.height]))
2557 }
2558
2559 #[cfg(feature = "canvas")]
2563 pub fn render_png_raster_with_size(self, w: u32, h: u32) -> Result<Vec<u8>, GGError> {
2564 let (built, layout) = self.prepare(w, h)?;
2565 let mut backend =
2566 crate::render::pixel_backend::PixelBackend::new(w, h, layout.plot_area.clone());
2567 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
2568 backend.into_png().map_err(GGError::Render)
2569 }
2570
2571 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
2578 pub fn render_png(self) -> Result<Vec<u8>, GGError> {
2579 self.render_png_with_size(800, 600)
2580 }
2581
2582 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
2585 pub fn render_png_with_size(self, w: u32, h: u32) -> Result<Vec<u8>, GGError> {
2586 let (built, layout) = self.prepare(w, h)?;
2587
2588 let mut rgb = vec![0u8; (w as usize) * (h as usize) * 3];
2591 {
2592 let backend = plotters::prelude::BitMapBackend::with_buffer(&mut rgb, (w, h));
2593 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
2594 }
2595
2596 let img = image::RgbImage::from_raw(w, h, rgb).ok_or_else(|| {
2597 GGError::Render(RenderError::BackendError(
2598 "PNG buffer size mismatch".to_string(),
2599 ))
2600 })?;
2601 let mut out = std::io::Cursor::new(Vec::new());
2602 img.write_to(&mut out, image::ImageOutputFormat::Png)
2603 .map_err(|e| GGError::Render(RenderError::BackendError(format!("{:?}", e))))?;
2604 Ok(out.into_inner())
2605 }
2606
2607 pub(crate) fn prepare(
2609 self,
2610 w: u32,
2611 h: u32,
2612 ) -> Result<(crate::build::BuiltPlot, PlotLayout), GGError> {
2613 let (mut built, meta) = self.build_for_render()?;
2614 let layout = Self::layout_built(&mut built, &meta, w, h);
2615 Ok((built, layout))
2616 }
2617
2618 pub(crate) fn build_for_render(self) -> Result<(crate::build::BuiltPlot, RenderMeta), GGError> {
2621 let plot = self;
2622
2623 let has_title = plot.labels.title.is_some();
2624 let has_subtitle = plot.labels.subtitle.is_some();
2625 let has_caption = plot.labels.caption.is_some();
2626 let has_legend = plot.has_legend_mapping();
2627 let x_label = plot.labels.x.clone();
2628 let y_label = plot.labels.y.clone();
2629
2630 let mut built = PlotBuilder::build(plot)?;
2631
2632 built.theme.resolve_inheritance();
2634
2635 if let Some(ref label) = x_label {
2637 if let Some(s) = built.scales.get_mut(&crate::aes::Aesthetic::X) {
2638 s.set_name(label);
2639 }
2640 }
2641 if let Some(ref label) = y_label {
2642 if let Some(s) = built.scales.get_mut(&crate::aes::Aesthetic::Y) {
2643 s.set_name(label);
2644 }
2645 }
2646
2647 Ok((
2648 built,
2649 RenderMeta {
2650 has_title,
2651 has_subtitle,
2652 has_caption,
2653 has_legend,
2654 },
2655 ))
2656 }
2657
2658 pub(crate) fn layout_built(
2661 built: &mut crate::build::BuiltPlot,
2662 meta: &RenderMeta,
2663 w: u32,
2664 h: u32,
2665 ) -> PlotLayout {
2666 let RenderMeta {
2667 has_title,
2668 has_subtitle,
2669 has_caption,
2670 has_legend,
2671 } = *meta;
2672 let x_axis_top = built
2673 .scales
2674 .get(&crate::aes::Aesthetic::X)
2675 .map(|s| s.axis_position_opposite())
2676 .unwrap_or(false);
2677
2678 let flipped = built.coord.is_flipped();
2682 let h_aes = if flipped {
2683 crate::aes::Aesthetic::Y
2684 } else {
2685 crate::aes::Aesthetic::X
2686 };
2687 let v_aes = if flipped {
2688 crate::aes::Aesthetic::X
2689 } else {
2690 crate::aes::Aesthetic::Y
2691 };
2692
2693 let drawn_x_labels: Vec<(f64, String)> = built
2701 .scales
2702 .get(&h_aes)
2703 .map(|hs| {
2704 hs.breaks()
2705 .into_iter()
2706 .filter(|(_, label)| !label.is_empty())
2707 .collect()
2708 })
2709 .unwrap_or_default();
2710 let h_is_discrete = built
2711 .scales
2712 .get(&h_aes)
2713 .map(|hs| hs.is_discrete())
2714 .unwrap_or(false);
2715
2716 if built.theme.axis_text_x.visible
2729 && built.theme.axis_text_x.angle.abs() < 1.0
2730 && h_is_discrete
2731 && !drawn_x_labels.is_empty()
2732 {
2733 let font = built.theme.axis_text_x.size;
2734 let max_w = drawn_x_labels
2735 .iter()
2736 .map(|(_, l)| crate::render::text::text_width(l, font))
2737 .fold(0.0_f64, f64::max);
2738 let n = drawn_x_labels.len() as f64;
2739 let spacing = 0.9 * w as f64 / n; if max_w > spacing {
2741 let vertical = max_w * std::f64::consts::FRAC_1_SQRT_2 > spacing;
2745 built.theme.axis_text_x.angle = if vertical { 270.0 } else { -45.0 };
2746 }
2747 }
2748
2749 let x_label_height = if built.theme.axis_text_x.visible
2764 && built.theme.axis_text_x.angle.abs() > 10.0
2765 && !drawn_x_labels.is_empty()
2766 {
2767 let font = built.theme.axis_text_x.size;
2768 let angle = built.theme.axis_text_x.angle;
2769 let dir = if x_axis_top { -1.0 } else { 1.0 };
2770 let (rise, fall) = crate::render::text::rotated_label_rise_fall(
2771 drawn_x_labels.iter().map(|(_, l)| l.as_str()),
2772 font,
2773 angle,
2774 crate::render::text::rotated_anchor_frac(angle, dir),
2775 );
2776 Some(built.theme.legend_spacing / 2.0 + font / 2.0 + rise + fall)
2777 } else {
2778 None
2779 };
2780
2781 let y_label_width = if built.theme.axis_text_y.visible {
2785 built.scales.get(&v_aes).map(|vs| {
2786 let max_ch = vs
2787 .breaks()
2788 .iter()
2789 .map(|(_, l)| l.chars().count())
2790 .max()
2791 .unwrap_or(0);
2792 let measured = max_ch as f64 * built.theme.axis_text_y.size * 0.6 + 4.0;
2793 let default = built.theme.axis_text_y.size * 3.5 + 4.0;
2794 measured.max(default).min(0.35 * w as f64)
2795 })
2796 } else {
2797 None
2798 };
2799
2800 let mut extras = crate::render::layout::LayoutExtras::default();
2811 let can_reserve = built.facet.is_none()
2812 && built.theme.axis_text_x.visible
2813 && built.theme.axis_text_x_fit == crate::theme::AxisLabelFit::Reserve
2814 && !built.coord.is_polar()
2815 && built.coord.supports_axis_reserve();
2816 if can_reserve {
2817 if let Some(hs) = built.scales.get(&h_aes) {
2818 let breaks = hs.breaks();
2819 if let (Some(first), Some(last)) = (breaks.first(), breaks.last()) {
2820 let angle = built.theme.axis_text_x.angle;
2821 let anchor = if angle.abs() > 10.0 {
2822 let dir = if x_axis_top { -1.0 } else { 1.0 };
2823 crate::render::text::rotated_anchor_frac(angle, dir)
2824 } else {
2825 0.5
2826 };
2827 let size = built.theme.axis_text_x.size;
2828 const EDGE: f64 = 1.0;
2829 for _ in 0..2 {
2830 let layout = PlotLayout::compute_with_extras(
2831 w as f64,
2832 h as f64,
2833 &built.theme,
2834 has_title,
2835 has_subtitle,
2836 has_caption,
2837 has_legend,
2838 x_axis_top,
2839 y_label_width,
2840 x_label_height,
2841 extras,
2842 );
2843 let area = &layout.plot_area;
2844 let edge_y = area.y + area.height;
2845 let to_point = |pos: f64| if flipped { (0.0, pos) } else { (pos, 0.0) };
2846 let px_first = built.coord.transform(to_point(first.0), area).0;
2847 let px_last = built.coord.transform(to_point(last.0), area).0;
2848 let bbox_first = crate::render::text::label_bbox(
2849 &first.1, size, px_first, edge_y, angle, anchor,
2850 );
2851 let bbox_last = crate::render::text::label_bbox(
2852 &last.1, size, px_last, edge_y, angle, anchor,
2853 );
2854 let deficit_left = (EDGE - bbox_first[0]).max(0.0);
2855 let deficit_right = (bbox_last[2] - (w as f64 - EDGE)).max(0.0);
2856 if deficit_left <= 0.0 && deficit_right <= 0.0 {
2857 break;
2858 }
2859 let (p_first, p_last) = (first.0, last.0);
2868 if deficit_left > 0.0 && deficit_right > 0.0 {
2869 let (a, b, c, d) = (1.0 - p_first, p_first, 1.0 - p_last, p_last);
2874 let det = a * d - b * c;
2875 if det.abs() > 0.01 {
2876 extras.left +=
2877 ((deficit_left * d + deficit_right * b) / det).max(0.0);
2878 extras.right +=
2879 ((deficit_right * a + deficit_left * c) / det).max(0.0);
2880 } else {
2881 extras.left += deficit_left / (1.0 - p_first).max(0.05);
2885 extras.right += deficit_right / p_last.max(0.05);
2886 }
2887 } else if deficit_left > 0.0 {
2888 extras.left += deficit_left / (1.0 - p_first).max(0.05);
2889 } else if deficit_right > 0.0 {
2890 extras.right += deficit_right / p_last.max(0.05);
2891 }
2892 const MIN_PANEL_WIDTH: f64 = 50.0;
2907 let cap = (w as f64 - MIN_PANEL_WIDTH).max(0.0);
2908 if extras.left + extras.right > cap {
2909 let scale = if extras.left + extras.right > 0.0 {
2910 cap / (extras.left + extras.right)
2911 } else {
2912 0.0
2913 };
2914 extras.left *= scale;
2915 extras.right *= scale;
2916 }
2917 }
2918 }
2919 }
2920 }
2921
2922 if has_legend
2929 && !matches!(
2930 built.theme.legend_position,
2931 crate::theme::LegendPosition::None
2932 )
2933 {
2934 let legend_aes =
2935 crate::guide::legend::legend_scales_for(&built.scales, &built.suppressed_aes);
2936 extras.legend_max_key_size = legend_aes
2940 .iter()
2941 .filter_map(|aes| {
2942 let scale = built.scales.get(aes)?;
2943 let breaks = scale.breaks();
2944 Some(crate::guide::legend::size_key_diameter(
2945 aes,
2946 &built.scales,
2947 scale,
2948 &breaks,
2949 ))
2950 })
2951 .fold(0.0_f64, f64::max);
2952 let has_discrete_guide = legend_aes.iter().any(|a| {
2953 built
2954 .scales
2955 .get(a)
2956 .map(|s| s.is_discrete())
2957 .unwrap_or(false)
2958 });
2959 if has_discrete_guide {
2960 let layout0 = PlotLayout::compute_with_extras(
2961 w as f64,
2962 h as f64,
2963 &built.theme,
2964 has_title,
2965 has_subtitle,
2966 has_caption,
2967 has_legend,
2968 x_axis_top,
2969 y_label_width,
2970 x_label_height,
2971 extras,
2972 );
2973 let (legend_x0, _, mut is_horizontal) = crate::guide::legend::legend_position(
2983 &built.theme,
2984 &layout0.plot_area,
2985 extras.legend_extra_rows,
2986 (0.0, 0.0),
2987 &layout0.total,
2988 );
2989 if let Some(dir) = built.theme.legend_direction {
2990 is_horizontal = matches!(dir, crate::theme::LegendDirection::Horizontal);
2991 }
2992 let avail_width =
2993 (layout0.plot_area.x + layout0.plot_area.width - legend_x0).max(0.0);
2994 let mut legend_warnings = Vec::new();
2995 let mut plans = crate::guide::legend::plan_all_legends(
2996 &built.scales,
2997 &built.guide_legend,
2998 &built.theme,
2999 &built.suppressed_aes,
3000 avail_width,
3001 layout0.plot_area.height,
3002 is_horizontal,
3003 &mut legend_warnings,
3004 );
3005 built.warnings.extend(legend_warnings);
3006
3007 if !plans.is_empty() {
3008 extras.legend_extra_rows = if is_horizontal {
3014 plans
3015 .values()
3016 .map(|p| p.rows.saturating_sub(1))
3017 .max()
3018 .unwrap_or(0)
3019 } else {
3020 plans.values().map(|p| p.rows.saturating_sub(1)).sum()
3021 };
3022 extras.legend_extra_width = plans
3029 .values()
3030 .map(|p| p.cols.saturating_sub(1) as f64 * p.col_pitch)
3031 .fold(0.0_f64, f64::max);
3032
3033 if !is_horizontal {
3045 let final_layout = PlotLayout::compute_with_extras(
3046 w as f64,
3047 h as f64,
3048 &built.theme,
3049 has_title,
3050 has_subtitle,
3051 has_caption,
3052 has_legend,
3053 x_axis_top,
3054 y_label_width,
3055 x_label_height,
3056 extras,
3057 );
3058 let (legend_x_final, _, _) = crate::guide::legend::legend_position(
3064 &built.theme,
3065 &final_layout.plot_area,
3066 extras.legend_extra_rows,
3067 (0.0, 0.0),
3068 &final_layout.total,
3069 );
3070 let swatch_and_gap =
3071 built.theme.legend_key_width + built.theme.legend_spacing;
3072 let text_size = built.theme.legend_text.size;
3073 fn right_edge_of(
3079 legend_x: f64,
3080 swatch_and_gap: f64,
3081 text_size: f64,
3082 plan: &crate::guide::legend::LegendPlan,
3083 breaks: &[(f64, String)],
3084 ) -> f64 {
3085 plan.entries
3086 .iter()
3087 .filter_map(|e| breaks.get(e.break_idx).map(|(_, l)| (e, l)))
3088 .map(|(e, label)| {
3089 let text =
3090 e.label_override.as_deref().unwrap_or(label.as_str());
3091 legend_x
3092 + e.x_offset
3093 + swatch_and_gap
3094 + crate::render::text::text_width(text, text_size)
3095 })
3096 .fold(0.0_f64, f64::max)
3097 }
3098
3099 let mut updates: Vec<(
3100 crate::aes::Aesthetic,
3101 crate::guide::legend::LegendPlan,
3102 )> = Vec::new();
3103 let mut reduced_aes: Vec<crate::aes::Aesthetic> = Vec::new();
3110 for (aes, plan) in &plans {
3111 if plan.cols <= 1 {
3112 continue;
3113 }
3114 let Some(scale) = built.scales.get(aes) else {
3115 continue;
3116 };
3117 let breaks = scale.breaks();
3118 if right_edge_of(
3119 legend_x_final,
3120 swatch_and_gap,
3121 text_size,
3122 plan,
3123 &breaks,
3124 ) <= w as f64
3125 {
3126 continue; }
3128
3129 let n = breaks.len();
3132 let mut reduced: Vec<crate::guide::legend::LegendPlan> = Vec::new();
3133 for c in (1..plan.cols).rev() {
3134 let mut candidate_guide = built.guide_legend.clone();
3135 candidate_guide.ncol = Some(c);
3136 candidate_guide.nrow = None;
3137 let mut tmp_warnings = Vec::new();
3138 let candidate_guide =
3139 candidate_guide.validated(n, &mut tmp_warnings);
3140 if let Some(cand) = crate::guide::legend::plan_legend(
3141 &breaks,
3142 &candidate_guide,
3143 &built.theme,
3144 avail_width,
3145 layout0.plot_area.height,
3146 false,
3147 ) {
3148 reduced.push(cand);
3149 }
3150 }
3151 if let Some(fits) = reduced.iter().find(|c| {
3152 right_edge_of(legend_x_final, swatch_and_gap, text_size, c, &breaks)
3153 <= w as f64
3154 }) {
3155 extras.legend_extra_rows =
3156 extras.legend_extra_rows.max(fits.rows.saturating_sub(1));
3157 updates.push((aes.clone(), fits.clone()));
3158 reduced_aes.push(aes.clone());
3159 continue;
3160 }
3161
3162 let base = reduced.last().cloned().unwrap_or_else(|| plan.clone());
3167 extras.legend_extra_rows =
3168 extras.legend_extra_rows.max(base.rows.saturating_sub(1));
3169 let mut truncated = base.clone();
3170 for e in &mut truncated.entries {
3171 let Some((_, label)) = breaks.get(e.break_idx) else {
3172 continue;
3173 };
3174 let avail = (w as f64
3175 - (legend_x_final + e.x_offset + swatch_and_gap))
3176 .max(0.0);
3177 if let Some(short) =
3178 crate::render::text::truncate_to_width(label, avail, text_size)
3179 {
3180 e.label_override = Some(short);
3181 }
3182 }
3183
3184 let truncated_edge = right_edge_of(
3188 legend_x_final,
3189 swatch_and_gap,
3190 text_size,
3191 &truncated,
3192 &breaks,
3193 );
3194 if truncated_edge > w as f64 {
3195 built.warnings.push(format!(
3196 "legend: the {}-column grid still doesn't fit the {w}px chart (needs about {} px)",
3197 truncated.cols,
3198 truncated_edge.ceil() as i64
3199 ));
3200 }
3201 updates.push((aes.clone(), truncated));
3202 }
3203 for (aes, new_plan) in &updates {
3204 plans.insert(aes.clone(), new_plan.clone());
3205 }
3206
3207 if !reduced_aes.is_empty() {
3248 let original_reserve = extras.legend_extra_width;
3249 let tighter_reserve = plans
3250 .values()
3251 .map(|p| p.cols.saturating_sub(1) as f64 * p.col_pitch)
3252 .fold(0.0_f64, f64::max);
3253 if tighter_reserve < original_reserve {
3254 let mut retry_extras = extras;
3255 retry_extras.legend_extra_width = tighter_reserve;
3256 let retry_layout = PlotLayout::compute_with_extras(
3257 w as f64,
3258 h as f64,
3259 &built.theme,
3260 has_title,
3261 has_subtitle,
3262 has_caption,
3263 has_legend,
3264 x_axis_top,
3265 y_label_width,
3266 x_label_height,
3267 retry_extras,
3268 );
3269 let (retry_x, _, _) = crate::guide::legend::legend_position(
3275 &built.theme,
3276 &retry_layout.plot_area,
3277 retry_extras.legend_extra_rows,
3278 (0.0, 0.0),
3279 &retry_layout.total,
3280 );
3281 let all_still_fit = plans.iter().all(|(aes, plan)| {
3282 let Some(scale) = built.scales.get(aes) else {
3283 return true;
3284 };
3285 let breaks = scale.breaks();
3286 right_edge_of(retry_x, swatch_and_gap, text_size, plan, &breaks)
3287 <= w as f64
3288 });
3289 if all_still_fit {
3290 extras.legend_extra_width = tighter_reserve;
3291 }
3292 }
3293 }
3294 }
3295 for (aes, plan) in &plans {
3296 if let Some(ov) = &plan.overflow {
3297 let n = built
3298 .scales
3299 .get(aes)
3300 .map(|s| s.breaks().len())
3301 .unwrap_or(ov.dropped);
3302 let shown = n.saturating_sub(ov.dropped);
3303 built.warnings.push(format!(
3304 "legend: {} of {n} entries don't fit the chart; the legend shows {shown} and \"+{} more\"",
3305 ov.dropped, ov.dropped
3306 ));
3307 }
3308 }
3309 }
3310 built.legend_plans = plans;
3316 }
3317 }
3318
3319 PlotLayout::compute_with_extras(
3320 w as f64,
3321 h as f64,
3322 &built.theme,
3323 has_title,
3324 has_subtitle,
3325 has_caption,
3326 has_legend,
3327 x_axis_top,
3328 y_label_width,
3329 x_label_height,
3330 extras,
3331 )
3332 }
3333
3334 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
3337 fn render_into<DB>(
3338 area: plotters::drawing::DrawingArea<DB, plotters::coord::Shift>,
3339 built: &crate::build::BuiltPlot,
3340 layout: &PlotLayout,
3341 ) -> Result<(), GGError>
3342 where
3343 DB: plotters::prelude::DrawingBackend,
3344 DB::ErrorType: 'static,
3345 {
3346 area.fill(&plotters::prelude::WHITE)
3347 .map_err(|e| GGError::Render(RenderError::BackendError(format!("{:?}", e))))?;
3348 let mut adapter = PlottersAdapter::new(&area, layout.plot_area.clone());
3349 PlotRenderer::render(built, &mut adapter).map_err(GGError::Render)?;
3350 area.present()
3351 .map_err(|e| GGError::Render(RenderError::BackendError(format!("{:?}", e))))?;
3352 Ok(())
3353 }
3354
3355 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
3358 pub fn ggsave(
3359 self,
3360 path: &str,
3361 width_inches: f64,
3362 height_inches: f64,
3363 dpi: f64,
3364 ) -> Result<(), GGError> {
3365 let w = (width_inches * dpi) as u32;
3366 let h = (height_inches * dpi) as u32;
3367 self.save_with_size(path, w, h)
3368 }
3369
3370 fn has_legend_mapping(&self) -> bool {
3385 use crate::guide::legend::is_legend_aesthetic;
3390 let plot_level = self
3391 .mapping
3392 .mappings
3393 .iter()
3394 .any(|m| is_legend_aesthetic(&m.aesthetic));
3395 plot_level
3396 || self.layers.iter().any(|layer| {
3397 if layer.show_legend == Some(false) {
3398 return false;
3399 }
3400 let effective = if layer.geom.inherit_aes() {
3401 self.mapping.merge(&layer.mapping)
3402 } else {
3403 layer.mapping.clone()
3404 };
3405 effective
3406 .mappings
3407 .iter()
3408 .any(|m| is_legend_aesthetic(&m.aesthetic))
3409 })
3410 }
3411}
3412
3413#[derive(Clone, Copy, Debug)]
3415pub(crate) struct RenderMeta {
3416 pub(crate) has_title: bool,
3417 pub(crate) has_subtitle: bool,
3418 pub(crate) has_caption: bool,
3419 pub(crate) has_legend: bool,
3420}
3421
3422#[derive(Debug)]
3424#[non_exhaustive]
3425pub enum GGError {
3426 Render(RenderError),
3427 UnsupportedFormat(String),
3428 Io(std::io::Error),
3429 ValidationError(String),
3430}
3431
3432impl std::fmt::Display for GGError {
3433 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3434 match self {
3435 GGError::Render(e) => write!(f, "Render error: {e}"),
3436 GGError::UnsupportedFormat(ext) => write!(f, "Unsupported output format: {ext}"),
3437 GGError::Io(e) => write!(f, "IO error: {e}"),
3438 GGError::ValidationError(msg) => write!(f, "Validation error: {msg}"),
3439 }
3440 }
3441}
3442
3443impl std::error::Error for GGError {}