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::density_ridges::GeomDensityRidges;
27use crate::geom::dotplot::GeomDotplot;
28use crate::geom::errorbar::GeomErrorbar;
29use crate::geom::freqpoly::GeomFreqpoly;
30use crate::geom::hex::GeomHex;
31use crate::geom::histogram::GeomHistogram;
32use crate::geom::jitter::GeomJitter;
33use crate::geom::line::GeomLine;
34use crate::geom::linerange::GeomLinerange;
35use crate::geom::path::GeomPath;
36use crate::geom::point::GeomPoint;
37use crate::geom::pointrange::GeomPointrange;
38use crate::geom::polygon::GeomPolygon;
39use crate::geom::qq::{GeomQQ, GeomQQLine};
40use crate::geom::rect::GeomRect;
41use crate::geom::refline::{GeomAbline, GeomHline, GeomVline};
42use crate::geom::ribbon::GeomRibbon;
43use crate::geom::rug::GeomRug;
44use crate::geom::segment::GeomSegment;
45use crate::geom::smooth::GeomSmooth;
46use crate::geom::spoke::GeomSpoke;
47use crate::geom::step::GeomStep;
48use crate::geom::text::{GeomLabel, GeomText};
49use crate::geom::tile::GeomTile;
50use crate::geom::violin::GeomViolin;
51use crate::geom::{Geom, GeomParams};
52use crate::position::Position;
53use crate::render::layout::PlotLayout;
54#[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
55use crate::render::plotters_backend::PlottersAdapter;
56use crate::render::renderer::PlotRenderer;
57use crate::render::RenderError;
58use crate::scale::continuous::ScaleContinuous;
59use crate::scale::transform::ScaleTransform;
60use crate::scale::Scale;
61use crate::stat::Stat;
62use crate::theme::Theme;
63
64mod stat_layers;
67
68#[derive(Clone, Debug, Default)]
70pub struct Labels {
71 pub title: Option<String>,
72 pub subtitle: Option<String>,
73 pub x: Option<String>,
74 pub y: Option<String>,
75 pub caption: Option<String>,
76 pub tag: Option<String>,
78}
79
80pub struct Layer {
82 pub data: Option<DataFrame>,
83 pub mapping: Aes,
84 pub geom: Box<dyn Geom>,
85 pub stat: Box<dyn Stat>,
86 pub position: Box<dyn Position>,
87 pub params: GeomParams,
88 pub show_legend: Option<bool>,
89 pub explicit_style: bool,
92 pub tooltip_template: Option<String>,
95}
96
97pub struct GGPlot {
99 pub(crate) data: DataFrame,
100 pub(crate) mapping: Aes,
101 pub(crate) layers: Vec<Layer>,
102 pub(crate) scales: Vec<Box<dyn Scale>>,
103 pub(crate) coord: Box<dyn Coord>,
104 pub(crate) theme: Theme,
105 pub(crate) labels: Labels,
106 pub(crate) facet: Facet,
107 pub(crate) annotations: Vec<Annotation>,
108 pub(crate) guide_legend: crate::guide::config::GuideLegend,
109 pub(crate) warnings: Vec<String>,
112 pub(crate) legend_bottom_share: Option<f64>,
114 pub(crate) legend_auto: Option<LegendAuto>,
116 pub(crate) default_aspect_ratio: Option<f64>,
119 pub(crate) hide_position_guides: bool,
122 pub(crate) hide_y_guides: bool,
124 pub(crate) locale: Option<crate::locale::Locale>,
126 pub(crate) svg_root_data: bool,
131 pub(crate) root_attrs: Vec<(String, String)>,
134 pub(crate) svg_warnings_attr: bool,
138 pub(crate) svg_formatted_values: bool,
142 pub(crate) layer_svg_attrs: Vec<(usize, String, String)>,
146 pub(crate) svg_title: Option<String>,
151 pub(crate) svg_desc: Option<String>,
156}
157
158impl GGPlot {
159 pub fn new(data: impl GGData) -> Self {
166 GGPlot {
167 data: data.into_dataframe(),
168 mapping: Aes::default(),
169 layers: Vec::new(),
170 scales: Vec::new(),
171 coord: Box::new(CoordCartesian::new()),
172 theme: Theme::default(),
173 labels: Labels::default(),
174 facet: Facet::default(),
175 annotations: Vec::new(),
176 guide_legend: crate::guide::config::GuideLegend::default(),
177 warnings: Vec::new(),
178 legend_bottom_share: None,
179 legend_auto: None,
180 default_aspect_ratio: None,
181 hide_position_guides: false,
182 hide_y_guides: false,
183 locale: None,
184 svg_root_data: true,
185 root_attrs: Vec::new(),
186 svg_warnings_attr: false,
187 svg_formatted_values: false,
188 layer_svg_attrs: Vec::new(),
189 svg_title: None,
190 svg_desc: None,
191 }
192 }
193
194 pub fn aes(mut self, mapping: Aes) -> Self {
196 self.warnings.extend(mapping.warnings.iter().cloned());
197 self.mapping = mapping;
198 self
199 }
200
201 pub fn geom_point(self) -> Self {
204 self.add_geom(GeomPoint::default())
205 }
206
207 pub fn geom_point_with(self, geom: GeomPoint) -> Self {
208 self.add_geom_with(geom)
209 }
210
211 pub fn geom_line(self) -> Self {
212 self.add_geom(GeomLine::default())
213 }
214
215 pub fn geom_line_with(self, geom: GeomLine) -> Self {
216 self.add_geom_with(geom)
217 }
218
219 pub fn geom_bar(self) -> Self {
220 self.add_geom(GeomBar::default())
221 }
222
223 pub fn geom_bar_with(self, geom: GeomBar) -> Self {
224 self.add_geom_with(geom)
225 }
226
227 pub fn geom_histogram(self) -> Self {
228 self.add_geom(GeomHistogram::default())
229 }
230
231 pub fn geom_histogram_with(self, geom: GeomHistogram) -> Self {
232 self.add_geom_with(geom)
233 }
234
235 pub fn geom_boxplot(self) -> Self {
236 self.add_geom(GeomBoxplot::default())
237 }
238
239 pub fn geom_boxplot_with(self, geom: GeomBoxplot) -> Self {
240 self.add_geom_with(geom)
241 }
242
243 pub fn geom_smooth(self) -> Self {
244 self.add_geom(GeomSmooth::default())
245 }
246
247 pub fn geom_smooth_with(self, geom: GeomSmooth) -> Self {
248 self.add_geom_with(geom)
249 }
250
251 pub fn geom_col(self) -> Self {
252 self.add_geom(GeomCol::default())
253 }
254
255 pub fn geom_col_with(self, geom: GeomCol) -> Self {
256 self.add_geom_with(geom)
257 }
258
259 pub fn geom_hline(self, yintercept: f64) -> Self {
263 self.add_refline(
264 GeomHline::new(yintercept),
265 false,
266 &[("yintercept", yintercept)],
267 )
268 }
269
270 pub fn geom_hline_with(self, geom: GeomHline) -> Self {
272 let y = geom.yintercept;
273 self.add_refline(geom, true, &[("yintercept", y)])
274 }
275
276 pub fn geom_hline_aes(self, mapping: Aes) -> Self {
300 self.add_geom(GeomHline::mapped()).layer_aes(mapping)
301 }
302
303 pub fn geom_hline_aes_with(self, geom: GeomHline, mapping: Aes) -> Self {
305 self.add_geom_with(geom).layer_aes(mapping)
306 }
307
308 pub fn geom_vline(self, xintercept: f64) -> Self {
311 self.add_refline(
312 GeomVline::new(xintercept),
313 false,
314 &[("xintercept", xintercept)],
315 )
316 }
317
318 pub fn geom_vline_with(self, geom: GeomVline) -> Self {
320 let x = geom.xintercept;
321 self.add_refline(geom, true, &[("xintercept", x)])
322 }
323
324 pub fn geom_vline_aes(self, mapping: Aes) -> Self {
327 self.add_geom(GeomVline::mapped()).layer_aes(mapping)
328 }
329
330 pub fn geom_vline_aes_with(self, geom: GeomVline, mapping: Aes) -> Self {
332 self.add_geom_with(geom).layer_aes(mapping)
333 }
334
335 pub fn geom_abline(self, slope: f64, intercept: f64) -> Self {
338 self.add_refline(
339 GeomAbline::new(slope, intercept),
340 false,
341 &[("slope", slope), ("intercept", intercept)],
342 )
343 }
344
345 pub fn geom_abline_with(self, geom: GeomAbline) -> Self {
347 let (b, a) = (geom.slope, geom.intercept);
348 self.add_refline(geom, true, &[("slope", b), ("intercept", a)])
349 }
350
351 pub fn geom_abline_aes(self, mapping: Aes) -> Self {
354 self.add_geom(GeomAbline::mapped()).layer_aes(mapping)
355 }
356
357 pub fn geom_abline_aes_with(self, geom: GeomAbline, mapping: Aes) -> Self {
359 self.add_geom_with(geom).layer_aes(mapping)
360 }
361
362 fn add_refline(
365 self,
366 geom: impl Geom + 'static,
367 explicit: bool,
368 values: &[(&str, f64)],
369 ) -> Self {
370 let mut data = DataFrame::new();
371 let mut mapping = Aes::new();
372 for (col, v) in values {
373 data.add_column(col.to_string(), vec![Value::Float(*v)]);
374 mapping = match *col {
375 "xintercept" => mapping.xintercept(col),
376 "yintercept" => mapping.yintercept(col),
377 "slope" => mapping.slope(col),
378 _ => mapping.intercept(col),
379 };
380 }
381 let plot = if explicit {
382 self.add_geom_with(geom)
383 } else {
384 self.add_geom(geom)
385 };
386 plot.layer_aes(mapping).layer_data(data)
387 }
388
389 pub fn geom_text(self) -> Self {
390 self.add_geom(GeomText::default())
391 }
392
393 pub fn geom_text_with(self, geom: GeomText) -> Self {
394 self.add_geom_with(geom)
395 }
396
397 #[cfg(feature = "ggpubr")]
402 pub fn stat_cor(self) -> Self {
403 self.geom_text().stat(crate::stat::cor::StatCor::default())
404 }
405
406 #[cfg(feature = "ggpubr")]
409 pub fn stat_cor_with(self, stat: crate::stat::cor::StatCor) -> Self {
410 self.geom_text().stat(stat)
411 }
412
413 #[cfg(feature = "ggpubr")]
418 pub fn stat_compare_means(self) -> Self {
419 self.geom_text()
420 .stat(crate::stat::compare_means::StatCompareMeans::default())
421 }
422
423 #[cfg(feature = "ggpubr")]
426 pub fn stat_compare_means_with(
427 self,
428 stat: crate::stat::compare_means::StatCompareMeans,
429 ) -> Self {
430 self.geom_text().stat(stat)
431 }
432
433 #[cfg(feature = "ggpubr")]
439 pub fn stat_compare_means_pairwise(self, comparisons: &[(&str, &str)]) -> Self {
440 self.stat_compare_means_pairwise_with(
441 crate::stat::compare_means::CompareMethod::Auto,
442 comparisons,
443 )
444 }
445
446 #[cfg(feature = "ggpubr")]
449 pub fn stat_compare_means_pairwise_with(
450 self,
451 method: crate::stat::compare_means::CompareMethod,
452 comparisons: &[(&str, &str)],
453 ) -> Self {
454 let col_for = |a: crate::aes::Aesthetic| {
456 self.mapping
457 .mappings
458 .iter()
459 .find(|m| m.aesthetic == a)
460 .map(|m| m.column.clone())
461 };
462 let (xcol, ycol) = match (
463 col_for(crate::aes::Aesthetic::X),
464 col_for(crate::aes::Aesthetic::Y),
465 ) {
466 (Some(x), Some(y)) => (x, y),
467 _ => return self,
468 };
469 let (xc, yc) = match (self.data.column(&xcol), self.data.column(&ycol)) {
470 (Some(x), Some(y)) => (x, y),
471 _ => return self,
472 };
473
474 let mut groups: Vec<(String, Vec<f64>)> = Vec::new();
476 let mut ymax = f64::NEG_INFINITY;
477 let mut ymin = f64::INFINITY;
478 for (xv, yv) in xc.iter().zip(yc.iter()) {
479 let y = match yv.as_f64() {
480 Some(y) if y.is_finite() => y,
481 _ => continue,
482 };
483 ymax = ymax.max(y);
484 ymin = ymin.min(y);
485 let key = xv.to_group_key();
486 if let Some(g) = groups.iter_mut().find(|(k, _)| *k == key) {
487 g.1.push(y);
488 } else {
489 groups.push((key, vec![y]));
490 }
491 }
492 if groups.len() < 2 {
493 return self;
494 }
495 let step = if ymax > ymin {
496 (ymax - ymin) * 0.12
497 } else {
498 1.0
499 };
500
501 let (mut xmin_v, mut xmax_v, mut y_v, mut label_v) =
503 (Vec::new(), Vec::new(), Vec::new(), Vec::new());
504 let mut placed = 0usize;
505 for (a, b) in comparisons {
506 let ga = groups.iter().find(|(k, _)| k == a).map(|g| &g.1);
507 let gb = groups.iter().find(|(k, _)| k == b).map(|g| &g.1);
508 let (ga, gb) = match (ga, gb) {
509 (Some(x), Some(y)) if x.len() >= 2 && y.len() >= 2 => (x, y),
510 _ => continue,
511 };
512 let p = match crate::stat::compare_means::pairwise_p(method, ga, gb) {
513 Some(p) => p,
514 None => continue,
515 };
516 xmin_v.push(Value::Str((*a).to_string()));
517 xmax_v.push(Value::Str((*b).to_string()));
518 y_v.push(Value::Float(ymax + step * (placed as f64 + 1.0)));
519 label_v.push(Value::Str(crate::stat::cor::format_p_value(p)));
520 placed += 1;
521 }
522 if xmin_v.is_empty() {
523 return self;
524 }
525
526 let data = vec![
527 ("xmin".to_string(), xmin_v),
528 ("xmax".to_string(), xmax_v),
529 ("y".to_string(), y_v),
530 ("label".to_string(), label_v),
531 ];
532 self.add_geom(crate::geom::bracket::GeomBracket::default())
533 .layer_data(data)
534 .layer_aes(Aes::new().xmin("xmin").xmax("xmax").y("y").label("label"))
535 }
536
537 pub fn geom_bracket(self, xmin: &str, xmax: &str, y: f64, label: &str) -> Self {
542 self.geom_bracket_many(
543 crate::geom::bracket::GeomBracket::default(),
544 &[(xmin, xmax, y, label)],
545 )
546 }
547
548 pub fn geom_bracket_many(
552 self,
553 geom: crate::geom::bracket::GeomBracket,
554 brackets: &[(&str, &str, f64, &str)],
555 ) -> Self {
556 let xmin = brackets
557 .iter()
558 .map(|b| Value::Str(b.0.to_string()))
559 .collect::<Vec<_>>();
560 let xmax = brackets
561 .iter()
562 .map(|b| Value::Str(b.1.to_string()))
563 .collect::<Vec<_>>();
564 let y = brackets
565 .iter()
566 .map(|b| Value::Float(b.2))
567 .collect::<Vec<_>>();
568 let label = brackets
569 .iter()
570 .map(|b| Value::Str(b.3.to_string()))
571 .collect::<Vec<_>>();
572 let data = vec![
573 ("xmin".to_string(), xmin),
574 ("xmax".to_string(), xmax),
575 ("y".to_string(), y),
576 ("label".to_string(), label),
577 ];
578 self.add_geom(geom)
579 .layer_data(data)
580 .layer_aes(Aes::new().xmin("xmin").xmax("xmax").y("y").label("label"))
581 }
582
583 pub fn geom_bracket_table(
592 mut self,
593 table: impl GGData,
594 spec: crate::geom::bracket::BracketTable,
595 ) -> Self {
596 let table = table.into_dataframe();
597 let col_for = |a: crate::aes::Aesthetic| {
598 self.mapping
599 .mappings
600 .iter()
601 .find(|m| m.aesthetic == a)
602 .map(|m| m.column.clone())
603 };
604 let x_levels: Vec<String> = col_for(crate::aes::Aesthetic::X)
607 .and_then(|c| self.data.column(&c))
608 .filter(|col| col.iter().any(|v| matches!(v, Value::Str(_))))
609 .map(|col| {
610 let mut seen = std::collections::HashSet::new();
611 col.iter()
612 .filter(|v| !v.is_na())
613 .map(|v| v.to_group_key())
614 .filter(|k| seen.insert(k.clone()))
615 .collect()
616 })
617 .unwrap_or_default();
618 let y_range = col_for(crate::aes::Aesthetic::Y)
619 .and_then(|c| self.data.column(&c))
620 .and_then(|col| {
621 let (lo, hi) = col
622 .iter()
623 .filter_map(|v| v.as_f64())
624 .filter(|v| v.is_finite())
625 .fold((f64::INFINITY, f64::NEG_INFINITY), |(lo, hi), v| {
626 (lo.min(v), hi.max(v))
627 });
628 (lo <= hi).then_some((lo, hi))
629 });
630 let mut warnings = Vec::new();
631 let resolved = spec.resolve(&table, &x_levels, y_range, &mut warnings);
632 self.warnings.extend(warnings);
633 match resolved {
634 Some(data) => self
635 .add_geom(crate::geom::bracket::GeomBracket::from(spec.geom))
636 .layer_data(data)
637 .layer_aes(Aes::new().xmin("xmin").xmax("xmax").y("y").label("label")),
638 None => self,
639 }
640 }
641
642 pub fn geom_text_repel(self) -> Self {
647 self.add_geom(crate::geom::repel::GeomTextRepel::default())
648 }
649
650 pub fn geom_text_repel_with(self, geom: crate::geom::repel::GeomTextRepel) -> Self {
653 self.add_geom_with(geom)
654 }
655
656 pub fn geom_label_repel(self) -> Self {
659 self.add_geom(crate::geom::repel::GeomLabelRepel::default())
660 }
661
662 pub fn geom_label_repel_with(self, geom: crate::geom::repel::GeomLabelRepel) -> Self {
664 self.add_geom_with(geom)
665 }
666
667 pub fn geom_label(self) -> Self {
668 self.add_geom(GeomLabel::default())
669 }
670
671 pub fn geom_label_with(self, geom: GeomLabel) -> Self {
672 self.add_geom_with(geom)
673 }
674
675 pub fn geom_area(self) -> Self {
676 self.add_geom(GeomArea::default())
677 }
678
679 pub fn geom_area_with(self, geom: GeomArea) -> Self {
680 self.add_geom_with(geom)
681 }
682
683 pub fn geom_ribbon(self) -> Self {
684 self.add_geom(GeomRibbon::default())
685 }
686
687 pub fn geom_ribbon_with(self, geom: GeomRibbon) -> Self {
688 self.add_geom_with(geom)
689 }
690
691 pub fn geom_errorbar(self) -> Self {
692 self.add_geom(GeomErrorbar::default())
693 }
694
695 pub fn geom_errorbar_with(self, geom: GeomErrorbar) -> Self {
696 self.add_geom_with(geom)
697 }
698
699 pub fn geom_segment(self) -> Self {
700 self.add_geom(GeomSegment::default())
701 }
702
703 pub fn geom_segment_with(self, geom: GeomSegment) -> Self {
704 self.add_geom_with(geom)
705 }
706
707 pub fn geom_density(self) -> Self {
708 self.add_geom(GeomDensity::default())
709 }
710
711 pub fn geom_density_with(self, geom: GeomDensity) -> Self {
712 self.add_geom_with(geom)
713 }
714
715 pub fn geom_rug(self) -> Self {
716 self.add_geom(GeomRug::default())
717 }
718
719 pub fn geom_rug_with(self, geom: GeomRug) -> Self {
720 self.add_geom_with(geom)
721 }
722
723 pub fn geom_jitter(self) -> Self {
724 self.add_geom(GeomJitter::default())
725 }
726
727 pub fn geom_jitter_with(self, geom: GeomJitter) -> Self {
728 self.add_geom_with(geom)
729 }
730
731 pub fn geom_path(self) -> Self {
732 self.add_geom(GeomPath::default())
733 }
734
735 pub fn geom_path_with(self, geom: GeomPath) -> Self {
736 self.add_geom_with(geom)
737 }
738
739 pub fn stat_ellipse(self) -> Self {
741 self.geom_path()
742 .stat(crate::stat::ellipse::StatEllipse::default())
743 }
744
745 pub fn stat_ellipse_level(self, level: f64) -> Self {
747 self.geom_path()
748 .stat(crate::stat::ellipse::StatEllipse::new(level))
749 }
750
751 #[cfg(feature = "regression")]
754 pub fn stat_quantile(mut self, taus: &[f64]) -> Self {
755 for &tau in taus {
756 self = self
757 .geom_path()
758 .stat(crate::stat::quantile::StatQuantile::new(tau));
759 }
760 self
761 }
762
763 #[cfg(feature = "regression")]
765 pub fn geom_quantile(self) -> Self {
766 self.stat_quantile(&[0.25, 0.5, 0.75])
767 }
768
769 pub fn geom_step(self) -> Self {
770 self.add_geom(GeomStep::default())
771 }
772
773 pub fn geom_step_with(self, geom: GeomStep) -> Self {
774 self.add_geom_with(geom)
775 }
776
777 pub fn geom_freqpoly(self) -> Self {
778 self.add_geom(GeomFreqpoly::default())
779 }
780
781 pub fn geom_freqpoly_with(self, geom: GeomFreqpoly) -> Self {
782 self.add_geom_with(geom)
783 }
784
785 pub fn geom_linerange(self) -> Self {
786 self.add_geom(GeomLinerange::default())
787 }
788
789 pub fn geom_linerange_with(self, geom: GeomLinerange) -> Self {
790 self.add_geom_with(geom)
791 }
792
793 pub fn geom_pointrange(self) -> Self {
794 self.add_geom(GeomPointrange::default())
795 }
796
797 pub fn geom_pointrange_with(self, geom: GeomPointrange) -> Self {
798 self.add_geom_with(geom)
799 }
800
801 pub fn geom_crossbar(self) -> Self {
802 self.add_geom(GeomCrossbar::default())
803 }
804
805 pub fn geom_crossbar_with(self, geom: GeomCrossbar) -> Self {
806 self.add_geom_with(geom)
807 }
808
809 pub fn geom_spoke(self) -> Self {
810 self.add_geom(GeomSpoke::default())
811 }
812
813 pub fn geom_spoke_with(self, geom: GeomSpoke) -> Self {
814 self.add_geom_with(geom)
815 }
816
817 pub fn geom_rect(self) -> Self {
818 self.add_geom(GeomRect::default())
819 }
820
821 pub fn geom_rect_with(self, geom: GeomRect) -> Self {
822 self.add_geom_with(geom)
823 }
824
825 pub fn geom_tile(self) -> Self {
826 self.add_geom(GeomTile::default())
827 }
828
829 pub fn geom_tile_with(self, geom: GeomTile) -> Self {
830 self.add_geom_with(geom)
831 }
832
833 pub fn geom_raster(self) -> Self {
835 self.add_geom(crate::geom::raster::GeomRaster::default())
836 }
837
838 pub fn geom_raster_with(self, geom: crate::geom::raster::GeomRaster) -> Self {
839 self.add_geom_with(geom)
840 }
841
842 pub fn geom_polygon(self) -> Self {
843 self.add_geom(GeomPolygon::default())
844 }
845
846 pub fn geom_polygon_with(self, geom: GeomPolygon) -> Self {
847 self.add_geom_with(geom)
848 }
849
850 #[cfg(feature = "sf")]
852 pub fn geom_sf(self) -> Self {
853 self.add_geom(crate::geom::sf::GeomSf::default())
854 }
855
856 #[cfg(feature = "sf")]
857 pub fn geom_sf_with(self, geom: crate::geom::sf::GeomSf) -> Self {
858 self.add_geom_with(geom)
859 }
860
861 #[cfg(feature = "sf")]
864 pub fn geom_sf_text(self) -> Self {
865 self.add_geom(crate::geom::sf_text::GeomSfText::default())
866 }
867
868 #[cfg(feature = "sf")]
869 pub fn geom_sf_text_with(self, geom: crate::geom::sf_text::GeomSfText) -> Self {
870 self.add_geom_with(geom)
871 }
872
873 #[cfg(feature = "sf")]
876 pub fn geom_sf_label(self) -> Self {
877 self.add_geom(crate::geom::sf_text::GeomSfLabel::default())
878 }
879
880 #[cfg(feature = "sf")]
881 pub fn geom_sf_label_with(self, geom: crate::geom::sf_text::GeomSfLabel) -> Self {
882 self.add_geom_with(geom)
883 }
884
885 #[cfg(feature = "sf")]
889 pub fn annotation_scale(self) -> Self {
890 self.add_geom(crate::geom::annotation_scale::GeomAnnotationScale::default())
891 }
892
893 #[cfg(feature = "sf")]
894 pub fn annotation_scale_with(
895 self,
896 geom: crate::geom::annotation_scale::GeomAnnotationScale,
897 ) -> Self {
898 self.add_geom_with(geom)
899 }
900
901 #[cfg(feature = "sf")]
904 pub fn annotation_north_arrow_with(
905 self,
906 geom: crate::geom::annotation_scale::GeomNorthArrow,
907 ) -> Self {
908 self.add_geom_with(geom)
909 }
910
911 #[cfg(feature = "sf")]
914 pub fn annotation_attribution(self, text: impl Into<String>) -> Self {
915 self.add_geom(crate::geom::annotation_scale::GeomAttribution::new(text))
916 }
917
918 #[cfg(feature = "tiles")]
926 pub fn annotation_map_tile(
927 self,
928 source: crate::geom::map_tile::TileSource,
929 fetcher: impl crate::geom::map_tile::TileFetcher + 'static,
930 ) -> Self {
931 self.annotation_map_tile_with(crate::geom::map_tile::GeomMapTile::new(source, fetcher))
932 }
933
934 #[cfg(feature = "tiles")]
937 pub fn annotation_map_tile_with(self, geom: crate::geom::map_tile::GeomMapTile) -> Self {
938 let attribution = geom.source.attribution.clone();
939 let mut plot = self.add_geom_with(geom);
940 if let Some(layer) = plot.layers.pop() {
942 plot.layers.insert(0, layer);
943 for (idx, ..) in plot.layer_svg_attrs.iter_mut() {
944 *idx += 1;
945 }
946 }
947 if attribution.is_empty() {
948 plot
949 } else {
950 plot.annotation_attribution(attribution)
951 }
952 }
953
954 #[cfg(feature = "sf")]
955 pub fn annotation_attribution_with(
956 self,
957 geom: crate::geom::annotation_scale::GeomAttribution,
958 ) -> Self {
959 self.add_geom_with(geom)
960 }
961
962 #[cfg(feature = "sf")]
970 pub fn bivariate_legend(
971 self,
972 geom: crate::geom::bivariate_legend::GeomBivariateLegend,
973 ) -> Self {
974 self.add_geom(geom)
975 }
976
977 #[cfg(feature = "sf")]
982 pub fn bivariate_legend_counts(
983 self,
984 geom: crate::geom::bivariate_legend::GeomBivariateLegendCounts,
985 ) -> Self {
986 self.add_geom(geom)
987 }
988
989 pub fn geom_curve(self) -> Self {
990 self.add_geom(GeomCurve::default())
991 }
992
993 pub fn geom_curve_with(self, geom: GeomCurve) -> Self {
994 self.add_geom_with(geom)
995 }
996
997 pub fn geom_violin(self) -> Self {
998 self.add_geom(GeomViolin::default())
999 }
1000
1001 pub fn geom_violin_with(self, geom: GeomViolin) -> Self {
1002 self.add_geom_with(geom)
1003 }
1004
1005 pub fn geom_density_ridges(self) -> Self {
1009 self.add_geom(GeomDensityRidges::default())
1010 }
1011
1012 pub fn geom_density_ridges_with(self, geom: GeomDensityRidges) -> Self {
1013 self.add_geom_with(geom)
1014 }
1015
1016 pub fn geom_dotplot(self) -> Self {
1017 self.add_geom(GeomDotplot::default())
1018 }
1019
1020 pub fn geom_dotplot_with(self, geom: GeomDotplot) -> Self {
1021 self.add_geom_with(geom)
1022 }
1023
1024 pub fn geom_qq(self) -> Self {
1025 self.add_geom(GeomQQ::default())
1026 }
1027
1028 pub fn geom_qq_with(self, geom: GeomQQ) -> Self {
1029 self.add_geom_with(geom)
1030 }
1031
1032 pub fn geom_qq_line(self) -> Self {
1033 self.add_geom(GeomQQLine::default())
1034 }
1035
1036 pub fn geom_qq_line_with(self, geom: GeomQQLine) -> Self {
1037 self.add_geom_with(geom)
1038 }
1039
1040 pub fn geom_bin2d(self) -> Self {
1041 self.add_geom(GeomBin2d::default())
1042 }
1043
1044 pub fn geom_bin2d_with(self, geom: GeomBin2d) -> Self {
1045 self.add_geom_with(geom)
1046 }
1047
1048 pub fn geom_hex(self) -> Self {
1049 self.add_geom(GeomHex::default())
1050 }
1051
1052 pub fn geom_hex_with(self, geom: GeomHex) -> Self {
1053 self.add_geom_with(geom)
1054 }
1055
1056 pub fn geom_count(self) -> Self {
1057 self.add_geom(GeomCount::default())
1058 }
1059
1060 pub fn geom_count_with(self, geom: GeomCount) -> Self {
1061 self.add_geom_with(geom)
1062 }
1063
1064 pub fn geom_contour(self) -> Self {
1065 self.add_geom(GeomContour::default())
1066 }
1067
1068 pub fn geom_contour_with(self, geom: GeomContour) -> Self {
1069 self.add_geom_with(geom)
1070 }
1071
1072 pub fn geom_contour_filled(self) -> Self {
1075 self.add_geom(GeomPolygon {
1076 line_width: 0.0,
1077 alpha: 1.0,
1078 ..GeomPolygon::default()
1079 })
1080 .stat(crate::stat::contour_filled::StatContourFilled::default())
1081 }
1082
1083 pub fn geom_density2d(self) -> Self {
1084 self.add_geom(GeomDensity2d::default())
1085 }
1086
1087 pub fn geom_density2d_with(self, geom: GeomDensity2d) -> Self {
1088 self.add_geom_with(geom)
1089 }
1090
1091 pub fn geom_waterfall(self) -> Self {
1097 self.default_styled(|p| {
1098 p.geom_waterfall_with(crate::geom::waterfall::GeomWaterfall::default())
1099 })
1100 }
1101
1102 pub fn geom_waterfall_with(self, geom: crate::geom::waterfall::GeomWaterfall) -> Self {
1109 use crate::scale::color::RGBAColor;
1110 use crate::stat::waterfall::{WATERFALL_DECREASE, WATERFALL_INCREASE, WATERFALL_TOTAL};
1111 let rgba = |(r, g, b): (u8, u8, u8)| RGBAColor::new(r, g, b);
1112 let mut values = vec![
1113 (WATERFALL_INCREASE, rgba(geom.up)),
1114 (WATERFALL_DECREASE, rgba(geom.down)),
1115 ];
1116 if geom.has_totals() {
1117 values.push((WATERFALL_TOTAL, rgba(geom.total)));
1118 }
1119 let fill_mapped = self
1120 .mapping
1121 .get_mapping(&crate::aes::Aesthetic::Fill)
1122 .is_some();
1123 let has_fill_scale = self
1124 .scales
1125 .iter()
1126 .any(|s| s.aesthetic() == crate::aes::Aesthetic::Fill);
1127 let mut plot = self.add_geom_with(geom);
1128 if !fill_mapped {
1129 plot = plot.layer_aes(Aes::new().after_stat_fill("direction"));
1130 if !has_fill_scale {
1131 plot = plot.scale_fill_manual(values);
1132 }
1133 }
1134 plot
1135 }
1136
1137 pub fn geom_pareto(self) -> Self {
1141 self.add_pareto(crate::geom::pareto::GeomPareto::default(), false)
1142 }
1143
1144 pub fn geom_pareto_with(self, geom: crate::geom::pareto::GeomPareto) -> Self {
1150 self.add_pareto(geom, true)
1151 }
1152
1153 fn add_pareto(self, geom: crate::geom::pareto::GeomPareto, explicit: bool) -> Self {
1154 let has_y_scale = self
1155 .scales
1156 .iter()
1157 .any(|s| s.aesthetic() == crate::aes::Aesthetic::Y);
1158 let plot = if explicit {
1159 self.add_geom_with(geom)
1160 } else {
1161 self.add_geom(geom)
1162 };
1163 if has_y_scale {
1164 plot
1165 } else {
1166 plot.scale_y_continuous(ScaleContinuous::new().with_sec_axis(
1167 crate::scale::sec_axis::SecAxis::percent_of_max().with_name("Cumulative %"),
1168 ))
1169 }
1170 }
1171
1172 pub fn geom_sankey(self) -> Self {
1179 self.add_sankey(crate::geom::sankey::GeomSankey::default(), false)
1180 }
1181
1182 pub fn geom_sankey_with(self, geom: crate::geom::sankey::GeomSankey) -> Self {
1184 self.add_sankey(geom, true)
1185 }
1186
1187 fn add_sankey(self, geom: crate::geom::sankey::GeomSankey, explicit: bool) -> Self {
1188 let mut plot = if explicit {
1189 self.add_geom_with(geom)
1190 } else {
1191 self.add_geom(geom)
1192 };
1193 plot.hide_position_guides = true;
1194 plot.layer_aes(Aes::new().after_stat_fill("node"))
1195 .show_legend(false)
1196 }
1197
1198 pub fn geom_chord(self) -> Self {
1205 self.add_chord(crate::geom::chord::GeomChord::default(), false)
1206 }
1207
1208 pub fn geom_chord_with(self, geom: crate::geom::chord::GeomChord) -> Self {
1210 self.add_chord(geom, true)
1211 }
1212
1213 fn add_chord(self, geom: crate::geom::chord::GeomChord, explicit: bool) -> Self {
1214 let (ex, ey) = geom.extents();
1215 let mut plot = if explicit {
1216 self.add_geom_with(geom)
1217 } else {
1218 self.add_geom(geom)
1219 };
1220 plot.hide_position_guides = true;
1221 plot.default_aspect_ratio = Some(ey / ex);
1222 plot.layer_aes(Aes::new().after_stat_fill("node"))
1223 .show_legend(false)
1224 }
1225
1226 pub fn geom_arcdiagram(self) -> Self {
1231 self.add_arcdiagram(crate::geom::arcdiagram::GeomArcdiagram::default(), false)
1232 }
1233
1234 pub fn geom_arcdiagram_with(self, geom: crate::geom::arcdiagram::GeomArcdiagram) -> Self {
1237 self.add_arcdiagram(geom, true)
1238 }
1239
1240 fn add_arcdiagram(self, geom: crate::geom::arcdiagram::GeomArcdiagram, explicit: bool) -> Self {
1241 let mut plot = if explicit {
1242 self.add_geom_with(geom)
1243 } else {
1244 self.add_geom(geom)
1245 };
1246 plot.hide_position_guides = true;
1247 plot.layer_aes(Aes::new().after_stat_fill("node"))
1248 .show_legend(false)
1249 }
1250
1251 pub fn geom_treemap(self) -> Self {
1259 self.add_treemap(crate::geom::treemap::GeomTreemap::default(), false)
1260 }
1261
1262 pub fn geom_treemap_with(self, geom: crate::geom::treemap::GeomTreemap) -> Self {
1264 self.add_treemap(geom, true)
1265 }
1266
1267 fn add_treemap(self, geom: crate::geom::treemap::GeomTreemap, explicit: bool) -> Self {
1268 use crate::aes::Aesthetic;
1269 let aspect = geom.aspect;
1270 let has = |plot: &Self, aes: Aesthetic| plot.scales.iter().any(|s| s.aesthetic() == aes);
1271 let (has_x, has_y) = (has(&self, Aesthetic::X), has(&self, Aesthetic::Y));
1272 let fill_by = match (
1273 self.mapping.get_mapping(&Aesthetic::Fill),
1274 self.mapping.get_mapping(&Aesthetic::Subgroup),
1275 ) {
1276 (None, Some(sub)) => Some(sub.to_string()),
1277 _ => None,
1278 };
1279 let mut plot = if explicit {
1280 self.add_geom_with(geom)
1281 } else {
1282 self.add_geom(geom)
1283 };
1284 plot.hide_position_guides = true;
1285 plot.default_aspect_ratio = Some(1.0 / aspect.max(1e-6));
1286 if let Some(sub) = fill_by {
1287 plot = plot.layer_aes(Aes::new().fill(&sub));
1288 }
1289 if !has_x {
1290 plot = plot.scale_x_continuous(ScaleContinuous::new().with_expand(0.0, 0.0));
1291 }
1292 if !has_y {
1293 plot = plot.scale_y_continuous(ScaleContinuous::new().with_expand(0.0, 0.0));
1294 }
1295 plot
1296 }
1297
1298 pub fn geom_sunburst<S: Into<String>>(self, levels: impl IntoIterator<Item = S>) -> Self {
1305 let geom = crate::geom::partition::GeomPartition::sunburst(levels);
1306 let depth = geom.levels.len().max(1) as f64;
1308 let inner = geom.hole / (geom.hole + depth);
1309 let mut plot = self.default_styled(|p| p.geom_partition_with(geom));
1310 plot.coord = Box::new(CoordPolar::new().inner_radius(inner));
1311 plot
1312 }
1313
1314 pub fn geom_icicle<S: Into<String>>(self, levels: impl IntoIterator<Item = S>) -> Self {
1318 self.default_styled(|p| {
1319 p.geom_partition_with(crate::geom::partition::GeomPartition::icicle(levels))
1320 })
1321 }
1322
1323 pub fn geom_partition_with(self, geom: crate::geom::partition::GeomPartition) -> Self {
1327 use crate::aes::Aesthetic;
1328 let has = |plot: &Self, aes: Aesthetic| plot.scales.iter().any(|s| s.aesthetic() == aes);
1329 let (has_x, has_y) = (has(&self, Aesthetic::X), has(&self, Aesthetic::Y));
1330 let fill_mapped = self.mapping.get_mapping(&Aesthetic::Fill).is_some();
1331 let mut plot = self.add_geom_with(geom);
1332 plot.hide_position_guides = true;
1333 if !fill_mapped {
1334 plot = plot
1335 .layer_aes(Aes::new().after_stat_fill("root"))
1336 .show_legend(false);
1337 }
1338 if !has_x {
1339 plot = plot.scale_x_continuous(ScaleContinuous::new().with_expand(0.0, 0.0));
1340 }
1341 if !has_y {
1342 plot = plot.scale_y_continuous(ScaleContinuous::new().with_expand(0.0, 0.0));
1343 }
1344 plot
1345 }
1346
1347 pub fn geom_funnel(self) -> Self {
1355 self.default_styled(|p| p.geom_funnel_with(crate::geom::funnel::GeomFunnel::default()))
1356 }
1357
1358 pub fn geom_pyramid(self) -> Self {
1360 self.default_styled(|p| p.geom_funnel_with(crate::geom::funnel::GeomFunnel::pyramid()))
1361 }
1362
1363 pub fn geom_funnel_with(self, geom: crate::geom::funnel::GeomFunnel) -> Self {
1365 let fill_mapped = self
1366 .mapping
1367 .get_mapping(&crate::aes::Aesthetic::Fill)
1368 .is_some();
1369 let mut plot = self.add_geom_with(geom);
1370 plot.hide_position_guides = true;
1371 if !fill_mapped {
1372 plot = plot
1373 .layer_aes(Aes::new().after_stat_fill("stage"))
1374 .show_legend(false);
1375 }
1376 plot
1377 }
1378
1379 pub fn geom_stream(self) -> Self {
1385 self.geom_area().position(
1386 crate::position::stack::position_stack()
1387 .with_offset(crate::position::stack::StackOffset::Wiggle),
1388 )
1389 }
1390
1391 pub fn geom_lollipop(self) -> Self {
1394 self.add_geom(crate::geom::lollipop::GeomLollipop::default())
1395 }
1396
1397 pub fn geom_lollipop_with(self, geom: crate::geom::lollipop::GeomLollipop) -> Self {
1398 self.add_geom_with(geom)
1399 }
1400
1401 pub fn geom_dumbbell(self) -> Self {
1405 self.add_geom(crate::geom::lollipop::GeomDumbbell::default())
1406 }
1407
1408 pub fn geom_dumbbell_with(self, geom: crate::geom::lollipop::GeomDumbbell) -> Self {
1409 self.add_geom_with(geom)
1410 }
1411
1412 pub fn geom_bullet(self, geom: crate::geom::bullet::GeomBullet) -> Self {
1418 self.add_geom_with(geom).coord_flip()
1419 }
1420
1421 pub fn geom_bullet_vertical(self, geom: crate::geom::bullet::GeomBullet) -> Self {
1423 self.add_geom_with(geom)
1424 }
1425
1426 pub fn geom_waffle(self, rows: usize) -> Self {
1430 self.default_styled(|p| p.geom_waffle_with(crate::geom::waffle::GeomWaffle::waffle(rows)))
1431 }
1432
1433 pub fn geom_parliament(self, rows: usize) -> Self {
1437 self.default_styled(|p| {
1438 p.geom_waffle_with(crate::geom::waffle::GeomWaffle::parliament(rows))
1439 })
1440 }
1441
1442 pub fn geom_waffle_with(self, geom: crate::geom::waffle::GeomWaffle) -> Self {
1444 let mut plot = self.add_geom_with(geom);
1445 plot.hide_position_guides = true;
1446 plot
1447 }
1448
1449 pub fn geom_packed_bubble(self) -> Self {
1454 self.default_styled(|p| {
1455 p.geom_packed_bubble_with(crate::geom::pack::GeomPackedBubble::default())
1456 })
1457 }
1458
1459 pub fn geom_packed_bubble_with(self, geom: crate::geom::pack::GeomPackedBubble) -> Self {
1461 use crate::aes::Aesthetic;
1462 let fill_by = match (
1463 self.mapping.get_mapping(&Aesthetic::Fill),
1464 self.mapping.get_mapping(&Aesthetic::Subgroup),
1465 ) {
1466 (None, Some(sub)) => Some(sub.to_string()),
1467 _ => None,
1468 };
1469 let mut plot = self.add_geom_with(geom);
1470 plot.hide_position_guides = true;
1471 plot.default_aspect_ratio = Some(1.0);
1472 if let Some(sub) = fill_by {
1473 plot = plot.layer_aes(Aes::new().fill(&sub));
1474 }
1475 plot
1476 }
1477
1478 pub fn geom_network(self) -> Self {
1484 self.add_network(crate::geom::network::GeomNetwork::default(), false)
1485 }
1486
1487 pub fn geom_network_with(self, geom: crate::geom::network::GeomNetwork) -> Self {
1489 self.add_network(geom, true)
1490 }
1491
1492 fn add_network(self, geom: crate::geom::network::GeomNetwork, explicit: bool) -> Self {
1493 let by_component = geom.color_components;
1494 let mut plot = if explicit {
1495 self.add_geom_with(geom)
1496 } else {
1497 self.add_geom(geom)
1498 };
1499 plot.hide_position_guides = true;
1500 plot.default_aspect_ratio = Some(1.0);
1501 if by_component {
1502 plot = plot
1503 .layer_aes(Aes::new().after_stat_fill("component"))
1504 .show_legend(false);
1505 }
1506 plot
1507 }
1508
1509 pub fn geom_tree(self) -> Self {
1516 self.default_styled(|p| p.geom_tree_with(crate::geom::tree::GeomTree::default()))
1517 }
1518
1519 pub fn geom_dendrogram(self) -> Self {
1523 self.default_styled(|p| p.geom_tree_with(crate::geom::tree::GeomTree::dendrogram()))
1524 }
1525
1526 pub fn geom_tree_with(self, geom: crate::geom::tree::GeomTree) -> Self {
1528 let radial = geom.orientation == crate::stat::tree::TreeOrientation::Radial;
1529 let mut plot = self.add_geom_with(geom);
1530 plot.hide_position_guides = true;
1531 if radial {
1532 plot.default_aspect_ratio = Some(1.0);
1533 }
1534 plot
1535 }
1536
1537 pub fn geom_venn(self) -> Self {
1543 self.default_styled(|p| p.geom_venn_with(crate::geom::venn::GeomVenn::default()))
1544 }
1545
1546 pub fn geom_venn_with(self, geom: crate::geom::venn::GeomVenn) -> Self {
1548 let mut plot = self.add_geom_with(geom);
1549 plot.hide_position_guides = true;
1550 plot.default_aspect_ratio = Some(1.0);
1551 plot.layer_aes(Aes::new().after_stat_fill("set"))
1552 .show_legend(false)
1553 }
1554
1555 pub fn geom_wordcloud(self) -> Self {
1560 self.default_styled(|p| {
1561 p.geom_wordcloud_with(crate::geom::wordcloud::GeomWordcloud::default())
1562 })
1563 }
1564
1565 pub fn geom_wordcloud_with(self, geom: crate::geom::wordcloud::GeomWordcloud) -> Self {
1568 let mut plot = self.add_geom_with(geom);
1569 plot.hide_position_guides = true;
1570 plot
1571 }
1572
1573 pub fn geom_variwide(self) -> Self {
1578 self.default_styled(|p| {
1579 p.geom_marimekko_with(crate::geom::marimekko::GeomMarimekko::variwide())
1580 })
1581 }
1582
1583 pub fn geom_marimekko(self) -> Self {
1587 self.default_styled(|p| {
1588 p.geom_marimekko_with(crate::geom::marimekko::GeomMarimekko::marimekko())
1589 })
1590 }
1591
1592 pub fn geom_marimekko_with(self, geom: crate::geom::marimekko::GeomMarimekko) -> Self {
1594 use crate::aes::Aesthetic;
1595 let has = |plot: &Self, aes: Aesthetic| plot.scales.iter().any(|s| s.aesthetic() == aes);
1596 let (has_x, has_y) = (has(&self, Aesthetic::X), has(&self, Aesthetic::Y));
1597 let axis = self.mapping.get_mapping(&Aesthetic::X).and_then(|xc| {
1599 let x = self.data.column(xc)?;
1600 let w = self
1601 .mapping
1602 .get_mapping(&Aesthetic::Weight)
1603 .and_then(|wc| self.data.column(wc));
1604 let totals = crate::stat::marimekko::column_totals(x, w);
1605 let widths: Vec<f64> = totals.iter().map(|t| t.1).collect();
1606 let spans = crate::stat::marimekko::column_spans(&widths, geom.gap);
1607 Some((
1608 spans
1609 .iter()
1610 .map(|s| (s.0 + s.1) / 2.0)
1611 .collect::<Vec<f64>>(),
1612 totals.into_iter().map(|t| t.0).collect::<Vec<String>>(),
1613 ))
1614 });
1615 let mosaic = geom.mosaic;
1616 let mut plot = self.add_geom_with(geom);
1617 if !has_x {
1618 let mut sx = ScaleContinuous::new().with_expand(0.0, 0.0);
1619 if let Some((breaks, labels)) = axis {
1620 sx = sx.with_breaks(breaks).with_labels(labels);
1621 }
1622 plot = plot.scale_x_continuous(sx);
1623 }
1624 if mosaic && !has_y {
1625 plot = plot.scale_y_continuous(
1626 ScaleContinuous::new()
1627 .with_expand(0.0, 0.0)
1628 .with_label_formatter(|v| format!("{}%", (v * 100.0).round())),
1629 );
1630 }
1631 plot
1632 }
1633
1634 pub fn geom_timeline(self) -> Self {
1639 let mut plot = self.add_geom(crate::geom::timeline::GeomTimeline::default());
1640 plot.hide_y_guides = true;
1641 plot
1642 }
1643
1644 pub fn geom_timeline_with(self, geom: crate::geom::timeline::GeomTimeline) -> Self {
1646 let mut plot = self.add_geom_with(geom);
1647 plot.hide_y_guides = true;
1648 plot
1649 }
1650
1651 pub fn geom_xrange(self) -> Self {
1658 self.add_xrange(crate::geom::xrange::GeomXrange::default(), false)
1659 }
1660
1661 pub fn geom_xrange_with(self, geom: crate::geom::xrange::GeomXrange) -> Self {
1663 self.add_xrange(geom, true)
1664 }
1665
1666 fn add_xrange(self, geom: crate::geom::xrange::GeomXrange, explicit: bool) -> Self {
1667 use crate::aes::Aesthetic;
1668 let has_y = self.scales.iter().any(|s| s.aesthetic() == Aesthetic::Y);
1669 let levels: Option<Vec<String>> = self
1671 .mapping
1672 .get_mapping(&Aesthetic::Y)
1673 .and_then(|c| self.data.column(c))
1674 .map(|col| {
1675 let mut seen: indexmap::IndexSet<String> = indexmap::IndexSet::new();
1676 for v in col.iter().filter(|v| !v.is_na()) {
1677 seen.insert(v.key_str().into_owned());
1678 }
1679 seen.into_iter().rev().collect()
1680 });
1681 let mut plot = if explicit {
1682 self.add_geom_with(geom)
1683 } else {
1684 self.add_geom(geom)
1685 };
1686 if let (false, Some(levels)) = (has_y, levels) {
1687 let refs: Vec<&str> = levels.iter().map(String::as_str).collect();
1688 plot = plot
1689 .scale_y_discrete(crate::scale::discrete::ScaleDiscrete::new().with_limits(refs));
1690 }
1691 plot
1692 }
1693
1694 pub fn geom_tilemap(self, shape: crate::geom::tilemap::TileShape) -> Self {
1699 self.default_styled(|p| {
1700 p.geom_tilemap_with(crate::geom::tilemap::GeomTilemap {
1701 shape,
1702 ..Default::default()
1703 })
1704 })
1705 }
1706
1707 pub fn geom_tilemap_with(self, geom: crate::geom::tilemap::GeomTilemap) -> Self {
1709 let mut plot = self.add_geom_with(geom);
1710 plot.hide_position_guides = true;
1711 plot
1712 }
1713
1714 pub fn geom_windbarb(self, geom: crate::geom::windbarb::GeomWindbarb) -> Self {
1719 self.add_geom(geom)
1720 }
1721
1722 pub fn geom_variable_pie(self) -> Self {
1726 let mut plot = self.add_geom(crate::geom::variablepie::GeomVariablePie::default());
1727 plot.hide_position_guides = true;
1728 plot.default_aspect_ratio = Some(1.0);
1729 plot
1730 }
1731
1732 pub fn geom_variable_pie_with(self, geom: crate::geom::variablepie::GeomVariablePie) -> Self {
1735 let mut plot = self.add_geom_with(geom);
1736 plot.hide_position_guides = true;
1737 plot.default_aspect_ratio = Some(1.0);
1738 plot
1739 }
1740
1741 pub fn geom_hlc(self) -> Self {
1744 self.add_geom(crate::geom::candlestick::GeomOhlc::hlc())
1745 }
1746
1747 pub fn geom_heikin_ashi(self) -> Self {
1751 self.add_geom(crate::geom::candlestick::GeomCandlestick::default())
1752 .stat(crate::stat::heikin_ashi::StatHeikinAshi)
1753 }
1754
1755 pub fn geom_renko(self, box_size: f64) -> Self {
1759 self.add_geom(crate::geom::renko::GeomRenko::renko(box_size))
1760 .xlab("Brick")
1761 }
1762
1763 pub fn geom_point_figure(self, box_size: f64, reversal: usize) -> Self {
1767 self.add_geom(crate::geom::renko::GeomRenko::point_figure(
1768 box_size, reversal,
1769 ))
1770 .xlab("Column")
1771 }
1772
1773 pub fn geom_flags(self) -> Self {
1778 self.add_geom(crate::geom::flags::GeomFlags::default())
1779 }
1780
1781 pub fn geom_flags_with(self, geom: crate::geom::flags::GeomFlags) -> Self {
1782 self.add_geom_with(geom)
1783 }
1784
1785 #[cfg(feature = "sf")]
1790 pub fn geom_flow(self, geom: crate::geom::flow::GeomFlow) -> Self {
1791 self.add_geom(geom)
1792 }
1793
1794 pub fn geom_candlestick(self) -> Self {
1797 self.add_geom(crate::geom::candlestick::GeomCandlestick::default())
1798 }
1799
1800 pub fn geom_candlestick_with(self, geom: crate::geom::candlestick::GeomCandlestick) -> Self {
1801 self.add_geom_with(geom)
1802 }
1803
1804 pub fn geom_ohlc(self) -> Self {
1807 self.add_geom(crate::geom::candlestick::GeomOhlc::default())
1808 }
1809
1810 pub fn geom_ohlc_with(self, geom: crate::geom::candlestick::GeomOhlc) -> Self {
1811 self.add_geom_with(geom)
1812 }
1813
1814 pub fn geom_calendar(self) -> Self {
1825 self.geom_calendar_with(
1826 GeomTile {
1827 color: (255, 255, 255),
1828 line_width: 1.5,
1829 ..Default::default()
1830 },
1831 false,
1832 )
1833 }
1834
1835 pub fn geom_calendar_with(mut self, tile: GeomTile, monday_first: bool) -> Self {
1838 use crate::stat::calendar::{
1839 day_number, month_boundaries, month_breaks, month_breaks_localized, weekday_labels,
1840 CalendarGrid, StatCalendar, MAX_CALENDAR_YEARS,
1841 };
1842 let grid = self
1843 .mapping
1844 .get_mapping(&crate::aes::Aesthetic::X)
1845 .and_then(|c| self.data.column(c))
1846 .and_then(|col| {
1847 CalendarGrid::from_days(col.iter().filter_map(day_number), monday_first)
1848 });
1849 let Some((grid, clipped)) = grid else {
1850 return self.add_geom_with(tile).stat(StatCalendar {
1852 grid: None,
1853 monday_first,
1854 });
1855 };
1856 if clipped {
1857 self.warnings.push(format!(
1858 "geom_calendar: dates more than {MAX_CALENDAR_YEARS} years before the newest were dropped"
1859 ));
1860 }
1861 let (xb, _) = month_breaks(&grid);
1862 let yb = if monday_first {
1864 vec![6.0, 4.0, 2.0]
1865 } else {
1866 vec![5.0, 3.0, 1.0]
1867 };
1868 let segs = month_boundaries(&grid);
1869 let col = |f: fn(&(f64, f64, f64, f64)) -> f64| -> Vec<Value> {
1870 segs.iter().map(|s| Value::Float(f(s))).collect()
1871 };
1872 let boundaries = vec![
1873 ("x".to_string(), col(|s| s.0)),
1874 ("y".to_string(), col(|s| s.1)),
1875 ("xend".to_string(), col(|s| s.2)),
1876 ("yend".to_string(), col(|s| s.3)),
1877 ];
1878 self.default_aspect_ratio = Some(7.0 / grid.n_weeks().max(1) as f64);
1879 let plot = self
1880 .add_geom_with(tile)
1881 .stat(StatCalendar {
1882 grid: Some(grid),
1883 monday_first,
1884 })
1885 .scale_x_continuous(
1886 ScaleContinuous::new()
1887 .with_breaks(xb)
1888 .with_localized_labels(move |l| month_breaks_localized(&grid, l).1)
1890 .with_expand(0.0, 0.0),
1891 )
1892 .scale_y_continuous(
1893 ScaleContinuous::new()
1894 .with_breaks(yb)
1895 .with_localized_labels(weekday_labels)
1896 .with_expand(0.0, 0.0),
1897 );
1898 if segs.is_empty() {
1899 return plot;
1900 }
1901 plot.add_geom_with(crate::geom::segment::GeomCalendarBorder)
1903 .layer_data(boundaries)
1904 .layer_aes(Aes::new().x("x").y("y").xend("xend").yend("yend"))
1905 .show_legend(false)
1906 }
1907
1908 pub fn geom_blank(self) -> Self {
1909 self.add_geom(GeomBlank)
1910 }
1911
1912 fn default_styled(self, build: impl FnOnce(Self) -> Self) -> Self {
1919 let i = self.layers.len();
1920 let mut plot = build(self);
1921 if let Some(layer) = plot.layers.get_mut(i) {
1922 layer.explicit_style = false;
1923 }
1924 plot
1925 }
1926
1927 fn add_geom_with(self, geom: impl Geom + 'static) -> Self {
1928 let mut plot = self.add_geom(geom);
1929 if let Some(layer) = plot.layers.last_mut() {
1930 layer.explicit_style = true;
1931 }
1932 plot
1933 }
1934
1935 fn add_geom(mut self, geom: impl Geom + 'static) -> Self {
1936 let stat = geom.default_stat();
1937 let position = geom.default_position();
1938 let params = geom.default_params();
1939 self.layers.push(Layer {
1940 data: None,
1941 mapping: Aes::default(),
1942 geom: Box::new(geom),
1943 stat,
1944 position,
1945 params,
1946 show_legend: None,
1947 explicit_style: false,
1948 tooltip_template: None,
1949 });
1950 self
1951 }
1952
1953 pub fn stat(mut self, stat: impl Stat + 'static) -> Self {
1957 if let Some(layer) = self.layers.last_mut() {
1958 layer.stat = Box::new(stat);
1959 }
1960 self
1961 }
1962
1963 pub fn position(mut self, pos: impl Position + 'static) -> Self {
1965 if let Some(layer) = self.layers.last_mut() {
1966 layer.position = Box::new(pos);
1967 }
1968 self
1969 }
1970
1971 pub fn layer_data(mut self, data: impl GGData) -> Self {
1973 if let Some(layer) = self.layers.last_mut() {
1974 layer.data = Some(data.into_dataframe());
1975 }
1976 self
1977 }
1978
1979 pub fn layer_aes(mut self, mapping: Aes) -> Self {
1981 self.warnings.extend(mapping.warnings.iter().cloned());
1982 if let Some(layer) = self.layers.last_mut() {
1983 layer.mapping = mapping;
1984 }
1985 self
1986 }
1987
1988 pub fn tooltip(mut self, template: &str) -> Self {
1999 if let Some(layer) = self.layers.last_mut() {
2000 layer.tooltip_template = Some(template.to_string());
2001 }
2002 self
2003 }
2004
2005 pub fn show_legend(mut self, show: bool) -> Self {
2008 if let Some(layer) = self.layers.last_mut() {
2009 layer.show_legend = Some(show);
2010 }
2011 self
2012 }
2013
2014 pub fn decorative(mut self) -> Self {
2041 if let Some(layer) = self.layers.last_mut() {
2042 let geom = std::mem::replace(&mut layer.geom, Box::new(GeomBlank));
2043 layer.geom = Box::new(crate::geom::decorative::Decorative(geom));
2044 if layer.show_legend.is_none() {
2045 layer.show_legend = Some(false);
2046 }
2047 }
2048 self
2049 }
2050
2051 pub fn layer_svg_attr(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
2085 let (name, value) = (name.into(), value.into());
2086 let Some(idx) = self.layers.len().checked_sub(1) else {
2087 self.warnings.push(format!(
2088 "layer_svg_attr(\"{name}\") called before any layer was added — ignored"
2089 ));
2090 return self;
2091 };
2092 if let Some((n, v)) =
2093 crate::render::svg_backend::validate_layer_svg_attr(&name, &value, &mut self.warnings)
2094 {
2095 self.layer_svg_attrs
2096 .retain(|(i, k, _)| !(*i == idx && *k == n));
2097 self.layer_svg_attrs.push((idx, n, v));
2098 }
2099 self
2100 }
2101
2102 pub fn layer_svg_attrs<N: Into<String>, V: Into<String>>(
2104 self,
2105 attrs: impl IntoIterator<Item = (N, V)>,
2106 ) -> Self {
2107 attrs
2108 .into_iter()
2109 .fold(self, |p, (n, v)| p.layer_svg_attr(n, v))
2110 }
2111
2112 pub fn scale_x_continuous(mut self, s: ScaleContinuous) -> 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_continuous(mut self, s: ScaleContinuous) -> 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_x_discrete(mut self, s: crate::scale::discrete::ScaleDiscrete) -> Self {
2127 let s = s.for_aesthetic(crate::aes::Aesthetic::X);
2128 self.scales.push(Box::new(s));
2129 self
2130 }
2131
2132 pub fn scale_y_discrete(mut self, s: crate::scale::discrete::ScaleDiscrete) -> Self {
2133 let s = s.for_aesthetic(crate::aes::Aesthetic::Y);
2134 self.scales.push(Box::new(s));
2135 self
2136 }
2137
2138 pub fn scale_color(mut self, s: impl Scale + 'static) -> Self {
2139 self.scales.push(Box::new(s));
2140 self
2141 }
2142
2143 pub fn scale_fill(mut self, s: impl Scale + 'static) -> Self {
2144 self.scales.push(Box::new(s));
2145 self
2146 }
2147
2148 pub fn scale_color_manual(self, values: Vec<(&str, crate::scale::color::RGBAColor)>) -> Self {
2149 let s = crate::scale::manual::ScaleManual::new(crate::aes::Aesthetic::Color, values);
2150 self.scale_color(s)
2151 }
2152
2153 pub fn scale_fill_manual(self, values: Vec<(&str, crate::scale::color::RGBAColor)>) -> Self {
2154 let s = crate::scale::manual::ScaleManual::new(crate::aes::Aesthetic::Fill, values);
2155 self.scale_fill(s)
2156 }
2157
2158 pub fn scale_colour_identity(self) -> Self {
2161 let s = crate::scale::identity::ScaleColorIdentity::new(crate::aes::Aesthetic::Color);
2162 self.scale_color(s)
2163 }
2164
2165 pub fn scale_color_identity(self) -> Self {
2167 self.scale_colour_identity()
2168 }
2169
2170 pub fn scale_fill_identity(self) -> Self {
2173 let s = crate::scale::identity::ScaleColorIdentity::new(crate::aes::Aesthetic::Fill);
2174 self.scale_fill(s)
2175 }
2176
2177 pub fn scale_color_viridis(self) -> Self {
2178 use crate::scale::color::ScaleColorDiscrete;
2179 use crate::scale::palettes::PaletteName;
2180 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Color)
2181 .with_named_palette(&PaletteName::Viridis);
2182 self.scale_color(s)
2183 }
2184
2185 pub fn scale_color_brewer(self, name: crate::scale::palettes::PaletteName) -> Self {
2186 use crate::scale::color::ScaleColorDiscrete;
2187 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Color).with_named_palette(&name);
2188 self.scale_color(s)
2189 }
2190
2191 pub fn scale_color_gradient(
2192 self,
2193 low: crate::scale::color::RGBAColor,
2194 high: crate::scale::color::RGBAColor,
2195 ) -> Self {
2196 use crate::scale::color::ScaleColorContinuous;
2197 let s = ScaleColorContinuous::new(crate::aes::Aesthetic::Color).with_colors(low, high);
2198 self.scale_color(s)
2199 }
2200
2201 pub fn scale_fill_gradient(
2202 self,
2203 low: crate::scale::color::RGBAColor,
2204 high: crate::scale::color::RGBAColor,
2205 ) -> Self {
2206 use crate::scale::color::ScaleColorContinuous;
2207 let s = ScaleColorContinuous::new(crate::aes::Aesthetic::Fill).with_colors(low, high);
2208 self.scale_fill(s)
2209 }
2210
2211 pub fn scale_color_gradient2(
2212 self,
2213 low: crate::scale::color::RGBAColor,
2214 mid: crate::scale::color::RGBAColor,
2215 high: crate::scale::color::RGBAColor,
2216 ) -> Self {
2217 use crate::scale::gradient::ScaleColorGradient2;
2218 let s = ScaleColorGradient2::new(crate::aes::Aesthetic::Color).with_colors(low, mid, high);
2219 self.scale_color(s)
2220 }
2221
2222 pub fn scale_fill_gradient2(
2223 self,
2224 low: crate::scale::color::RGBAColor,
2225 mid: crate::scale::color::RGBAColor,
2226 high: crate::scale::color::RGBAColor,
2227 ) -> Self {
2228 use crate::scale::gradient::ScaleColorGradient2;
2229 let s = ScaleColorGradient2::new(crate::aes::Aesthetic::Fill).with_colors(low, mid, high);
2230 self.scale_fill(s)
2231 }
2232
2233 pub fn scale_fill_viridis(self) -> Self {
2234 use crate::scale::color::ScaleColorDiscrete;
2235 use crate::scale::palettes::PaletteName;
2236 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill)
2237 .with_named_palette(&PaletteName::Viridis);
2238 self.scale_fill(s)
2239 }
2240
2241 pub fn scale_color_viridis_c(self) -> Self {
2243 use crate::scale::gradient_n::ScaleColorGradientN;
2244 let s = ScaleColorGradientN::viridis(crate::aes::Aesthetic::Color);
2245 self.scale_color(s)
2246 }
2247
2248 pub fn scale_fill_viridis_c(self) -> Self {
2250 use crate::scale::gradient_n::ScaleColorGradientN;
2251 let s = ScaleColorGradientN::viridis(crate::aes::Aesthetic::Fill);
2252 self.scale_fill(s)
2253 }
2254
2255 pub fn scale_color_gradientn(self, stops: Vec<(f64, crate::scale::color::RGBAColor)>) -> Self {
2257 use crate::scale::gradient_n::ScaleColorGradientN;
2258 let s = ScaleColorGradientN::new(crate::aes::Aesthetic::Color, stops);
2259 self.scale_color(s)
2260 }
2261
2262 pub fn scale_fill_gradientn(self, stops: Vec<(f64, crate::scale::color::RGBAColor)>) -> Self {
2264 use crate::scale::gradient_n::ScaleColorGradientN;
2265 let s = ScaleColorGradientN::new(crate::aes::Aesthetic::Fill, stops);
2266 self.scale_fill(s)
2267 }
2268
2269 pub fn scale_color_steps(
2272 self,
2273 low: crate::scale::color::RGBAColor,
2274 high: crate::scale::color::RGBAColor,
2275 n_bins: usize,
2276 ) -> Self {
2277 let s = crate::scale::steps::ScaleColorSteps::two(
2278 crate::aes::Aesthetic::Color,
2279 (low.r, low.g, low.b),
2280 (high.r, high.g, high.b),
2281 n_bins,
2282 );
2283 self.scale_color(s)
2284 }
2285
2286 pub fn scale_color_stepsn(
2288 self,
2289 stops: Vec<crate::scale::color::RGBAColor>,
2290 n_bins: usize,
2291 ) -> Self {
2292 let s = crate::scale::steps::ScaleColorSteps::new(
2293 crate::aes::Aesthetic::Color,
2294 stops.iter().map(|c| (c.r, c.g, c.b)).collect(),
2295 n_bins,
2296 );
2297 self.scale_color(s)
2298 }
2299
2300 pub fn scale_color_fermenter(
2302 self,
2303 name: crate::scale::palettes::PaletteName,
2304 n_bins: usize,
2305 ) -> Self {
2306 let stops = crate::scale::palettes::palette(&name)
2307 .iter()
2308 .map(|c| (c.r, c.g, c.b))
2309 .collect();
2310 let s =
2311 crate::scale::steps::ScaleColorSteps::new(crate::aes::Aesthetic::Color, stops, n_bins);
2312 self.scale_color(s)
2313 }
2314
2315 pub fn scale_fill_steps(
2317 self,
2318 low: crate::scale::color::RGBAColor,
2319 high: crate::scale::color::RGBAColor,
2320 n_bins: usize,
2321 ) -> Self {
2322 let s = crate::scale::steps::ScaleColorSteps::two(
2323 crate::aes::Aesthetic::Fill,
2324 (low.r, low.g, low.b),
2325 (high.r, high.g, high.b),
2326 n_bins,
2327 );
2328 self.scale_fill(s)
2329 }
2330
2331 pub fn scale_fill_binned(
2342 self,
2343 breaks: Vec<f64>,
2344 low: crate::scale::color::RGBAColor,
2345 high: crate::scale::color::RGBAColor,
2346 ) -> Self {
2347 let s = crate::scale::binned::ScaleFillBinned::two(
2348 crate::aes::Aesthetic::Fill,
2349 breaks,
2350 (low.r, low.g, low.b),
2351 (high.r, high.g, high.b),
2352 );
2353 self.scale_fill(s)
2354 }
2355
2356 pub fn scale_fill_binned_with(
2360 self,
2361 breaks: Vec<f64>,
2362 colors: Vec<crate::scale::color::RGBAColor>,
2363 ) -> Self {
2364 let s = crate::scale::binned::ScaleFillBinned::new(
2365 crate::aes::Aesthetic::Fill,
2366 breaks,
2367 colors.iter().map(|c| (c.r, c.g, c.b)).collect(),
2368 );
2369 self.scale_fill(s)
2370 }
2371
2372 pub fn scale_fill_fermenter(
2374 self,
2375 name: crate::scale::palettes::PaletteName,
2376 n_bins: usize,
2377 ) -> Self {
2378 let stops = crate::scale::palettes::palette(&name)
2379 .iter()
2380 .map(|c| (c.r, c.g, c.b))
2381 .collect();
2382 let s =
2383 crate::scale::steps::ScaleColorSteps::new(crate::aes::Aesthetic::Fill, stops, n_bins);
2384 self.scale_fill(s)
2385 }
2386
2387 pub fn scale_fill_discrete_sorted(self) -> Self {
2392 use crate::scale::color::ScaleColorDiscrete;
2393 self.scale_fill(ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill).sorted())
2394 }
2395
2396 pub fn scale_color_discrete_sorted(self) -> Self {
2399 use crate::scale::color::ScaleColorDiscrete;
2400 self.scale_color(ScaleColorDiscrete::new(crate::aes::Aesthetic::Color).sorted())
2401 }
2402
2403 pub fn scale_fill_brewer(self, name: crate::scale::palettes::PaletteName) -> Self {
2404 use crate::scale::color::ScaleColorDiscrete;
2405 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill).with_named_palette(&name);
2406 self.scale_fill(s)
2407 }
2408
2409 pub fn scale_linetype_manual(
2410 self,
2411 values: Vec<(&str, crate::render::backend::Linetype)>,
2412 ) -> Self {
2413 let s = crate::scale::linetype_manual::ScaleLinetypeManual::new(values);
2414 self.scale_color(s)
2415 }
2416
2417 pub fn scale_shape_manual(
2418 self,
2419 values: Vec<(&str, crate::render::backend::PointShape)>,
2420 ) -> Self {
2421 let s = crate::scale::shape_manual::ScaleShapeManual::new(values);
2422 self.scale_color(s)
2423 }
2424
2425 pub fn scale_color_grey(self) -> Self {
2426 let s = crate::scale::grey::ScaleColorGrey::new(crate::aes::Aesthetic::Color);
2427 self.scale_color(s)
2428 }
2429
2430 pub fn scale_fill_grey(self) -> Self {
2431 let s = crate::scale::grey::ScaleColorGrey::new(crate::aes::Aesthetic::Fill);
2432 self.scale_fill(s)
2433 }
2434
2435 pub fn scale_color_grey_with(self, s: crate::scale::grey::ScaleColorGrey) -> Self {
2436 self.scale_color(s)
2437 }
2438
2439 pub fn scale_fill_grey_with(self, s: crate::scale::grey::ScaleColorGrey) -> Self {
2440 self.scale_fill(s)
2441 }
2442
2443 pub fn scale_x_reverse(self) -> Self {
2444 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reverse))
2445 }
2446
2447 pub fn scale_y_reverse(self) -> Self {
2448 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reverse))
2449 }
2450
2451 pub fn scale_x_datetime(mut self, s: crate::scale::datetime::ScaleDateTime) -> Self {
2452 let s = s.for_aesthetic(crate::aes::Aesthetic::X);
2453 self.scales.push(Box::new(s));
2454 self
2455 }
2456
2457 pub fn scale_y_datetime(mut self, s: crate::scale::datetime::ScaleDateTime) -> Self {
2458 let s = s.for_aesthetic(crate::aes::Aesthetic::Y);
2459 self.scales.push(Box::new(s));
2460 self
2461 }
2462
2463 pub fn scale_size(mut self, s: crate::scale::size::ScaleSizeContinuous) -> Self {
2464 self.scales.push(Box::new(s));
2465 self
2466 }
2467
2468 pub fn scale_size_area(mut self, max_size: f64) -> Self {
2472 self.scales.push(Box::new(
2473 crate::scale::size::ScaleSizeContinuous::new().area(max_size),
2474 ));
2475 self
2476 }
2477
2478 pub fn scale_alpha(mut self, s: crate::scale::alpha::ScaleAlphaContinuous) -> Self {
2479 self.scales.push(Box::new(s));
2480 self
2481 }
2482
2483 pub fn scale_linewidth(mut self, s: crate::scale::linewidth::ScaleLinewidthContinuous) -> Self {
2487 self.scales.push(Box::new(s));
2488 self
2489 }
2490
2491 pub fn xlim(self, min: f64, max: f64) -> Self {
2492 self.scale_x_continuous(ScaleContinuous::new().with_limits(min, max))
2493 }
2494
2495 pub fn ylim(self, min: f64, max: f64) -> Self {
2496 self.scale_y_continuous(ScaleContinuous::new().with_limits(min, max))
2497 }
2498
2499 pub fn scale_x_log10(self) -> Self {
2500 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log10))
2501 }
2502
2503 pub fn scale_y_log10(self) -> Self {
2504 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log10))
2505 }
2506
2507 pub fn scale_x_sqrt(self) -> Self {
2508 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Sqrt))
2509 }
2510
2511 pub fn scale_y_sqrt(self) -> Self {
2512 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Sqrt))
2513 }
2514
2515 pub fn scale_x_log2(self) -> Self {
2516 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log2))
2517 }
2518
2519 pub fn scale_y_log2(self) -> Self {
2520 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log2))
2521 }
2522
2523 pub fn scale_x_ln(self) -> Self {
2524 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Ln))
2525 }
2526
2527 pub fn scale_y_ln(self) -> Self {
2528 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Ln))
2529 }
2530
2531 pub fn scale_x_logit(self) -> Self {
2533 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Logit))
2534 }
2535
2536 pub fn scale_y_logit(self) -> Self {
2537 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Logit))
2538 }
2539
2540 pub fn scale_x_probit(self) -> Self {
2542 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Probit))
2543 }
2544
2545 pub fn scale_y_probit(self) -> Self {
2546 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Probit))
2547 }
2548
2549 pub fn scale_x_pseudo_log(self) -> Self {
2551 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::PseudoLog))
2552 }
2553
2554 pub fn scale_y_pseudo_log(self) -> Self {
2555 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::PseudoLog))
2556 }
2557
2558 pub fn scale_x_reciprocal(self) -> Self {
2560 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reciprocal))
2561 }
2562
2563 pub fn scale_y_reciprocal(self) -> Self {
2564 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reciprocal))
2565 }
2566
2567 pub fn scale_x_exp(self) -> Self {
2569 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Exp))
2570 }
2571
2572 pub fn scale_y_exp(self) -> Self {
2573 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Exp))
2574 }
2575
2576 pub fn scale_x_boxcox(self, lambda: f64) -> Self {
2578 self.scale_x_continuous(
2579 ScaleContinuous::new().with_transform(ScaleTransform::BoxCox(lambda)),
2580 )
2581 }
2582
2583 pub fn scale_y_boxcox(self, lambda: f64) -> Self {
2584 self.scale_y_continuous(
2585 ScaleContinuous::new().with_transform(ScaleTransform::BoxCox(lambda)),
2586 )
2587 }
2588
2589 pub fn facet_wrap(mut self, var: &str, ncol: Option<usize>) -> Self {
2592 self.facet = Facet::Wrap {
2593 var: var.to_string(),
2594 ncol,
2595 scales: FacetScales::Fixed,
2596 labeller: FacetLabeller::default(),
2597 levels: None,
2598 };
2599 self
2600 }
2601
2602 pub fn facet_wrap_free(mut self, var: &str, ncol: Option<usize>, scales: FacetScales) -> Self {
2603 self.facet = Facet::Wrap {
2604 var: var.to_string(),
2605 ncol,
2606 scales,
2607 labeller: FacetLabeller::default(),
2608 levels: None,
2609 };
2610 self
2611 }
2612
2613 pub fn facet_wrap_labeller(
2614 mut self,
2615 var: &str,
2616 ncol: Option<usize>,
2617 labeller: FacetLabeller,
2618 ) -> Self {
2619 self.facet = Facet::Wrap {
2620 var: var.to_string(),
2621 ncol,
2622 scales: FacetScales::Fixed,
2623 labeller,
2624 levels: None,
2625 };
2626 self
2627 }
2628
2629 pub fn facet_levels<S: AsRef<str>>(mut self, levels: &[S]) -> Self {
2636 if let Facet::Wrap { levels: l, .. } = &mut self.facet {
2637 let mut seen = Vec::<String>::new();
2638 for s in levels {
2639 if !seen.iter().any(|x| x == s.as_ref()) {
2640 seen.push(s.as_ref().to_string());
2641 }
2642 }
2643 *l = Some(seen);
2644 }
2645 self
2646 }
2647
2648 pub fn facet_grid(mut self, row: Option<&str>, col: Option<&str>) -> Self {
2649 self.facet = Facet::Grid {
2650 row_var: row.map(String::from),
2651 col_var: col.map(String::from),
2652 scales: FacetScales::Fixed,
2653 labeller: FacetLabeller::default(),
2654 space: FacetSpace::Fixed,
2655 };
2656 self
2657 }
2658
2659 pub fn facet_grid_free(
2660 mut self,
2661 row: Option<&str>,
2662 col: Option<&str>,
2663 scales: FacetScales,
2664 ) -> Self {
2665 self.facet = Facet::Grid {
2666 row_var: row.map(String::from),
2667 col_var: col.map(String::from),
2668 scales,
2669 labeller: FacetLabeller::default(),
2670 space: FacetSpace::Fixed,
2671 };
2672 self
2673 }
2674
2675 pub fn facet_grid_multi(
2679 mut self,
2680 row: Option<&str>,
2681 cols: &[&str],
2682 scales: FacetScales,
2683 space: FacetSpace,
2684 ) -> Self {
2685 let col_var = if cols.len() > 1 {
2686 let n = self.data.nrows();
2688 let mut combined = Vec::with_capacity(n);
2689 for i in 0..n {
2690 let parts: Vec<String> = cols
2691 .iter()
2692 .map(|c| {
2693 self.data
2694 .column(c)
2695 .and_then(|col| col.get(i))
2696 .map(|v| v.to_group_key())
2697 .unwrap_or_default()
2698 })
2699 .collect();
2700 combined.push(crate::data::Value::Str(parts.join(" . ")));
2701 }
2702 let name = "__facet_cols__".to_string();
2703 self.data.add_column(name.clone(), combined);
2704 Some(name)
2705 } else {
2706 cols.first().map(|s| s.to_string())
2707 };
2708 self.facet = Facet::Grid {
2709 row_var: row.map(String::from),
2710 col_var,
2711 scales,
2712 labeller: FacetLabeller::default(),
2713 space,
2714 };
2715 self
2716 }
2717
2718 pub fn facet_grid_space(
2721 mut self,
2722 row: Option<&str>,
2723 col: Option<&str>,
2724 scales: FacetScales,
2725 space: FacetSpace,
2726 ) -> Self {
2727 self.facet = Facet::Grid {
2728 row_var: row.map(String::from),
2729 col_var: col.map(String::from),
2730 scales,
2731 labeller: FacetLabeller::default(),
2732 space,
2733 };
2734 self
2735 }
2736
2737 pub fn facet_grid_labeller(
2738 mut self,
2739 row: Option<&str>,
2740 col: Option<&str>,
2741 labeller: FacetLabeller,
2742 ) -> Self {
2743 self.facet = Facet::Grid {
2744 row_var: row.map(String::from),
2745 col_var: col.map(String::from),
2746 scales: FacetScales::Fixed,
2747 labeller,
2748 space: FacetSpace::Fixed,
2749 };
2750 self
2751 }
2752
2753 pub fn coord_flip(mut self) -> Self {
2756 self.coord = Box::new(CoordFlip);
2757 self
2758 }
2759
2760 pub fn coord_fixed(mut self, ratio: f64) -> Self {
2761 self.coord = Box::new(CoordFixed::new(ratio));
2762 self
2763 }
2764
2765 #[cfg(feature = "sf")]
2769 pub fn coord_sf(mut self) -> Self {
2770 self.coord = Box::new(crate::coord::sf::CoordSf::new());
2771 self
2772 }
2773
2774 #[cfg(feature = "sf")]
2779 pub fn coord_sf_with(mut self, coord: crate::coord::sf::CoordSf) -> Self {
2780 self.coord = Box::new(coord);
2781 self
2782 }
2783
2784 pub fn svg_root_data(mut self, on: bool) -> Self {
2791 self.svg_root_data = on;
2792 self
2793 }
2794
2795 pub fn svg_attr(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
2805 self.root_attrs.push((name.into(), value.into()));
2806 self
2807 }
2808
2809 pub fn svg_attrs(mut self, attrs: impl IntoIterator<Item = (String, String)>) -> Self {
2811 self.root_attrs.extend(attrs);
2812 self
2813 }
2814
2815 pub fn svg_warnings_attr(mut self, on: bool) -> Self {
2820 self.svg_warnings_attr = on;
2821 self
2822 }
2823
2824 pub fn svg_formatted_values(mut self, on: bool) -> Self {
2833 self.svg_formatted_values = on;
2834 self
2835 }
2836
2837 pub fn svg_title(mut self, title: impl Into<String>) -> Self {
2847 self.svg_title = Some(title.into());
2848 self
2849 }
2850
2851 pub fn svg_desc(mut self, desc: impl Into<String>) -> Self {
2859 self.svg_desc = Some(desc.into());
2860 self
2861 }
2862
2863 pub fn coord_trans(mut self, x: Option<ScaleTransform>, y: Option<ScaleTransform>) -> Self {
2868 self.coord = Box::new(crate::coord::trans::CoordTrans::new(x, y));
2869 self
2870 }
2871
2872 pub fn coord_trans_y(self, y: ScaleTransform) -> Self {
2874 self.coord_trans(None, Some(y))
2875 }
2876
2877 pub fn coord_trans_x(self, x: ScaleTransform) -> Self {
2879 self.coord_trans(Some(x), None)
2880 }
2881
2882 pub fn coord_cartesian_zoom(
2884 mut self,
2885 xlim: Option<(f64, f64)>,
2886 ylim: Option<(f64, f64)>,
2887 ) -> Self {
2888 let mut c = CoordCartesian::new();
2889 if let Some((min, max)) = xlim {
2890 c = c.xlim(min, max);
2891 }
2892 if let Some((min, max)) = ylim {
2893 c = c.ylim(min, max);
2894 }
2895 self.coord = Box::new(c);
2896 self
2897 }
2898
2899 pub fn coord_polar(mut self) -> Self {
2900 self.coord = Box::new(CoordPolar::new());
2901 self
2902 }
2903
2904 pub fn coord_radar(mut self) -> Self {
2908 self.coord = Box::new(crate::coord::radar::CoordRadar::new());
2909 self
2910 }
2911
2912 pub fn coord_radar_with(mut self, coord: crate::coord::radar::CoordRadar) -> Self {
2913 self.coord = Box::new(coord);
2914 self
2915 }
2916
2917 pub fn coord_polar_with(mut self, coord: CoordPolar) -> Self {
2918 self.coord = Box::new(coord);
2919 self
2920 }
2921
2922 pub fn theme(mut self, theme: Theme) -> Self {
2927 self.apply_preset(theme);
2928 self
2929 }
2930
2931 fn apply_preset(&mut self, theme: Theme) {
2932 let primary = self.theme.primary;
2933 self.theme = theme;
2934 if self.theme.primary.is_none() {
2935 self.theme.primary = primary;
2936 }
2937 }
2938
2939 pub fn axis_text_x_angle(mut self, degrees: f64) -> Self {
2943 self.theme.axis_text_x.angle = degrees;
2944 self
2945 }
2946
2947 pub fn axis_text_y_angle(mut self, degrees: f64) -> Self {
2949 self.theme.axis_text_y.angle = degrees;
2950 self
2951 }
2952
2953 pub fn axis_text_x_dodge(mut self, n: usize) -> Self {
2956 self.theme.axis_text_x_dodge = n.max(1);
2957 self
2958 }
2959
2960 pub fn aspect_ratio(mut self, ratio: f64) -> Self {
2963 self.theme.aspect_ratio = Some(ratio);
2964 self
2965 }
2966
2967 pub fn panel_ontop(mut self) -> Self {
2969 self.theme.panel_ontop = true;
2970 self
2971 }
2972
2973 pub fn axis_minor_ticks(mut self) -> Self {
2975 self.theme.axis_minor_ticks = true;
2976 self
2977 }
2978
2979 pub fn axis_text_x_fit(mut self, fit: crate::theme::AxisLabelFit) -> Self {
2984 self.theme.axis_text_x_fit = fit;
2985 self
2986 }
2987
2988 pub fn axis_text_x_check_overlap(mut self, on: bool) -> Self {
2991 self.theme.axis_text_x_check_overlap = on;
2992 self
2993 }
2994
2995 pub fn title_position(mut self, pos: crate::theme::TitlePosition) -> Self {
2998 self.theme.title_position = pos;
2999 self
3000 }
3001
3002 pub fn tag_position(mut self, pos: crate::theme::TagPosition) -> Self {
3004 self.theme.tag_position = pos;
3005 self
3006 }
3007
3008 pub fn legend_direction(mut self, dir: crate::theme::LegendDirection) -> Self {
3010 self.theme.legend_direction = Some(dir);
3011 self
3012 }
3013
3014 pub fn legend_position_inside(mut self, x: f64, y: f64) -> Self {
3021 self.theme.legend_position = crate::theme::LegendPosition::Inside(x, y);
3022 self
3023 }
3024
3025 pub fn legend_position(mut self, pos: crate::theme::LegendPosition) -> Self {
3027 self.theme.legend_position = pos;
3028 self
3029 }
3030
3031 pub fn legend_bottom_when_narrow(mut self, share: f64) -> Self {
3038 self.legend_bottom_share = Some(share);
3039 self
3040 }
3041
3042 pub fn legend_inside_auto(self) -> Self {
3053 self.legend_inside_auto_with(&crate::theme::LegendCorner::ALL, None)
3054 }
3055
3056 pub fn legend_inside_auto_with(
3061 mut self,
3062 corners: &[crate::theme::LegendCorner],
3063 fallback: Option<crate::theme::LegendPosition>,
3064 ) -> Self {
3065 use crate::theme::LegendPosition as P;
3066 let mut c = [None; 4];
3067 for (slot, corner) in c.iter_mut().zip(corners) {
3068 *slot = Some(*corner);
3069 }
3070 let fallback = match fallback {
3071 Some(P::Top) => Some(LegendSide::Top),
3072 Some(P::Right) => Some(LegendSide::Right),
3073 Some(P::Bottom) => Some(LegendSide::Bottom),
3074 Some(P::Left) => Some(LegendSide::Left),
3075 _ => None,
3076 };
3077 self.legend_auto = Some(LegendAuto {
3078 corners: c,
3079 fallback,
3080 });
3081 self
3082 }
3083
3084 pub fn primary_color(mut self, color: (u8, u8, u8)) -> Self {
3085 self.theme.primary = Some(color);
3086 self
3087 }
3088
3089 pub fn theme_minimal(mut self) -> Self {
3090 self.apply_preset(crate::theme::presets::theme_minimal());
3091 self
3092 }
3093
3094 pub fn theme_bw(mut self) -> Self {
3095 self.apply_preset(crate::theme::presets::theme_bw());
3096 self
3097 }
3098
3099 pub fn theme_gray(mut self) -> Self {
3100 self.apply_preset(crate::theme::presets::theme_gray());
3101 self
3102 }
3103
3104 pub fn theme_classic(mut self) -> Self {
3105 self.apply_preset(crate::theme::presets::theme_classic());
3106 self
3107 }
3108
3109 pub fn theme_pubr(mut self) -> Self {
3111 self.apply_preset(crate::theme::presets::theme_pubr());
3112 self
3113 }
3114
3115 pub fn theme_linedraw(mut self) -> Self {
3116 self.apply_preset(crate::theme::presets::theme_linedraw());
3117 self
3118 }
3119
3120 pub fn theme_light(mut self) -> Self {
3121 self.apply_preset(crate::theme::presets::theme_light());
3122 self
3123 }
3124
3125 pub fn theme_dark(mut self) -> Self {
3126 self.apply_preset(crate::theme::presets::theme_dark());
3127 self
3128 }
3129
3130 pub fn theme_void(mut self) -> Self {
3131 self.apply_preset(crate::theme::presets::theme_void());
3132 self
3133 }
3134
3135 pub fn theme_update(mut self, update: crate::theme::ThemeUpdate) -> Self {
3138 self.theme = self.theme.update(update);
3139 self
3140 }
3141
3142 pub fn guides(mut self, guide: crate::guide::config::GuideLegend) -> Self {
3146 self.guide_legend = guide;
3147 self
3148 }
3149
3150 pub fn labs(mut self, labels: Labels) -> Self {
3153 if labels.title.is_some() {
3154 self.labels.title = labels.title;
3155 }
3156 if labels.subtitle.is_some() {
3157 self.labels.subtitle = labels.subtitle;
3158 }
3159 if labels.x.is_some() {
3160 self.labels.x = labels.x;
3161 }
3162 if labels.y.is_some() {
3163 self.labels.y = labels.y;
3164 }
3165 if labels.caption.is_some() {
3166 self.labels.caption = labels.caption;
3167 }
3168 if labels.tag.is_some() {
3169 self.labels.tag = labels.tag;
3170 }
3171 self
3172 }
3173
3174 pub fn title(mut self, title: &str) -> Self {
3175 self.labels.title = Some(title.to_string());
3176 self
3177 }
3178
3179 pub fn tag(mut self, tag: &str) -> Self {
3182 self.labels.tag = Some(tag.to_string());
3183 self
3184 }
3185
3186 pub fn subtitle(mut self, subtitle: &str) -> Self {
3187 self.labels.subtitle = Some(subtitle.to_string());
3188 self
3189 }
3190
3191 pub fn xlab(mut self, label: &str) -> Self {
3192 self.labels.x = Some(label.to_string());
3193 self
3194 }
3195
3196 pub fn ylab(mut self, label: &str) -> Self {
3197 self.labels.y = Some(label.to_string());
3198 self
3199 }
3200
3201 pub fn caption(mut self, caption: &str) -> Self {
3202 self.labels.caption = Some(caption.to_string());
3203 self
3204 }
3205
3206 pub fn annotate(mut self, annotation: Annotation) -> Self {
3210 self.annotations.push(annotation);
3211 self
3212 }
3213
3214 pub fn annotate_text(self, label: &str, x: f64, y: f64) -> Self {
3216 self.annotate(Annotation::text(label, x, y))
3217 }
3218
3219 pub fn annotate_rect(self, xmin: f64, xmax: f64, ymin: f64, ymax: f64) -> Self {
3221 self.annotate(Annotation::rect(xmin, xmax, ymin, ymax))
3222 }
3223
3224 pub fn annotate_segment(self, x: f64, y: f64, xend: f64, yend: f64) -> Self {
3226 self.annotate(Annotation::segment(x, y, xend, yend))
3227 }
3228
3229 pub fn locale(mut self, locale: crate::locale::Locale) -> Self {
3252 self.locale = Some(locale);
3253 self
3254 }
3255
3256 pub fn try_build(self) -> Result<crate::build::BuiltPlot, GGError> {
3260 PlotBuilder::build(self)
3261 }
3262
3263 pub fn build(self) -> crate::build::BuiltPlot {
3267 self.try_build().expect("plot build failed")
3268 }
3269
3270 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
3274 pub fn save(self, path: &str) -> Result<(), GGError> {
3275 self.save_with_size(path, 800, 600)
3276 }
3277
3278 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
3280 pub fn save_with_size(self, path: &str, w: u32, h: u32) -> Result<(), GGError> {
3281 let (built, layout) = self.prepare(w, h)?;
3282
3283 let ext = path.rsplit('.').next().unwrap_or("svg").to_lowercase();
3285
3286 match ext.as_str() {
3287 "svg" => {
3288 let backend = plotters::prelude::SVGBackend::new(path, (w, h));
3289 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
3290 }
3291 "png" | "bmp" | "gif" | "jpeg" | "jpg" | "tiff" => {
3292 let backend = plotters::prelude::BitMapBackend::new(path, (w, h));
3293 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
3294 }
3295 _ => {
3296 return Err(GGError::UnsupportedFormat(ext));
3297 }
3298 }
3299
3300 Ok(())
3301 }
3302
3303 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
3309 pub fn render_svg(self) -> Result<String, GGError> {
3310 self.render_svg_with_size(800, 600)
3311 }
3312
3313 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
3317 pub fn render_svg_with_size(self, w: u32, h: u32) -> Result<String, GGError> {
3318 let (built, layout) = self.prepare(w, h)?;
3319 let mut buf = String::new();
3320 {
3321 let backend = plotters::prelude::SVGBackend::with_string(&mut buf, (w, h));
3322 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
3323 }
3324 Ok(buf)
3325 }
3326
3327 pub fn render_svg_native(self) -> Result<String, GGError> {
3331 self.render_svg_native_with_size(800, 600)
3332 }
3333
3334 pub fn render_svg_native_with_size(self, w: u32, h: u32) -> Result<String, GGError> {
3342 Ok(self.render_native(w, h)?.0.finish())
3343 }
3344
3345 pub fn render_svg_native_with_warnings(
3350 self,
3351 w: u32,
3352 h: u32,
3353 ) -> Result<(String, Vec<String>), GGError> {
3354 let (backend, warnings, _) = self.render_native(w, h)?;
3355 Ok((backend.finish(), warnings))
3356 }
3357
3358 pub fn render_svg_native_at(self, x: f64, y: f64, w: u32, h: u32) -> Result<String, GGError> {
3370 Ok(self.render_native(w, h)?.0.finish_fragment(x, y))
3371 }
3372
3373 pub fn render_svg_area_with_size(self, w: u32, h: u32) -> Result<(String, [f64; 4]), GGError> {
3377 let (backend, _, pa) = self.render_native(w, h)?;
3378 Ok((backend.finish(), [pa.x, pa.y, pa.width, pa.height]))
3379 }
3380
3381 fn render_native(
3385 self,
3386 w: u32,
3387 h: u32,
3388 ) -> Result<
3389 (
3390 crate::render::svg_backend::SvgBackend,
3391 Vec<String>,
3392 crate::render::Rect,
3393 ),
3394 GGError,
3395 > {
3396 let svg_root_data = self.svg_root_data;
3397 let root_attrs = self.root_attrs.clone();
3398 let svg_warnings_attr = self.svg_warnings_attr;
3399 let svg_formatted_values = self.svg_formatted_values;
3400 let svg_title = self.svg_title.clone();
3401 let svg_desc = self.svg_desc.clone();
3402 let (built, layout) = self.prepare(w, h)?;
3403 let pa = layout.plot_area.clone();
3404 let mut backend = crate::render::svg_backend::SvgBackend::new(w, h, pa.clone());
3405 backend.set_formatted_values(svg_formatted_values);
3406 backend.set_svg_title(svg_title.clone());
3407 backend.set_svg_desc(svg_desc.clone());
3408 let existing_root_attrs = if svg_root_data {
3409 let attrs = crate::render::svg_backend::root_data_attrs(&built);
3410 backend.set_root_attrs(attrs.clone());
3411 let mut reserved = attrs;
3415 for name in ["data-plot", "data-viewport", "data-panels"] {
3418 reserved.push((name.to_string(), String::new()));
3419 }
3420 reserved
3421 } else {
3422 backend.without_plot_attr();
3423 Vec::new()
3424 };
3425 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
3426 let mut warnings = built.warnings;
3427 warnings.extend(backend.take_warnings());
3428
3429 let mut reserved = existing_root_attrs;
3430 if svg_warnings_attr {
3431 reserved.push(("data-warnings".to_string(), String::new()));
3432 }
3433 if svg_title.is_some() || svg_desc.is_some() {
3438 reserved.push(("role".to_string(), String::new()));
3439 }
3440 if svg_title.is_some() {
3441 reserved.push(("aria-labelledby".to_string(), String::new()));
3442 }
3443 if svg_desc.is_some() {
3444 reserved.push(("aria-describedby".to_string(), String::new()));
3445 }
3446 let extra = crate::render::svg_backend::validate_root_attrs(
3447 &root_attrs,
3448 &reserved,
3449 "plot",
3450 &mut warnings,
3451 );
3452 backend.extend_root_attrs(extra);
3453 if svg_warnings_attr {
3454 backend.extend_root_attrs(vec![(
3455 "data-warnings".to_string(),
3456 crate::render::svg_backend::warnings_json(&warnings),
3457 )]);
3458 }
3459 Ok((backend, warnings, pa))
3460 }
3461
3462 #[cfg(feature = "canvas")]
3467 pub fn render_rgba_with_size(self, w: u32, h: u32) -> Result<(u32, u32, Vec<u8>), GGError> {
3468 let (built, layout) = self.prepare(w, h)?;
3469 let mut backend =
3470 crate::render::pixel_backend::PixelBackend::new(w, h, layout.plot_area.clone());
3471 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
3472 let (ow, oh) = backend.dimensions();
3473 Ok((ow, oh, backend.into_rgba()))
3474 }
3475
3476 #[cfg(feature = "canvas")]
3480 pub fn render_rgba_area_with_size(
3481 self,
3482 w: u32,
3483 h: u32,
3484 ) -> Result<(Vec<u8>, [f64; 4]), GGError> {
3485 let (built, layout) = self.prepare(w, h)?;
3486 let pa = layout.plot_area.clone();
3487 let mut backend = crate::render::pixel_backend::PixelBackend::new(w, h, pa.clone());
3488 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
3489 Ok((backend.into_rgba(), [pa.x, pa.y, pa.width, pa.height]))
3490 }
3491
3492 #[cfg(feature = "canvas")]
3496 pub fn render_png_raster_with_size(self, w: u32, h: u32) -> Result<Vec<u8>, GGError> {
3497 let (built, layout) = self.prepare(w, h)?;
3498 let mut backend =
3499 crate::render::pixel_backend::PixelBackend::new(w, h, layout.plot_area.clone());
3500 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
3501 backend.into_png().map_err(GGError::Render)
3502 }
3503
3504 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
3511 pub fn render_png(self) -> Result<Vec<u8>, GGError> {
3512 self.render_png_with_size(800, 600)
3513 }
3514
3515 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
3518 pub fn render_png_with_size(self, w: u32, h: u32) -> Result<Vec<u8>, GGError> {
3519 let (built, layout) = self.prepare(w, h)?;
3520
3521 let mut rgb = vec![0u8; (w as usize) * (h as usize) * 3];
3524 {
3525 let backend = plotters::prelude::BitMapBackend::with_buffer(&mut rgb, (w, h));
3526 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
3527 }
3528
3529 let img = image::RgbImage::from_raw(w, h, rgb).ok_or_else(|| {
3530 GGError::Render(RenderError::BackendError(
3531 "PNG buffer size mismatch".to_string(),
3532 ))
3533 })?;
3534 let mut out = std::io::Cursor::new(Vec::new());
3535 img.write_to(&mut out, image::ImageOutputFormat::Png)
3536 .map_err(|e| GGError::Render(RenderError::BackendError(format!("{:?}", e))))?;
3537 Ok(out.into_inner())
3538 }
3539
3540 pub(crate) fn prepare(
3542 self,
3543 w: u32,
3544 h: u32,
3545 ) -> Result<(crate::build::BuiltPlot, PlotLayout), GGError> {
3546 let (mut built, meta) = self.build_for_render()?;
3547 let layout = Self::layout_built(&mut built, &meta, w, h);
3548 Ok((built, layout))
3549 }
3550
3551 pub(crate) fn build_for_render(self) -> Result<(crate::build::BuiltPlot, RenderMeta), GGError> {
3554 let plot = self;
3555
3556 let has_title = plot.labels.title.is_some();
3557 let has_subtitle = plot.labels.subtitle.is_some();
3558 let has_caption = plot.labels.caption.is_some();
3559 let has_legend = plot.has_legend_mapping();
3560 let legend_bottom_share = plot.legend_bottom_share;
3561 let legend_auto = plot.legend_auto;
3562 let x_label = plot.labels.x.clone();
3563 let y_label = plot.labels.y.clone();
3564
3565 let mut built = PlotBuilder::build(plot)?;
3566
3567 built.theme.resolve_inheritance();
3569
3570 if let Some(ref label) = x_label {
3572 if let Some(s) = built.scales.get_mut(&crate::aes::Aesthetic::X) {
3573 s.set_name(label);
3574 }
3575 }
3576 if let Some(ref label) = y_label {
3577 if let Some(s) = built.scales.get_mut(&crate::aes::Aesthetic::Y) {
3578 s.set_name(label);
3579 }
3580 }
3581
3582 Ok((
3583 built,
3584 RenderMeta {
3585 has_title,
3586 has_subtitle,
3587 has_caption,
3588 has_legend,
3589 legend_bottom_share,
3590 legend_auto,
3591 },
3592 ))
3593 }
3594
3595 pub(crate) fn layout_built(
3598 built: &mut crate::build::BuiltPlot,
3599 meta: &RenderMeta,
3600 w: u32,
3601 h: u32,
3602 ) -> PlotLayout {
3603 match meta.legend_auto {
3604 Some(auto) if meta.has_legend && built.panels.is_empty() => {
3605 Self::layout_legend_auto(built, meta, auto, w, h)
3606 }
3607 _ => Self::layout_built_inner(built, meta, w, h),
3608 }
3609 }
3610
3611 fn layout_legend_auto(
3614 built: &mut crate::build::BuiltPlot,
3615 meta: &RenderMeta,
3616 auto: LegendAuto,
3617 w: u32,
3618 h: u32,
3619 ) -> PlotLayout {
3620 use crate::render::probe::Probe;
3621 use crate::theme::LegendPosition as P;
3622 let total = crate::render::Rect {
3623 x: 0.0,
3624 y: 0.0,
3625 width: w as f64,
3626 height: h as f64,
3627 };
3628 let (theme0, n_warnings) = (built.theme.clone(), built.warnings.len());
3631 let reset = |built: &mut crate::build::BuiltPlot, pos: P| {
3632 built.theme = theme0.clone();
3633 built.theme.legend_position = pos;
3634 built.warnings.truncate(n_warnings);
3635 };
3636
3637 reset(built, P::Inside(1.0, 0.0));
3638 let layout = Self::layout_built_inner(built, meta, w, h);
3639 let pa = layout.plot_area.clone();
3640 let mut marks = Probe::new(pa.clone(), total.clone());
3641 for layer in built.layers.iter().filter(|l| l.data.nrows() > 0) {
3642 let _ = layer.geom.draw(
3643 &layer.data,
3644 built.coord.as_ref(),
3645 &built.scales,
3646 &built.theme,
3647 &mut marks,
3648 );
3649 }
3650 for corner in auto.corners.iter().flatten() {
3651 built.theme.legend_position = corner.inside();
3652 let mut legend = Probe::new(pa.clone(), total.clone());
3653 let drawn = crate::guide::legend::draw_legend_planned(
3654 &built.scales,
3655 &built.theme,
3656 &pa,
3657 pa.width,
3658 &mut legend,
3659 &built.guide_legend,
3660 &built.suppressed_aes,
3661 &built.legend_plans,
3662 );
3663 let Some((x0, y0, x1, y1)) = legend.extent().filter(|_| drawn.is_ok()) else {
3664 continue;
3665 };
3666 const PAD: f64 = 2.0;
3667 if !marks.hits((x0 - PAD, y0 - PAD, x1 + PAD, y1 + PAD)) {
3668 built.legend_at = Some(format!("inside-{}", corner.name()));
3669 return layout;
3670 }
3671 }
3672
3673 let sides = match auto.fallback {
3676 Some(side) => vec![side],
3677 None => vec![LegendSide::Top, LegendSide::Right],
3678 };
3679 let data_area = |built: &crate::build::BuiltPlot, layout: &PlotLayout| {
3680 let r = built
3681 .coord
3682 .data_rect(&layout.plot_area)
3683 .unwrap_or_else(|| layout.plot_area.clone());
3684 r.width.max(0.0) * r.height.max(0.0)
3685 };
3686 let mut best = (sides[0], f64::MIN);
3687 for &side in &sides {
3688 reset(built, side.position());
3689 let trial = Self::layout_built_inner(built, meta, w, h);
3690 let area = data_area(built, &trial);
3691 if area > best.1 {
3692 best = (side, area);
3693 }
3694 }
3695 reset(built, best.0.position());
3696 let layout = Self::layout_built_inner(built, meta, w, h);
3697 built.legend_at = Some(
3698 match built.theme.legend_position {
3699 P::Top => "top",
3700 P::Right => "right",
3701 P::Bottom => "bottom",
3702 _ => "left",
3703 }
3704 .to_string(),
3705 );
3706 layout
3707 }
3708
3709 fn layout_built_inner(
3710 built: &mut crate::build::BuiltPlot,
3711 meta: &RenderMeta,
3712 w: u32,
3713 h: u32,
3714 ) -> PlotLayout {
3715 let RenderMeta {
3716 has_title,
3717 has_subtitle,
3718 has_caption,
3719 has_legend,
3720 legend_bottom_share,
3721 legend_auto: _,
3722 } = *meta;
3723 let x_axis_top = built
3724 .scales
3725 .get(&crate::aes::Aesthetic::X)
3726 .map(|s| s.axis_position_opposite())
3727 .unwrap_or(false);
3728
3729 if let Some(share) = legend_bottom_share {
3732 if has_legend
3733 && matches!(
3734 built.theme.legend_position,
3735 crate::theme::LegendPosition::Right
3736 )
3737 {
3738 let panel_width = |pos| {
3739 let mut theme = built.theme.clone();
3740 theme.legend_position = pos;
3741 PlotLayout::compute_with_extras(
3742 w as f64,
3743 h as f64,
3744 &theme,
3745 has_title,
3746 has_subtitle,
3747 has_caption,
3748 has_legend,
3749 x_axis_top,
3750 None,
3751 None,
3752 crate::render::layout::LayoutExtras::default(),
3753 )
3754 .plot_area
3755 .width
3756 };
3757 let free = panel_width(crate::theme::LegendPosition::None);
3760 if panel_width(crate::theme::LegendPosition::Right) < (1.0 - share) * free {
3761 built.theme.legend_position = crate::theme::LegendPosition::Bottom;
3762 }
3763 }
3764 }
3765
3766 let flipped = built.coord.is_flipped();
3770 let h_aes = if flipped {
3771 crate::aes::Aesthetic::Y
3772 } else {
3773 crate::aes::Aesthetic::X
3774 };
3775 let v_aes = if flipped {
3776 crate::aes::Aesthetic::X
3777 } else {
3778 crate::aes::Aesthetic::Y
3779 };
3780
3781 let drawn_x_labels: Vec<(f64, String)> = built
3789 .scales
3790 .get(&h_aes)
3791 .map(|hs| {
3792 hs.breaks()
3793 .into_iter()
3794 .filter(|(_, label)| !label.is_empty())
3795 .collect()
3796 })
3797 .unwrap_or_default();
3798 let h_is_discrete = built
3799 .scales
3800 .get(&h_aes)
3801 .map(|hs| hs.is_discrete())
3802 .unwrap_or(false);
3803
3804 if built.theme.axis_text_x.visible
3817 && built.theme.axis_text_x.angle.abs() < 1.0
3818 && h_is_discrete
3819 && !drawn_x_labels.is_empty()
3820 {
3821 let font = built.theme.axis_text_x.size;
3822 let max_w = drawn_x_labels
3823 .iter()
3824 .map(|(_, l)| crate::render::text::text_width(l, font))
3825 .fold(0.0_f64, f64::max);
3826 let n = drawn_x_labels.len() as f64;
3827 let spacing = 0.9 * w as f64 / n; if max_w > spacing {
3829 let vertical = max_w * std::f64::consts::FRAC_1_SQRT_2 > spacing;
3833 built.theme.axis_text_x.angle = if vertical { 270.0 } else { -45.0 };
3834 }
3835 }
3836
3837 let x_label_height = if built.theme.axis_text_x.visible
3852 && built.theme.axis_text_x.angle.abs() > 10.0
3853 && !drawn_x_labels.is_empty()
3854 {
3855 let font = built.theme.axis_text_x.size;
3856 let angle = built.theme.axis_text_x.angle;
3857 let dir = if x_axis_top { -1.0 } else { 1.0 };
3858 let (rise, fall) = crate::render::text::rotated_label_rise_fall(
3859 drawn_x_labels.iter().map(|(_, l)| l.as_str()),
3860 font,
3861 angle,
3862 crate::render::text::rotated_anchor_frac(angle, dir),
3863 );
3864 Some(built.theme.legend_spacing / 2.0 + font / 2.0 + rise + fall)
3865 } else {
3866 None
3867 };
3868
3869 let y_label_width = if built.theme.axis_text_y.visible {
3873 built.scales.get(&v_aes).map(|vs| {
3874 crate::guide::axis::y_label_reserve(&built.theme, &vs.breaks()).min(0.35 * w as f64)
3875 })
3876 } else {
3877 None
3878 };
3879
3880 let mut extras = crate::render::layout::LayoutExtras::default();
3891 if let (Some(vs), Some(sec)) = (
3895 built.scales.get(&crate::aes::Aesthetic::Y),
3896 built.scales.sec_axis(&crate::aes::Aesthetic::Y),
3897 ) {
3898 let theme = &built.theme;
3899 let max_ch = match sec.own_ticks(vs) {
3900 Some(t) => t.iter().map(|(_, l)| l.chars().count()).max(),
3901 None => vs.breaks().iter().map(|(_, l)| l.chars().count() + 2).max(),
3902 }
3903 .unwrap_or(0);
3904 let text = if theme.axis_text_y.visible {
3905 (max_ch as f64 * theme.axis_text_y.size * 0.6).max(theme.axis_text_y.size * 3.5)
3906 } else {
3907 0.0
3908 };
3909 let title = if !sec.name.is_empty() && theme.axis_title_y.visible {
3910 theme.axis_title_y.size * 1.5
3911 } else {
3912 0.0
3913 };
3914 extras.right += theme.axis_ticks_length + theme.legend_spacing + text + title;
3915 }
3916 let can_reserve = built.facet.is_none()
3917 && built.theme.axis_text_x.visible
3918 && built.theme.axis_text_x_fit == crate::theme::AxisLabelFit::Reserve
3919 && !built.coord.is_polar()
3920 && built.coord.supports_axis_reserve();
3921 if can_reserve {
3922 if let Some(hs) = built.scales.get(&h_aes) {
3923 let breaks = hs.breaks();
3924 if let (Some(first), Some(last)) = (breaks.first(), breaks.last()) {
3925 let angle = built.theme.axis_text_x.angle;
3926 let anchor = if angle.abs() > 10.0 {
3927 let dir = if x_axis_top { -1.0 } else { 1.0 };
3928 crate::render::text::rotated_anchor_frac(angle, dir)
3929 } else {
3930 0.5
3931 };
3932 let size = built.theme.axis_text_x.size;
3933 const EDGE: f64 = 1.0;
3934 for _ in 0..2 {
3935 let layout = PlotLayout::compute_with_extras(
3936 w as f64,
3937 h as f64,
3938 &built.theme,
3939 has_title,
3940 has_subtitle,
3941 has_caption,
3942 has_legend,
3943 x_axis_top,
3944 y_label_width,
3945 x_label_height,
3946 extras,
3947 );
3948 let area = &layout.plot_area;
3949 let edge_y = area.y + area.height;
3950 let to_point = |pos: f64| if flipped { (0.0, pos) } else { (pos, 0.0) };
3951 let px_first = built.coord.transform(to_point(first.0), area).0;
3952 let px_last = built.coord.transform(to_point(last.0), area).0;
3953 let bbox_first = crate::render::text::label_bbox(
3954 &first.1, size, px_first, edge_y, angle, anchor,
3955 );
3956 let bbox_last = crate::render::text::label_bbox(
3957 &last.1, size, px_last, edge_y, angle, anchor,
3958 );
3959 let deficit_left = (EDGE - bbox_first[0]).max(0.0);
3960 let deficit_right = (bbox_last[2] - (w as f64 - EDGE)).max(0.0);
3961 if deficit_left <= 0.0 && deficit_right <= 0.0 {
3962 break;
3963 }
3964 let (p_first, p_last) = (first.0, last.0);
3973 if deficit_left > 0.0 && deficit_right > 0.0 {
3974 let (a, b, c, d) = (1.0 - p_first, p_first, 1.0 - p_last, p_last);
3979 let det = a * d - b * c;
3980 if det.abs() > 0.01 {
3981 extras.left +=
3982 ((deficit_left * d + deficit_right * b) / det).max(0.0);
3983 extras.right +=
3984 ((deficit_right * a + deficit_left * c) / det).max(0.0);
3985 } else {
3986 extras.left += deficit_left / (1.0 - p_first).max(0.05);
3990 extras.right += deficit_right / p_last.max(0.05);
3991 }
3992 } else if deficit_left > 0.0 {
3993 extras.left += deficit_left / (1.0 - p_first).max(0.05);
3994 } else if deficit_right > 0.0 {
3995 extras.right += deficit_right / p_last.max(0.05);
3996 }
3997 const MIN_PANEL_WIDTH: f64 = 50.0;
4012 let cap = (w as f64 - MIN_PANEL_WIDTH).max(0.0);
4013 if extras.left + extras.right > cap {
4014 let scale = if extras.left + extras.right > 0.0 {
4015 cap / (extras.left + extras.right)
4016 } else {
4017 0.0
4018 };
4019 extras.left *= scale;
4020 extras.right *= scale;
4021 }
4022 }
4023 }
4024 }
4025 }
4026
4027 if has_legend
4034 && !matches!(
4035 built.theme.legend_position,
4036 crate::theme::LegendPosition::None
4037 )
4038 {
4039 let legend_aes =
4040 crate::guide::legend::legend_scales_for(&built.scales, &built.suppressed_aes);
4041 extras.legend_max_key_size = legend_aes
4045 .iter()
4046 .filter_map(|aes| {
4047 let scale = built.scales.get(aes)?;
4048 let breaks = scale.breaks();
4049 Some(crate::guide::legend::size_key_diameter(
4050 aes,
4051 &built.scales,
4052 scale,
4053 &breaks,
4054 ))
4055 })
4056 .fold(0.0_f64, f64::max);
4057 let has_wrap_guide = legend_aes.iter().any(|a| {
4068 let is_discrete = built
4069 .scales
4070 .get(a)
4071 .map(|s| s.is_discrete())
4072 .unwrap_or(false);
4073 is_discrete || !crate::guide::legend::is_colorbar_aesthetic(a)
4074 });
4075 if has_wrap_guide {
4076 let layout0 = PlotLayout::compute_with_extras(
4077 w as f64,
4078 h as f64,
4079 &built.theme,
4080 has_title,
4081 has_subtitle,
4082 has_caption,
4083 has_legend,
4084 x_axis_top,
4085 y_label_width,
4086 x_label_height,
4087 extras,
4088 );
4089 let (legend_x0, _, mut is_horizontal) = crate::guide::legend::legend_position(
4099 &built.theme,
4100 &layout0.plot_area,
4101 extras.legend_extra_rows,
4102 (0.0, 0.0),
4103 0.0,
4104 &layout0.total,
4105 );
4106 if let Some(dir) = built.theme.legend_direction {
4107 is_horizontal = matches!(dir, crate::theme::LegendDirection::Horizontal);
4108 }
4109 let avail_width =
4110 (layout0.plot_area.x + layout0.plot_area.width - legend_x0).max(0.0);
4111 let mut legend_warnings = Vec::new();
4112 let mut plans = crate::guide::legend::plan_all_legends(
4113 &built.scales,
4114 &built.guide_legend,
4115 &built.theme,
4116 &built.suppressed_aes,
4117 avail_width,
4118 layout0.plot_area.height,
4119 is_horizontal,
4120 &mut legend_warnings,
4121 );
4122 built.warnings.extend(legend_warnings);
4123
4124 if !plans.is_empty() {
4125 extras.legend_extra_rows = if is_horizontal {
4131 plans
4132 .values()
4133 .map(|p| p.rows.saturating_sub(1))
4134 .max()
4135 .unwrap_or(0)
4136 } else {
4137 plans.values().map(|p| p.rows.saturating_sub(1)).sum()
4138 };
4139 extras.legend_extra_width = plans
4146 .values()
4147 .map(|p| p.cols.saturating_sub(1) as f64 * p.col_pitch)
4148 .fold(0.0_f64, f64::max);
4149
4150 if !is_horizontal {
4162 let final_layout = PlotLayout::compute_with_extras(
4163 w as f64,
4164 h as f64,
4165 &built.theme,
4166 has_title,
4167 has_subtitle,
4168 has_caption,
4169 has_legend,
4170 x_axis_top,
4171 y_label_width,
4172 x_label_height,
4173 extras,
4174 );
4175 let (legend_x_final, _, _) = crate::guide::legend::legend_position(
4181 &built.theme,
4182 &final_layout.plot_area,
4183 extras.legend_extra_rows,
4184 (0.0, 0.0),
4185 0.0,
4186 &final_layout.total,
4187 );
4188 let swatch_and_gap =
4189 built.theme.legend_key_width + built.theme.legend_spacing;
4190 let text_size = built.theme.legend_text.size;
4191 fn right_edge_of(
4197 legend_x: f64,
4198 swatch_and_gap: f64,
4199 text_size: f64,
4200 plan: &crate::guide::legend::LegendPlan,
4201 breaks: &[(f64, String)],
4202 ) -> f64 {
4203 plan.entries
4204 .iter()
4205 .filter_map(|e| breaks.get(e.break_idx).map(|(_, l)| (e, l)))
4206 .map(|(e, label)| {
4207 let text =
4208 e.label_override.as_deref().unwrap_or(label.as_str());
4209 legend_x
4210 + e.x_offset
4211 + swatch_and_gap
4212 + crate::render::text::text_width(text, text_size)
4213 })
4214 .fold(0.0_f64, f64::max)
4215 }
4216
4217 let mut updates: Vec<(
4218 crate::aes::Aesthetic,
4219 crate::guide::legend::LegendPlan,
4220 )> = Vec::new();
4221 let mut reduced_aes: Vec<crate::aes::Aesthetic> = Vec::new();
4228 for (aes, plan) in &plans {
4229 if plan.cols <= 1 {
4230 continue;
4231 }
4232 let Some(scale) = built.scales.get(aes) else {
4233 continue;
4234 };
4235 let breaks = scale.breaks();
4236 if right_edge_of(
4237 legend_x_final,
4238 swatch_and_gap,
4239 text_size,
4240 plan,
4241 &breaks,
4242 ) <= w as f64
4243 {
4244 continue; }
4246
4247 let n = breaks.len();
4250 let mut reduced: Vec<crate::guide::legend::LegendPlan> = Vec::new();
4251 for c in (1..plan.cols).rev() {
4252 let mut candidate_guide = built.guide_legend.clone();
4253 candidate_guide.ncol = Some(c);
4254 candidate_guide.nrow = None;
4255 let mut tmp_warnings = Vec::new();
4256 let candidate_guide =
4257 candidate_guide.validated(n, &mut tmp_warnings);
4258 if let Some(cand) = crate::guide::legend::plan_legend(
4259 &breaks,
4260 &candidate_guide,
4261 &built.theme,
4262 avail_width,
4263 layout0.plot_area.height,
4264 false,
4265 ) {
4266 reduced.push(cand);
4267 }
4268 }
4269 if let Some(fits) = reduced.iter().find(|c| {
4270 right_edge_of(legend_x_final, swatch_and_gap, text_size, c, &breaks)
4271 <= w as f64
4272 }) {
4273 extras.legend_extra_rows =
4274 extras.legend_extra_rows.max(fits.rows.saturating_sub(1));
4275 updates.push((aes.clone(), fits.clone()));
4276 reduced_aes.push(aes.clone());
4277 continue;
4278 }
4279
4280 let base = reduced.last().cloned().unwrap_or_else(|| plan.clone());
4285 extras.legend_extra_rows =
4286 extras.legend_extra_rows.max(base.rows.saturating_sub(1));
4287 let mut truncated = base.clone();
4288 for e in &mut truncated.entries {
4289 let Some((_, label)) = breaks.get(e.break_idx) else {
4290 continue;
4291 };
4292 let avail = (w as f64
4293 - (legend_x_final + e.x_offset + swatch_and_gap))
4294 .max(0.0);
4295 if let Some(short) =
4296 crate::render::text::truncate_to_width(label, avail, text_size)
4297 {
4298 e.label_override = Some(short);
4299 }
4300 }
4301
4302 let truncated_edge = right_edge_of(
4306 legend_x_final,
4307 swatch_and_gap,
4308 text_size,
4309 &truncated,
4310 &breaks,
4311 );
4312 if truncated_edge > w as f64 {
4313 built.warnings.push(format!(
4314 "legend: the {}-column grid still doesn't fit the {w}px chart (needs about {} px)",
4315 truncated.cols,
4316 truncated_edge.ceil() as i64
4317 ));
4318 }
4319 updates.push((aes.clone(), truncated));
4320 }
4321 for (aes, new_plan) in &updates {
4322 plans.insert(aes.clone(), new_plan.clone());
4323 }
4324
4325 if !reduced_aes.is_empty() {
4366 let original_reserve = extras.legend_extra_width;
4367 let tighter_reserve = plans
4368 .values()
4369 .map(|p| p.cols.saturating_sub(1) as f64 * p.col_pitch)
4370 .fold(0.0_f64, f64::max);
4371 if tighter_reserve < original_reserve {
4372 let mut retry_extras = extras;
4373 retry_extras.legend_extra_width = tighter_reserve;
4374 let retry_layout = PlotLayout::compute_with_extras(
4375 w as f64,
4376 h as f64,
4377 &built.theme,
4378 has_title,
4379 has_subtitle,
4380 has_caption,
4381 has_legend,
4382 x_axis_top,
4383 y_label_width,
4384 x_label_height,
4385 retry_extras,
4386 );
4387 let (retry_x, _, _) = crate::guide::legend::legend_position(
4393 &built.theme,
4394 &retry_layout.plot_area,
4395 retry_extras.legend_extra_rows,
4396 (0.0, 0.0),
4397 0.0,
4398 &retry_layout.total,
4399 );
4400 let all_still_fit = plans.iter().all(|(aes, plan)| {
4401 let Some(scale) = built.scales.get(aes) else {
4402 return true;
4403 };
4404 let breaks = scale.breaks();
4405 right_edge_of(retry_x, swatch_and_gap, text_size, plan, &breaks)
4406 <= w as f64
4407 });
4408 if all_still_fit {
4409 extras.legend_extra_width = tighter_reserve;
4410 }
4411 }
4412 }
4413 }
4414 for (aes, plan) in &plans {
4415 if let Some(ov) = &plan.overflow {
4416 let n = built
4417 .scales
4418 .get(aes)
4419 .map(|s| s.breaks().len())
4420 .unwrap_or(ov.dropped);
4421 let shown = n.saturating_sub(ov.dropped);
4422 built.warnings.push(format!(
4423 "legend: {} of {n} entries don't fit the chart; the legend shows {shown} and \"+{} more\"",
4424 ov.dropped, ov.dropped
4425 ));
4426 }
4427 }
4428 }
4429 built.legend_plans = plans;
4435 }
4436 }
4437
4438 if has_legend
4449 && !matches!(
4450 built.theme.legend_position,
4451 crate::theme::LegendPosition::None
4452 )
4453 {
4454 let is_horizontal = match built.theme.legend_direction {
4455 Some(dir) => matches!(dir, crate::theme::LegendDirection::Horizontal),
4456 None => matches!(
4457 built.theme.legend_position,
4458 crate::theme::LegendPosition::Top | crate::theme::LegendPosition::Bottom
4459 ),
4460 };
4461 if is_horizontal {
4462 let legend_aes =
4463 crate::guide::legend::legend_scales_for(&built.scales, &built.suppressed_aes);
4464 let continuous_colourbar = legend_aes.iter().find_map(|aes| {
4465 if !matches!(
4466 aes,
4467 crate::aes::Aesthetic::Color | crate::aes::Aesthetic::Fill
4468 ) {
4469 return None;
4470 }
4471 let scale = built.scales.get(aes)?;
4472 if scale.is_discrete() {
4473 return None;
4474 }
4475 Some(scale)
4476 });
4477 if let Some(scale) = continuous_colourbar {
4478 let title = built
4479 .guide_legend
4480 .title
4481 .as_deref()
4482 .unwrap_or_else(|| scale.name());
4483 let bar_height = crate::guide::legend::continuous_horizontal_bar_height(
4484 &built.theme,
4485 !title.is_empty(),
4486 );
4487 let key_h = built
4488 .theme
4489 .legend_key_height
4490 .max(extras.legend_max_key_size);
4491 extras.continuous_horizontal_legend_extra_height =
4492 (bar_height - key_h).max(0.0);
4493 }
4494 }
4495 }
4496
4497 PlotLayout::compute_with_extras(
4498 w as f64,
4499 h as f64,
4500 &built.theme,
4501 has_title,
4502 has_subtitle,
4503 has_caption,
4504 has_legend,
4505 x_axis_top,
4506 y_label_width,
4507 x_label_height,
4508 extras,
4509 )
4510 }
4511
4512 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
4515 fn render_into<DB>(
4516 area: plotters::drawing::DrawingArea<DB, plotters::coord::Shift>,
4517 built: &crate::build::BuiltPlot,
4518 layout: &PlotLayout,
4519 ) -> Result<(), GGError>
4520 where
4521 DB: plotters::prelude::DrawingBackend,
4522 DB::ErrorType: 'static,
4523 {
4524 area.fill(&plotters::prelude::WHITE)
4525 .map_err(|e| GGError::Render(RenderError::BackendError(format!("{:?}", e))))?;
4526 let mut adapter = PlottersAdapter::new(&area, layout.plot_area.clone());
4527 PlotRenderer::render(built, &mut adapter).map_err(GGError::Render)?;
4528 area.present()
4529 .map_err(|e| GGError::Render(RenderError::BackendError(format!("{:?}", e))))?;
4530 Ok(())
4531 }
4532
4533 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
4536 pub fn ggsave(
4537 self,
4538 path: &str,
4539 width_inches: f64,
4540 height_inches: f64,
4541 dpi: f64,
4542 ) -> Result<(), GGError> {
4543 let w = (width_inches * dpi) as u32;
4544 let h = (height_inches * dpi) as u32;
4545 self.save_with_size(path, w, h)
4546 }
4547
4548 fn has_legend_mapping(&self) -> bool {
4563 use crate::guide::legend::is_legend_aesthetic;
4568 let plot_level = self
4569 .mapping
4570 .mappings
4571 .iter()
4572 .any(|m| is_legend_aesthetic(&m.aesthetic));
4573 plot_level
4574 || self.layers.iter().any(|layer| {
4575 if layer.show_legend == Some(false) {
4576 return false;
4577 }
4578 let effective = if layer.geom.inherit_aes() {
4579 self.mapping.merge(&layer.mapping)
4580 } else {
4581 layer.mapping.clone()
4582 };
4583 effective
4584 .mappings
4585 .iter()
4586 .any(|m| is_legend_aesthetic(&m.aesthetic))
4587 })
4588 }
4589}
4590
4591#[derive(Clone, Copy, Debug)]
4593pub(crate) struct RenderMeta {
4594 pub(crate) has_title: bool,
4595 pub(crate) has_subtitle: bool,
4596 pub(crate) has_caption: bool,
4597 pub(crate) has_legend: bool,
4598 pub(crate) legend_bottom_share: Option<f64>,
4599 pub(crate) legend_auto: Option<LegendAuto>,
4600}
4601
4602#[derive(Clone, Copy, Debug)]
4604pub(crate) struct LegendAuto {
4605 corners: [Option<crate::theme::LegendCorner>; 4],
4606 fallback: Option<LegendSide>,
4607}
4608
4609#[derive(Clone, Copy, Debug)]
4611enum LegendSide {
4612 Top,
4613 Right,
4614 Bottom,
4615 Left,
4616}
4617
4618impl LegendSide {
4619 fn position(self) -> crate::theme::LegendPosition {
4620 use crate::theme::LegendPosition as P;
4621 match self {
4622 LegendSide::Top => P::Top,
4623 LegendSide::Right => P::Right,
4624 LegendSide::Bottom => P::Bottom,
4625 LegendSide::Left => P::Left,
4626 }
4627 }
4628}
4629
4630#[derive(Debug)]
4632#[non_exhaustive]
4633pub enum GGError {
4634 Render(RenderError),
4635 UnsupportedFormat(String),
4636 Io(std::io::Error),
4637 ValidationError(String),
4638}
4639
4640impl std::fmt::Display for GGError {
4641 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4642 match self {
4643 GGError::Render(e) => write!(f, "Render error: {e}"),
4644 GGError::UnsupportedFormat(ext) => write!(f, "Unsupported output format: {ext}"),
4645 GGError::Io(e) => write!(f, "IO error: {e}"),
4646 GGError::ValidationError(msg) => write!(f, "Validation error: {msg}"),
4647 }
4648 }
4649}
4650
4651impl std::error::Error for GGError {}