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) legend_bottom_share: Option<f64>,
113 pub(crate) legend_auto: Option<LegendAuto>,
115 pub(crate) default_aspect_ratio: Option<f64>,
118 pub(crate) hide_position_guides: bool,
121 pub(crate) hide_y_guides: bool,
123 pub(crate) locale: Option<crate::locale::Locale>,
125 pub(crate) svg_root_data: bool,
130 pub(crate) root_attrs: Vec<(String, String)>,
133 pub(crate) svg_warnings_attr: bool,
137 pub(crate) svg_formatted_values: bool,
141 pub(crate) layer_svg_attrs: Vec<(usize, String, String)>,
145 pub(crate) svg_title: Option<String>,
150 pub(crate) svg_desc: Option<String>,
155}
156
157impl GGPlot {
158 pub fn new(data: impl GGData) -> Self {
165 GGPlot {
166 data: data.into_dataframe(),
167 mapping: Aes::default(),
168 layers: Vec::new(),
169 scales: Vec::new(),
170 coord: Box::new(CoordCartesian::new()),
171 theme: Theme::default(),
172 labels: Labels::default(),
173 facet: Facet::default(),
174 annotations: Vec::new(),
175 guide_legend: crate::guide::config::GuideLegend::default(),
176 warnings: Vec::new(),
177 legend_bottom_share: None,
178 legend_auto: None,
179 default_aspect_ratio: None,
180 hide_position_guides: false,
181 hide_y_guides: false,
182 locale: None,
183 svg_root_data: true,
184 root_attrs: Vec::new(),
185 svg_warnings_attr: false,
186 svg_formatted_values: false,
187 layer_svg_attrs: Vec::new(),
188 svg_title: None,
189 svg_desc: None,
190 }
191 }
192
193 pub fn aes(mut self, mapping: Aes) -> Self {
195 self.warnings.extend(mapping.warnings.iter().cloned());
196 self.mapping = mapping;
197 self
198 }
199
200 pub fn geom_point(self) -> Self {
203 self.add_geom(GeomPoint::default())
204 }
205
206 pub fn geom_point_with(self, geom: GeomPoint) -> Self {
207 self.add_geom_with(geom)
208 }
209
210 pub fn geom_line(self) -> Self {
211 self.add_geom(GeomLine::default())
212 }
213
214 pub fn geom_line_with(self, geom: GeomLine) -> Self {
215 self.add_geom_with(geom)
216 }
217
218 pub fn geom_bar(self) -> Self {
219 self.add_geom(GeomBar::default())
220 }
221
222 pub fn geom_bar_with(self, geom: GeomBar) -> Self {
223 self.add_geom_with(geom)
224 }
225
226 pub fn geom_histogram(self) -> Self {
227 self.add_geom(GeomHistogram::default())
228 }
229
230 pub fn geom_histogram_with(self, geom: GeomHistogram) -> Self {
231 self.add_geom_with(geom)
232 }
233
234 pub fn geom_boxplot(self) -> Self {
235 self.add_geom(GeomBoxplot::default())
236 }
237
238 pub fn geom_boxplot_with(self, geom: GeomBoxplot) -> Self {
239 self.add_geom_with(geom)
240 }
241
242 pub fn geom_smooth(self) -> Self {
243 self.add_geom(GeomSmooth::default())
244 }
245
246 pub fn geom_smooth_with(self, geom: GeomSmooth) -> Self {
247 self.add_geom_with(geom)
248 }
249
250 pub fn geom_col(self) -> Self {
251 self.add_geom(GeomCol::default())
252 }
253
254 pub fn geom_col_with(self, geom: GeomCol) -> Self {
255 self.add_geom_with(geom)
256 }
257
258 pub fn geom_hline(self, yintercept: f64) -> Self {
262 self.add_refline(
263 GeomHline::new(yintercept),
264 false,
265 &[("yintercept", yintercept)],
266 )
267 }
268
269 pub fn geom_hline_with(self, geom: GeomHline) -> Self {
271 let y = geom.yintercept;
272 self.add_refline(geom, true, &[("yintercept", y)])
273 }
274
275 pub fn geom_hline_aes(self, mapping: Aes) -> Self {
299 self.add_geom(GeomHline::mapped()).layer_aes(mapping)
300 }
301
302 pub fn geom_hline_aes_with(self, geom: GeomHline, mapping: Aes) -> Self {
304 self.add_geom_with(geom).layer_aes(mapping)
305 }
306
307 pub fn geom_vline(self, xintercept: f64) -> Self {
310 self.add_refline(
311 GeomVline::new(xintercept),
312 false,
313 &[("xintercept", xintercept)],
314 )
315 }
316
317 pub fn geom_vline_with(self, geom: GeomVline) -> Self {
319 let x = geom.xintercept;
320 self.add_refline(geom, true, &[("xintercept", x)])
321 }
322
323 pub fn geom_vline_aes(self, mapping: Aes) -> Self {
326 self.add_geom(GeomVline::mapped()).layer_aes(mapping)
327 }
328
329 pub fn geom_vline_aes_with(self, geom: GeomVline, mapping: Aes) -> Self {
331 self.add_geom_with(geom).layer_aes(mapping)
332 }
333
334 pub fn geom_abline(self, slope: f64, intercept: f64) -> Self {
337 self.add_refline(
338 GeomAbline::new(slope, intercept),
339 false,
340 &[("slope", slope), ("intercept", intercept)],
341 )
342 }
343
344 pub fn geom_abline_with(self, geom: GeomAbline) -> Self {
346 let (b, a) = (geom.slope, geom.intercept);
347 self.add_refline(geom, true, &[("slope", b), ("intercept", a)])
348 }
349
350 pub fn geom_abline_aes(self, mapping: Aes) -> Self {
353 self.add_geom(GeomAbline::mapped()).layer_aes(mapping)
354 }
355
356 pub fn geom_abline_aes_with(self, geom: GeomAbline, mapping: Aes) -> Self {
358 self.add_geom_with(geom).layer_aes(mapping)
359 }
360
361 fn add_refline(
364 self,
365 geom: impl Geom + 'static,
366 explicit: bool,
367 values: &[(&str, f64)],
368 ) -> Self {
369 let mut data = DataFrame::new();
370 let mut mapping = Aes::new();
371 for (col, v) in values {
372 data.add_column(col.to_string(), vec![Value::Float(*v)]);
373 mapping = match *col {
374 "xintercept" => mapping.xintercept(col),
375 "yintercept" => mapping.yintercept(col),
376 "slope" => mapping.slope(col),
377 _ => mapping.intercept(col),
378 };
379 }
380 let plot = if explicit {
381 self.add_geom_with(geom)
382 } else {
383 self.add_geom(geom)
384 };
385 plot.layer_aes(mapping).layer_data(data)
386 }
387
388 pub fn geom_text(self) -> Self {
389 self.add_geom(GeomText::default())
390 }
391
392 pub fn geom_text_with(self, geom: GeomText) -> Self {
393 self.add_geom_with(geom)
394 }
395
396 #[cfg(feature = "ggpubr")]
401 pub fn stat_cor(self) -> Self {
402 self.geom_text().stat(crate::stat::cor::StatCor::default())
403 }
404
405 #[cfg(feature = "ggpubr")]
408 pub fn stat_cor_with(self, stat: crate::stat::cor::StatCor) -> Self {
409 self.geom_text().stat(stat)
410 }
411
412 #[cfg(feature = "ggpubr")]
417 pub fn stat_compare_means(self) -> Self {
418 self.geom_text()
419 .stat(crate::stat::compare_means::StatCompareMeans::default())
420 }
421
422 #[cfg(feature = "ggpubr")]
425 pub fn stat_compare_means_with(
426 self,
427 stat: crate::stat::compare_means::StatCompareMeans,
428 ) -> Self {
429 self.geom_text().stat(stat)
430 }
431
432 #[cfg(feature = "ggpubr")]
438 pub fn stat_compare_means_pairwise(self, comparisons: &[(&str, &str)]) -> Self {
439 self.stat_compare_means_pairwise_with(
440 crate::stat::compare_means::CompareMethod::Auto,
441 comparisons,
442 )
443 }
444
445 #[cfg(feature = "ggpubr")]
448 pub fn stat_compare_means_pairwise_with(
449 self,
450 method: crate::stat::compare_means::CompareMethod,
451 comparisons: &[(&str, &str)],
452 ) -> Self {
453 let col_for = |a: crate::aes::Aesthetic| {
455 self.mapping
456 .mappings
457 .iter()
458 .find(|m| m.aesthetic == a)
459 .map(|m| m.column.clone())
460 };
461 let (xcol, ycol) = match (
462 col_for(crate::aes::Aesthetic::X),
463 col_for(crate::aes::Aesthetic::Y),
464 ) {
465 (Some(x), Some(y)) => (x, y),
466 _ => return self,
467 };
468 let (xc, yc) = match (self.data.column(&xcol), self.data.column(&ycol)) {
469 (Some(x), Some(y)) => (x, y),
470 _ => return self,
471 };
472
473 let mut groups: Vec<(String, Vec<f64>)> = Vec::new();
475 let mut ymax = f64::NEG_INFINITY;
476 let mut ymin = f64::INFINITY;
477 for (xv, yv) in xc.iter().zip(yc.iter()) {
478 let y = match yv.as_f64() {
479 Some(y) if y.is_finite() => y,
480 _ => continue,
481 };
482 ymax = ymax.max(y);
483 ymin = ymin.min(y);
484 let key = xv.to_group_key();
485 if let Some(g) = groups.iter_mut().find(|(k, _)| *k == key) {
486 g.1.push(y);
487 } else {
488 groups.push((key, vec![y]));
489 }
490 }
491 if groups.len() < 2 {
492 return self;
493 }
494 let step = if ymax > ymin {
495 (ymax - ymin) * 0.12
496 } else {
497 1.0
498 };
499
500 let (mut xmin_v, mut xmax_v, mut y_v, mut label_v) =
502 (Vec::new(), Vec::new(), Vec::new(), Vec::new());
503 let mut placed = 0usize;
504 for (a, b) in comparisons {
505 let ga = groups.iter().find(|(k, _)| k == a).map(|g| &g.1);
506 let gb = groups.iter().find(|(k, _)| k == b).map(|g| &g.1);
507 let (ga, gb) = match (ga, gb) {
508 (Some(x), Some(y)) if x.len() >= 2 && y.len() >= 2 => (x, y),
509 _ => continue,
510 };
511 let p = match crate::stat::compare_means::pairwise_p(method, ga, gb) {
512 Some(p) => p,
513 None => continue,
514 };
515 xmin_v.push(Value::Str((*a).to_string()));
516 xmax_v.push(Value::Str((*b).to_string()));
517 y_v.push(Value::Float(ymax + step * (placed as f64 + 1.0)));
518 label_v.push(Value::Str(crate::stat::cor::format_p_value(p)));
519 placed += 1;
520 }
521 if xmin_v.is_empty() {
522 return self;
523 }
524
525 let data = vec![
526 ("xmin".to_string(), xmin_v),
527 ("xmax".to_string(), xmax_v),
528 ("y".to_string(), y_v),
529 ("label".to_string(), label_v),
530 ];
531 self.add_geom(crate::geom::bracket::GeomBracket::default())
532 .layer_data(data)
533 .layer_aes(Aes::new().xmin("xmin").xmax("xmax").y("y").label("label"))
534 }
535
536 pub fn geom_bracket(self, xmin: &str, xmax: &str, y: f64, label: &str) -> Self {
541 self.geom_bracket_many(
542 crate::geom::bracket::GeomBracket::default(),
543 &[(xmin, xmax, y, label)],
544 )
545 }
546
547 pub fn geom_bracket_many(
551 self,
552 geom: crate::geom::bracket::GeomBracket,
553 brackets: &[(&str, &str, f64, &str)],
554 ) -> Self {
555 let xmin = brackets
556 .iter()
557 .map(|b| Value::Str(b.0.to_string()))
558 .collect::<Vec<_>>();
559 let xmax = brackets
560 .iter()
561 .map(|b| Value::Str(b.1.to_string()))
562 .collect::<Vec<_>>();
563 let y = brackets
564 .iter()
565 .map(|b| Value::Float(b.2))
566 .collect::<Vec<_>>();
567 let label = brackets
568 .iter()
569 .map(|b| Value::Str(b.3.to_string()))
570 .collect::<Vec<_>>();
571 let data = vec![
572 ("xmin".to_string(), xmin),
573 ("xmax".to_string(), xmax),
574 ("y".to_string(), y),
575 ("label".to_string(), label),
576 ];
577 self.add_geom(geom)
578 .layer_data(data)
579 .layer_aes(Aes::new().xmin("xmin").xmax("xmax").y("y").label("label"))
580 }
581
582 pub fn geom_bracket_table(
591 mut self,
592 table: impl GGData,
593 spec: crate::geom::bracket::BracketTable,
594 ) -> Self {
595 let table = table.into_dataframe();
596 let col_for = |a: crate::aes::Aesthetic| {
597 self.mapping
598 .mappings
599 .iter()
600 .find(|m| m.aesthetic == a)
601 .map(|m| m.column.clone())
602 };
603 let x_levels: Vec<String> = col_for(crate::aes::Aesthetic::X)
606 .and_then(|c| self.data.column(&c))
607 .filter(|col| col.iter().any(|v| matches!(v, Value::Str(_))))
608 .map(|col| {
609 let mut seen = std::collections::HashSet::new();
610 col.iter()
611 .filter(|v| !v.is_na())
612 .map(|v| v.to_group_key())
613 .filter(|k| seen.insert(k.clone()))
614 .collect()
615 })
616 .unwrap_or_default();
617 let y_range = col_for(crate::aes::Aesthetic::Y)
618 .and_then(|c| self.data.column(&c))
619 .and_then(|col| {
620 let (lo, hi) = col
621 .iter()
622 .filter_map(|v| v.as_f64())
623 .filter(|v| v.is_finite())
624 .fold((f64::INFINITY, f64::NEG_INFINITY), |(lo, hi), v| {
625 (lo.min(v), hi.max(v))
626 });
627 (lo <= hi).then_some((lo, hi))
628 });
629 let mut warnings = Vec::new();
630 let resolved = spec.resolve(&table, &x_levels, y_range, &mut warnings);
631 self.warnings.extend(warnings);
632 match resolved {
633 Some(data) => self
634 .add_geom(crate::geom::bracket::GeomBracket::from(spec.geom))
635 .layer_data(data)
636 .layer_aes(Aes::new().xmin("xmin").xmax("xmax").y("y").label("label")),
637 None => self,
638 }
639 }
640
641 pub fn geom_text_repel(self) -> Self {
646 self.add_geom(crate::geom::repel::GeomTextRepel::default())
647 }
648
649 pub fn geom_text_repel_with(self, geom: crate::geom::repel::GeomTextRepel) -> Self {
652 self.add_geom_with(geom)
653 }
654
655 pub fn geom_label_repel(self) -> Self {
658 self.add_geom(crate::geom::repel::GeomLabelRepel::default())
659 }
660
661 pub fn geom_label_repel_with(self, geom: crate::geom::repel::GeomLabelRepel) -> Self {
663 self.add_geom_with(geom)
664 }
665
666 pub fn geom_label(self) -> Self {
667 self.add_geom(GeomLabel::default())
668 }
669
670 pub fn geom_label_with(self, geom: GeomLabel) -> Self {
671 self.add_geom_with(geom)
672 }
673
674 pub fn geom_area(self) -> Self {
675 self.add_geom(GeomArea::default())
676 }
677
678 pub fn geom_area_with(self, geom: GeomArea) -> Self {
679 self.add_geom_with(geom)
680 }
681
682 pub fn geom_ribbon(self) -> Self {
683 self.add_geom(GeomRibbon::default())
684 }
685
686 pub fn geom_ribbon_with(self, geom: GeomRibbon) -> Self {
687 self.add_geom_with(geom)
688 }
689
690 pub fn geom_errorbar(self) -> Self {
691 self.add_geom(GeomErrorbar::default())
692 }
693
694 pub fn geom_errorbar_with(self, geom: GeomErrorbar) -> Self {
695 self.add_geom_with(geom)
696 }
697
698 pub fn geom_segment(self) -> Self {
699 self.add_geom(GeomSegment::default())
700 }
701
702 pub fn geom_segment_with(self, geom: GeomSegment) -> Self {
703 self.add_geom_with(geom)
704 }
705
706 pub fn geom_density(self) -> Self {
707 self.add_geom(GeomDensity::default())
708 }
709
710 pub fn geom_density_with(self, geom: GeomDensity) -> Self {
711 self.add_geom_with(geom)
712 }
713
714 pub fn geom_rug(self) -> Self {
715 self.add_geom(GeomRug::default())
716 }
717
718 pub fn geom_rug_with(self, geom: GeomRug) -> Self {
719 self.add_geom_with(geom)
720 }
721
722 pub fn geom_jitter(self) -> Self {
723 self.add_geom(GeomJitter::default())
724 }
725
726 pub fn geom_jitter_with(self, geom: GeomJitter) -> Self {
727 self.add_geom_with(geom)
728 }
729
730 pub fn geom_path(self) -> Self {
731 self.add_geom(GeomPath::default())
732 }
733
734 pub fn geom_path_with(self, geom: GeomPath) -> Self {
735 self.add_geom_with(geom)
736 }
737
738 pub fn stat_ellipse(self) -> Self {
740 self.geom_path()
741 .stat(crate::stat::ellipse::StatEllipse::default())
742 }
743
744 pub fn stat_ellipse_level(self, level: f64) -> Self {
746 self.geom_path()
747 .stat(crate::stat::ellipse::StatEllipse::new(level))
748 }
749
750 #[cfg(feature = "regression")]
753 pub fn stat_quantile(mut self, taus: &[f64]) -> Self {
754 for &tau in taus {
755 self = self
756 .geom_path()
757 .stat(crate::stat::quantile::StatQuantile::new(tau));
758 }
759 self
760 }
761
762 #[cfg(feature = "regression")]
764 pub fn geom_quantile(self) -> Self {
765 self.stat_quantile(&[0.25, 0.5, 0.75])
766 }
767
768 pub fn geom_step(self) -> Self {
769 self.add_geom(GeomStep::default())
770 }
771
772 pub fn geom_step_with(self, geom: GeomStep) -> Self {
773 self.add_geom_with(geom)
774 }
775
776 pub fn geom_freqpoly(self) -> Self {
777 self.add_geom(GeomFreqpoly::default())
778 }
779
780 pub fn geom_freqpoly_with(self, geom: GeomFreqpoly) -> Self {
781 self.add_geom_with(geom)
782 }
783
784 pub fn geom_linerange(self) -> Self {
785 self.add_geom(GeomLinerange::default())
786 }
787
788 pub fn geom_linerange_with(self, geom: GeomLinerange) -> Self {
789 self.add_geom_with(geom)
790 }
791
792 pub fn geom_pointrange(self) -> Self {
793 self.add_geom(GeomPointrange::default())
794 }
795
796 pub fn geom_pointrange_with(self, geom: GeomPointrange) -> Self {
797 self.add_geom_with(geom)
798 }
799
800 pub fn geom_crossbar(self) -> Self {
801 self.add_geom(GeomCrossbar::default())
802 }
803
804 pub fn geom_crossbar_with(self, geom: GeomCrossbar) -> Self {
805 self.add_geom_with(geom)
806 }
807
808 pub fn geom_spoke(self) -> Self {
809 self.add_geom(GeomSpoke::default())
810 }
811
812 pub fn geom_spoke_with(self, geom: GeomSpoke) -> Self {
813 self.add_geom_with(geom)
814 }
815
816 pub fn geom_rect(self) -> Self {
817 self.add_geom(GeomRect::default())
818 }
819
820 pub fn geom_rect_with(self, geom: GeomRect) -> Self {
821 self.add_geom_with(geom)
822 }
823
824 pub fn geom_tile(self) -> Self {
825 self.add_geom(GeomTile::default())
826 }
827
828 pub fn geom_tile_with(self, geom: GeomTile) -> Self {
829 self.add_geom_with(geom)
830 }
831
832 pub fn geom_raster(self) -> Self {
834 self.add_geom(crate::geom::raster::GeomRaster::default())
835 }
836
837 pub fn geom_raster_with(self, geom: crate::geom::raster::GeomRaster) -> Self {
838 self.add_geom_with(geom)
839 }
840
841 pub fn geom_polygon(self) -> Self {
842 self.add_geom(GeomPolygon::default())
843 }
844
845 pub fn geom_polygon_with(self, geom: GeomPolygon) -> Self {
846 self.add_geom_with(geom)
847 }
848
849 #[cfg(feature = "sf")]
851 pub fn geom_sf(self) -> Self {
852 self.add_geom(crate::geom::sf::GeomSf::default())
853 }
854
855 #[cfg(feature = "sf")]
856 pub fn geom_sf_with(self, geom: crate::geom::sf::GeomSf) -> Self {
857 self.add_geom_with(geom)
858 }
859
860 #[cfg(feature = "sf")]
863 pub fn geom_sf_text(self) -> Self {
864 self.add_geom(crate::geom::sf_text::GeomSfText::default())
865 }
866
867 #[cfg(feature = "sf")]
868 pub fn geom_sf_text_with(self, geom: crate::geom::sf_text::GeomSfText) -> Self {
869 self.add_geom_with(geom)
870 }
871
872 #[cfg(feature = "sf")]
875 pub fn geom_sf_label(self) -> Self {
876 self.add_geom(crate::geom::sf_text::GeomSfLabel::default())
877 }
878
879 #[cfg(feature = "sf")]
880 pub fn geom_sf_label_with(self, geom: crate::geom::sf_text::GeomSfLabel) -> Self {
881 self.add_geom_with(geom)
882 }
883
884 #[cfg(feature = "sf")]
888 pub fn annotation_scale(self) -> Self {
889 self.add_geom(crate::geom::annotation_scale::GeomAnnotationScale::default())
890 }
891
892 #[cfg(feature = "sf")]
893 pub fn annotation_scale_with(
894 self,
895 geom: crate::geom::annotation_scale::GeomAnnotationScale,
896 ) -> Self {
897 self.add_geom_with(geom)
898 }
899
900 #[cfg(feature = "sf")]
903 pub fn annotation_north_arrow_with(
904 self,
905 geom: crate::geom::annotation_scale::GeomNorthArrow,
906 ) -> Self {
907 self.add_geom_with(geom)
908 }
909
910 #[cfg(feature = "sf")]
913 pub fn annotation_attribution(self, text: impl Into<String>) -> Self {
914 self.add_geom(crate::geom::annotation_scale::GeomAttribution::new(text))
915 }
916
917 #[cfg(feature = "tiles")]
925 pub fn annotation_map_tile(
926 self,
927 source: crate::geom::map_tile::TileSource,
928 fetcher: impl crate::geom::map_tile::TileFetcher + 'static,
929 ) -> Self {
930 self.annotation_map_tile_with(crate::geom::map_tile::GeomMapTile::new(source, fetcher))
931 }
932
933 #[cfg(feature = "tiles")]
936 pub fn annotation_map_tile_with(self, geom: crate::geom::map_tile::GeomMapTile) -> Self {
937 let attribution = geom.source.attribution.clone();
938 let mut plot = self.add_geom_with(geom);
939 if let Some(layer) = plot.layers.pop() {
941 plot.layers.insert(0, layer);
942 for (idx, ..) in plot.layer_svg_attrs.iter_mut() {
943 *idx += 1;
944 }
945 }
946 if attribution.is_empty() {
947 plot
948 } else {
949 plot.annotation_attribution(attribution)
950 }
951 }
952
953 #[cfg(feature = "sf")]
954 pub fn annotation_attribution_with(
955 self,
956 geom: crate::geom::annotation_scale::GeomAttribution,
957 ) -> Self {
958 self.add_geom_with(geom)
959 }
960
961 #[cfg(feature = "sf")]
969 pub fn bivariate_legend(
970 self,
971 geom: crate::geom::bivariate_legend::GeomBivariateLegend,
972 ) -> Self {
973 self.add_geom(geom)
974 }
975
976 #[cfg(feature = "sf")]
981 pub fn bivariate_legend_counts(
982 self,
983 geom: crate::geom::bivariate_legend::GeomBivariateLegendCounts,
984 ) -> Self {
985 self.add_geom(geom)
986 }
987
988 pub fn geom_curve(self) -> Self {
989 self.add_geom(GeomCurve::default())
990 }
991
992 pub fn geom_curve_with(self, geom: GeomCurve) -> Self {
993 self.add_geom_with(geom)
994 }
995
996 pub fn geom_violin(self) -> Self {
997 self.add_geom(GeomViolin::default())
998 }
999
1000 pub fn geom_violin_with(self, geom: GeomViolin) -> Self {
1001 self.add_geom_with(geom)
1002 }
1003
1004 pub fn geom_dotplot(self) -> Self {
1005 self.add_geom(GeomDotplot::default())
1006 }
1007
1008 pub fn geom_dotplot_with(self, geom: GeomDotplot) -> Self {
1009 self.add_geom_with(geom)
1010 }
1011
1012 pub fn geom_qq(self) -> Self {
1013 self.add_geom(GeomQQ::default())
1014 }
1015
1016 pub fn geom_qq_with(self, geom: GeomQQ) -> Self {
1017 self.add_geom_with(geom)
1018 }
1019
1020 pub fn geom_qq_line(self) -> Self {
1021 self.add_geom(GeomQQLine::default())
1022 }
1023
1024 pub fn geom_qq_line_with(self, geom: GeomQQLine) -> Self {
1025 self.add_geom_with(geom)
1026 }
1027
1028 pub fn geom_bin2d(self) -> Self {
1029 self.add_geom(GeomBin2d::default())
1030 }
1031
1032 pub fn geom_bin2d_with(self, geom: GeomBin2d) -> Self {
1033 self.add_geom_with(geom)
1034 }
1035
1036 pub fn geom_hex(self) -> Self {
1037 self.add_geom(GeomHex::default())
1038 }
1039
1040 pub fn geom_hex_with(self, geom: GeomHex) -> Self {
1041 self.add_geom_with(geom)
1042 }
1043
1044 pub fn geom_count(self) -> Self {
1045 self.add_geom(GeomCount::default())
1046 }
1047
1048 pub fn geom_count_with(self, geom: GeomCount) -> Self {
1049 self.add_geom_with(geom)
1050 }
1051
1052 pub fn geom_contour(self) -> Self {
1053 self.add_geom(GeomContour::default())
1054 }
1055
1056 pub fn geom_contour_with(self, geom: GeomContour) -> Self {
1057 self.add_geom_with(geom)
1058 }
1059
1060 pub fn geom_contour_filled(self) -> Self {
1063 self.add_geom(GeomPolygon {
1064 line_width: 0.0,
1065 alpha: 1.0,
1066 ..GeomPolygon::default()
1067 })
1068 .stat(crate::stat::contour_filled::StatContourFilled::default())
1069 }
1070
1071 pub fn geom_density2d(self) -> Self {
1072 self.add_geom(GeomDensity2d::default())
1073 }
1074
1075 pub fn geom_density2d_with(self, geom: GeomDensity2d) -> Self {
1076 self.add_geom_with(geom)
1077 }
1078
1079 pub fn geom_waterfall(self) -> Self {
1085 self.default_styled(|p| {
1086 p.geom_waterfall_with(crate::geom::waterfall::GeomWaterfall::default())
1087 })
1088 }
1089
1090 pub fn geom_waterfall_with(self, geom: crate::geom::waterfall::GeomWaterfall) -> Self {
1097 use crate::scale::color::RGBAColor;
1098 use crate::stat::waterfall::{WATERFALL_DECREASE, WATERFALL_INCREASE, WATERFALL_TOTAL};
1099 let rgba = |(r, g, b): (u8, u8, u8)| RGBAColor::new(r, g, b);
1100 let mut values = vec![
1101 (WATERFALL_INCREASE, rgba(geom.up)),
1102 (WATERFALL_DECREASE, rgba(geom.down)),
1103 ];
1104 if geom.has_totals() {
1105 values.push((WATERFALL_TOTAL, rgba(geom.total)));
1106 }
1107 let fill_mapped = self
1108 .mapping
1109 .get_mapping(&crate::aes::Aesthetic::Fill)
1110 .is_some();
1111 let has_fill_scale = self
1112 .scales
1113 .iter()
1114 .any(|s| s.aesthetic() == crate::aes::Aesthetic::Fill);
1115 let mut plot = self.add_geom_with(geom);
1116 if !fill_mapped {
1117 plot = plot.layer_aes(Aes::new().after_stat_fill("direction"));
1118 if !has_fill_scale {
1119 plot = plot.scale_fill_manual(values);
1120 }
1121 }
1122 plot
1123 }
1124
1125 pub fn geom_pareto(self) -> Self {
1129 self.add_pareto(crate::geom::pareto::GeomPareto::default(), false)
1130 }
1131
1132 pub fn geom_pareto_with(self, geom: crate::geom::pareto::GeomPareto) -> Self {
1138 self.add_pareto(geom, true)
1139 }
1140
1141 fn add_pareto(self, geom: crate::geom::pareto::GeomPareto, explicit: bool) -> Self {
1142 let has_y_scale = self
1143 .scales
1144 .iter()
1145 .any(|s| s.aesthetic() == crate::aes::Aesthetic::Y);
1146 let plot = if explicit {
1147 self.add_geom_with(geom)
1148 } else {
1149 self.add_geom(geom)
1150 };
1151 if has_y_scale {
1152 plot
1153 } else {
1154 plot.scale_y_continuous(ScaleContinuous::new().with_sec_axis(
1155 crate::scale::sec_axis::SecAxis::percent_of_max().with_name("Cumulative %"),
1156 ))
1157 }
1158 }
1159
1160 pub fn geom_sankey(self) -> Self {
1167 self.add_sankey(crate::geom::sankey::GeomSankey::default(), false)
1168 }
1169
1170 pub fn geom_sankey_with(self, geom: crate::geom::sankey::GeomSankey) -> Self {
1172 self.add_sankey(geom, true)
1173 }
1174
1175 fn add_sankey(self, geom: crate::geom::sankey::GeomSankey, explicit: bool) -> Self {
1176 let mut plot = if explicit {
1177 self.add_geom_with(geom)
1178 } else {
1179 self.add_geom(geom)
1180 };
1181 plot.hide_position_guides = true;
1182 plot.layer_aes(Aes::new().after_stat_fill("node"))
1183 .show_legend(false)
1184 }
1185
1186 pub fn geom_chord(self) -> Self {
1193 self.add_chord(crate::geom::chord::GeomChord::default(), false)
1194 }
1195
1196 pub fn geom_chord_with(self, geom: crate::geom::chord::GeomChord) -> Self {
1198 self.add_chord(geom, true)
1199 }
1200
1201 fn add_chord(self, geom: crate::geom::chord::GeomChord, explicit: bool) -> Self {
1202 let (ex, ey) = geom.extents();
1203 let mut plot = if explicit {
1204 self.add_geom_with(geom)
1205 } else {
1206 self.add_geom(geom)
1207 };
1208 plot.hide_position_guides = true;
1209 plot.default_aspect_ratio = Some(ey / ex);
1210 plot.layer_aes(Aes::new().after_stat_fill("node"))
1211 .show_legend(false)
1212 }
1213
1214 pub fn geom_arcdiagram(self) -> Self {
1219 self.add_arcdiagram(crate::geom::arcdiagram::GeomArcdiagram::default(), false)
1220 }
1221
1222 pub fn geom_arcdiagram_with(self, geom: crate::geom::arcdiagram::GeomArcdiagram) -> Self {
1225 self.add_arcdiagram(geom, true)
1226 }
1227
1228 fn add_arcdiagram(self, geom: crate::geom::arcdiagram::GeomArcdiagram, explicit: bool) -> Self {
1229 let mut plot = if explicit {
1230 self.add_geom_with(geom)
1231 } else {
1232 self.add_geom(geom)
1233 };
1234 plot.hide_position_guides = true;
1235 plot.layer_aes(Aes::new().after_stat_fill("node"))
1236 .show_legend(false)
1237 }
1238
1239 pub fn geom_treemap(self) -> Self {
1247 self.add_treemap(crate::geom::treemap::GeomTreemap::default(), false)
1248 }
1249
1250 pub fn geom_treemap_with(self, geom: crate::geom::treemap::GeomTreemap) -> Self {
1252 self.add_treemap(geom, true)
1253 }
1254
1255 fn add_treemap(self, geom: crate::geom::treemap::GeomTreemap, explicit: bool) -> Self {
1256 use crate::aes::Aesthetic;
1257 let aspect = geom.aspect;
1258 let has = |plot: &Self, aes: Aesthetic| plot.scales.iter().any(|s| s.aesthetic() == aes);
1259 let (has_x, has_y) = (has(&self, Aesthetic::X), has(&self, Aesthetic::Y));
1260 let fill_by = match (
1261 self.mapping.get_mapping(&Aesthetic::Fill),
1262 self.mapping.get_mapping(&Aesthetic::Subgroup),
1263 ) {
1264 (None, Some(sub)) => Some(sub.to_string()),
1265 _ => None,
1266 };
1267 let mut plot = if explicit {
1268 self.add_geom_with(geom)
1269 } else {
1270 self.add_geom(geom)
1271 };
1272 plot.hide_position_guides = true;
1273 plot.default_aspect_ratio = Some(1.0 / aspect.max(1e-6));
1274 if let Some(sub) = fill_by {
1275 plot = plot.layer_aes(Aes::new().fill(&sub));
1276 }
1277 if !has_x {
1278 plot = plot.scale_x_continuous(ScaleContinuous::new().with_expand(0.0, 0.0));
1279 }
1280 if !has_y {
1281 plot = plot.scale_y_continuous(ScaleContinuous::new().with_expand(0.0, 0.0));
1282 }
1283 plot
1284 }
1285
1286 pub fn geom_sunburst<S: Into<String>>(self, levels: impl IntoIterator<Item = S>) -> Self {
1293 let geom = crate::geom::partition::GeomPartition::sunburst(levels);
1294 let depth = geom.levels.len().max(1) as f64;
1296 let inner = geom.hole / (geom.hole + depth);
1297 let mut plot = self.default_styled(|p| p.geom_partition_with(geom));
1298 plot.coord = Box::new(CoordPolar::new().inner_radius(inner));
1299 plot
1300 }
1301
1302 pub fn geom_icicle<S: Into<String>>(self, levels: impl IntoIterator<Item = S>) -> Self {
1306 self.default_styled(|p| {
1307 p.geom_partition_with(crate::geom::partition::GeomPartition::icicle(levels))
1308 })
1309 }
1310
1311 pub fn geom_partition_with(self, geom: crate::geom::partition::GeomPartition) -> Self {
1315 use crate::aes::Aesthetic;
1316 let has = |plot: &Self, aes: Aesthetic| plot.scales.iter().any(|s| s.aesthetic() == aes);
1317 let (has_x, has_y) = (has(&self, Aesthetic::X), has(&self, Aesthetic::Y));
1318 let fill_mapped = self.mapping.get_mapping(&Aesthetic::Fill).is_some();
1319 let mut plot = self.add_geom_with(geom);
1320 plot.hide_position_guides = true;
1321 if !fill_mapped {
1322 plot = plot
1323 .layer_aes(Aes::new().after_stat_fill("root"))
1324 .show_legend(false);
1325 }
1326 if !has_x {
1327 plot = plot.scale_x_continuous(ScaleContinuous::new().with_expand(0.0, 0.0));
1328 }
1329 if !has_y {
1330 plot = plot.scale_y_continuous(ScaleContinuous::new().with_expand(0.0, 0.0));
1331 }
1332 plot
1333 }
1334
1335 pub fn geom_funnel(self) -> Self {
1343 self.default_styled(|p| p.geom_funnel_with(crate::geom::funnel::GeomFunnel::default()))
1344 }
1345
1346 pub fn geom_pyramid(self) -> Self {
1348 self.default_styled(|p| p.geom_funnel_with(crate::geom::funnel::GeomFunnel::pyramid()))
1349 }
1350
1351 pub fn geom_funnel_with(self, geom: crate::geom::funnel::GeomFunnel) -> Self {
1353 let fill_mapped = self
1354 .mapping
1355 .get_mapping(&crate::aes::Aesthetic::Fill)
1356 .is_some();
1357 let mut plot = self.add_geom_with(geom);
1358 plot.hide_position_guides = true;
1359 if !fill_mapped {
1360 plot = plot
1361 .layer_aes(Aes::new().after_stat_fill("stage"))
1362 .show_legend(false);
1363 }
1364 plot
1365 }
1366
1367 pub fn geom_stream(self) -> Self {
1373 self.geom_area().position(
1374 crate::position::stack::position_stack()
1375 .with_offset(crate::position::stack::StackOffset::Wiggle),
1376 )
1377 }
1378
1379 pub fn geom_lollipop(self) -> Self {
1382 self.add_geom(crate::geom::lollipop::GeomLollipop::default())
1383 }
1384
1385 pub fn geom_lollipop_with(self, geom: crate::geom::lollipop::GeomLollipop) -> Self {
1386 self.add_geom_with(geom)
1387 }
1388
1389 pub fn geom_dumbbell(self) -> Self {
1393 self.add_geom(crate::geom::lollipop::GeomDumbbell::default())
1394 }
1395
1396 pub fn geom_dumbbell_with(self, geom: crate::geom::lollipop::GeomDumbbell) -> Self {
1397 self.add_geom_with(geom)
1398 }
1399
1400 pub fn geom_bullet(self, geom: crate::geom::bullet::GeomBullet) -> Self {
1406 self.add_geom_with(geom).coord_flip()
1407 }
1408
1409 pub fn geom_bullet_vertical(self, geom: crate::geom::bullet::GeomBullet) -> Self {
1411 self.add_geom_with(geom)
1412 }
1413
1414 pub fn geom_waffle(self, rows: usize) -> Self {
1418 self.default_styled(|p| p.geom_waffle_with(crate::geom::waffle::GeomWaffle::waffle(rows)))
1419 }
1420
1421 pub fn geom_parliament(self, rows: usize) -> Self {
1425 self.default_styled(|p| {
1426 p.geom_waffle_with(crate::geom::waffle::GeomWaffle::parliament(rows))
1427 })
1428 }
1429
1430 pub fn geom_waffle_with(self, geom: crate::geom::waffle::GeomWaffle) -> Self {
1432 let mut plot = self.add_geom_with(geom);
1433 plot.hide_position_guides = true;
1434 plot
1435 }
1436
1437 pub fn geom_packed_bubble(self) -> Self {
1442 self.default_styled(|p| {
1443 p.geom_packed_bubble_with(crate::geom::pack::GeomPackedBubble::default())
1444 })
1445 }
1446
1447 pub fn geom_packed_bubble_with(self, geom: crate::geom::pack::GeomPackedBubble) -> Self {
1449 use crate::aes::Aesthetic;
1450 let fill_by = match (
1451 self.mapping.get_mapping(&Aesthetic::Fill),
1452 self.mapping.get_mapping(&Aesthetic::Subgroup),
1453 ) {
1454 (None, Some(sub)) => Some(sub.to_string()),
1455 _ => None,
1456 };
1457 let mut plot = self.add_geom_with(geom);
1458 plot.hide_position_guides = true;
1459 plot.default_aspect_ratio = Some(1.0);
1460 if let Some(sub) = fill_by {
1461 plot = plot.layer_aes(Aes::new().fill(&sub));
1462 }
1463 plot
1464 }
1465
1466 pub fn geom_network(self) -> Self {
1472 self.add_network(crate::geom::network::GeomNetwork::default(), false)
1473 }
1474
1475 pub fn geom_network_with(self, geom: crate::geom::network::GeomNetwork) -> Self {
1477 self.add_network(geom, true)
1478 }
1479
1480 fn add_network(self, geom: crate::geom::network::GeomNetwork, explicit: bool) -> Self {
1481 let by_component = geom.color_components;
1482 let mut plot = if explicit {
1483 self.add_geom_with(geom)
1484 } else {
1485 self.add_geom(geom)
1486 };
1487 plot.hide_position_guides = true;
1488 plot.default_aspect_ratio = Some(1.0);
1489 if by_component {
1490 plot = plot
1491 .layer_aes(Aes::new().after_stat_fill("component"))
1492 .show_legend(false);
1493 }
1494 plot
1495 }
1496
1497 pub fn geom_tree(self) -> Self {
1504 self.default_styled(|p| p.geom_tree_with(crate::geom::tree::GeomTree::default()))
1505 }
1506
1507 pub fn geom_dendrogram(self) -> Self {
1511 self.default_styled(|p| p.geom_tree_with(crate::geom::tree::GeomTree::dendrogram()))
1512 }
1513
1514 pub fn geom_tree_with(self, geom: crate::geom::tree::GeomTree) -> Self {
1516 let radial = geom.orientation == crate::stat::tree::TreeOrientation::Radial;
1517 let mut plot = self.add_geom_with(geom);
1518 plot.hide_position_guides = true;
1519 if radial {
1520 plot.default_aspect_ratio = Some(1.0);
1521 }
1522 plot
1523 }
1524
1525 pub fn geom_venn(self) -> Self {
1531 self.default_styled(|p| p.geom_venn_with(crate::geom::venn::GeomVenn::default()))
1532 }
1533
1534 pub fn geom_venn_with(self, geom: crate::geom::venn::GeomVenn) -> Self {
1536 let mut plot = self.add_geom_with(geom);
1537 plot.hide_position_guides = true;
1538 plot.default_aspect_ratio = Some(1.0);
1539 plot.layer_aes(Aes::new().after_stat_fill("set"))
1540 .show_legend(false)
1541 }
1542
1543 pub fn geom_wordcloud(self) -> Self {
1548 self.default_styled(|p| {
1549 p.geom_wordcloud_with(crate::geom::wordcloud::GeomWordcloud::default())
1550 })
1551 }
1552
1553 pub fn geom_wordcloud_with(self, geom: crate::geom::wordcloud::GeomWordcloud) -> Self {
1556 let mut plot = self.add_geom_with(geom);
1557 plot.hide_position_guides = true;
1558 plot
1559 }
1560
1561 pub fn geom_variwide(self) -> Self {
1566 self.default_styled(|p| {
1567 p.geom_marimekko_with(crate::geom::marimekko::GeomMarimekko::variwide())
1568 })
1569 }
1570
1571 pub fn geom_marimekko(self) -> Self {
1575 self.default_styled(|p| {
1576 p.geom_marimekko_with(crate::geom::marimekko::GeomMarimekko::marimekko())
1577 })
1578 }
1579
1580 pub fn geom_marimekko_with(self, geom: crate::geom::marimekko::GeomMarimekko) -> Self {
1582 use crate::aes::Aesthetic;
1583 let has = |plot: &Self, aes: Aesthetic| plot.scales.iter().any(|s| s.aesthetic() == aes);
1584 let (has_x, has_y) = (has(&self, Aesthetic::X), has(&self, Aesthetic::Y));
1585 let axis = self.mapping.get_mapping(&Aesthetic::X).and_then(|xc| {
1587 let x = self.data.column(xc)?;
1588 let w = self
1589 .mapping
1590 .get_mapping(&Aesthetic::Weight)
1591 .and_then(|wc| self.data.column(wc));
1592 let totals = crate::stat::marimekko::column_totals(x, w);
1593 let widths: Vec<f64> = totals.iter().map(|t| t.1).collect();
1594 let spans = crate::stat::marimekko::column_spans(&widths, geom.gap);
1595 Some((
1596 spans
1597 .iter()
1598 .map(|s| (s.0 + s.1) / 2.0)
1599 .collect::<Vec<f64>>(),
1600 totals.into_iter().map(|t| t.0).collect::<Vec<String>>(),
1601 ))
1602 });
1603 let mosaic = geom.mosaic;
1604 let mut plot = self.add_geom_with(geom);
1605 if !has_x {
1606 let mut sx = ScaleContinuous::new().with_expand(0.0, 0.0);
1607 if let Some((breaks, labels)) = axis {
1608 sx = sx.with_breaks(breaks).with_labels(labels);
1609 }
1610 plot = plot.scale_x_continuous(sx);
1611 }
1612 if mosaic && !has_y {
1613 plot = plot.scale_y_continuous(
1614 ScaleContinuous::new()
1615 .with_expand(0.0, 0.0)
1616 .with_label_formatter(|v| format!("{}%", (v * 100.0).round())),
1617 );
1618 }
1619 plot
1620 }
1621
1622 pub fn geom_timeline(self) -> Self {
1627 let mut plot = self.add_geom(crate::geom::timeline::GeomTimeline::default());
1628 plot.hide_y_guides = true;
1629 plot
1630 }
1631
1632 pub fn geom_timeline_with(self, geom: crate::geom::timeline::GeomTimeline) -> Self {
1634 let mut plot = self.add_geom_with(geom);
1635 plot.hide_y_guides = true;
1636 plot
1637 }
1638
1639 pub fn geom_xrange(self) -> Self {
1646 self.add_xrange(crate::geom::xrange::GeomXrange::default(), false)
1647 }
1648
1649 pub fn geom_xrange_with(self, geom: crate::geom::xrange::GeomXrange) -> Self {
1651 self.add_xrange(geom, true)
1652 }
1653
1654 fn add_xrange(self, geom: crate::geom::xrange::GeomXrange, explicit: bool) -> Self {
1655 use crate::aes::Aesthetic;
1656 let has_y = self.scales.iter().any(|s| s.aesthetic() == Aesthetic::Y);
1657 let levels: Option<Vec<String>> = self
1659 .mapping
1660 .get_mapping(&Aesthetic::Y)
1661 .and_then(|c| self.data.column(c))
1662 .map(|col| {
1663 let mut seen: indexmap::IndexSet<String> = indexmap::IndexSet::new();
1664 for v in col.iter().filter(|v| !v.is_na()) {
1665 seen.insert(v.key_str().into_owned());
1666 }
1667 seen.into_iter().rev().collect()
1668 });
1669 let mut plot = if explicit {
1670 self.add_geom_with(geom)
1671 } else {
1672 self.add_geom(geom)
1673 };
1674 if let (false, Some(levels)) = (has_y, levels) {
1675 let refs: Vec<&str> = levels.iter().map(String::as_str).collect();
1676 plot = plot
1677 .scale_y_discrete(crate::scale::discrete::ScaleDiscrete::new().with_limits(refs));
1678 }
1679 plot
1680 }
1681
1682 pub fn geom_tilemap(self, shape: crate::geom::tilemap::TileShape) -> Self {
1687 self.default_styled(|p| {
1688 p.geom_tilemap_with(crate::geom::tilemap::GeomTilemap {
1689 shape,
1690 ..Default::default()
1691 })
1692 })
1693 }
1694
1695 pub fn geom_tilemap_with(self, geom: crate::geom::tilemap::GeomTilemap) -> Self {
1697 let mut plot = self.add_geom_with(geom);
1698 plot.hide_position_guides = true;
1699 plot
1700 }
1701
1702 pub fn geom_windbarb(self, geom: crate::geom::windbarb::GeomWindbarb) -> Self {
1707 self.add_geom(geom)
1708 }
1709
1710 pub fn geom_variable_pie(self) -> Self {
1714 let mut plot = self.add_geom(crate::geom::variablepie::GeomVariablePie::default());
1715 plot.hide_position_guides = true;
1716 plot.default_aspect_ratio = Some(1.0);
1717 plot
1718 }
1719
1720 pub fn geom_variable_pie_with(self, geom: crate::geom::variablepie::GeomVariablePie) -> Self {
1723 let mut plot = self.add_geom_with(geom);
1724 plot.hide_position_guides = true;
1725 plot.default_aspect_ratio = Some(1.0);
1726 plot
1727 }
1728
1729 pub fn geom_hlc(self) -> Self {
1732 self.add_geom(crate::geom::candlestick::GeomOhlc::hlc())
1733 }
1734
1735 pub fn geom_heikin_ashi(self) -> Self {
1739 self.add_geom(crate::geom::candlestick::GeomCandlestick::default())
1740 .stat(crate::stat::heikin_ashi::StatHeikinAshi)
1741 }
1742
1743 pub fn geom_renko(self, box_size: f64) -> Self {
1747 self.add_geom(crate::geom::renko::GeomRenko::renko(box_size))
1748 .xlab("Brick")
1749 }
1750
1751 pub fn geom_point_figure(self, box_size: f64, reversal: usize) -> Self {
1755 self.add_geom(crate::geom::renko::GeomRenko::point_figure(
1756 box_size, reversal,
1757 ))
1758 .xlab("Column")
1759 }
1760
1761 pub fn geom_flags(self) -> Self {
1766 self.add_geom(crate::geom::flags::GeomFlags::default())
1767 }
1768
1769 pub fn geom_flags_with(self, geom: crate::geom::flags::GeomFlags) -> Self {
1770 self.add_geom_with(geom)
1771 }
1772
1773 #[cfg(feature = "sf")]
1778 pub fn geom_flow(self, geom: crate::geom::flow::GeomFlow) -> Self {
1779 self.add_geom(geom)
1780 }
1781
1782 pub fn geom_candlestick(self) -> Self {
1785 self.add_geom(crate::geom::candlestick::GeomCandlestick::default())
1786 }
1787
1788 pub fn geom_candlestick_with(self, geom: crate::geom::candlestick::GeomCandlestick) -> Self {
1789 self.add_geom_with(geom)
1790 }
1791
1792 pub fn geom_ohlc(self) -> Self {
1795 self.add_geom(crate::geom::candlestick::GeomOhlc::default())
1796 }
1797
1798 pub fn geom_ohlc_with(self, geom: crate::geom::candlestick::GeomOhlc) -> Self {
1799 self.add_geom_with(geom)
1800 }
1801
1802 pub fn geom_calendar(self) -> Self {
1813 self.geom_calendar_with(
1814 GeomTile {
1815 color: (255, 255, 255),
1816 line_width: 1.5,
1817 ..Default::default()
1818 },
1819 false,
1820 )
1821 }
1822
1823 pub fn geom_calendar_with(mut self, tile: GeomTile, monday_first: bool) -> Self {
1826 use crate::stat::calendar::{
1827 day_number, month_boundaries, month_breaks, month_breaks_localized, weekday_labels,
1828 CalendarGrid, StatCalendar, MAX_CALENDAR_YEARS,
1829 };
1830 let grid = self
1831 .mapping
1832 .get_mapping(&crate::aes::Aesthetic::X)
1833 .and_then(|c| self.data.column(c))
1834 .and_then(|col| {
1835 CalendarGrid::from_days(col.iter().filter_map(day_number), monday_first)
1836 });
1837 let Some((grid, clipped)) = grid else {
1838 return self.add_geom_with(tile).stat(StatCalendar {
1840 grid: None,
1841 monday_first,
1842 });
1843 };
1844 if clipped {
1845 self.warnings.push(format!(
1846 "geom_calendar: dates more than {MAX_CALENDAR_YEARS} years before the newest were dropped"
1847 ));
1848 }
1849 let (xb, _) = month_breaks(&grid);
1850 let yb = if monday_first {
1852 vec![6.0, 4.0, 2.0]
1853 } else {
1854 vec![5.0, 3.0, 1.0]
1855 };
1856 let segs = month_boundaries(&grid);
1857 let col = |f: fn(&(f64, f64, f64, f64)) -> f64| -> Vec<Value> {
1858 segs.iter().map(|s| Value::Float(f(s))).collect()
1859 };
1860 let boundaries = vec![
1861 ("x".to_string(), col(|s| s.0)),
1862 ("y".to_string(), col(|s| s.1)),
1863 ("xend".to_string(), col(|s| s.2)),
1864 ("yend".to_string(), col(|s| s.3)),
1865 ];
1866 self.default_aspect_ratio = Some(7.0 / grid.n_weeks().max(1) as f64);
1867 let plot = self
1868 .add_geom_with(tile)
1869 .stat(StatCalendar {
1870 grid: Some(grid),
1871 monday_first,
1872 })
1873 .scale_x_continuous(
1874 ScaleContinuous::new()
1875 .with_breaks(xb)
1876 .with_localized_labels(move |l| month_breaks_localized(&grid, l).1)
1878 .with_expand(0.0, 0.0),
1879 )
1880 .scale_y_continuous(
1881 ScaleContinuous::new()
1882 .with_breaks(yb)
1883 .with_localized_labels(weekday_labels)
1884 .with_expand(0.0, 0.0),
1885 );
1886 if segs.is_empty() {
1887 return plot;
1888 }
1889 plot.add_geom_with(crate::geom::segment::GeomCalendarBorder)
1891 .layer_data(boundaries)
1892 .layer_aes(Aes::new().x("x").y("y").xend("xend").yend("yend"))
1893 .show_legend(false)
1894 }
1895
1896 pub fn geom_blank(self) -> Self {
1897 self.add_geom(GeomBlank)
1898 }
1899
1900 fn default_styled(self, build: impl FnOnce(Self) -> Self) -> Self {
1907 let i = self.layers.len();
1908 let mut plot = build(self);
1909 if let Some(layer) = plot.layers.get_mut(i) {
1910 layer.explicit_style = false;
1911 }
1912 plot
1913 }
1914
1915 fn add_geom_with(self, geom: impl Geom + 'static) -> Self {
1916 let mut plot = self.add_geom(geom);
1917 if let Some(layer) = plot.layers.last_mut() {
1918 layer.explicit_style = true;
1919 }
1920 plot
1921 }
1922
1923 fn add_geom(mut self, geom: impl Geom + 'static) -> Self {
1924 let stat = geom.default_stat();
1925 let position = geom.default_position();
1926 let params = geom.default_params();
1927 self.layers.push(Layer {
1928 data: None,
1929 mapping: Aes::default(),
1930 geom: Box::new(geom),
1931 stat,
1932 position,
1933 params,
1934 show_legend: None,
1935 explicit_style: false,
1936 tooltip_template: None,
1937 });
1938 self
1939 }
1940
1941 pub fn stat(mut self, stat: impl Stat + 'static) -> Self {
1945 if let Some(layer) = self.layers.last_mut() {
1946 layer.stat = Box::new(stat);
1947 }
1948 self
1949 }
1950
1951 pub fn position(mut self, pos: impl Position + 'static) -> Self {
1953 if let Some(layer) = self.layers.last_mut() {
1954 layer.position = Box::new(pos);
1955 }
1956 self
1957 }
1958
1959 pub fn layer_data(mut self, data: impl GGData) -> Self {
1961 if let Some(layer) = self.layers.last_mut() {
1962 layer.data = Some(data.into_dataframe());
1963 }
1964 self
1965 }
1966
1967 pub fn layer_aes(mut self, mapping: Aes) -> Self {
1969 self.warnings.extend(mapping.warnings.iter().cloned());
1970 if let Some(layer) = self.layers.last_mut() {
1971 layer.mapping = mapping;
1972 }
1973 self
1974 }
1975
1976 pub fn tooltip(mut self, template: &str) -> Self {
1987 if let Some(layer) = self.layers.last_mut() {
1988 layer.tooltip_template = Some(template.to_string());
1989 }
1990 self
1991 }
1992
1993 pub fn show_legend(mut self, show: bool) -> Self {
1996 if let Some(layer) = self.layers.last_mut() {
1997 layer.show_legend = Some(show);
1998 }
1999 self
2000 }
2001
2002 pub fn decorative(mut self) -> Self {
2029 if let Some(layer) = self.layers.last_mut() {
2030 let geom = std::mem::replace(&mut layer.geom, Box::new(GeomBlank));
2031 layer.geom = Box::new(crate::geom::decorative::Decorative(geom));
2032 if layer.show_legend.is_none() {
2033 layer.show_legend = Some(false);
2034 }
2035 }
2036 self
2037 }
2038
2039 pub fn layer_svg_attr(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
2073 let (name, value) = (name.into(), value.into());
2074 let Some(idx) = self.layers.len().checked_sub(1) else {
2075 self.warnings.push(format!(
2076 "layer_svg_attr(\"{name}\") called before any layer was added — ignored"
2077 ));
2078 return self;
2079 };
2080 if let Some((n, v)) =
2081 crate::render::svg_backend::validate_layer_svg_attr(&name, &value, &mut self.warnings)
2082 {
2083 self.layer_svg_attrs
2084 .retain(|(i, k, _)| !(*i == idx && *k == n));
2085 self.layer_svg_attrs.push((idx, n, v));
2086 }
2087 self
2088 }
2089
2090 pub fn layer_svg_attrs<N: Into<String>, V: Into<String>>(
2092 self,
2093 attrs: impl IntoIterator<Item = (N, V)>,
2094 ) -> Self {
2095 attrs
2096 .into_iter()
2097 .fold(self, |p, (n, v)| p.layer_svg_attr(n, v))
2098 }
2099
2100 pub fn scale_x_continuous(mut self, s: ScaleContinuous) -> Self {
2103 let s = s.for_aesthetic(crate::aes::Aesthetic::X);
2104 self.scales.push(Box::new(s));
2105 self
2106 }
2107
2108 pub fn scale_y_continuous(mut self, s: ScaleContinuous) -> Self {
2109 let s = s.for_aesthetic(crate::aes::Aesthetic::Y);
2110 self.scales.push(Box::new(s));
2111 self
2112 }
2113
2114 pub fn scale_x_discrete(mut self, s: crate::scale::discrete::ScaleDiscrete) -> Self {
2115 let s = s.for_aesthetic(crate::aes::Aesthetic::X);
2116 self.scales.push(Box::new(s));
2117 self
2118 }
2119
2120 pub fn scale_y_discrete(mut self, s: crate::scale::discrete::ScaleDiscrete) -> Self {
2121 let s = s.for_aesthetic(crate::aes::Aesthetic::Y);
2122 self.scales.push(Box::new(s));
2123 self
2124 }
2125
2126 pub fn scale_color(mut self, s: impl Scale + 'static) -> Self {
2127 self.scales.push(Box::new(s));
2128 self
2129 }
2130
2131 pub fn scale_fill(mut self, s: impl Scale + 'static) -> Self {
2132 self.scales.push(Box::new(s));
2133 self
2134 }
2135
2136 pub fn scale_color_manual(self, values: Vec<(&str, crate::scale::color::RGBAColor)>) -> Self {
2137 let s = crate::scale::manual::ScaleManual::new(crate::aes::Aesthetic::Color, values);
2138 self.scale_color(s)
2139 }
2140
2141 pub fn scale_fill_manual(self, values: Vec<(&str, crate::scale::color::RGBAColor)>) -> Self {
2142 let s = crate::scale::manual::ScaleManual::new(crate::aes::Aesthetic::Fill, values);
2143 self.scale_fill(s)
2144 }
2145
2146 pub fn scale_colour_identity(self) -> Self {
2149 let s = crate::scale::identity::ScaleColorIdentity::new(crate::aes::Aesthetic::Color);
2150 self.scale_color(s)
2151 }
2152
2153 pub fn scale_color_identity(self) -> Self {
2155 self.scale_colour_identity()
2156 }
2157
2158 pub fn scale_fill_identity(self) -> Self {
2161 let s = crate::scale::identity::ScaleColorIdentity::new(crate::aes::Aesthetic::Fill);
2162 self.scale_fill(s)
2163 }
2164
2165 pub fn scale_color_viridis(self) -> Self {
2166 use crate::scale::color::ScaleColorDiscrete;
2167 use crate::scale::palettes::PaletteName;
2168 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Color)
2169 .with_named_palette(&PaletteName::Viridis);
2170 self.scale_color(s)
2171 }
2172
2173 pub fn scale_color_brewer(self, name: crate::scale::palettes::PaletteName) -> Self {
2174 use crate::scale::color::ScaleColorDiscrete;
2175 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Color).with_named_palette(&name);
2176 self.scale_color(s)
2177 }
2178
2179 pub fn scale_color_gradient(
2180 self,
2181 low: crate::scale::color::RGBAColor,
2182 high: crate::scale::color::RGBAColor,
2183 ) -> Self {
2184 use crate::scale::color::ScaleColorContinuous;
2185 let s = ScaleColorContinuous::new(crate::aes::Aesthetic::Color).with_colors(low, high);
2186 self.scale_color(s)
2187 }
2188
2189 pub fn scale_fill_gradient(
2190 self,
2191 low: crate::scale::color::RGBAColor,
2192 high: crate::scale::color::RGBAColor,
2193 ) -> Self {
2194 use crate::scale::color::ScaleColorContinuous;
2195 let s = ScaleColorContinuous::new(crate::aes::Aesthetic::Fill).with_colors(low, high);
2196 self.scale_fill(s)
2197 }
2198
2199 pub fn scale_color_gradient2(
2200 self,
2201 low: crate::scale::color::RGBAColor,
2202 mid: crate::scale::color::RGBAColor,
2203 high: crate::scale::color::RGBAColor,
2204 ) -> Self {
2205 use crate::scale::gradient::ScaleColorGradient2;
2206 let s = ScaleColorGradient2::new(crate::aes::Aesthetic::Color).with_colors(low, mid, high);
2207 self.scale_color(s)
2208 }
2209
2210 pub fn scale_fill_gradient2(
2211 self,
2212 low: crate::scale::color::RGBAColor,
2213 mid: crate::scale::color::RGBAColor,
2214 high: crate::scale::color::RGBAColor,
2215 ) -> Self {
2216 use crate::scale::gradient::ScaleColorGradient2;
2217 let s = ScaleColorGradient2::new(crate::aes::Aesthetic::Fill).with_colors(low, mid, high);
2218 self.scale_fill(s)
2219 }
2220
2221 pub fn scale_fill_viridis(self) -> Self {
2222 use crate::scale::color::ScaleColorDiscrete;
2223 use crate::scale::palettes::PaletteName;
2224 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill)
2225 .with_named_palette(&PaletteName::Viridis);
2226 self.scale_fill(s)
2227 }
2228
2229 pub fn scale_color_viridis_c(self) -> Self {
2231 use crate::scale::gradient_n::ScaleColorGradientN;
2232 let s = ScaleColorGradientN::viridis(crate::aes::Aesthetic::Color);
2233 self.scale_color(s)
2234 }
2235
2236 pub fn scale_fill_viridis_c(self) -> Self {
2238 use crate::scale::gradient_n::ScaleColorGradientN;
2239 let s = ScaleColorGradientN::viridis(crate::aes::Aesthetic::Fill);
2240 self.scale_fill(s)
2241 }
2242
2243 pub fn scale_color_gradientn(self, stops: Vec<(f64, crate::scale::color::RGBAColor)>) -> Self {
2245 use crate::scale::gradient_n::ScaleColorGradientN;
2246 let s = ScaleColorGradientN::new(crate::aes::Aesthetic::Color, stops);
2247 self.scale_color(s)
2248 }
2249
2250 pub fn scale_fill_gradientn(self, stops: Vec<(f64, crate::scale::color::RGBAColor)>) -> Self {
2252 use crate::scale::gradient_n::ScaleColorGradientN;
2253 let s = ScaleColorGradientN::new(crate::aes::Aesthetic::Fill, stops);
2254 self.scale_fill(s)
2255 }
2256
2257 pub fn scale_color_steps(
2260 self,
2261 low: crate::scale::color::RGBAColor,
2262 high: crate::scale::color::RGBAColor,
2263 n_bins: usize,
2264 ) -> Self {
2265 let s = crate::scale::steps::ScaleColorSteps::two(
2266 crate::aes::Aesthetic::Color,
2267 (low.r, low.g, low.b),
2268 (high.r, high.g, high.b),
2269 n_bins,
2270 );
2271 self.scale_color(s)
2272 }
2273
2274 pub fn scale_color_stepsn(
2276 self,
2277 stops: Vec<crate::scale::color::RGBAColor>,
2278 n_bins: usize,
2279 ) -> Self {
2280 let s = crate::scale::steps::ScaleColorSteps::new(
2281 crate::aes::Aesthetic::Color,
2282 stops.iter().map(|c| (c.r, c.g, c.b)).collect(),
2283 n_bins,
2284 );
2285 self.scale_color(s)
2286 }
2287
2288 pub fn scale_color_fermenter(
2290 self,
2291 name: crate::scale::palettes::PaletteName,
2292 n_bins: usize,
2293 ) -> Self {
2294 let stops = crate::scale::palettes::palette(&name)
2295 .iter()
2296 .map(|c| (c.r, c.g, c.b))
2297 .collect();
2298 let s =
2299 crate::scale::steps::ScaleColorSteps::new(crate::aes::Aesthetic::Color, stops, n_bins);
2300 self.scale_color(s)
2301 }
2302
2303 pub fn scale_fill_steps(
2305 self,
2306 low: crate::scale::color::RGBAColor,
2307 high: crate::scale::color::RGBAColor,
2308 n_bins: usize,
2309 ) -> Self {
2310 let s = crate::scale::steps::ScaleColorSteps::two(
2311 crate::aes::Aesthetic::Fill,
2312 (low.r, low.g, low.b),
2313 (high.r, high.g, high.b),
2314 n_bins,
2315 );
2316 self.scale_fill(s)
2317 }
2318
2319 pub fn scale_fill_binned(
2330 self,
2331 breaks: Vec<f64>,
2332 low: crate::scale::color::RGBAColor,
2333 high: crate::scale::color::RGBAColor,
2334 ) -> Self {
2335 let s = crate::scale::binned::ScaleFillBinned::two(
2336 crate::aes::Aesthetic::Fill,
2337 breaks,
2338 (low.r, low.g, low.b),
2339 (high.r, high.g, high.b),
2340 );
2341 self.scale_fill(s)
2342 }
2343
2344 pub fn scale_fill_binned_with(
2348 self,
2349 breaks: Vec<f64>,
2350 colors: Vec<crate::scale::color::RGBAColor>,
2351 ) -> Self {
2352 let s = crate::scale::binned::ScaleFillBinned::new(
2353 crate::aes::Aesthetic::Fill,
2354 breaks,
2355 colors.iter().map(|c| (c.r, c.g, c.b)).collect(),
2356 );
2357 self.scale_fill(s)
2358 }
2359
2360 pub fn scale_fill_fermenter(
2362 self,
2363 name: crate::scale::palettes::PaletteName,
2364 n_bins: usize,
2365 ) -> Self {
2366 let stops = crate::scale::palettes::palette(&name)
2367 .iter()
2368 .map(|c| (c.r, c.g, c.b))
2369 .collect();
2370 let s =
2371 crate::scale::steps::ScaleColorSteps::new(crate::aes::Aesthetic::Fill, stops, n_bins);
2372 self.scale_fill(s)
2373 }
2374
2375 pub fn scale_fill_discrete_sorted(self) -> Self {
2380 use crate::scale::color::ScaleColorDiscrete;
2381 self.scale_fill(ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill).sorted())
2382 }
2383
2384 pub fn scale_color_discrete_sorted(self) -> Self {
2387 use crate::scale::color::ScaleColorDiscrete;
2388 self.scale_color(ScaleColorDiscrete::new(crate::aes::Aesthetic::Color).sorted())
2389 }
2390
2391 pub fn scale_fill_brewer(self, name: crate::scale::palettes::PaletteName) -> Self {
2392 use crate::scale::color::ScaleColorDiscrete;
2393 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill).with_named_palette(&name);
2394 self.scale_fill(s)
2395 }
2396
2397 pub fn scale_linetype_manual(
2398 self,
2399 values: Vec<(&str, crate::render::backend::Linetype)>,
2400 ) -> Self {
2401 let s = crate::scale::linetype_manual::ScaleLinetypeManual::new(values);
2402 self.scale_color(s)
2403 }
2404
2405 pub fn scale_shape_manual(
2406 self,
2407 values: Vec<(&str, crate::render::backend::PointShape)>,
2408 ) -> Self {
2409 let s = crate::scale::shape_manual::ScaleShapeManual::new(values);
2410 self.scale_color(s)
2411 }
2412
2413 pub fn scale_color_grey(self) -> Self {
2414 let s = crate::scale::grey::ScaleColorGrey::new(crate::aes::Aesthetic::Color);
2415 self.scale_color(s)
2416 }
2417
2418 pub fn scale_fill_grey(self) -> Self {
2419 let s = crate::scale::grey::ScaleColorGrey::new(crate::aes::Aesthetic::Fill);
2420 self.scale_fill(s)
2421 }
2422
2423 pub fn scale_color_grey_with(self, s: crate::scale::grey::ScaleColorGrey) -> Self {
2424 self.scale_color(s)
2425 }
2426
2427 pub fn scale_fill_grey_with(self, s: crate::scale::grey::ScaleColorGrey) -> Self {
2428 self.scale_fill(s)
2429 }
2430
2431 pub fn scale_x_reverse(self) -> Self {
2432 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reverse))
2433 }
2434
2435 pub fn scale_y_reverse(self) -> Self {
2436 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reverse))
2437 }
2438
2439 pub fn scale_x_datetime(mut self, s: crate::scale::datetime::ScaleDateTime) -> Self {
2440 let s = s.for_aesthetic(crate::aes::Aesthetic::X);
2441 self.scales.push(Box::new(s));
2442 self
2443 }
2444
2445 pub fn scale_y_datetime(mut self, s: crate::scale::datetime::ScaleDateTime) -> Self {
2446 let s = s.for_aesthetic(crate::aes::Aesthetic::Y);
2447 self.scales.push(Box::new(s));
2448 self
2449 }
2450
2451 pub fn scale_size(mut self, s: crate::scale::size::ScaleSizeContinuous) -> Self {
2452 self.scales.push(Box::new(s));
2453 self
2454 }
2455
2456 pub fn scale_size_area(mut self, max_size: f64) -> Self {
2460 self.scales.push(Box::new(
2461 crate::scale::size::ScaleSizeContinuous::new().area(max_size),
2462 ));
2463 self
2464 }
2465
2466 pub fn scale_alpha(mut self, s: crate::scale::alpha::ScaleAlphaContinuous) -> Self {
2467 self.scales.push(Box::new(s));
2468 self
2469 }
2470
2471 pub fn scale_linewidth(mut self, s: crate::scale::linewidth::ScaleLinewidthContinuous) -> Self {
2475 self.scales.push(Box::new(s));
2476 self
2477 }
2478
2479 pub fn xlim(self, min: f64, max: f64) -> Self {
2480 self.scale_x_continuous(ScaleContinuous::new().with_limits(min, max))
2481 }
2482
2483 pub fn ylim(self, min: f64, max: f64) -> Self {
2484 self.scale_y_continuous(ScaleContinuous::new().with_limits(min, max))
2485 }
2486
2487 pub fn scale_x_log10(self) -> Self {
2488 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log10))
2489 }
2490
2491 pub fn scale_y_log10(self) -> Self {
2492 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log10))
2493 }
2494
2495 pub fn scale_x_sqrt(self) -> Self {
2496 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Sqrt))
2497 }
2498
2499 pub fn scale_y_sqrt(self) -> Self {
2500 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Sqrt))
2501 }
2502
2503 pub fn scale_x_log2(self) -> Self {
2504 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log2))
2505 }
2506
2507 pub fn scale_y_log2(self) -> Self {
2508 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log2))
2509 }
2510
2511 pub fn scale_x_ln(self) -> Self {
2512 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Ln))
2513 }
2514
2515 pub fn scale_y_ln(self) -> Self {
2516 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Ln))
2517 }
2518
2519 pub fn scale_x_logit(self) -> Self {
2521 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Logit))
2522 }
2523
2524 pub fn scale_y_logit(self) -> Self {
2525 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Logit))
2526 }
2527
2528 pub fn scale_x_probit(self) -> Self {
2530 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Probit))
2531 }
2532
2533 pub fn scale_y_probit(self) -> Self {
2534 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Probit))
2535 }
2536
2537 pub fn scale_x_pseudo_log(self) -> Self {
2539 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::PseudoLog))
2540 }
2541
2542 pub fn scale_y_pseudo_log(self) -> Self {
2543 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::PseudoLog))
2544 }
2545
2546 pub fn scale_x_reciprocal(self) -> Self {
2548 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reciprocal))
2549 }
2550
2551 pub fn scale_y_reciprocal(self) -> Self {
2552 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reciprocal))
2553 }
2554
2555 pub fn scale_x_exp(self) -> Self {
2557 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Exp))
2558 }
2559
2560 pub fn scale_y_exp(self) -> Self {
2561 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Exp))
2562 }
2563
2564 pub fn scale_x_boxcox(self, lambda: f64) -> Self {
2566 self.scale_x_continuous(
2567 ScaleContinuous::new().with_transform(ScaleTransform::BoxCox(lambda)),
2568 )
2569 }
2570
2571 pub fn scale_y_boxcox(self, lambda: f64) -> Self {
2572 self.scale_y_continuous(
2573 ScaleContinuous::new().with_transform(ScaleTransform::BoxCox(lambda)),
2574 )
2575 }
2576
2577 pub fn facet_wrap(mut self, var: &str, ncol: Option<usize>) -> Self {
2580 self.facet = Facet::Wrap {
2581 var: var.to_string(),
2582 ncol,
2583 scales: FacetScales::Fixed,
2584 labeller: FacetLabeller::default(),
2585 levels: None,
2586 };
2587 self
2588 }
2589
2590 pub fn facet_wrap_free(mut self, var: &str, ncol: Option<usize>, scales: FacetScales) -> Self {
2591 self.facet = Facet::Wrap {
2592 var: var.to_string(),
2593 ncol,
2594 scales,
2595 labeller: FacetLabeller::default(),
2596 levels: None,
2597 };
2598 self
2599 }
2600
2601 pub fn facet_wrap_labeller(
2602 mut self,
2603 var: &str,
2604 ncol: Option<usize>,
2605 labeller: FacetLabeller,
2606 ) -> Self {
2607 self.facet = Facet::Wrap {
2608 var: var.to_string(),
2609 ncol,
2610 scales: FacetScales::Fixed,
2611 labeller,
2612 levels: None,
2613 };
2614 self
2615 }
2616
2617 pub fn facet_levels<S: AsRef<str>>(mut self, levels: &[S]) -> Self {
2624 if let Facet::Wrap { levels: l, .. } = &mut self.facet {
2625 let mut seen = Vec::<String>::new();
2626 for s in levels {
2627 if !seen.iter().any(|x| x == s.as_ref()) {
2628 seen.push(s.as_ref().to_string());
2629 }
2630 }
2631 *l = Some(seen);
2632 }
2633 self
2634 }
2635
2636 pub fn facet_grid(mut self, row: Option<&str>, col: Option<&str>) -> Self {
2637 self.facet = Facet::Grid {
2638 row_var: row.map(String::from),
2639 col_var: col.map(String::from),
2640 scales: FacetScales::Fixed,
2641 labeller: FacetLabeller::default(),
2642 space: FacetSpace::Fixed,
2643 };
2644 self
2645 }
2646
2647 pub fn facet_grid_free(
2648 mut self,
2649 row: Option<&str>,
2650 col: Option<&str>,
2651 scales: FacetScales,
2652 ) -> Self {
2653 self.facet = Facet::Grid {
2654 row_var: row.map(String::from),
2655 col_var: col.map(String::from),
2656 scales,
2657 labeller: FacetLabeller::default(),
2658 space: FacetSpace::Fixed,
2659 };
2660 self
2661 }
2662
2663 pub fn facet_grid_multi(
2667 mut self,
2668 row: Option<&str>,
2669 cols: &[&str],
2670 scales: FacetScales,
2671 space: FacetSpace,
2672 ) -> Self {
2673 let col_var = if cols.len() > 1 {
2674 let n = self.data.nrows();
2676 let mut combined = Vec::with_capacity(n);
2677 for i in 0..n {
2678 let parts: Vec<String> = cols
2679 .iter()
2680 .map(|c| {
2681 self.data
2682 .column(c)
2683 .and_then(|col| col.get(i))
2684 .map(|v| v.to_group_key())
2685 .unwrap_or_default()
2686 })
2687 .collect();
2688 combined.push(crate::data::Value::Str(parts.join(" . ")));
2689 }
2690 let name = "__facet_cols__".to_string();
2691 self.data.add_column(name.clone(), combined);
2692 Some(name)
2693 } else {
2694 cols.first().map(|s| s.to_string())
2695 };
2696 self.facet = Facet::Grid {
2697 row_var: row.map(String::from),
2698 col_var,
2699 scales,
2700 labeller: FacetLabeller::default(),
2701 space,
2702 };
2703 self
2704 }
2705
2706 pub fn facet_grid_space(
2709 mut self,
2710 row: Option<&str>,
2711 col: Option<&str>,
2712 scales: FacetScales,
2713 space: FacetSpace,
2714 ) -> Self {
2715 self.facet = Facet::Grid {
2716 row_var: row.map(String::from),
2717 col_var: col.map(String::from),
2718 scales,
2719 labeller: FacetLabeller::default(),
2720 space,
2721 };
2722 self
2723 }
2724
2725 pub fn facet_grid_labeller(
2726 mut self,
2727 row: Option<&str>,
2728 col: Option<&str>,
2729 labeller: FacetLabeller,
2730 ) -> Self {
2731 self.facet = Facet::Grid {
2732 row_var: row.map(String::from),
2733 col_var: col.map(String::from),
2734 scales: FacetScales::Fixed,
2735 labeller,
2736 space: FacetSpace::Fixed,
2737 };
2738 self
2739 }
2740
2741 pub fn coord_flip(mut self) -> Self {
2744 self.coord = Box::new(CoordFlip);
2745 self
2746 }
2747
2748 pub fn coord_fixed(mut self, ratio: f64) -> Self {
2749 self.coord = Box::new(CoordFixed::new(ratio));
2750 self
2751 }
2752
2753 #[cfg(feature = "sf")]
2757 pub fn coord_sf(mut self) -> Self {
2758 self.coord = Box::new(crate::coord::sf::CoordSf::new());
2759 self
2760 }
2761
2762 #[cfg(feature = "sf")]
2767 pub fn coord_sf_with(mut self, coord: crate::coord::sf::CoordSf) -> Self {
2768 self.coord = Box::new(coord);
2769 self
2770 }
2771
2772 pub fn svg_root_data(mut self, on: bool) -> Self {
2779 self.svg_root_data = on;
2780 self
2781 }
2782
2783 pub fn svg_attr(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
2793 self.root_attrs.push((name.into(), value.into()));
2794 self
2795 }
2796
2797 pub fn svg_attrs(mut self, attrs: impl IntoIterator<Item = (String, String)>) -> Self {
2799 self.root_attrs.extend(attrs);
2800 self
2801 }
2802
2803 pub fn svg_warnings_attr(mut self, on: bool) -> Self {
2808 self.svg_warnings_attr = on;
2809 self
2810 }
2811
2812 pub fn svg_formatted_values(mut self, on: bool) -> Self {
2821 self.svg_formatted_values = on;
2822 self
2823 }
2824
2825 pub fn svg_title(mut self, title: impl Into<String>) -> Self {
2835 self.svg_title = Some(title.into());
2836 self
2837 }
2838
2839 pub fn svg_desc(mut self, desc: impl Into<String>) -> Self {
2847 self.svg_desc = Some(desc.into());
2848 self
2849 }
2850
2851 pub fn coord_trans(mut self, x: Option<ScaleTransform>, y: Option<ScaleTransform>) -> Self {
2856 self.coord = Box::new(crate::coord::trans::CoordTrans::new(x, y));
2857 self
2858 }
2859
2860 pub fn coord_trans_y(self, y: ScaleTransform) -> Self {
2862 self.coord_trans(None, Some(y))
2863 }
2864
2865 pub fn coord_trans_x(self, x: ScaleTransform) -> Self {
2867 self.coord_trans(Some(x), None)
2868 }
2869
2870 pub fn coord_cartesian_zoom(
2872 mut self,
2873 xlim: Option<(f64, f64)>,
2874 ylim: Option<(f64, f64)>,
2875 ) -> Self {
2876 let mut c = CoordCartesian::new();
2877 if let Some((min, max)) = xlim {
2878 c = c.xlim(min, max);
2879 }
2880 if let Some((min, max)) = ylim {
2881 c = c.ylim(min, max);
2882 }
2883 self.coord = Box::new(c);
2884 self
2885 }
2886
2887 pub fn coord_polar(mut self) -> Self {
2888 self.coord = Box::new(CoordPolar::new());
2889 self
2890 }
2891
2892 pub fn coord_radar(mut self) -> Self {
2896 self.coord = Box::new(crate::coord::radar::CoordRadar::new());
2897 self
2898 }
2899
2900 pub fn coord_radar_with(mut self, coord: crate::coord::radar::CoordRadar) -> Self {
2901 self.coord = Box::new(coord);
2902 self
2903 }
2904
2905 pub fn coord_polar_with(mut self, coord: CoordPolar) -> Self {
2906 self.coord = Box::new(coord);
2907 self
2908 }
2909
2910 pub fn theme(mut self, theme: Theme) -> Self {
2915 self.apply_preset(theme);
2916 self
2917 }
2918
2919 fn apply_preset(&mut self, theme: Theme) {
2920 let primary = self.theme.primary;
2921 self.theme = theme;
2922 if self.theme.primary.is_none() {
2923 self.theme.primary = primary;
2924 }
2925 }
2926
2927 pub fn axis_text_x_angle(mut self, degrees: f64) -> Self {
2931 self.theme.axis_text_x.angle = degrees;
2932 self
2933 }
2934
2935 pub fn axis_text_y_angle(mut self, degrees: f64) -> Self {
2937 self.theme.axis_text_y.angle = degrees;
2938 self
2939 }
2940
2941 pub fn axis_text_x_dodge(mut self, n: usize) -> Self {
2944 self.theme.axis_text_x_dodge = n.max(1);
2945 self
2946 }
2947
2948 pub fn aspect_ratio(mut self, ratio: f64) -> Self {
2951 self.theme.aspect_ratio = Some(ratio);
2952 self
2953 }
2954
2955 pub fn panel_ontop(mut self) -> Self {
2957 self.theme.panel_ontop = true;
2958 self
2959 }
2960
2961 pub fn axis_minor_ticks(mut self) -> Self {
2963 self.theme.axis_minor_ticks = true;
2964 self
2965 }
2966
2967 pub fn axis_text_x_fit(mut self, fit: crate::theme::AxisLabelFit) -> Self {
2972 self.theme.axis_text_x_fit = fit;
2973 self
2974 }
2975
2976 pub fn axis_text_x_check_overlap(mut self, on: bool) -> Self {
2979 self.theme.axis_text_x_check_overlap = on;
2980 self
2981 }
2982
2983 pub fn title_position(mut self, pos: crate::theme::TitlePosition) -> Self {
2986 self.theme.title_position = pos;
2987 self
2988 }
2989
2990 pub fn tag_position(mut self, pos: crate::theme::TagPosition) -> Self {
2992 self.theme.tag_position = pos;
2993 self
2994 }
2995
2996 pub fn legend_direction(mut self, dir: crate::theme::LegendDirection) -> Self {
2998 self.theme.legend_direction = Some(dir);
2999 self
3000 }
3001
3002 pub fn legend_position_inside(mut self, x: f64, y: f64) -> Self {
3009 self.theme.legend_position = crate::theme::LegendPosition::Inside(x, y);
3010 self
3011 }
3012
3013 pub fn legend_position(mut self, pos: crate::theme::LegendPosition) -> Self {
3015 self.theme.legend_position = pos;
3016 self
3017 }
3018
3019 pub fn legend_bottom_when_narrow(mut self, share: f64) -> Self {
3026 self.legend_bottom_share = Some(share);
3027 self
3028 }
3029
3030 pub fn legend_inside_auto(self) -> Self {
3041 self.legend_inside_auto_with(&crate::theme::LegendCorner::ALL, None)
3042 }
3043
3044 pub fn legend_inside_auto_with(
3049 mut self,
3050 corners: &[crate::theme::LegendCorner],
3051 fallback: Option<crate::theme::LegendPosition>,
3052 ) -> Self {
3053 use crate::theme::LegendPosition as P;
3054 let mut c = [None; 4];
3055 for (slot, corner) in c.iter_mut().zip(corners) {
3056 *slot = Some(*corner);
3057 }
3058 let fallback = match fallback {
3059 Some(P::Top) => Some(LegendSide::Top),
3060 Some(P::Right) => Some(LegendSide::Right),
3061 Some(P::Bottom) => Some(LegendSide::Bottom),
3062 Some(P::Left) => Some(LegendSide::Left),
3063 _ => None,
3064 };
3065 self.legend_auto = Some(LegendAuto {
3066 corners: c,
3067 fallback,
3068 });
3069 self
3070 }
3071
3072 pub fn primary_color(mut self, color: (u8, u8, u8)) -> Self {
3073 self.theme.primary = Some(color);
3074 self
3075 }
3076
3077 pub fn theme_minimal(mut self) -> Self {
3078 self.apply_preset(crate::theme::presets::theme_minimal());
3079 self
3080 }
3081
3082 pub fn theme_bw(mut self) -> Self {
3083 self.apply_preset(crate::theme::presets::theme_bw());
3084 self
3085 }
3086
3087 pub fn theme_gray(mut self) -> Self {
3088 self.apply_preset(crate::theme::presets::theme_gray());
3089 self
3090 }
3091
3092 pub fn theme_classic(mut self) -> Self {
3093 self.apply_preset(crate::theme::presets::theme_classic());
3094 self
3095 }
3096
3097 pub fn theme_pubr(mut self) -> Self {
3099 self.apply_preset(crate::theme::presets::theme_pubr());
3100 self
3101 }
3102
3103 pub fn theme_linedraw(mut self) -> Self {
3104 self.apply_preset(crate::theme::presets::theme_linedraw());
3105 self
3106 }
3107
3108 pub fn theme_light(mut self) -> Self {
3109 self.apply_preset(crate::theme::presets::theme_light());
3110 self
3111 }
3112
3113 pub fn theme_dark(mut self) -> Self {
3114 self.apply_preset(crate::theme::presets::theme_dark());
3115 self
3116 }
3117
3118 pub fn theme_void(mut self) -> Self {
3119 self.apply_preset(crate::theme::presets::theme_void());
3120 self
3121 }
3122
3123 pub fn theme_update(mut self, update: crate::theme::ThemeUpdate) -> Self {
3126 self.theme = self.theme.update(update);
3127 self
3128 }
3129
3130 pub fn guides(mut self, guide: crate::guide::config::GuideLegend) -> Self {
3134 self.guide_legend = guide;
3135 self
3136 }
3137
3138 pub fn labs(mut self, labels: Labels) -> Self {
3141 if labels.title.is_some() {
3142 self.labels.title = labels.title;
3143 }
3144 if labels.subtitle.is_some() {
3145 self.labels.subtitle = labels.subtitle;
3146 }
3147 if labels.x.is_some() {
3148 self.labels.x = labels.x;
3149 }
3150 if labels.y.is_some() {
3151 self.labels.y = labels.y;
3152 }
3153 if labels.caption.is_some() {
3154 self.labels.caption = labels.caption;
3155 }
3156 if labels.tag.is_some() {
3157 self.labels.tag = labels.tag;
3158 }
3159 self
3160 }
3161
3162 pub fn title(mut self, title: &str) -> Self {
3163 self.labels.title = Some(title.to_string());
3164 self
3165 }
3166
3167 pub fn tag(mut self, tag: &str) -> Self {
3170 self.labels.tag = Some(tag.to_string());
3171 self
3172 }
3173
3174 pub fn subtitle(mut self, subtitle: &str) -> Self {
3175 self.labels.subtitle = Some(subtitle.to_string());
3176 self
3177 }
3178
3179 pub fn xlab(mut self, label: &str) -> Self {
3180 self.labels.x = Some(label.to_string());
3181 self
3182 }
3183
3184 pub fn ylab(mut self, label: &str) -> Self {
3185 self.labels.y = Some(label.to_string());
3186 self
3187 }
3188
3189 pub fn caption(mut self, caption: &str) -> Self {
3190 self.labels.caption = Some(caption.to_string());
3191 self
3192 }
3193
3194 pub fn annotate(mut self, annotation: Annotation) -> Self {
3198 self.annotations.push(annotation);
3199 self
3200 }
3201
3202 pub fn annotate_text(self, label: &str, x: f64, y: f64) -> Self {
3204 self.annotate(Annotation::text(label, x, y))
3205 }
3206
3207 pub fn annotate_rect(self, xmin: f64, xmax: f64, ymin: f64, ymax: f64) -> Self {
3209 self.annotate(Annotation::rect(xmin, xmax, ymin, ymax))
3210 }
3211
3212 pub fn annotate_segment(self, x: f64, y: f64, xend: f64, yend: f64) -> Self {
3214 self.annotate(Annotation::segment(x, y, xend, yend))
3215 }
3216
3217 pub fn locale(mut self, locale: crate::locale::Locale) -> Self {
3240 self.locale = Some(locale);
3241 self
3242 }
3243
3244 pub fn try_build(self) -> Result<crate::build::BuiltPlot, GGError> {
3248 PlotBuilder::build(self)
3249 }
3250
3251 pub fn build(self) -> crate::build::BuiltPlot {
3255 self.try_build().expect("plot build failed")
3256 }
3257
3258 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
3262 pub fn save(self, path: &str) -> Result<(), GGError> {
3263 self.save_with_size(path, 800, 600)
3264 }
3265
3266 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
3268 pub fn save_with_size(self, path: &str, w: u32, h: u32) -> Result<(), GGError> {
3269 let (built, layout) = self.prepare(w, h)?;
3270
3271 let ext = path.rsplit('.').next().unwrap_or("svg").to_lowercase();
3273
3274 match ext.as_str() {
3275 "svg" => {
3276 let backend = plotters::prelude::SVGBackend::new(path, (w, h));
3277 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
3278 }
3279 "png" | "bmp" | "gif" | "jpeg" | "jpg" | "tiff" => {
3280 let backend = plotters::prelude::BitMapBackend::new(path, (w, h));
3281 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
3282 }
3283 _ => {
3284 return Err(GGError::UnsupportedFormat(ext));
3285 }
3286 }
3287
3288 Ok(())
3289 }
3290
3291 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
3297 pub fn render_svg(self) -> Result<String, GGError> {
3298 self.render_svg_with_size(800, 600)
3299 }
3300
3301 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
3305 pub fn render_svg_with_size(self, w: u32, h: u32) -> Result<String, GGError> {
3306 let (built, layout) = self.prepare(w, h)?;
3307 let mut buf = String::new();
3308 {
3309 let backend = plotters::prelude::SVGBackend::with_string(&mut buf, (w, h));
3310 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
3311 }
3312 Ok(buf)
3313 }
3314
3315 pub fn render_svg_native(self) -> Result<String, GGError> {
3319 self.render_svg_native_with_size(800, 600)
3320 }
3321
3322 pub fn render_svg_native_with_size(self, w: u32, h: u32) -> Result<String, GGError> {
3330 Ok(self.render_native(w, h)?.0.finish())
3331 }
3332
3333 pub fn render_svg_native_with_warnings(
3338 self,
3339 w: u32,
3340 h: u32,
3341 ) -> Result<(String, Vec<String>), GGError> {
3342 let (backend, warnings, _) = self.render_native(w, h)?;
3343 Ok((backend.finish(), warnings))
3344 }
3345
3346 pub fn render_svg_native_at(self, x: f64, y: f64, w: u32, h: u32) -> Result<String, GGError> {
3358 Ok(self.render_native(w, h)?.0.finish_fragment(x, y))
3359 }
3360
3361 pub fn render_svg_area_with_size(self, w: u32, h: u32) -> Result<(String, [f64; 4]), GGError> {
3365 let (backend, _, pa) = self.render_native(w, h)?;
3366 Ok((backend.finish(), [pa.x, pa.y, pa.width, pa.height]))
3367 }
3368
3369 fn render_native(
3373 self,
3374 w: u32,
3375 h: u32,
3376 ) -> Result<
3377 (
3378 crate::render::svg_backend::SvgBackend,
3379 Vec<String>,
3380 crate::render::Rect,
3381 ),
3382 GGError,
3383 > {
3384 let svg_root_data = self.svg_root_data;
3385 let root_attrs = self.root_attrs.clone();
3386 let svg_warnings_attr = self.svg_warnings_attr;
3387 let svg_formatted_values = self.svg_formatted_values;
3388 let svg_title = self.svg_title.clone();
3389 let svg_desc = self.svg_desc.clone();
3390 let (built, layout) = self.prepare(w, h)?;
3391 let pa = layout.plot_area.clone();
3392 let mut backend = crate::render::svg_backend::SvgBackend::new(w, h, pa.clone());
3393 backend.set_formatted_values(svg_formatted_values);
3394 backend.set_svg_title(svg_title.clone());
3395 backend.set_svg_desc(svg_desc.clone());
3396 let existing_root_attrs = if svg_root_data {
3397 let attrs = crate::render::svg_backend::root_data_attrs(&built);
3398 backend.set_root_attrs(attrs.clone());
3399 let mut reserved = attrs;
3403 for name in ["data-plot", "data-viewport", "data-panels"] {
3406 reserved.push((name.to_string(), String::new()));
3407 }
3408 reserved
3409 } else {
3410 backend.without_plot_attr();
3411 Vec::new()
3412 };
3413 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
3414 let mut warnings = built.warnings;
3415 warnings.extend(backend.take_warnings());
3416
3417 let mut reserved = existing_root_attrs;
3418 if svg_warnings_attr {
3419 reserved.push(("data-warnings".to_string(), String::new()));
3420 }
3421 if svg_title.is_some() || svg_desc.is_some() {
3426 reserved.push(("role".to_string(), String::new()));
3427 }
3428 if svg_title.is_some() {
3429 reserved.push(("aria-labelledby".to_string(), String::new()));
3430 }
3431 if svg_desc.is_some() {
3432 reserved.push(("aria-describedby".to_string(), String::new()));
3433 }
3434 let extra = crate::render::svg_backend::validate_root_attrs(
3435 &root_attrs,
3436 &reserved,
3437 "plot",
3438 &mut warnings,
3439 );
3440 backend.extend_root_attrs(extra);
3441 if svg_warnings_attr {
3442 backend.extend_root_attrs(vec![(
3443 "data-warnings".to_string(),
3444 crate::render::svg_backend::warnings_json(&warnings),
3445 )]);
3446 }
3447 Ok((backend, warnings, pa))
3448 }
3449
3450 #[cfg(feature = "canvas")]
3455 pub fn render_rgba_with_size(self, w: u32, h: u32) -> Result<(u32, u32, Vec<u8>), GGError> {
3456 let (built, layout) = self.prepare(w, h)?;
3457 let mut backend =
3458 crate::render::pixel_backend::PixelBackend::new(w, h, layout.plot_area.clone());
3459 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
3460 let (ow, oh) = backend.dimensions();
3461 Ok((ow, oh, backend.into_rgba()))
3462 }
3463
3464 #[cfg(feature = "canvas")]
3468 pub fn render_rgba_area_with_size(
3469 self,
3470 w: u32,
3471 h: u32,
3472 ) -> Result<(Vec<u8>, [f64; 4]), GGError> {
3473 let (built, layout) = self.prepare(w, h)?;
3474 let pa = layout.plot_area.clone();
3475 let mut backend = crate::render::pixel_backend::PixelBackend::new(w, h, pa.clone());
3476 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
3477 Ok((backend.into_rgba(), [pa.x, pa.y, pa.width, pa.height]))
3478 }
3479
3480 #[cfg(feature = "canvas")]
3484 pub fn render_png_raster_with_size(self, w: u32, h: u32) -> Result<Vec<u8>, GGError> {
3485 let (built, layout) = self.prepare(w, h)?;
3486 let mut backend =
3487 crate::render::pixel_backend::PixelBackend::new(w, h, layout.plot_area.clone());
3488 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
3489 backend.into_png().map_err(GGError::Render)
3490 }
3491
3492 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
3499 pub fn render_png(self) -> Result<Vec<u8>, GGError> {
3500 self.render_png_with_size(800, 600)
3501 }
3502
3503 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
3506 pub fn render_png_with_size(self, w: u32, h: u32) -> Result<Vec<u8>, GGError> {
3507 let (built, layout) = self.prepare(w, h)?;
3508
3509 let mut rgb = vec![0u8; (w as usize) * (h as usize) * 3];
3512 {
3513 let backend = plotters::prelude::BitMapBackend::with_buffer(&mut rgb, (w, h));
3514 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
3515 }
3516
3517 let img = image::RgbImage::from_raw(w, h, rgb).ok_or_else(|| {
3518 GGError::Render(RenderError::BackendError(
3519 "PNG buffer size mismatch".to_string(),
3520 ))
3521 })?;
3522 let mut out = std::io::Cursor::new(Vec::new());
3523 img.write_to(&mut out, image::ImageOutputFormat::Png)
3524 .map_err(|e| GGError::Render(RenderError::BackendError(format!("{:?}", e))))?;
3525 Ok(out.into_inner())
3526 }
3527
3528 pub(crate) fn prepare(
3530 self,
3531 w: u32,
3532 h: u32,
3533 ) -> Result<(crate::build::BuiltPlot, PlotLayout), GGError> {
3534 let (mut built, meta) = self.build_for_render()?;
3535 let layout = Self::layout_built(&mut built, &meta, w, h);
3536 Ok((built, layout))
3537 }
3538
3539 pub(crate) fn build_for_render(self) -> Result<(crate::build::BuiltPlot, RenderMeta), GGError> {
3542 let plot = self;
3543
3544 let has_title = plot.labels.title.is_some();
3545 let has_subtitle = plot.labels.subtitle.is_some();
3546 let has_caption = plot.labels.caption.is_some();
3547 let has_legend = plot.has_legend_mapping();
3548 let legend_bottom_share = plot.legend_bottom_share;
3549 let legend_auto = plot.legend_auto;
3550 let x_label = plot.labels.x.clone();
3551 let y_label = plot.labels.y.clone();
3552
3553 let mut built = PlotBuilder::build(plot)?;
3554
3555 built.theme.resolve_inheritance();
3557
3558 if let Some(ref label) = x_label {
3560 if let Some(s) = built.scales.get_mut(&crate::aes::Aesthetic::X) {
3561 s.set_name(label);
3562 }
3563 }
3564 if let Some(ref label) = y_label {
3565 if let Some(s) = built.scales.get_mut(&crate::aes::Aesthetic::Y) {
3566 s.set_name(label);
3567 }
3568 }
3569
3570 Ok((
3571 built,
3572 RenderMeta {
3573 has_title,
3574 has_subtitle,
3575 has_caption,
3576 has_legend,
3577 legend_bottom_share,
3578 legend_auto,
3579 },
3580 ))
3581 }
3582
3583 pub(crate) fn layout_built(
3586 built: &mut crate::build::BuiltPlot,
3587 meta: &RenderMeta,
3588 w: u32,
3589 h: u32,
3590 ) -> PlotLayout {
3591 match meta.legend_auto {
3592 Some(auto) if meta.has_legend && built.panels.is_empty() => {
3593 Self::layout_legend_auto(built, meta, auto, w, h)
3594 }
3595 _ => Self::layout_built_inner(built, meta, w, h),
3596 }
3597 }
3598
3599 fn layout_legend_auto(
3602 built: &mut crate::build::BuiltPlot,
3603 meta: &RenderMeta,
3604 auto: LegendAuto,
3605 w: u32,
3606 h: u32,
3607 ) -> PlotLayout {
3608 use crate::render::probe::Probe;
3609 use crate::theme::LegendPosition as P;
3610 let total = crate::render::Rect {
3611 x: 0.0,
3612 y: 0.0,
3613 width: w as f64,
3614 height: h as f64,
3615 };
3616 let (theme0, n_warnings) = (built.theme.clone(), built.warnings.len());
3619 let reset = |built: &mut crate::build::BuiltPlot, pos: P| {
3620 built.theme = theme0.clone();
3621 built.theme.legend_position = pos;
3622 built.warnings.truncate(n_warnings);
3623 };
3624
3625 reset(built, P::Inside(1.0, 0.0));
3626 let layout = Self::layout_built_inner(built, meta, w, h);
3627 let pa = layout.plot_area.clone();
3628 let mut marks = Probe::new(pa.clone(), total.clone());
3629 for layer in built.layers.iter().filter(|l| l.data.nrows() > 0) {
3630 let _ = layer.geom.draw(
3631 &layer.data,
3632 built.coord.as_ref(),
3633 &built.scales,
3634 &built.theme,
3635 &mut marks,
3636 );
3637 }
3638 for corner in auto.corners.iter().flatten() {
3639 built.theme.legend_position = corner.inside();
3640 let mut legend = Probe::new(pa.clone(), total.clone());
3641 let drawn = crate::guide::legend::draw_legend_planned(
3642 &built.scales,
3643 &built.theme,
3644 &pa,
3645 pa.width,
3646 &mut legend,
3647 &built.guide_legend,
3648 &built.suppressed_aes,
3649 &built.legend_plans,
3650 );
3651 let Some((x0, y0, x1, y1)) = legend.extent().filter(|_| drawn.is_ok()) else {
3652 continue;
3653 };
3654 const PAD: f64 = 2.0;
3655 if !marks.hits((x0 - PAD, y0 - PAD, x1 + PAD, y1 + PAD)) {
3656 built.legend_at = Some(format!("inside-{}", corner.name()));
3657 return layout;
3658 }
3659 }
3660
3661 let sides = match auto.fallback {
3664 Some(side) => vec![side],
3665 None => vec![LegendSide::Top, LegendSide::Right],
3666 };
3667 let data_area = |built: &crate::build::BuiltPlot, layout: &PlotLayout| {
3668 let r = built
3669 .coord
3670 .data_rect(&layout.plot_area)
3671 .unwrap_or_else(|| layout.plot_area.clone());
3672 r.width.max(0.0) * r.height.max(0.0)
3673 };
3674 let mut best = (sides[0], f64::MIN);
3675 for &side in &sides {
3676 reset(built, side.position());
3677 let trial = Self::layout_built_inner(built, meta, w, h);
3678 let area = data_area(built, &trial);
3679 if area > best.1 {
3680 best = (side, area);
3681 }
3682 }
3683 reset(built, best.0.position());
3684 let layout = Self::layout_built_inner(built, meta, w, h);
3685 built.legend_at = Some(
3686 match built.theme.legend_position {
3687 P::Top => "top",
3688 P::Right => "right",
3689 P::Bottom => "bottom",
3690 _ => "left",
3691 }
3692 .to_string(),
3693 );
3694 layout
3695 }
3696
3697 fn layout_built_inner(
3698 built: &mut crate::build::BuiltPlot,
3699 meta: &RenderMeta,
3700 w: u32,
3701 h: u32,
3702 ) -> PlotLayout {
3703 let RenderMeta {
3704 has_title,
3705 has_subtitle,
3706 has_caption,
3707 has_legend,
3708 legend_bottom_share,
3709 legend_auto: _,
3710 } = *meta;
3711 let x_axis_top = built
3712 .scales
3713 .get(&crate::aes::Aesthetic::X)
3714 .map(|s| s.axis_position_opposite())
3715 .unwrap_or(false);
3716
3717 if let Some(share) = legend_bottom_share {
3720 if has_legend
3721 && matches!(
3722 built.theme.legend_position,
3723 crate::theme::LegendPosition::Right
3724 )
3725 {
3726 let panel_width = |pos| {
3727 let mut theme = built.theme.clone();
3728 theme.legend_position = pos;
3729 PlotLayout::compute_with_extras(
3730 w as f64,
3731 h as f64,
3732 &theme,
3733 has_title,
3734 has_subtitle,
3735 has_caption,
3736 has_legend,
3737 x_axis_top,
3738 None,
3739 None,
3740 crate::render::layout::LayoutExtras::default(),
3741 )
3742 .plot_area
3743 .width
3744 };
3745 let free = panel_width(crate::theme::LegendPosition::None);
3748 if panel_width(crate::theme::LegendPosition::Right) < (1.0 - share) * free {
3749 built.theme.legend_position = crate::theme::LegendPosition::Bottom;
3750 }
3751 }
3752 }
3753
3754 let flipped = built.coord.is_flipped();
3758 let h_aes = if flipped {
3759 crate::aes::Aesthetic::Y
3760 } else {
3761 crate::aes::Aesthetic::X
3762 };
3763 let v_aes = if flipped {
3764 crate::aes::Aesthetic::X
3765 } else {
3766 crate::aes::Aesthetic::Y
3767 };
3768
3769 let drawn_x_labels: Vec<(f64, String)> = built
3777 .scales
3778 .get(&h_aes)
3779 .map(|hs| {
3780 hs.breaks()
3781 .into_iter()
3782 .filter(|(_, label)| !label.is_empty())
3783 .collect()
3784 })
3785 .unwrap_or_default();
3786 let h_is_discrete = built
3787 .scales
3788 .get(&h_aes)
3789 .map(|hs| hs.is_discrete())
3790 .unwrap_or(false);
3791
3792 if built.theme.axis_text_x.visible
3805 && built.theme.axis_text_x.angle.abs() < 1.0
3806 && h_is_discrete
3807 && !drawn_x_labels.is_empty()
3808 {
3809 let font = built.theme.axis_text_x.size;
3810 let max_w = drawn_x_labels
3811 .iter()
3812 .map(|(_, l)| crate::render::text::text_width(l, font))
3813 .fold(0.0_f64, f64::max);
3814 let n = drawn_x_labels.len() as f64;
3815 let spacing = 0.9 * w as f64 / n; if max_w > spacing {
3817 let vertical = max_w * std::f64::consts::FRAC_1_SQRT_2 > spacing;
3821 built.theme.axis_text_x.angle = if vertical { 270.0 } else { -45.0 };
3822 }
3823 }
3824
3825 let x_label_height = if built.theme.axis_text_x.visible
3840 && built.theme.axis_text_x.angle.abs() > 10.0
3841 && !drawn_x_labels.is_empty()
3842 {
3843 let font = built.theme.axis_text_x.size;
3844 let angle = built.theme.axis_text_x.angle;
3845 let dir = if x_axis_top { -1.0 } else { 1.0 };
3846 let (rise, fall) = crate::render::text::rotated_label_rise_fall(
3847 drawn_x_labels.iter().map(|(_, l)| l.as_str()),
3848 font,
3849 angle,
3850 crate::render::text::rotated_anchor_frac(angle, dir),
3851 );
3852 Some(built.theme.legend_spacing / 2.0 + font / 2.0 + rise + fall)
3853 } else {
3854 None
3855 };
3856
3857 let y_label_width = if built.theme.axis_text_y.visible {
3861 built.scales.get(&v_aes).map(|vs| {
3862 crate::guide::axis::y_label_reserve(&built.theme, &vs.breaks()).min(0.35 * w as f64)
3863 })
3864 } else {
3865 None
3866 };
3867
3868 let mut extras = crate::render::layout::LayoutExtras::default();
3879 if let (Some(vs), Some(sec)) = (
3883 built.scales.get(&crate::aes::Aesthetic::Y),
3884 built.scales.sec_axis(&crate::aes::Aesthetic::Y),
3885 ) {
3886 let theme = &built.theme;
3887 let max_ch = match sec.own_ticks(vs) {
3888 Some(t) => t.iter().map(|(_, l)| l.chars().count()).max(),
3889 None => vs.breaks().iter().map(|(_, l)| l.chars().count() + 2).max(),
3890 }
3891 .unwrap_or(0);
3892 let text = if theme.axis_text_y.visible {
3893 (max_ch as f64 * theme.axis_text_y.size * 0.6).max(theme.axis_text_y.size * 3.5)
3894 } else {
3895 0.0
3896 };
3897 let title = if !sec.name.is_empty() && theme.axis_title_y.visible {
3898 theme.axis_title_y.size * 1.5
3899 } else {
3900 0.0
3901 };
3902 extras.right += theme.axis_ticks_length + theme.legend_spacing + text + title;
3903 }
3904 let can_reserve = built.facet.is_none()
3905 && built.theme.axis_text_x.visible
3906 && built.theme.axis_text_x_fit == crate::theme::AxisLabelFit::Reserve
3907 && !built.coord.is_polar()
3908 && built.coord.supports_axis_reserve();
3909 if can_reserve {
3910 if let Some(hs) = built.scales.get(&h_aes) {
3911 let breaks = hs.breaks();
3912 if let (Some(first), Some(last)) = (breaks.first(), breaks.last()) {
3913 let angle = built.theme.axis_text_x.angle;
3914 let anchor = if angle.abs() > 10.0 {
3915 let dir = if x_axis_top { -1.0 } else { 1.0 };
3916 crate::render::text::rotated_anchor_frac(angle, dir)
3917 } else {
3918 0.5
3919 };
3920 let size = built.theme.axis_text_x.size;
3921 const EDGE: f64 = 1.0;
3922 for _ in 0..2 {
3923 let layout = PlotLayout::compute_with_extras(
3924 w as f64,
3925 h as f64,
3926 &built.theme,
3927 has_title,
3928 has_subtitle,
3929 has_caption,
3930 has_legend,
3931 x_axis_top,
3932 y_label_width,
3933 x_label_height,
3934 extras,
3935 );
3936 let area = &layout.plot_area;
3937 let edge_y = area.y + area.height;
3938 let to_point = |pos: f64| if flipped { (0.0, pos) } else { (pos, 0.0) };
3939 let px_first = built.coord.transform(to_point(first.0), area).0;
3940 let px_last = built.coord.transform(to_point(last.0), area).0;
3941 let bbox_first = crate::render::text::label_bbox(
3942 &first.1, size, px_first, edge_y, angle, anchor,
3943 );
3944 let bbox_last = crate::render::text::label_bbox(
3945 &last.1, size, px_last, edge_y, angle, anchor,
3946 );
3947 let deficit_left = (EDGE - bbox_first[0]).max(0.0);
3948 let deficit_right = (bbox_last[2] - (w as f64 - EDGE)).max(0.0);
3949 if deficit_left <= 0.0 && deficit_right <= 0.0 {
3950 break;
3951 }
3952 let (p_first, p_last) = (first.0, last.0);
3961 if deficit_left > 0.0 && deficit_right > 0.0 {
3962 let (a, b, c, d) = (1.0 - p_first, p_first, 1.0 - p_last, p_last);
3967 let det = a * d - b * c;
3968 if det.abs() > 0.01 {
3969 extras.left +=
3970 ((deficit_left * d + deficit_right * b) / det).max(0.0);
3971 extras.right +=
3972 ((deficit_right * a + deficit_left * c) / det).max(0.0);
3973 } else {
3974 extras.left += deficit_left / (1.0 - p_first).max(0.05);
3978 extras.right += deficit_right / p_last.max(0.05);
3979 }
3980 } else if deficit_left > 0.0 {
3981 extras.left += deficit_left / (1.0 - p_first).max(0.05);
3982 } else if deficit_right > 0.0 {
3983 extras.right += deficit_right / p_last.max(0.05);
3984 }
3985 const MIN_PANEL_WIDTH: f64 = 50.0;
4000 let cap = (w as f64 - MIN_PANEL_WIDTH).max(0.0);
4001 if extras.left + extras.right > cap {
4002 let scale = if extras.left + extras.right > 0.0 {
4003 cap / (extras.left + extras.right)
4004 } else {
4005 0.0
4006 };
4007 extras.left *= scale;
4008 extras.right *= scale;
4009 }
4010 }
4011 }
4012 }
4013 }
4014
4015 if has_legend
4022 && !matches!(
4023 built.theme.legend_position,
4024 crate::theme::LegendPosition::None
4025 )
4026 {
4027 let legend_aes =
4028 crate::guide::legend::legend_scales_for(&built.scales, &built.suppressed_aes);
4029 extras.legend_max_key_size = legend_aes
4033 .iter()
4034 .filter_map(|aes| {
4035 let scale = built.scales.get(aes)?;
4036 let breaks = scale.breaks();
4037 Some(crate::guide::legend::size_key_diameter(
4038 aes,
4039 &built.scales,
4040 scale,
4041 &breaks,
4042 ))
4043 })
4044 .fold(0.0_f64, f64::max);
4045 let has_wrap_guide = legend_aes.iter().any(|a| {
4056 let is_discrete = built
4057 .scales
4058 .get(a)
4059 .map(|s| s.is_discrete())
4060 .unwrap_or(false);
4061 is_discrete || !crate::guide::legend::is_colorbar_aesthetic(a)
4062 });
4063 if has_wrap_guide {
4064 let layout0 = PlotLayout::compute_with_extras(
4065 w as f64,
4066 h as f64,
4067 &built.theme,
4068 has_title,
4069 has_subtitle,
4070 has_caption,
4071 has_legend,
4072 x_axis_top,
4073 y_label_width,
4074 x_label_height,
4075 extras,
4076 );
4077 let (legend_x0, _, mut is_horizontal) = crate::guide::legend::legend_position(
4087 &built.theme,
4088 &layout0.plot_area,
4089 extras.legend_extra_rows,
4090 (0.0, 0.0),
4091 &layout0.total,
4092 );
4093 if let Some(dir) = built.theme.legend_direction {
4094 is_horizontal = matches!(dir, crate::theme::LegendDirection::Horizontal);
4095 }
4096 let avail_width =
4097 (layout0.plot_area.x + layout0.plot_area.width - legend_x0).max(0.0);
4098 let mut legend_warnings = Vec::new();
4099 let mut plans = crate::guide::legend::plan_all_legends(
4100 &built.scales,
4101 &built.guide_legend,
4102 &built.theme,
4103 &built.suppressed_aes,
4104 avail_width,
4105 layout0.plot_area.height,
4106 is_horizontal,
4107 &mut legend_warnings,
4108 );
4109 built.warnings.extend(legend_warnings);
4110
4111 if !plans.is_empty() {
4112 extras.legend_extra_rows = if is_horizontal {
4118 plans
4119 .values()
4120 .map(|p| p.rows.saturating_sub(1))
4121 .max()
4122 .unwrap_or(0)
4123 } else {
4124 plans.values().map(|p| p.rows.saturating_sub(1)).sum()
4125 };
4126 extras.legend_extra_width = plans
4133 .values()
4134 .map(|p| p.cols.saturating_sub(1) as f64 * p.col_pitch)
4135 .fold(0.0_f64, f64::max);
4136
4137 if !is_horizontal {
4149 let final_layout = PlotLayout::compute_with_extras(
4150 w as f64,
4151 h as f64,
4152 &built.theme,
4153 has_title,
4154 has_subtitle,
4155 has_caption,
4156 has_legend,
4157 x_axis_top,
4158 y_label_width,
4159 x_label_height,
4160 extras,
4161 );
4162 let (legend_x_final, _, _) = crate::guide::legend::legend_position(
4168 &built.theme,
4169 &final_layout.plot_area,
4170 extras.legend_extra_rows,
4171 (0.0, 0.0),
4172 &final_layout.total,
4173 );
4174 let swatch_and_gap =
4175 built.theme.legend_key_width + built.theme.legend_spacing;
4176 let text_size = built.theme.legend_text.size;
4177 fn right_edge_of(
4183 legend_x: f64,
4184 swatch_and_gap: f64,
4185 text_size: f64,
4186 plan: &crate::guide::legend::LegendPlan,
4187 breaks: &[(f64, String)],
4188 ) -> f64 {
4189 plan.entries
4190 .iter()
4191 .filter_map(|e| breaks.get(e.break_idx).map(|(_, l)| (e, l)))
4192 .map(|(e, label)| {
4193 let text =
4194 e.label_override.as_deref().unwrap_or(label.as_str());
4195 legend_x
4196 + e.x_offset
4197 + swatch_and_gap
4198 + crate::render::text::text_width(text, text_size)
4199 })
4200 .fold(0.0_f64, f64::max)
4201 }
4202
4203 let mut updates: Vec<(
4204 crate::aes::Aesthetic,
4205 crate::guide::legend::LegendPlan,
4206 )> = Vec::new();
4207 let mut reduced_aes: Vec<crate::aes::Aesthetic> = Vec::new();
4214 for (aes, plan) in &plans {
4215 if plan.cols <= 1 {
4216 continue;
4217 }
4218 let Some(scale) = built.scales.get(aes) else {
4219 continue;
4220 };
4221 let breaks = scale.breaks();
4222 if right_edge_of(
4223 legend_x_final,
4224 swatch_and_gap,
4225 text_size,
4226 plan,
4227 &breaks,
4228 ) <= w as f64
4229 {
4230 continue; }
4232
4233 let n = breaks.len();
4236 let mut reduced: Vec<crate::guide::legend::LegendPlan> = Vec::new();
4237 for c in (1..plan.cols).rev() {
4238 let mut candidate_guide = built.guide_legend.clone();
4239 candidate_guide.ncol = Some(c);
4240 candidate_guide.nrow = None;
4241 let mut tmp_warnings = Vec::new();
4242 let candidate_guide =
4243 candidate_guide.validated(n, &mut tmp_warnings);
4244 if let Some(cand) = crate::guide::legend::plan_legend(
4245 &breaks,
4246 &candidate_guide,
4247 &built.theme,
4248 avail_width,
4249 layout0.plot_area.height,
4250 false,
4251 ) {
4252 reduced.push(cand);
4253 }
4254 }
4255 if let Some(fits) = reduced.iter().find(|c| {
4256 right_edge_of(legend_x_final, swatch_and_gap, text_size, c, &breaks)
4257 <= w as f64
4258 }) {
4259 extras.legend_extra_rows =
4260 extras.legend_extra_rows.max(fits.rows.saturating_sub(1));
4261 updates.push((aes.clone(), fits.clone()));
4262 reduced_aes.push(aes.clone());
4263 continue;
4264 }
4265
4266 let base = reduced.last().cloned().unwrap_or_else(|| plan.clone());
4271 extras.legend_extra_rows =
4272 extras.legend_extra_rows.max(base.rows.saturating_sub(1));
4273 let mut truncated = base.clone();
4274 for e in &mut truncated.entries {
4275 let Some((_, label)) = breaks.get(e.break_idx) else {
4276 continue;
4277 };
4278 let avail = (w as f64
4279 - (legend_x_final + e.x_offset + swatch_and_gap))
4280 .max(0.0);
4281 if let Some(short) =
4282 crate::render::text::truncate_to_width(label, avail, text_size)
4283 {
4284 e.label_override = Some(short);
4285 }
4286 }
4287
4288 let truncated_edge = right_edge_of(
4292 legend_x_final,
4293 swatch_and_gap,
4294 text_size,
4295 &truncated,
4296 &breaks,
4297 );
4298 if truncated_edge > w as f64 {
4299 built.warnings.push(format!(
4300 "legend: the {}-column grid still doesn't fit the {w}px chart (needs about {} px)",
4301 truncated.cols,
4302 truncated_edge.ceil() as i64
4303 ));
4304 }
4305 updates.push((aes.clone(), truncated));
4306 }
4307 for (aes, new_plan) in &updates {
4308 plans.insert(aes.clone(), new_plan.clone());
4309 }
4310
4311 if !reduced_aes.is_empty() {
4352 let original_reserve = extras.legend_extra_width;
4353 let tighter_reserve = plans
4354 .values()
4355 .map(|p| p.cols.saturating_sub(1) as f64 * p.col_pitch)
4356 .fold(0.0_f64, f64::max);
4357 if tighter_reserve < original_reserve {
4358 let mut retry_extras = extras;
4359 retry_extras.legend_extra_width = tighter_reserve;
4360 let retry_layout = PlotLayout::compute_with_extras(
4361 w as f64,
4362 h as f64,
4363 &built.theme,
4364 has_title,
4365 has_subtitle,
4366 has_caption,
4367 has_legend,
4368 x_axis_top,
4369 y_label_width,
4370 x_label_height,
4371 retry_extras,
4372 );
4373 let (retry_x, _, _) = crate::guide::legend::legend_position(
4379 &built.theme,
4380 &retry_layout.plot_area,
4381 retry_extras.legend_extra_rows,
4382 (0.0, 0.0),
4383 &retry_layout.total,
4384 );
4385 let all_still_fit = plans.iter().all(|(aes, plan)| {
4386 let Some(scale) = built.scales.get(aes) else {
4387 return true;
4388 };
4389 let breaks = scale.breaks();
4390 right_edge_of(retry_x, swatch_and_gap, text_size, plan, &breaks)
4391 <= w as f64
4392 });
4393 if all_still_fit {
4394 extras.legend_extra_width = tighter_reserve;
4395 }
4396 }
4397 }
4398 }
4399 for (aes, plan) in &plans {
4400 if let Some(ov) = &plan.overflow {
4401 let n = built
4402 .scales
4403 .get(aes)
4404 .map(|s| s.breaks().len())
4405 .unwrap_or(ov.dropped);
4406 let shown = n.saturating_sub(ov.dropped);
4407 built.warnings.push(format!(
4408 "legend: {} of {n} entries don't fit the chart; the legend shows {shown} and \"+{} more\"",
4409 ov.dropped, ov.dropped
4410 ));
4411 }
4412 }
4413 }
4414 built.legend_plans = plans;
4420 }
4421 }
4422
4423 if has_legend
4434 && !matches!(
4435 built.theme.legend_position,
4436 crate::theme::LegendPosition::None
4437 )
4438 {
4439 let is_horizontal = match built.theme.legend_direction {
4440 Some(dir) => matches!(dir, crate::theme::LegendDirection::Horizontal),
4441 None => matches!(
4442 built.theme.legend_position,
4443 crate::theme::LegendPosition::Top | crate::theme::LegendPosition::Bottom
4444 ),
4445 };
4446 if is_horizontal {
4447 let legend_aes =
4448 crate::guide::legend::legend_scales_for(&built.scales, &built.suppressed_aes);
4449 let continuous_colourbar = legend_aes.iter().find_map(|aes| {
4450 if !matches!(
4451 aes,
4452 crate::aes::Aesthetic::Color | crate::aes::Aesthetic::Fill
4453 ) {
4454 return None;
4455 }
4456 let scale = built.scales.get(aes)?;
4457 if scale.is_discrete() {
4458 return None;
4459 }
4460 Some(scale)
4461 });
4462 if let Some(scale) = continuous_colourbar {
4463 let title = built
4464 .guide_legend
4465 .title
4466 .as_deref()
4467 .unwrap_or_else(|| scale.name());
4468 let bar_height = crate::guide::legend::continuous_horizontal_bar_height(
4469 &built.theme,
4470 !title.is_empty(),
4471 );
4472 let key_h = built
4473 .theme
4474 .legend_key_height
4475 .max(extras.legend_max_key_size);
4476 extras.continuous_horizontal_legend_extra_height =
4477 (bar_height - key_h).max(0.0);
4478 }
4479 }
4480 }
4481
4482 PlotLayout::compute_with_extras(
4483 w as f64,
4484 h as f64,
4485 &built.theme,
4486 has_title,
4487 has_subtitle,
4488 has_caption,
4489 has_legend,
4490 x_axis_top,
4491 y_label_width,
4492 x_label_height,
4493 extras,
4494 )
4495 }
4496
4497 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
4500 fn render_into<DB>(
4501 area: plotters::drawing::DrawingArea<DB, plotters::coord::Shift>,
4502 built: &crate::build::BuiltPlot,
4503 layout: &PlotLayout,
4504 ) -> Result<(), GGError>
4505 where
4506 DB: plotters::prelude::DrawingBackend,
4507 DB::ErrorType: 'static,
4508 {
4509 area.fill(&plotters::prelude::WHITE)
4510 .map_err(|e| GGError::Render(RenderError::BackendError(format!("{:?}", e))))?;
4511 let mut adapter = PlottersAdapter::new(&area, layout.plot_area.clone());
4512 PlotRenderer::render(built, &mut adapter).map_err(GGError::Render)?;
4513 area.present()
4514 .map_err(|e| GGError::Render(RenderError::BackendError(format!("{:?}", e))))?;
4515 Ok(())
4516 }
4517
4518 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
4521 pub fn ggsave(
4522 self,
4523 path: &str,
4524 width_inches: f64,
4525 height_inches: f64,
4526 dpi: f64,
4527 ) -> Result<(), GGError> {
4528 let w = (width_inches * dpi) as u32;
4529 let h = (height_inches * dpi) as u32;
4530 self.save_with_size(path, w, h)
4531 }
4532
4533 fn has_legend_mapping(&self) -> bool {
4548 use crate::guide::legend::is_legend_aesthetic;
4553 let plot_level = self
4554 .mapping
4555 .mappings
4556 .iter()
4557 .any(|m| is_legend_aesthetic(&m.aesthetic));
4558 plot_level
4559 || self.layers.iter().any(|layer| {
4560 if layer.show_legend == Some(false) {
4561 return false;
4562 }
4563 let effective = if layer.geom.inherit_aes() {
4564 self.mapping.merge(&layer.mapping)
4565 } else {
4566 layer.mapping.clone()
4567 };
4568 effective
4569 .mappings
4570 .iter()
4571 .any(|m| is_legend_aesthetic(&m.aesthetic))
4572 })
4573 }
4574}
4575
4576#[derive(Clone, Copy, Debug)]
4578pub(crate) struct RenderMeta {
4579 pub(crate) has_title: bool,
4580 pub(crate) has_subtitle: bool,
4581 pub(crate) has_caption: bool,
4582 pub(crate) has_legend: bool,
4583 pub(crate) legend_bottom_share: Option<f64>,
4584 pub(crate) legend_auto: Option<LegendAuto>,
4585}
4586
4587#[derive(Clone, Copy, Debug)]
4589pub(crate) struct LegendAuto {
4590 corners: [Option<crate::theme::LegendCorner>; 4],
4591 fallback: Option<LegendSide>,
4592}
4593
4594#[derive(Clone, Copy, Debug)]
4596enum LegendSide {
4597 Top,
4598 Right,
4599 Bottom,
4600 Left,
4601}
4602
4603impl LegendSide {
4604 fn position(self) -> crate::theme::LegendPosition {
4605 use crate::theme::LegendPosition as P;
4606 match self {
4607 LegendSide::Top => P::Top,
4608 LegendSide::Right => P::Right,
4609 LegendSide::Bottom => P::Bottom,
4610 LegendSide::Left => P::Left,
4611 }
4612 }
4613}
4614
4615#[derive(Debug)]
4617#[non_exhaustive]
4618pub enum GGError {
4619 Render(RenderError),
4620 UnsupportedFormat(String),
4621 Io(std::io::Error),
4622 ValidationError(String),
4623}
4624
4625impl std::fmt::Display for GGError {
4626 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4627 match self {
4628 GGError::Render(e) => write!(f, "Render error: {e}"),
4629 GGError::UnsupportedFormat(ext) => write!(f, "Unsupported output format: {ext}"),
4630 GGError::Io(e) => write!(f, "IO error: {e}"),
4631 GGError::ValidationError(msg) => write!(f, "Validation error: {msg}"),
4632 }
4633 }
4634}
4635
4636impl std::error::Error for GGError {}