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 pub key_glyph: Option<crate::guide::key::KeyGlyph>,
97 pub show_legend_aes: Vec<(crate::aes::Aesthetic, bool)>,
99}
100
101pub struct GGPlot {
103 pub(crate) data: DataFrame,
104 pub(crate) mapping: Aes,
105 pub(crate) layers: Vec<Layer>,
106 pub(crate) scales: Vec<Box<dyn Scale>>,
107 pub(crate) coord: Box<dyn Coord>,
108 pub(crate) theme: Theme,
109 pub(crate) labels: Labels,
110 pub(crate) facet: Facet,
111 pub(crate) facet_axes: crate::facet::FacetAxes,
113 pub(crate) annotations: Vec<Annotation>,
114 pub(crate) guide_legend: crate::guide::config::GuideLegend,
115 pub(crate) warnings: Vec<String>,
118 pub(crate) legend_bottom_share: Option<f64>,
120 pub(crate) clip: bool,
123 pub(crate) svg_classes: bool,
126 pub(crate) legend_auto: Option<LegendAuto>,
128 pub(crate) default_aspect_ratio: Option<f64>,
131 pub(crate) hide_position_guides: bool,
134 pub(crate) hide_y_guides: bool,
136 pub(crate) locale: Option<crate::locale::Locale>,
138 pub(crate) svg_root_data: bool,
143 pub(crate) root_attrs: Vec<(String, String)>,
146 pub(crate) svg_warnings_attr: bool,
150 pub(crate) svg_formatted_values: bool,
154 pub(crate) layer_svg_attrs: Vec<(usize, String, String)>,
158 pub(crate) svg_title: Option<String>,
163 pub(crate) svg_desc: Option<String>,
168}
169
170impl GGPlot {
171 pub fn qplot(data: impl GGData, x: &str, y: Option<&str>) -> Self {
180 let plot = GGPlot::new(data);
181 match y {
182 Some(y) => plot.aes(Aes::new().x(x).y(y)).geom_point(),
183 None => {
184 let text = plot
185 .data
186 .column(x)
187 .and_then(|c| c.iter().find(|v| !v.is_na()))
188 .is_some_and(|v| matches!(v, Value::Str(_) | Value::Bool(_)));
189 let plot = plot.aes(Aes::new().x(x));
190 if text {
191 plot.geom_bar()
192 } else {
193 plot.geom_histogram()
194 }
195 }
196 }
197 }
198
199 pub fn new(data: impl GGData) -> Self {
200 GGPlot {
201 data: data.into_dataframe(),
202 mapping: Aes::default(),
203 layers: Vec::new(),
204 scales: Vec::new(),
205 coord: Box::new(CoordCartesian::new()),
206 theme: Theme::default(),
207 labels: Labels::default(),
208 facet: Facet::default(),
209 facet_axes: crate::facet::FacetAxes::default(),
210 annotations: Vec::new(),
211 guide_legend: crate::guide::config::GuideLegend::default(),
212 warnings: Vec::new(),
213 legend_bottom_share: None,
214 clip: true,
215 svg_classes: false,
216 legend_auto: None,
217 default_aspect_ratio: None,
218 hide_position_guides: false,
219 hide_y_guides: false,
220 locale: None,
221 svg_root_data: true,
222 root_attrs: Vec::new(),
223 svg_warnings_attr: false,
224 svg_formatted_values: false,
225 layer_svg_attrs: Vec::new(),
226 svg_title: None,
227 svg_desc: None,
228 }
229 }
230
231 pub fn aes(mut self, mapping: Aes) -> Self {
233 self.warnings.extend(mapping.warnings.iter().cloned());
234 self.mapping = mapping;
235 self
236 }
237
238 pub fn geom_point(self) -> Self {
241 self.add_geom(GeomPoint::default())
242 }
243
244 pub fn geom_point_with(self, geom: GeomPoint) -> Self {
245 self.add_geom_with(geom)
246 }
247
248 pub fn geom_line(self) -> Self {
249 self.add_geom(GeomLine::default())
250 }
251
252 pub fn geom_line_with(self, geom: GeomLine) -> Self {
253 self.add_geom_with(geom)
254 }
255
256 pub fn geom_bar(self) -> Self {
257 self.add_geom(GeomBar::default())
258 }
259
260 pub fn geom_bar_with(self, geom: GeomBar) -> Self {
261 self.add_geom_with(geom)
262 }
263
264 pub fn geom_histogram(self) -> Self {
265 self.add_geom(GeomHistogram::default())
266 }
267
268 pub fn geom_histogram_with(self, geom: GeomHistogram) -> Self {
269 self.add_geom_with(geom)
270 }
271
272 pub fn geom_boxplot(self) -> Self {
273 self.add_geom(GeomBoxplot::default())
274 }
275
276 pub fn geom_boxplot_with(self, geom: GeomBoxplot) -> Self {
277 self.add_geom_with(geom)
278 }
279
280 pub fn geom_smooth(self) -> Self {
281 self.add_geom(GeomSmooth::default())
282 }
283
284 pub fn geom_smooth_with(self, geom: GeomSmooth) -> Self {
285 self.add_geom_with(geom)
286 }
287
288 pub fn geom_col(self) -> Self {
289 self.add_geom(GeomCol::default())
290 }
291
292 pub fn geom_col_with(self, geom: GeomCol) -> Self {
293 self.add_geom_with(geom)
294 }
295
296 pub fn geom_hline(self, yintercept: f64) -> Self {
300 self.add_refline(
301 GeomHline::new(yintercept),
302 false,
303 &[("yintercept", yintercept)],
304 )
305 }
306
307 pub fn geom_hline_with(self, geom: GeomHline) -> Self {
309 let y = geom.yintercept;
310 self.add_refline(geom, true, &[("yintercept", y)])
311 }
312
313 pub fn geom_hline_aes(self, mapping: Aes) -> Self {
337 self.add_geom(GeomHline::mapped()).layer_aes(mapping)
338 }
339
340 pub fn geom_hline_aes_with(self, geom: GeomHline, mapping: Aes) -> Self {
342 self.add_geom_with(geom).layer_aes(mapping)
343 }
344
345 pub fn geom_vline(self, xintercept: f64) -> Self {
348 self.add_refline(
349 GeomVline::new(xintercept),
350 false,
351 &[("xintercept", xintercept)],
352 )
353 }
354
355 pub fn geom_vline_with(self, geom: GeomVline) -> Self {
357 let x = geom.xintercept;
358 self.add_refline(geom, true, &[("xintercept", x)])
359 }
360
361 pub fn geom_vline_aes(self, mapping: Aes) -> Self {
364 self.add_geom(GeomVline::mapped()).layer_aes(mapping)
365 }
366
367 pub fn geom_vline_aes_with(self, geom: GeomVline, mapping: Aes) -> Self {
369 self.add_geom_with(geom).layer_aes(mapping)
370 }
371
372 pub fn geom_abline(self, slope: f64, intercept: f64) -> Self {
375 self.add_refline(
376 GeomAbline::new(slope, intercept),
377 false,
378 &[("slope", slope), ("intercept", intercept)],
379 )
380 }
381
382 pub fn geom_abline_with(self, geom: GeomAbline) -> Self {
384 let (b, a) = (geom.slope, geom.intercept);
385 self.add_refline(geom, true, &[("slope", b), ("intercept", a)])
386 }
387
388 pub fn geom_abline_aes(self, mapping: Aes) -> Self {
391 self.add_geom(GeomAbline::mapped()).layer_aes(mapping)
392 }
393
394 pub fn geom_abline_aes_with(self, geom: GeomAbline, mapping: Aes) -> Self {
396 self.add_geom_with(geom).layer_aes(mapping)
397 }
398
399 fn add_refline(
402 self,
403 geom: impl Geom + 'static,
404 explicit: bool,
405 values: &[(&str, f64)],
406 ) -> Self {
407 let mut data = DataFrame::new();
408 let mut mapping = Aes::new();
409 for (col, v) in values {
410 data.add_column(col.to_string(), vec![Value::Float(*v)]);
411 mapping = match *col {
412 "xintercept" => mapping.xintercept(col),
413 "yintercept" => mapping.yintercept(col),
414 "slope" => mapping.slope(col),
415 _ => mapping.intercept(col),
416 };
417 }
418 let plot = if explicit {
419 self.add_geom_with(geom)
420 } else {
421 self.add_geom(geom)
422 };
423 plot.layer_aes(mapping).layer_data(data)
424 }
425
426 pub fn geom_text(self) -> Self {
427 self.add_geom(GeomText::default())
428 }
429
430 pub fn geom_text_with(self, geom: GeomText) -> Self {
431 self.add_geom_with(geom)
432 }
433
434 #[cfg(feature = "ggpubr")]
439 pub fn stat_cor(self) -> Self {
440 self.geom_text().stat(crate::stat::cor::StatCor::default())
441 }
442
443 #[cfg(feature = "ggpubr")]
446 pub fn stat_cor_with(self, stat: crate::stat::cor::StatCor) -> Self {
447 self.geom_text().stat(stat)
448 }
449
450 #[cfg(feature = "ggpubr")]
455 pub fn stat_compare_means(self) -> Self {
456 self.geom_text()
457 .stat(crate::stat::compare_means::StatCompareMeans::default())
458 }
459
460 #[cfg(feature = "ggpubr")]
463 pub fn stat_compare_means_with(
464 self,
465 stat: crate::stat::compare_means::StatCompareMeans,
466 ) -> Self {
467 self.geom_text().stat(stat)
468 }
469
470 #[cfg(feature = "ggpubr")]
476 pub fn stat_compare_means_pairwise(self, comparisons: &[(&str, &str)]) -> Self {
477 self.stat_compare_means_pairwise_with(
478 crate::stat::compare_means::CompareMethod::Auto,
479 comparisons,
480 )
481 }
482
483 #[cfg(feature = "ggpubr")]
486 pub fn stat_compare_means_pairwise_with(
487 self,
488 method: crate::stat::compare_means::CompareMethod,
489 comparisons: &[(&str, &str)],
490 ) -> Self {
491 let col_for = |a: crate::aes::Aesthetic| {
493 self.mapping
494 .mappings
495 .iter()
496 .find(|m| m.aesthetic == a)
497 .map(|m| m.column.clone())
498 };
499 let (xcol, ycol) = match (
500 col_for(crate::aes::Aesthetic::X),
501 col_for(crate::aes::Aesthetic::Y),
502 ) {
503 (Some(x), Some(y)) => (x, y),
504 _ => return self,
505 };
506 let (xc, yc) = match (self.data.column(&xcol), self.data.column(&ycol)) {
507 (Some(x), Some(y)) => (x, y),
508 _ => return self,
509 };
510
511 let mut groups: Vec<(String, Vec<f64>)> = Vec::new();
513 let mut ymax = f64::NEG_INFINITY;
514 let mut ymin = f64::INFINITY;
515 for (xv, yv) in xc.iter().zip(yc.iter()) {
516 let y = match yv.as_f64() {
517 Some(y) if y.is_finite() => y,
518 _ => continue,
519 };
520 ymax = ymax.max(y);
521 ymin = ymin.min(y);
522 let key = xv.to_group_key();
523 if let Some(g) = groups.iter_mut().find(|(k, _)| *k == key) {
524 g.1.push(y);
525 } else {
526 groups.push((key, vec![y]));
527 }
528 }
529 if groups.len() < 2 {
530 return self;
531 }
532 let step = if ymax > ymin {
533 (ymax - ymin) * 0.12
534 } else {
535 1.0
536 };
537
538 let (mut xmin_v, mut xmax_v, mut y_v, mut label_v) =
540 (Vec::new(), Vec::new(), Vec::new(), Vec::new());
541 let mut placed = 0usize;
542 for (a, b) in comparisons {
543 let ga = groups.iter().find(|(k, _)| k == a).map(|g| &g.1);
544 let gb = groups.iter().find(|(k, _)| k == b).map(|g| &g.1);
545 let (ga, gb) = match (ga, gb) {
546 (Some(x), Some(y)) if x.len() >= 2 && y.len() >= 2 => (x, y),
547 _ => continue,
548 };
549 let p = match crate::stat::compare_means::pairwise_p(method, ga, gb) {
550 Some(p) => p,
551 None => continue,
552 };
553 xmin_v.push(Value::Str((*a).to_string()));
554 xmax_v.push(Value::Str((*b).to_string()));
555 y_v.push(Value::Float(ymax + step * (placed as f64 + 1.0)));
556 label_v.push(Value::Str(crate::stat::cor::format_p_value(p)));
557 placed += 1;
558 }
559 if xmin_v.is_empty() {
560 return self;
561 }
562
563 let data = vec![
564 ("xmin".to_string(), xmin_v),
565 ("xmax".to_string(), xmax_v),
566 ("y".to_string(), y_v),
567 ("label".to_string(), label_v),
568 ];
569 self.add_geom(crate::geom::bracket::GeomBracket::default())
570 .layer_data(data)
571 .layer_aes(Aes::new().xmin("xmin").xmax("xmax").y("y").label("label"))
572 }
573
574 pub fn geom_bracket(self, xmin: &str, xmax: &str, y: f64, label: &str) -> Self {
579 self.geom_bracket_many(
580 crate::geom::bracket::GeomBracket::default(),
581 &[(xmin, xmax, y, label)],
582 )
583 }
584
585 pub fn geom_bracket_many(
589 self,
590 geom: crate::geom::bracket::GeomBracket,
591 brackets: &[(&str, &str, f64, &str)],
592 ) -> Self {
593 let xmin = brackets
594 .iter()
595 .map(|b| Value::Str(b.0.to_string()))
596 .collect::<Vec<_>>();
597 let xmax = brackets
598 .iter()
599 .map(|b| Value::Str(b.1.to_string()))
600 .collect::<Vec<_>>();
601 let y = brackets
602 .iter()
603 .map(|b| Value::Float(b.2))
604 .collect::<Vec<_>>();
605 let label = brackets
606 .iter()
607 .map(|b| Value::Str(b.3.to_string()))
608 .collect::<Vec<_>>();
609 let data = vec![
610 ("xmin".to_string(), xmin),
611 ("xmax".to_string(), xmax),
612 ("y".to_string(), y),
613 ("label".to_string(), label),
614 ];
615 self.add_geom(geom)
616 .layer_data(data)
617 .layer_aes(Aes::new().xmin("xmin").xmax("xmax").y("y").label("label"))
618 }
619
620 pub fn geom_bracket_table(
629 mut self,
630 table: impl GGData,
631 spec: crate::geom::bracket::BracketTable,
632 ) -> Self {
633 let table = table.into_dataframe();
634 let col_for = |a: crate::aes::Aesthetic| {
635 self.mapping
636 .mappings
637 .iter()
638 .find(|m| m.aesthetic == a)
639 .map(|m| m.column.clone())
640 };
641 let x_levels: Vec<String> = col_for(crate::aes::Aesthetic::X)
644 .and_then(|c| self.data.column(&c))
645 .filter(|col| col.iter().any(|v| matches!(v, Value::Str(_))))
646 .map(|col| {
647 let mut seen = std::collections::HashSet::new();
648 col.iter()
649 .filter(|v| !v.is_na())
650 .map(|v| v.to_group_key())
651 .filter(|k| seen.insert(k.clone()))
652 .collect()
653 })
654 .unwrap_or_default();
655 let y_range = col_for(crate::aes::Aesthetic::Y)
656 .and_then(|c| self.data.column(&c))
657 .and_then(|col| {
658 let (lo, hi) = col
659 .iter()
660 .filter_map(|v| v.as_f64())
661 .filter(|v| v.is_finite())
662 .fold((f64::INFINITY, f64::NEG_INFINITY), |(lo, hi), v| {
663 (lo.min(v), hi.max(v))
664 });
665 (lo <= hi).then_some((lo, hi))
666 });
667 let mut warnings = Vec::new();
668 let resolved = spec.resolve(&table, &x_levels, y_range, &mut warnings);
669 self.warnings.extend(warnings);
670 match resolved {
671 Some(data) => self
672 .add_geom(crate::geom::bracket::GeomBracket::from(spec.geom))
673 .layer_data(data)
674 .layer_aes(Aes::new().xmin("xmin").xmax("xmax").y("y").label("label")),
675 None => self,
676 }
677 }
678
679 pub fn geom_text_repel(self) -> Self {
684 self.add_geom(crate::geom::repel::GeomTextRepel::default())
685 }
686
687 pub fn geom_text_repel_with(self, geom: crate::geom::repel::GeomTextRepel) -> Self {
690 self.add_geom_with(geom)
691 }
692
693 pub fn geom_label_repel(self) -> Self {
696 self.add_geom(crate::geom::repel::GeomLabelRepel::default())
697 }
698
699 pub fn geom_label_repel_with(self, geom: crate::geom::repel::GeomLabelRepel) -> Self {
701 self.add_geom_with(geom)
702 }
703
704 pub fn geom_label(self) -> Self {
705 self.add_geom(GeomLabel::default())
706 }
707
708 pub fn geom_label_with(self, geom: GeomLabel) -> Self {
709 self.add_geom_with(geom)
710 }
711
712 pub fn geom_area(self) -> Self {
713 self.add_geom(GeomArea::default())
714 }
715
716 pub fn geom_area_with(self, geom: GeomArea) -> Self {
717 self.add_geom_with(geom)
718 }
719
720 pub fn geom_ribbon(self) -> Self {
721 self.add_geom(GeomRibbon::default())
722 }
723
724 pub fn geom_ribbon_with(self, geom: GeomRibbon) -> Self {
725 self.add_geom_with(geom)
726 }
727
728 pub fn geom_errorbar(self) -> Self {
729 self.add_geom(GeomErrorbar::default())
730 }
731
732 pub fn geom_errorbar_with(self, geom: GeomErrorbar) -> Self {
733 self.add_geom_with(geom)
734 }
735
736 pub fn geom_segment(self) -> Self {
737 self.add_geom(GeomSegment::default())
738 }
739
740 pub fn geom_segment_with(self, geom: GeomSegment) -> Self {
741 self.add_geom_with(geom)
742 }
743
744 pub fn geom_density(self) -> Self {
745 self.add_geom(GeomDensity::default())
746 }
747
748 pub fn geom_density_with(self, geom: GeomDensity) -> Self {
749 self.add_geom_with(geom)
750 }
751
752 pub fn geom_rug(self) -> Self {
753 self.add_geom(GeomRug::default())
754 }
755
756 pub fn geom_rug_with(self, geom: GeomRug) -> Self {
757 self.add_geom_with(geom)
758 }
759
760 pub fn geom_jitter(self) -> Self {
761 self.add_geom(GeomJitter::default())
762 }
763
764 pub fn geom_jitter_with(self, geom: GeomJitter) -> Self {
765 self.add_geom_with(geom)
766 }
767
768 pub fn geom_path(self) -> Self {
769 self.add_geom(GeomPath::default())
770 }
771
772 pub fn geom_path_with(self, geom: GeomPath) -> Self {
773 self.add_geom_with(geom)
774 }
775
776 pub fn geom_function(self, fun: impl Fn(f64) -> f64 + Send + Sync + 'static) -> Self {
780 self.geom_line()
781 .stat(crate::stat::function::StatFunction::new(fun))
782 }
783
784 pub fn geom_function_xlim(
786 self,
787 fun: impl Fn(f64) -> f64 + Send + Sync + 'static,
788 lo: f64,
789 hi: f64,
790 ) -> Self {
791 let range = vec![("x".to_string(), vec![Value::Float(lo), Value::Float(hi)])];
792 self.geom_line()
793 .layer_data(range)
794 .layer_aes(Aes::new().x("x"))
795 .stat(crate::stat::function::StatFunction::new(fun).with_xlim(lo, hi))
796 }
797
798 pub fn stat_connect(self, connection: crate::stat::connect::Connection) -> Self {
801 self.geom_path()
802 .stat(crate::stat::connect::StatConnect::new(connection))
803 }
804
805 pub fn stat_unique(self) -> Self {
808 self.geom_point().stat(crate::stat::unique::StatUnique)
809 }
810
811 pub fn stat_manual(
814 self,
815 fun: impl Fn(&crate::data::DataFrame) -> crate::data::DataFrame + Send + Sync + 'static,
816 ) -> Self {
817 self.geom_point()
818 .stat(crate::stat::manual::StatManual::new(fun))
819 }
820
821 pub fn stat_summary_hex(self, fun: crate::stat::summary::SummaryFun) -> Self {
824 self.geom_hex()
825 .stat(crate::stat::binhex::StatSummaryHex::new(fun))
826 }
827
828 #[cfg(feature = "sf")]
832 pub fn stat_sf_coordinates(self) -> Self {
833 self.geom_point()
834 .stat(crate::stat::sf_coordinates::StatSfCoordinates::default())
835 }
836
837 pub fn stat_ellipse(self) -> Self {
839 self.geom_path()
840 .stat(crate::stat::ellipse::StatEllipse::default())
841 }
842
843 pub fn stat_ellipse_level(self, level: f64) -> Self {
845 self.geom_path()
846 .stat(crate::stat::ellipse::StatEllipse::new(level))
847 }
848
849 #[cfg(feature = "regression")]
852 pub fn stat_quantile(mut self, taus: &[f64]) -> Self {
853 for &tau in taus {
854 self = self
855 .geom_path()
856 .stat(crate::stat::quantile::StatQuantile::new(tau));
857 }
858 self
859 }
860
861 #[cfg(feature = "regression")]
863 pub fn geom_quantile(self) -> Self {
864 self.stat_quantile(&[0.25, 0.5, 0.75])
865 }
866
867 pub fn geom_step(self) -> Self {
868 self.add_geom(GeomStep::default())
869 }
870
871 pub fn geom_step_with(self, geom: GeomStep) -> Self {
872 self.add_geom_with(geom)
873 }
874
875 pub fn geom_freqpoly(self) -> Self {
876 self.add_geom(GeomFreqpoly::default())
877 }
878
879 pub fn geom_freqpoly_with(self, geom: GeomFreqpoly) -> Self {
880 self.add_geom_with(geom)
881 }
882
883 pub fn geom_linerange(self) -> Self {
884 self.add_geom(GeomLinerange::default())
885 }
886
887 pub fn geom_linerange_with(self, geom: GeomLinerange) -> Self {
888 self.add_geom_with(geom)
889 }
890
891 pub fn geom_pointrange(self) -> Self {
892 self.add_geom(GeomPointrange::default())
893 }
894
895 pub fn geom_pointrange_with(self, geom: GeomPointrange) -> Self {
896 self.add_geom_with(geom)
897 }
898
899 pub fn geom_crossbar(self) -> Self {
900 self.add_geom(GeomCrossbar::default())
901 }
902
903 pub fn geom_crossbar_with(self, geom: GeomCrossbar) -> Self {
904 self.add_geom_with(geom)
905 }
906
907 pub fn geom_spoke(self) -> Self {
908 self.add_geom(GeomSpoke::default())
909 }
910
911 pub fn geom_spoke_with(self, geom: GeomSpoke) -> Self {
912 self.add_geom_with(geom)
913 }
914
915 pub fn geom_rect(self) -> Self {
916 self.add_geom(GeomRect::default())
917 }
918
919 pub fn geom_rect_with(self, geom: GeomRect) -> Self {
920 self.add_geom_with(geom)
921 }
922
923 pub fn geom_tile(self) -> Self {
924 self.add_geom(GeomTile::default())
925 }
926
927 pub fn geom_tile_with(self, geom: GeomTile) -> Self {
928 self.add_geom_with(geom)
929 }
930
931 pub fn geom_raster(self) -> Self {
933 self.add_geom(crate::geom::raster::GeomRaster::default())
934 }
935
936 pub fn geom_raster_with(self, geom: crate::geom::raster::GeomRaster) -> Self {
937 self.add_geom_with(geom)
938 }
939
940 pub fn geom_polygon(self) -> Self {
941 self.add_geom(GeomPolygon::default())
942 }
943
944 pub fn geom_polygon_with(self, geom: GeomPolygon) -> Self {
945 self.add_geom_with(geom)
946 }
947
948 #[cfg(feature = "sf")]
950 pub fn geom_sf(self) -> Self {
951 self.add_geom(crate::geom::sf::GeomSf::default())
952 }
953
954 #[cfg(feature = "sf")]
955 pub fn geom_sf_with(self, geom: crate::geom::sf::GeomSf) -> Self {
956 self.add_geom_with(geom)
957 }
958
959 #[cfg(feature = "sf")]
962 pub fn geom_sf_text(self) -> Self {
963 self.add_geom(crate::geom::sf_text::GeomSfText::default())
964 }
965
966 #[cfg(feature = "sf")]
967 pub fn geom_sf_text_with(self, geom: crate::geom::sf_text::GeomSfText) -> Self {
968 self.add_geom_with(geom)
969 }
970
971 #[cfg(feature = "sf")]
974 pub fn geom_sf_label(self) -> Self {
975 self.add_geom(crate::geom::sf_text::GeomSfLabel::default())
976 }
977
978 #[cfg(feature = "sf")]
979 pub fn geom_sf_label_with(self, geom: crate::geom::sf_text::GeomSfLabel) -> Self {
980 self.add_geom_with(geom)
981 }
982
983 #[cfg(feature = "sf")]
987 pub fn annotation_scale(self) -> Self {
988 self.add_geom(crate::geom::annotation_scale::GeomAnnotationScale::default())
989 }
990
991 #[cfg(feature = "sf")]
992 pub fn annotation_scale_with(
993 self,
994 geom: crate::geom::annotation_scale::GeomAnnotationScale,
995 ) -> Self {
996 self.add_geom_with(geom)
997 }
998
999 #[cfg(feature = "sf")]
1002 pub fn annotation_north_arrow_with(
1003 self,
1004 geom: crate::geom::annotation_scale::GeomNorthArrow,
1005 ) -> Self {
1006 self.add_geom_with(geom)
1007 }
1008
1009 #[cfg(feature = "sf")]
1012 pub fn annotation_attribution(self, text: impl Into<String>) -> Self {
1013 self.add_geom(crate::geom::annotation_scale::GeomAttribution::new(text))
1014 }
1015
1016 #[cfg(feature = "tiles")]
1024 pub fn annotation_map_tile(
1025 self,
1026 source: crate::geom::map_tile::TileSource,
1027 fetcher: impl crate::geom::map_tile::TileFetcher + 'static,
1028 ) -> Self {
1029 self.annotation_map_tile_with(crate::geom::map_tile::GeomMapTile::new(source, fetcher))
1030 }
1031
1032 #[cfg(feature = "tiles")]
1035 pub fn annotation_map_tile_with(self, geom: crate::geom::map_tile::GeomMapTile) -> Self {
1036 let attribution = geom.source.attribution.clone();
1037 let mut plot = self.add_geom_with(geom);
1038 if let Some(layer) = plot.layers.pop() {
1040 plot.layers.insert(0, layer);
1041 for (idx, ..) in plot.layer_svg_attrs.iter_mut() {
1042 *idx += 1;
1043 }
1044 }
1045 if attribution.is_empty() {
1046 plot
1047 } else {
1048 plot.annotation_attribution(attribution)
1049 }
1050 }
1051
1052 #[cfg(feature = "sf")]
1053 pub fn annotation_attribution_with(
1054 self,
1055 geom: crate::geom::annotation_scale::GeomAttribution,
1056 ) -> Self {
1057 self.add_geom_with(geom)
1058 }
1059
1060 #[cfg(feature = "sf")]
1068 pub fn bivariate_legend(
1069 self,
1070 geom: crate::geom::bivariate_legend::GeomBivariateLegend,
1071 ) -> Self {
1072 self.add_geom(geom)
1073 }
1074
1075 #[cfg(feature = "sf")]
1080 pub fn bivariate_legend_counts(
1081 self,
1082 geom: crate::geom::bivariate_legend::GeomBivariateLegendCounts,
1083 ) -> Self {
1084 self.add_geom(geom)
1085 }
1086
1087 pub fn geom_curve(self) -> Self {
1088 self.add_geom(GeomCurve::default())
1089 }
1090
1091 pub fn geom_curve_with(self, geom: GeomCurve) -> Self {
1092 self.add_geom_with(geom)
1093 }
1094
1095 pub fn geom_violin(self) -> Self {
1096 self.add_geom(GeomViolin::default())
1097 }
1098
1099 pub fn geom_violin_with(self, geom: GeomViolin) -> Self {
1100 self.add_geom_with(geom)
1101 }
1102
1103 pub fn geom_density_ridges(self) -> Self {
1107 self.add_geom(GeomDensityRidges::default())
1108 }
1109
1110 pub fn geom_density_ridges_with(self, geom: GeomDensityRidges) -> Self {
1111 self.add_geom_with(geom)
1112 }
1113
1114 pub fn geom_dotplot(self) -> Self {
1115 self.add_geom(GeomDotplot::default())
1116 }
1117
1118 pub fn geom_dotplot_with(self, geom: GeomDotplot) -> Self {
1119 self.add_geom_with(geom)
1120 }
1121
1122 pub fn geom_qq(self) -> Self {
1123 self.add_geom(GeomQQ::default())
1124 }
1125
1126 pub fn geom_qq_with(self, geom: GeomQQ) -> Self {
1127 self.add_geom_with(geom)
1128 }
1129
1130 pub fn geom_qq_line(self) -> Self {
1131 self.add_geom(GeomQQLine::default())
1132 }
1133
1134 pub fn geom_qq_line_with(self, geom: GeomQQLine) -> Self {
1135 self.add_geom_with(geom)
1136 }
1137
1138 pub fn geom_bin2d(self) -> Self {
1139 self.add_geom(GeomBin2d::default())
1140 }
1141
1142 pub fn geom_bin2d_with(self, geom: GeomBin2d) -> Self {
1143 self.add_geom_with(geom)
1144 }
1145
1146 pub fn geom_hex(self) -> Self {
1147 self.add_geom(GeomHex::default())
1148 }
1149
1150 pub fn geom_hex_with(self, geom: GeomHex) -> Self {
1151 self.add_geom_with(geom)
1152 }
1153
1154 pub fn geom_count(self) -> Self {
1155 self.add_geom(GeomCount::default())
1156 }
1157
1158 pub fn geom_count_with(self, geom: GeomCount) -> Self {
1159 self.add_geom_with(geom)
1160 }
1161
1162 pub fn geom_contour(self) -> Self {
1163 self.add_geom(GeomContour::default())
1164 }
1165
1166 pub fn geom_contour_with(self, geom: GeomContour) -> Self {
1167 self.add_geom_with(geom)
1168 }
1169
1170 pub fn geom_contour_filled(self) -> Self {
1173 self.add_geom(GeomPolygon {
1174 line_width: 0.0,
1175 alpha: 1.0,
1176 ..GeomPolygon::default()
1177 })
1178 .stat(crate::stat::contour_filled::StatContourFilled::default())
1179 }
1180
1181 pub fn geom_density2d(self) -> Self {
1182 self.add_geom(GeomDensity2d::default())
1183 }
1184
1185 pub fn geom_density2d_with(self, geom: GeomDensity2d) -> Self {
1186 self.add_geom_with(geom)
1187 }
1188
1189 pub fn geom_waterfall(self) -> Self {
1195 self.default_styled(|p| {
1196 p.geom_waterfall_with(crate::geom::waterfall::GeomWaterfall::default())
1197 })
1198 }
1199
1200 pub fn geom_waterfall_with(self, geom: crate::geom::waterfall::GeomWaterfall) -> Self {
1207 use crate::scale::color::RGBAColor;
1208 use crate::stat::waterfall::{WATERFALL_DECREASE, WATERFALL_INCREASE, WATERFALL_TOTAL};
1209 let rgba = |(r, g, b): (u8, u8, u8)| RGBAColor::new(r, g, b);
1210 let mut values = vec![
1211 (WATERFALL_INCREASE, rgba(geom.up)),
1212 (WATERFALL_DECREASE, rgba(geom.down)),
1213 ];
1214 if geom.has_totals() {
1215 values.push((WATERFALL_TOTAL, rgba(geom.total)));
1216 }
1217 let fill_mapped = self
1218 .mapping
1219 .get_mapping(&crate::aes::Aesthetic::Fill)
1220 .is_some();
1221 let has_fill_scale = self
1222 .scales
1223 .iter()
1224 .any(|s| s.aesthetic() == crate::aes::Aesthetic::Fill);
1225 let mut plot = self.add_geom_with(geom);
1226 if !fill_mapped {
1227 plot = plot.layer_aes(Aes::new().after_stat_fill("direction"));
1228 if !has_fill_scale {
1229 plot = plot.scale_fill_manual(values);
1230 }
1231 }
1232 plot
1233 }
1234
1235 pub fn geom_pareto(self) -> Self {
1239 self.add_pareto(crate::geom::pareto::GeomPareto::default(), false)
1240 }
1241
1242 pub fn geom_pareto_with(self, geom: crate::geom::pareto::GeomPareto) -> Self {
1248 self.add_pareto(geom, true)
1249 }
1250
1251 fn add_pareto(self, geom: crate::geom::pareto::GeomPareto, explicit: bool) -> Self {
1252 let has_y_scale = self
1253 .scales
1254 .iter()
1255 .any(|s| s.aesthetic() == crate::aes::Aesthetic::Y);
1256 let plot = if explicit {
1257 self.add_geom_with(geom)
1258 } else {
1259 self.add_geom(geom)
1260 };
1261 if has_y_scale {
1262 plot
1263 } else {
1264 plot.scale_y_continuous(ScaleContinuous::new().with_sec_axis(
1265 crate::scale::sec_axis::SecAxis::percent_of_max().with_name("Cumulative %"),
1266 ))
1267 }
1268 }
1269
1270 pub fn geom_sankey(self) -> Self {
1277 self.add_sankey(crate::geom::sankey::GeomSankey::default(), false)
1278 }
1279
1280 pub fn geom_sankey_with(self, geom: crate::geom::sankey::GeomSankey) -> Self {
1282 self.add_sankey(geom, true)
1283 }
1284
1285 fn add_sankey(self, geom: crate::geom::sankey::GeomSankey, explicit: bool) -> Self {
1286 let mut plot = if explicit {
1287 self.add_geom_with(geom)
1288 } else {
1289 self.add_geom(geom)
1290 };
1291 plot.hide_position_guides = true;
1292 plot.layer_aes(Aes::new().after_stat_fill("node"))
1293 .show_legend(false)
1294 }
1295
1296 pub fn geom_chord(self) -> Self {
1303 self.add_chord(crate::geom::chord::GeomChord::default(), false)
1304 }
1305
1306 pub fn geom_chord_with(self, geom: crate::geom::chord::GeomChord) -> Self {
1308 self.add_chord(geom, true)
1309 }
1310
1311 fn add_chord(self, geom: crate::geom::chord::GeomChord, explicit: bool) -> Self {
1312 let (ex, ey) = geom.extents();
1313 let mut plot = if explicit {
1314 self.add_geom_with(geom)
1315 } else {
1316 self.add_geom(geom)
1317 };
1318 plot.hide_position_guides = true;
1319 plot.default_aspect_ratio = Some(ey / ex);
1320 plot.layer_aes(Aes::new().after_stat_fill("node"))
1321 .show_legend(false)
1322 }
1323
1324 pub fn geom_arcdiagram(self) -> Self {
1329 self.add_arcdiagram(crate::geom::arcdiagram::GeomArcdiagram::default(), false)
1330 }
1331
1332 pub fn geom_arcdiagram_with(self, geom: crate::geom::arcdiagram::GeomArcdiagram) -> Self {
1335 self.add_arcdiagram(geom, true)
1336 }
1337
1338 fn add_arcdiagram(self, geom: crate::geom::arcdiagram::GeomArcdiagram, explicit: bool) -> Self {
1339 let mut plot = if explicit {
1340 self.add_geom_with(geom)
1341 } else {
1342 self.add_geom(geom)
1343 };
1344 plot.hide_position_guides = true;
1345 plot.layer_aes(Aes::new().after_stat_fill("node"))
1346 .show_legend(false)
1347 }
1348
1349 pub fn geom_treemap(self) -> Self {
1357 self.add_treemap(crate::geom::treemap::GeomTreemap::default(), false)
1358 }
1359
1360 pub fn geom_treemap_with(self, geom: crate::geom::treemap::GeomTreemap) -> Self {
1362 self.add_treemap(geom, true)
1363 }
1364
1365 fn add_treemap(self, geom: crate::geom::treemap::GeomTreemap, explicit: bool) -> Self {
1366 use crate::aes::Aesthetic;
1367 let aspect = geom.aspect;
1368 let has = |plot: &Self, aes: Aesthetic| plot.scales.iter().any(|s| s.aesthetic() == aes);
1369 let (has_x, has_y) = (has(&self, Aesthetic::X), has(&self, Aesthetic::Y));
1370 let fill_by = match (
1371 self.mapping.get_mapping(&Aesthetic::Fill),
1372 self.mapping.get_mapping(&Aesthetic::Subgroup),
1373 ) {
1374 (None, Some(sub)) => Some(sub.to_string()),
1375 _ => None,
1376 };
1377 let mut plot = if explicit {
1378 self.add_geom_with(geom)
1379 } else {
1380 self.add_geom(geom)
1381 };
1382 plot.hide_position_guides = true;
1383 plot.default_aspect_ratio = Some(1.0 / aspect.max(1e-6));
1384 if let Some(sub) = fill_by {
1385 plot = plot.layer_aes(Aes::new().fill(&sub));
1386 }
1387 if !has_x {
1388 plot = plot.scale_x_continuous(ScaleContinuous::new().with_expand(0.0, 0.0));
1389 }
1390 if !has_y {
1391 plot = plot.scale_y_continuous(ScaleContinuous::new().with_expand(0.0, 0.0));
1392 }
1393 plot
1394 }
1395
1396 pub fn geom_sunburst<S: Into<String>>(self, levels: impl IntoIterator<Item = S>) -> Self {
1403 let geom = crate::geom::partition::GeomPartition::sunburst(levels);
1404 let depth = geom.levels.len().max(1) as f64;
1406 let inner = geom.hole / (geom.hole + depth);
1407 let mut plot = self.default_styled(|p| p.geom_partition_with(geom));
1408 plot.coord = Box::new(CoordPolar::new().inner_radius(inner));
1409 plot
1410 }
1411
1412 pub fn geom_icicle<S: Into<String>>(self, levels: impl IntoIterator<Item = S>) -> Self {
1416 self.default_styled(|p| {
1417 p.geom_partition_with(crate::geom::partition::GeomPartition::icicle(levels))
1418 })
1419 }
1420
1421 pub fn geom_partition_with(self, geom: crate::geom::partition::GeomPartition) -> Self {
1425 use crate::aes::Aesthetic;
1426 let has = |plot: &Self, aes: Aesthetic| plot.scales.iter().any(|s| s.aesthetic() == aes);
1427 let (has_x, has_y) = (has(&self, Aesthetic::X), has(&self, Aesthetic::Y));
1428 let fill_mapped = self.mapping.get_mapping(&Aesthetic::Fill).is_some();
1429 let mut plot = self.add_geom_with(geom);
1430 plot.hide_position_guides = true;
1431 if !fill_mapped {
1432 plot = plot
1433 .layer_aes(Aes::new().after_stat_fill("root"))
1434 .show_legend(false);
1435 }
1436 if !has_x {
1437 plot = plot.scale_x_continuous(ScaleContinuous::new().with_expand(0.0, 0.0));
1438 }
1439 if !has_y {
1440 plot = plot.scale_y_continuous(ScaleContinuous::new().with_expand(0.0, 0.0));
1441 }
1442 plot
1443 }
1444
1445 pub fn geom_funnel(self) -> Self {
1453 self.default_styled(|p| p.geom_funnel_with(crate::geom::funnel::GeomFunnel::default()))
1454 }
1455
1456 pub fn geom_pyramid(self) -> Self {
1458 self.default_styled(|p| p.geom_funnel_with(crate::geom::funnel::GeomFunnel::pyramid()))
1459 }
1460
1461 pub fn geom_funnel_with(self, geom: crate::geom::funnel::GeomFunnel) -> Self {
1463 let fill_mapped = self
1464 .mapping
1465 .get_mapping(&crate::aes::Aesthetic::Fill)
1466 .is_some();
1467 let mut plot = self.add_geom_with(geom);
1468 plot.hide_position_guides = true;
1469 if !fill_mapped {
1470 plot = plot
1471 .layer_aes(Aes::new().after_stat_fill("stage"))
1472 .show_legend(false);
1473 }
1474 plot
1475 }
1476
1477 pub fn geom_stream(self) -> Self {
1483 self.geom_area().position(
1484 crate::position::stack::position_stack()
1485 .with_offset(crate::position::stack::StackOffset::Wiggle),
1486 )
1487 }
1488
1489 pub fn geom_lollipop(self) -> Self {
1492 self.add_geom(crate::geom::lollipop::GeomLollipop::default())
1493 }
1494
1495 pub fn geom_lollipop_with(self, geom: crate::geom::lollipop::GeomLollipop) -> Self {
1496 self.add_geom_with(geom)
1497 }
1498
1499 pub fn geom_dumbbell(self) -> Self {
1503 self.add_geom(crate::geom::lollipop::GeomDumbbell::default())
1504 }
1505
1506 pub fn geom_dumbbell_with(self, geom: crate::geom::lollipop::GeomDumbbell) -> Self {
1507 self.add_geom_with(geom)
1508 }
1509
1510 pub fn geom_bullet(self, geom: crate::geom::bullet::GeomBullet) -> Self {
1516 self.add_geom_with(geom).coord_flip()
1517 }
1518
1519 pub fn geom_bullet_vertical(self, geom: crate::geom::bullet::GeomBullet) -> Self {
1521 self.add_geom_with(geom)
1522 }
1523
1524 pub fn geom_waffle(self, rows: usize) -> Self {
1528 self.default_styled(|p| p.geom_waffle_with(crate::geom::waffle::GeomWaffle::waffle(rows)))
1529 }
1530
1531 pub fn geom_parliament(self, rows: usize) -> Self {
1535 self.default_styled(|p| {
1536 p.geom_waffle_with(crate::geom::waffle::GeomWaffle::parliament(rows))
1537 })
1538 }
1539
1540 pub fn geom_waffle_with(self, geom: crate::geom::waffle::GeomWaffle) -> Self {
1542 let mut plot = self.add_geom_with(geom);
1543 plot.hide_position_guides = true;
1544 plot
1545 }
1546
1547 pub fn geom_packed_bubble(self) -> Self {
1552 self.default_styled(|p| {
1553 p.geom_packed_bubble_with(crate::geom::pack::GeomPackedBubble::default())
1554 })
1555 }
1556
1557 pub fn geom_packed_bubble_with(self, geom: crate::geom::pack::GeomPackedBubble) -> Self {
1559 use crate::aes::Aesthetic;
1560 let fill_by = match (
1561 self.mapping.get_mapping(&Aesthetic::Fill),
1562 self.mapping.get_mapping(&Aesthetic::Subgroup),
1563 ) {
1564 (None, Some(sub)) => Some(sub.to_string()),
1565 _ => None,
1566 };
1567 let mut plot = self.add_geom_with(geom);
1568 plot.hide_position_guides = true;
1569 plot.default_aspect_ratio = Some(1.0);
1570 if let Some(sub) = fill_by {
1571 plot = plot.layer_aes(Aes::new().fill(&sub));
1572 }
1573 plot
1574 }
1575
1576 pub fn geom_network(self) -> Self {
1582 self.add_network(crate::geom::network::GeomNetwork::default(), false)
1583 }
1584
1585 pub fn geom_network_with(self, geom: crate::geom::network::GeomNetwork) -> Self {
1587 self.add_network(geom, true)
1588 }
1589
1590 fn add_network(self, geom: crate::geom::network::GeomNetwork, explicit: bool) -> Self {
1591 let by_component = geom.color_components;
1592 let mut plot = if explicit {
1593 self.add_geom_with(geom)
1594 } else {
1595 self.add_geom(geom)
1596 };
1597 plot.hide_position_guides = true;
1598 plot.default_aspect_ratio = Some(1.0);
1599 if by_component {
1600 plot = plot
1601 .layer_aes(Aes::new().after_stat_fill("component"))
1602 .show_legend(false);
1603 }
1604 plot
1605 }
1606
1607 pub fn geom_tree(self) -> Self {
1614 self.default_styled(|p| p.geom_tree_with(crate::geom::tree::GeomTree::default()))
1615 }
1616
1617 pub fn geom_dendrogram(self) -> Self {
1621 self.default_styled(|p| p.geom_tree_with(crate::geom::tree::GeomTree::dendrogram()))
1622 }
1623
1624 pub fn geom_tree_with(self, geom: crate::geom::tree::GeomTree) -> Self {
1626 let radial = geom.orientation == crate::stat::tree::TreeOrientation::Radial;
1627 let mut plot = self.add_geom_with(geom);
1628 plot.hide_position_guides = true;
1629 if radial {
1630 plot.default_aspect_ratio = Some(1.0);
1631 }
1632 plot
1633 }
1634
1635 pub fn geom_venn(self) -> Self {
1641 self.default_styled(|p| p.geom_venn_with(crate::geom::venn::GeomVenn::default()))
1642 }
1643
1644 pub fn geom_venn_with(self, geom: crate::geom::venn::GeomVenn) -> Self {
1646 let mut plot = self.add_geom_with(geom);
1647 plot.hide_position_guides = true;
1648 plot.default_aspect_ratio = Some(1.0);
1649 plot.layer_aes(Aes::new().after_stat_fill("set"))
1650 .show_legend(false)
1651 }
1652
1653 pub fn geom_wordcloud(self) -> Self {
1658 self.default_styled(|p| {
1659 p.geom_wordcloud_with(crate::geom::wordcloud::GeomWordcloud::default())
1660 })
1661 }
1662
1663 pub fn geom_wordcloud_with(self, geom: crate::geom::wordcloud::GeomWordcloud) -> Self {
1666 let mut plot = self.add_geom_with(geom);
1667 plot.hide_position_guides = true;
1668 plot
1669 }
1670
1671 pub fn geom_variwide(self) -> Self {
1676 self.default_styled(|p| {
1677 p.geom_marimekko_with(crate::geom::marimekko::GeomMarimekko::variwide())
1678 })
1679 }
1680
1681 pub fn geom_marimekko(self) -> Self {
1685 self.default_styled(|p| {
1686 p.geom_marimekko_with(crate::geom::marimekko::GeomMarimekko::marimekko())
1687 })
1688 }
1689
1690 pub fn geom_marimekko_with(self, geom: crate::geom::marimekko::GeomMarimekko) -> Self {
1692 use crate::aes::Aesthetic;
1693 let has = |plot: &Self, aes: Aesthetic| plot.scales.iter().any(|s| s.aesthetic() == aes);
1694 let (has_x, has_y) = (has(&self, Aesthetic::X), has(&self, Aesthetic::Y));
1695 let axis = self.mapping.get_mapping(&Aesthetic::X).and_then(|xc| {
1697 let x = self.data.column(xc)?;
1698 let w = self
1699 .mapping
1700 .get_mapping(&Aesthetic::Weight)
1701 .and_then(|wc| self.data.column(wc));
1702 let totals = crate::stat::marimekko::column_totals(x, w);
1703 let widths: Vec<f64> = totals.iter().map(|t| t.1).collect();
1704 let spans = crate::stat::marimekko::column_spans(&widths, geom.gap);
1705 Some((
1706 spans
1707 .iter()
1708 .map(|s| (s.0 + s.1) / 2.0)
1709 .collect::<Vec<f64>>(),
1710 totals.into_iter().map(|t| t.0).collect::<Vec<String>>(),
1711 ))
1712 });
1713 let mosaic = geom.mosaic;
1714 let mut plot = self.add_geom_with(geom);
1715 if !has_x {
1716 let mut sx = ScaleContinuous::new().with_expand(0.0, 0.0);
1717 if let Some((breaks, labels)) = axis {
1718 sx = sx.with_breaks(breaks).with_labels(labels);
1719 }
1720 plot = plot.scale_x_continuous(sx);
1721 }
1722 if mosaic && !has_y {
1723 plot = plot.scale_y_continuous(
1724 ScaleContinuous::new()
1725 .with_expand(0.0, 0.0)
1726 .with_label_formatter(|v| format!("{}%", (v * 100.0).round())),
1727 );
1728 }
1729 plot
1730 }
1731
1732 pub fn geom_timeline(self) -> Self {
1737 let mut plot = self.add_geom(crate::geom::timeline::GeomTimeline::default());
1738 plot.hide_y_guides = true;
1739 plot
1740 }
1741
1742 pub fn geom_timeline_with(self, geom: crate::geom::timeline::GeomTimeline) -> Self {
1744 let mut plot = self.add_geom_with(geom);
1745 plot.hide_y_guides = true;
1746 plot
1747 }
1748
1749 pub fn geom_xrange(self) -> Self {
1756 self.add_xrange(crate::geom::xrange::GeomXrange::default(), false)
1757 }
1758
1759 pub fn geom_xrange_with(self, geom: crate::geom::xrange::GeomXrange) -> Self {
1761 self.add_xrange(geom, true)
1762 }
1763
1764 fn add_xrange(self, geom: crate::geom::xrange::GeomXrange, explicit: bool) -> Self {
1765 use crate::aes::Aesthetic;
1766 let has_y = self.scales.iter().any(|s| s.aesthetic() == Aesthetic::Y);
1767 let levels: Option<Vec<String>> = self
1769 .mapping
1770 .get_mapping(&Aesthetic::Y)
1771 .and_then(|c| self.data.column(c))
1772 .map(|col| {
1773 let mut seen: indexmap::IndexSet<String> = indexmap::IndexSet::new();
1774 for v in col.iter().filter(|v| !v.is_na()) {
1775 seen.insert(v.key_str().into_owned());
1776 }
1777 seen.into_iter().rev().collect()
1778 });
1779 let mut plot = if explicit {
1780 self.add_geom_with(geom)
1781 } else {
1782 self.add_geom(geom)
1783 };
1784 if let (false, Some(levels)) = (has_y, levels) {
1785 let refs: Vec<&str> = levels.iter().map(String::as_str).collect();
1786 plot = plot
1787 .scale_y_discrete(crate::scale::discrete::ScaleDiscrete::new().with_limits(refs));
1788 }
1789 plot
1790 }
1791
1792 pub fn geom_tilemap(self, shape: crate::geom::tilemap::TileShape) -> Self {
1797 self.default_styled(|p| {
1798 p.geom_tilemap_with(crate::geom::tilemap::GeomTilemap {
1799 shape,
1800 ..Default::default()
1801 })
1802 })
1803 }
1804
1805 pub fn geom_tilemap_with(self, geom: crate::geom::tilemap::GeomTilemap) -> Self {
1807 let mut plot = self.add_geom_with(geom);
1808 plot.hide_position_guides = true;
1809 plot
1810 }
1811
1812 pub fn geom_windbarb(self, geom: crate::geom::windbarb::GeomWindbarb) -> Self {
1817 self.add_geom(geom)
1818 }
1819
1820 pub fn geom_variable_pie(self) -> Self {
1824 let mut plot = self.add_geom(crate::geom::variablepie::GeomVariablePie::default());
1825 plot.hide_position_guides = true;
1826 plot.default_aspect_ratio = Some(1.0);
1827 plot
1828 }
1829
1830 pub fn geom_variable_pie_with(self, geom: crate::geom::variablepie::GeomVariablePie) -> Self {
1833 let mut plot = self.add_geom_with(geom);
1834 plot.hide_position_guides = true;
1835 plot.default_aspect_ratio = Some(1.0);
1836 plot
1837 }
1838
1839 pub fn geom_hlc(self) -> Self {
1842 self.add_geom(crate::geom::candlestick::GeomOhlc::hlc())
1843 }
1844
1845 pub fn geom_heikin_ashi(self) -> Self {
1849 self.add_geom(crate::geom::candlestick::GeomCandlestick::default())
1850 .stat(crate::stat::heikin_ashi::StatHeikinAshi)
1851 }
1852
1853 pub fn geom_renko(self, box_size: f64) -> Self {
1857 self.add_geom(crate::geom::renko::GeomRenko::renko(box_size))
1858 .xlab("Brick")
1859 }
1860
1861 pub fn geom_point_figure(self, box_size: f64, reversal: usize) -> Self {
1865 self.add_geom(crate::geom::renko::GeomRenko::point_figure(
1866 box_size, reversal,
1867 ))
1868 .xlab("Column")
1869 }
1870
1871 pub fn geom_flags(self) -> Self {
1876 self.add_geom(crate::geom::flags::GeomFlags::default())
1877 }
1878
1879 pub fn geom_flags_with(self, geom: crate::geom::flags::GeomFlags) -> Self {
1880 self.add_geom_with(geom)
1881 }
1882
1883 #[cfg(feature = "sf")]
1888 pub fn geom_flow(self, geom: crate::geom::flow::GeomFlow) -> Self {
1889 self.add_geom(geom)
1890 }
1891
1892 pub fn geom_candlestick(self) -> Self {
1895 self.add_geom(crate::geom::candlestick::GeomCandlestick::default())
1896 }
1897
1898 pub fn geom_candlestick_with(self, geom: crate::geom::candlestick::GeomCandlestick) -> Self {
1899 self.add_geom_with(geom)
1900 }
1901
1902 pub fn geom_ohlc(self) -> Self {
1905 self.add_geom(crate::geom::candlestick::GeomOhlc::default())
1906 }
1907
1908 pub fn geom_ohlc_with(self, geom: crate::geom::candlestick::GeomOhlc) -> Self {
1909 self.add_geom_with(geom)
1910 }
1911
1912 pub fn geom_calendar(self) -> Self {
1923 self.geom_calendar_with(
1924 GeomTile {
1925 color: (255, 255, 255),
1926 line_width: 1.5,
1927 ..Default::default()
1928 },
1929 false,
1930 )
1931 }
1932
1933 pub fn geom_calendar_with(mut self, tile: GeomTile, monday_first: bool) -> Self {
1936 use crate::stat::calendar::{
1937 day_number, month_boundaries, month_breaks, month_breaks_localized, weekday_labels,
1938 CalendarGrid, StatCalendar, MAX_CALENDAR_YEARS,
1939 };
1940 let grid = self
1941 .mapping
1942 .get_mapping(&crate::aes::Aesthetic::X)
1943 .and_then(|c| self.data.column(c))
1944 .and_then(|col| {
1945 CalendarGrid::from_days(col.iter().filter_map(day_number), monday_first)
1946 });
1947 let Some((grid, clipped)) = grid else {
1948 return self.add_geom_with(tile).stat(StatCalendar {
1950 grid: None,
1951 monday_first,
1952 });
1953 };
1954 if clipped {
1955 self.warnings.push(format!(
1956 "geom_calendar: dates more than {MAX_CALENDAR_YEARS} years before the newest were dropped"
1957 ));
1958 }
1959 let (xb, _) = month_breaks(&grid);
1960 let yb = if monday_first {
1962 vec![6.0, 4.0, 2.0]
1963 } else {
1964 vec![5.0, 3.0, 1.0]
1965 };
1966 let segs = month_boundaries(&grid);
1967 let col = |f: fn(&(f64, f64, f64, f64)) -> f64| -> Vec<Value> {
1968 segs.iter().map(|s| Value::Float(f(s))).collect()
1969 };
1970 let boundaries = vec![
1971 ("x".to_string(), col(|s| s.0)),
1972 ("y".to_string(), col(|s| s.1)),
1973 ("xend".to_string(), col(|s| s.2)),
1974 ("yend".to_string(), col(|s| s.3)),
1975 ];
1976 self.default_aspect_ratio = Some(7.0 / grid.n_weeks().max(1) as f64);
1977 let plot = self
1978 .add_geom_with(tile)
1979 .stat(StatCalendar {
1980 grid: Some(grid),
1981 monday_first,
1982 })
1983 .scale_x_continuous(
1984 ScaleContinuous::new()
1985 .with_breaks(xb)
1986 .with_localized_labels(move |l| month_breaks_localized(&grid, l).1)
1988 .with_expand(0.0, 0.0),
1989 )
1990 .scale_y_continuous(
1991 ScaleContinuous::new()
1992 .with_breaks(yb)
1993 .with_localized_labels(weekday_labels)
1994 .with_expand(0.0, 0.0),
1995 );
1996 if segs.is_empty() {
1997 return plot;
1998 }
1999 plot.add_geom_with(crate::geom::segment::GeomCalendarBorder)
2001 .layer_data(boundaries)
2002 .layer_aes(Aes::new().x("x").y("y").xend("xend").yend("yend"))
2003 .show_legend(false)
2004 }
2005
2006 pub fn geom_blank(self) -> Self {
2007 self.add_geom(GeomBlank)
2008 }
2009
2010 fn default_styled(self, build: impl FnOnce(Self) -> Self) -> Self {
2017 let i = self.layers.len();
2018 let mut plot = build(self);
2019 if let Some(layer) = plot.layers.get_mut(i) {
2020 layer.explicit_style = false;
2021 }
2022 plot
2023 }
2024
2025 fn add_geom_with(self, geom: impl Geom + 'static) -> Self {
2026 let mut plot = self.add_geom(geom);
2027 if let Some(layer) = plot.layers.last_mut() {
2028 layer.explicit_style = true;
2029 }
2030 plot
2031 }
2032
2033 fn add_geom(mut self, geom: impl Geom + 'static) -> Self {
2034 let stat = geom.default_stat();
2035 let position = geom.default_position();
2036 let params = geom.default_params();
2037 self.layers.push(Layer {
2038 data: None,
2039 mapping: Aes::default(),
2040 geom: Box::new(geom),
2041 stat,
2042 position,
2043 params,
2044 show_legend: None,
2045 explicit_style: false,
2046 tooltip_template: None,
2047 key_glyph: None,
2048 show_legend_aes: Vec::new(),
2049 });
2050 self
2051 }
2052
2053 pub fn stat(mut self, stat: impl Stat + 'static) -> Self {
2057 if let Some(layer) = self.layers.last_mut() {
2058 layer.stat = Box::new(stat);
2059 }
2060 self
2061 }
2062
2063 pub fn position(mut self, pos: impl Position + 'static) -> Self {
2065 if let Some(layer) = self.layers.last_mut() {
2066 layer.position = Box::new(pos);
2067 }
2068 self
2069 }
2070
2071 pub fn layer_data(mut self, data: impl GGData) -> Self {
2073 if let Some(layer) = self.layers.last_mut() {
2074 layer.data = Some(data.into_dataframe());
2075 }
2076 self
2077 }
2078
2079 pub fn layer_aes(mut self, mapping: Aes) -> Self {
2081 self.warnings.extend(mapping.warnings.iter().cloned());
2082 if let Some(layer) = self.layers.last_mut() {
2083 layer.mapping = mapping;
2084 }
2085 self
2086 }
2087
2088 pub fn tooltip(mut self, template: &str) -> Self {
2099 if let Some(layer) = self.layers.last_mut() {
2100 layer.tooltip_template = Some(template.to_string());
2101 }
2102 self
2103 }
2104
2105 pub fn show_legend(mut self, show: bool) -> Self {
2108 if let Some(layer) = self.layers.last_mut() {
2109 layer.show_legend = Some(show);
2110 }
2111 self
2112 }
2113
2114 pub fn guide_none(mut self, aes: crate::aes::Aesthetic) -> Self {
2116 if !self.guide_legend.hidden.contains(&aes) {
2117 self.guide_legend.hidden.push(aes);
2118 }
2119 self
2120 }
2121
2122 pub fn guide_title(mut self, aes: crate::aes::Aesthetic, title: &str) -> Self {
2125 self.guide_legend.titles.retain(|(a, _)| *a != aes);
2126 self.guide_legend.titles.push((aes, title.to_string()));
2127 self
2128 }
2129
2130 pub fn guide_colourbar(
2137 mut self,
2138 aes: crate::aes::Aesthetic,
2139 bar: crate::guide::config::GuideColourbar,
2140 ) -> Self {
2141 self.guide_legend.colourbars.retain(|(a, _)| *a != aes);
2142 self.guide_legend.colourbars.push((aes, bar));
2143 self
2144 }
2145
2146 pub fn guide_bins(
2151 mut self,
2152 aes: crate::aes::Aesthetic,
2153 bins: crate::guide::config::GuideBins,
2154 ) -> Self {
2155 self.guide_legend.plain_keys.retain(|a| *a != aes);
2156 self.guide_legend.bins.retain(|(a, _)| *a != aes);
2157 self.guide_legend.bins.push((aes, bins));
2158 self
2159 }
2160
2161 pub fn guide_position(
2165 mut self,
2166 aes: crate::aes::Aesthetic,
2167 position: crate::theme::LegendPosition,
2168 ) -> Self {
2169 self.guide_legend.positions.retain(|(a, _)| *a != aes);
2170 self.guide_legend.positions.push((aes, position));
2171 self
2172 }
2173
2174 pub fn guide_custom(mut self, guide: crate::guide::config::GuideCustom) -> Self {
2177 self.guide_legend.custom.push(guide);
2178 self
2179 }
2180
2181 pub fn guide_legend_keys(mut self, aes: crate::aes::Aesthetic) -> Self {
2184 self.guide_legend.bins.retain(|(a, _)| *a != aes);
2185 if !self.guide_legend.plain_keys.contains(&aes) {
2186 self.guide_legend.plain_keys.push(aes);
2187 }
2188 self
2189 }
2190
2191 pub fn guide_coloursteps(self, aes: crate::aes::Aesthetic) -> Self {
2194 self.guide_colourbar(aes, crate::guide::config::GuideColourbar::steps())
2195 }
2196
2197 pub fn guide_reverse(mut self, aes: crate::aes::Aesthetic, reverse: bool) -> Self {
2200 self.guide_legend.reversed.retain(|a| *a != aes);
2201 if reverse {
2202 self.guide_legend.reversed.push(aes);
2203 }
2204 self
2205 }
2206
2207 pub fn guide_override(
2210 mut self,
2211 aes: crate::aes::Aesthetic,
2212 keys: crate::guide::config::KeyOverride,
2213 ) -> Self {
2214 self.guide_legend.overrides.retain(|(a, _)| *a != aes);
2215 self.guide_legend.overrides.push((aes, keys));
2216 self
2217 }
2218
2219 pub fn guide_axis_logticks(mut self, aes: crate::aes::Aesthetic) -> Self {
2223 for s in self.scales.iter_mut().filter(|s| s.aesthetic() == aes) {
2224 s.set_log_ticks(true);
2225 }
2226 self
2227 }
2228
2229 pub fn show_legend_for(mut self, aes: crate::aes::Aesthetic, show: bool) -> Self {
2232 if let Some(layer) = self.layers.last_mut() {
2233 layer.show_legend_aes.retain(|(a, _)| *a != aes);
2234 layer.show_legend_aes.push((aes, show));
2235 }
2236 self
2237 }
2238
2239 pub fn key_glyph(mut self, glyph: crate::guide::key::KeyGlyph) -> Self {
2242 if let Some(layer) = self.layers.last_mut() {
2243 layer.key_glyph = Some(glyph);
2244 }
2245 self
2246 }
2247
2248 pub fn decorative(mut self) -> Self {
2275 if let Some(layer) = self.layers.last_mut() {
2276 let geom = std::mem::replace(&mut layer.geom, Box::new(GeomBlank));
2277 layer.geom = Box::new(crate::geom::decorative::Decorative(geom));
2278 if layer.show_legend.is_none() {
2279 layer.show_legend = Some(false);
2280 }
2281 }
2282 self
2283 }
2284
2285 pub fn layer_svg_attr(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
2319 let (name, value) = (name.into(), value.into());
2320 let Some(idx) = self.layers.len().checked_sub(1) else {
2321 self.warnings.push(format!(
2322 "layer_svg_attr(\"{name}\") called before any layer was added — ignored"
2323 ));
2324 return self;
2325 };
2326 if let Some((n, v)) =
2327 crate::render::svg_backend::validate_layer_svg_attr(&name, &value, &mut self.warnings)
2328 {
2329 self.layer_svg_attrs
2330 .retain(|(i, k, _)| !(*i == idx && *k == n));
2331 self.layer_svg_attrs.push((idx, n, v));
2332 }
2333 self
2334 }
2335
2336 pub fn layer_svg_attrs<N: Into<String>, V: Into<String>>(
2338 self,
2339 attrs: impl IntoIterator<Item = (N, V)>,
2340 ) -> Self {
2341 attrs
2342 .into_iter()
2343 .fold(self, |p, (n, v)| p.layer_svg_attr(n, v))
2344 }
2345
2346 pub fn scale_x_continuous(mut self, s: ScaleContinuous) -> Self {
2349 let s = s.for_aesthetic(crate::aes::Aesthetic::X);
2350 self.scales.push(Box::new(s));
2351 self
2352 }
2353
2354 pub fn scale_y_continuous(mut self, s: ScaleContinuous) -> Self {
2355 let s = s.for_aesthetic(crate::aes::Aesthetic::Y);
2356 self.scales.push(Box::new(s));
2357 self
2358 }
2359
2360 pub fn scale_x_discrete(mut self, s: crate::scale::discrete::ScaleDiscrete) -> Self {
2361 let s = s.for_aesthetic(crate::aes::Aesthetic::X);
2362 self.scales.push(Box::new(s));
2363 self
2364 }
2365
2366 pub fn scale_y_discrete(mut self, s: crate::scale::discrete::ScaleDiscrete) -> Self {
2367 let s = s.for_aesthetic(crate::aes::Aesthetic::Y);
2368 self.scales.push(Box::new(s));
2369 self
2370 }
2371
2372 pub fn scale_color(mut self, s: impl Scale + 'static) -> Self {
2373 self.scales.push(Box::new(s));
2374 self
2375 }
2376
2377 pub fn scale_fill(mut self, s: impl Scale + 'static) -> Self {
2378 self.scales.push(Box::new(s));
2379 self
2380 }
2381
2382 pub fn scale_color_manual(self, values: Vec<(&str, crate::scale::color::RGBAColor)>) -> Self {
2383 let s = crate::scale::manual::ScaleManual::new(crate::aes::Aesthetic::Color, values);
2384 self.scale_color(s)
2385 }
2386
2387 pub fn scale_fill_manual(self, values: Vec<(&str, crate::scale::color::RGBAColor)>) -> Self {
2388 let s = crate::scale::manual::ScaleManual::new(crate::aes::Aesthetic::Fill, values);
2389 self.scale_fill(s)
2390 }
2391
2392 pub fn scale_colour_identity(self) -> Self {
2395 let s = crate::scale::identity::ScaleColorIdentity::new(crate::aes::Aesthetic::Color);
2396 self.scale_color(s)
2397 }
2398
2399 pub fn scale_color_identity(self) -> Self {
2401 self.scale_colour_identity()
2402 }
2403
2404 pub fn scale_fill_identity(self) -> Self {
2407 let s = crate::scale::identity::ScaleColorIdentity::new(crate::aes::Aesthetic::Fill);
2408 self.scale_fill(s)
2409 }
2410
2411 pub fn scale_color_viridis(self) -> Self {
2412 use crate::scale::color::ScaleColorDiscrete;
2413 use crate::scale::palettes::PaletteName;
2414 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Color)
2415 .with_named_palette(&PaletteName::Viridis);
2416 self.scale_color(s)
2417 }
2418
2419 pub fn scale_color_brewer(self, name: crate::scale::palettes::PaletteName) -> Self {
2420 use crate::scale::color::ScaleColorDiscrete;
2421 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Color).with_named_palette(&name);
2422 self.scale_color(s)
2423 }
2424
2425 pub fn scale_color_gradient(
2426 self,
2427 low: crate::scale::color::RGBAColor,
2428 high: crate::scale::color::RGBAColor,
2429 ) -> Self {
2430 use crate::scale::color::ScaleColorContinuous;
2431 let s = ScaleColorContinuous::new(crate::aes::Aesthetic::Color).with_colors(low, high);
2432 self.scale_color(s)
2433 }
2434
2435 pub fn scale_fill_gradient(
2436 self,
2437 low: crate::scale::color::RGBAColor,
2438 high: crate::scale::color::RGBAColor,
2439 ) -> Self {
2440 use crate::scale::color::ScaleColorContinuous;
2441 let s = ScaleColorContinuous::new(crate::aes::Aesthetic::Fill).with_colors(low, high);
2442 self.scale_fill(s)
2443 }
2444
2445 pub fn scale_color_gradient2(
2446 self,
2447 low: crate::scale::color::RGBAColor,
2448 mid: crate::scale::color::RGBAColor,
2449 high: crate::scale::color::RGBAColor,
2450 ) -> Self {
2451 use crate::scale::gradient::ScaleColorGradient2;
2452 let s = ScaleColorGradient2::new(crate::aes::Aesthetic::Color).with_colors(low, mid, high);
2453 self.scale_color(s)
2454 }
2455
2456 pub fn scale_fill_gradient2(
2457 self,
2458 low: crate::scale::color::RGBAColor,
2459 mid: crate::scale::color::RGBAColor,
2460 high: crate::scale::color::RGBAColor,
2461 ) -> Self {
2462 use crate::scale::gradient::ScaleColorGradient2;
2463 let s = ScaleColorGradient2::new(crate::aes::Aesthetic::Fill).with_colors(low, mid, high);
2464 self.scale_fill(s)
2465 }
2466
2467 pub fn scale_fill_viridis(self) -> Self {
2468 use crate::scale::color::ScaleColorDiscrete;
2469 use crate::scale::palettes::PaletteName;
2470 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill)
2471 .with_named_palette(&PaletteName::Viridis);
2472 self.scale_fill(s)
2473 }
2474
2475 pub fn scale_color_viridis_c(self) -> Self {
2477 use crate::scale::gradient_n::ScaleColorGradientN;
2478 let s = ScaleColorGradientN::viridis(crate::aes::Aesthetic::Color);
2479 self.scale_color(s)
2480 }
2481
2482 pub fn scale_fill_viridis_c(self) -> Self {
2484 use crate::scale::gradient_n::ScaleColorGradientN;
2485 let s = ScaleColorGradientN::viridis(crate::aes::Aesthetic::Fill);
2486 self.scale_fill(s)
2487 }
2488
2489 pub fn scale_color_gradientn(self, stops: Vec<(f64, crate::scale::color::RGBAColor)>) -> Self {
2491 use crate::scale::gradient_n::ScaleColorGradientN;
2492 let s = ScaleColorGradientN::new(crate::aes::Aesthetic::Color, stops);
2493 self.scale_color(s)
2494 }
2495
2496 pub fn scale_fill_gradientn(self, stops: Vec<(f64, crate::scale::color::RGBAColor)>) -> Self {
2498 use crate::scale::gradient_n::ScaleColorGradientN;
2499 let s = ScaleColorGradientN::new(crate::aes::Aesthetic::Fill, stops);
2500 self.scale_fill(s)
2501 }
2502
2503 pub fn scale_color_steps(
2506 self,
2507 low: crate::scale::color::RGBAColor,
2508 high: crate::scale::color::RGBAColor,
2509 n_bins: usize,
2510 ) -> Self {
2511 let s = crate::scale::steps::ScaleColorSteps::two(
2512 crate::aes::Aesthetic::Color,
2513 (low.r, low.g, low.b),
2514 (high.r, high.g, high.b),
2515 n_bins,
2516 );
2517 self.scale_color(s)
2518 }
2519
2520 pub fn scale_color_stepsn(
2522 self,
2523 stops: Vec<crate::scale::color::RGBAColor>,
2524 n_bins: usize,
2525 ) -> Self {
2526 let s = crate::scale::steps::ScaleColorSteps::new(
2527 crate::aes::Aesthetic::Color,
2528 stops.iter().map(|c| (c.r, c.g, c.b)).collect(),
2529 n_bins,
2530 );
2531 self.scale_color(s)
2532 }
2533
2534 pub fn scale_color_fermenter(
2536 self,
2537 name: crate::scale::palettes::PaletteName,
2538 n_bins: usize,
2539 ) -> Self {
2540 let stops = crate::scale::palettes::palette(&name)
2541 .iter()
2542 .map(|c| (c.r, c.g, c.b))
2543 .collect();
2544 let s =
2545 crate::scale::steps::ScaleColorSteps::new(crate::aes::Aesthetic::Color, stops, n_bins);
2546 self.scale_color(s)
2547 }
2548
2549 pub fn scale_color_steps2(
2553 self,
2554 low: crate::scale::color::RGBAColor,
2555 mid: crate::scale::color::RGBAColor,
2556 high: crate::scale::color::RGBAColor,
2557 midpoint: f64,
2558 n_bins: usize,
2559 ) -> Self {
2560 self.scale_color(crate::scale::steps::ScaleColorSteps::diverging(
2561 crate::aes::Aesthetic::Color,
2562 (low.r, low.g, low.b),
2563 (mid.r, mid.g, mid.b),
2564 (high.r, high.g, high.b),
2565 midpoint,
2566 n_bins,
2567 ))
2568 }
2569
2570 pub fn scale_fill_steps2(
2573 self,
2574 low: crate::scale::color::RGBAColor,
2575 mid: crate::scale::color::RGBAColor,
2576 high: crate::scale::color::RGBAColor,
2577 midpoint: f64,
2578 n_bins: usize,
2579 ) -> Self {
2580 self.scale_fill(crate::scale::steps::ScaleColorSteps::diverging(
2581 crate::aes::Aesthetic::Fill,
2582 (low.r, low.g, low.b),
2583 (mid.r, mid.g, mid.b),
2584 (high.r, high.g, high.b),
2585 midpoint,
2586 n_bins,
2587 ))
2588 }
2589
2590 pub fn scale_color_viridis_b(self, option: char, n_bins: usize) -> Self {
2593 self.scale_color(crate::scale::steps::ScaleColorSteps::viridis(
2594 crate::aes::Aesthetic::Color,
2595 option,
2596 n_bins,
2597 ))
2598 }
2599
2600 pub fn scale_fill_viridis_b(self, option: char, n_bins: usize) -> Self {
2603 self.scale_fill(crate::scale::steps::ScaleColorSteps::viridis(
2604 crate::aes::Aesthetic::Fill,
2605 option,
2606 n_bins,
2607 ))
2608 }
2609
2610 pub fn scale_fill_steps(
2611 self,
2612 low: crate::scale::color::RGBAColor,
2613 high: crate::scale::color::RGBAColor,
2614 n_bins: usize,
2615 ) -> Self {
2616 let s = crate::scale::steps::ScaleColorSteps::two(
2617 crate::aes::Aesthetic::Fill,
2618 (low.r, low.g, low.b),
2619 (high.r, high.g, high.b),
2620 n_bins,
2621 );
2622 self.scale_fill(s)
2623 }
2624
2625 pub fn scale_fill_binned(
2636 self,
2637 breaks: Vec<f64>,
2638 low: crate::scale::color::RGBAColor,
2639 high: crate::scale::color::RGBAColor,
2640 ) -> Self {
2641 let s = crate::scale::binned::ScaleFillBinned::two(
2642 crate::aes::Aesthetic::Fill,
2643 breaks,
2644 (low.r, low.g, low.b),
2645 (high.r, high.g, high.b),
2646 );
2647 self.scale_fill(s)
2648 }
2649
2650 pub fn scale_fill_binned_with(
2654 self,
2655 breaks: Vec<f64>,
2656 colors: Vec<crate::scale::color::RGBAColor>,
2657 ) -> Self {
2658 let s = crate::scale::binned::ScaleFillBinned::new(
2659 crate::aes::Aesthetic::Fill,
2660 breaks,
2661 colors.iter().map(|c| (c.r, c.g, c.b)).collect(),
2662 );
2663 self.scale_fill(s)
2664 }
2665
2666 pub fn scale_fill_fermenter(
2668 self,
2669 name: crate::scale::palettes::PaletteName,
2670 n_bins: usize,
2671 ) -> Self {
2672 let stops = crate::scale::palettes::palette(&name)
2673 .iter()
2674 .map(|c| (c.r, c.g, c.b))
2675 .collect();
2676 let s =
2677 crate::scale::steps::ScaleColorSteps::new(crate::aes::Aesthetic::Fill, stops, n_bins);
2678 self.scale_fill(s)
2679 }
2680
2681 pub fn scale_fill_discrete_sorted(self) -> Self {
2686 use crate::scale::color::ScaleColorDiscrete;
2687 self.scale_fill(ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill).sorted())
2688 }
2689
2690 pub fn scale_color_discrete_sorted(self) -> Self {
2693 use crate::scale::color::ScaleColorDiscrete;
2694 self.scale_color(ScaleColorDiscrete::new(crate::aes::Aesthetic::Color).sorted())
2695 }
2696
2697 pub fn scale_color_hue(self, p: crate::scale::color::HuePalette) -> Self {
2701 self.scale_color(
2702 crate::scale::color::ScaleColorDiscrete::new(crate::aes::Aesthetic::Color)
2703 .with_generated(crate::scale::color::GeneratedPalette::Hue(p)),
2704 )
2705 }
2706
2707 pub fn scale_fill_hue(self, p: crate::scale::color::HuePalette) -> Self {
2709 self.scale_fill(
2710 crate::scale::color::ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill)
2711 .with_generated(crate::scale::color::GeneratedPalette::Hue(p)),
2712 )
2713 }
2714
2715 pub fn scale_color_viridis_d(self, option: char, begin: f64, end: f64, direction: i32) -> Self {
2718 self.scale_color(
2719 crate::scale::color::ScaleColorDiscrete::new(crate::aes::Aesthetic::Color)
2720 .with_generated(crate::scale::color::GeneratedPalette::Viridis {
2721 option,
2722 begin,
2723 end,
2724 direction,
2725 }),
2726 )
2727 }
2728
2729 pub fn scale_fill_viridis_d(self, option: char, begin: f64, end: f64, direction: i32) -> Self {
2731 self.scale_fill(
2732 crate::scale::color::ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill)
2733 .with_generated(crate::scale::color::GeneratedPalette::Viridis {
2734 option,
2735 begin,
2736 end,
2737 direction,
2738 }),
2739 )
2740 }
2741
2742 pub fn scale_color_distiller(
2746 self,
2747 palette: crate::scale::palettes::PaletteName,
2748 direction: i32,
2749 ) -> Self {
2750 self.scale_color(distiller(crate::aes::Aesthetic::Color, &palette, direction))
2751 }
2752
2753 pub fn scale_fill_distiller(
2755 self,
2756 palette: crate::scale::palettes::PaletteName,
2757 direction: i32,
2758 ) -> Self {
2759 self.scale_fill(distiller(crate::aes::Aesthetic::Fill, &palette, direction))
2760 }
2761
2762 pub fn expand_limits(self, x: &[f64], y: &[f64]) -> Self {
2766 let n = x.len().max(y.len());
2767 if n == 0 {
2768 return self;
2769 }
2770 let col =
2771 |v: &[f64]| -> Vec<Value> { (0..n).map(|i| Value::Float(v[i % v.len()])).collect() };
2772 let mut data = Vec::new();
2773 let mut aes = Aes::new();
2774 if !x.is_empty() {
2775 data.push(("x".to_string(), col(x)));
2776 aes = aes.x("x");
2777 }
2778 if !y.is_empty() {
2779 data.push(("y".to_string(), col(y)));
2780 aes = aes.y("y");
2781 }
2782 self.geom_blank().layer_data(data).layer_aes(aes)
2783 }
2784
2785 pub fn scale_fill_brewer(self, name: crate::scale::palettes::PaletteName) -> Self {
2786 use crate::scale::color::ScaleColorDiscrete;
2787 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill).with_named_palette(&name);
2788 self.scale_fill(s)
2789 }
2790
2791 pub fn scale_linetype_manual(
2792 self,
2793 values: Vec<(&str, crate::render::backend::Linetype)>,
2794 ) -> Self {
2795 let s = crate::scale::linetype_manual::ScaleLinetypeManual::new(values);
2796 self.scale_color(s)
2797 }
2798
2799 pub fn scale_shape_manual(
2800 self,
2801 values: Vec<(&str, crate::render::backend::PointShape)>,
2802 ) -> Self {
2803 let s = crate::scale::shape_manual::ScaleShapeManual::new(values);
2804 self.scale_color(s)
2805 }
2806
2807 pub fn scale_color_grey(self) -> Self {
2808 let s = crate::scale::grey::ScaleColorGrey::new(crate::aes::Aesthetic::Color);
2809 self.scale_color(s)
2810 }
2811
2812 pub fn scale_fill_grey(self) -> Self {
2813 let s = crate::scale::grey::ScaleColorGrey::new(crate::aes::Aesthetic::Fill);
2814 self.scale_fill(s)
2815 }
2816
2817 pub fn scale_color_grey_with(self, s: crate::scale::grey::ScaleColorGrey) -> Self {
2818 self.scale_color(s)
2819 }
2820
2821 pub fn scale_fill_grey_with(self, s: crate::scale::grey::ScaleColorGrey) -> Self {
2822 self.scale_fill(s)
2823 }
2824
2825 pub fn scale_x_reverse(self) -> Self {
2826 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reverse))
2827 }
2828
2829 pub fn scale_y_reverse(self) -> Self {
2830 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reverse))
2831 }
2832
2833 pub fn scale_x_datetime(mut self, s: crate::scale::datetime::ScaleDateTime) -> Self {
2834 let s = s.for_aesthetic(crate::aes::Aesthetic::X);
2835 self.scales.push(Box::new(s));
2836 self
2837 }
2838
2839 pub fn scale_y_datetime(mut self, s: crate::scale::datetime::ScaleDateTime) -> Self {
2840 let s = s.for_aesthetic(crate::aes::Aesthetic::Y);
2841 self.scales.push(Box::new(s));
2842 self
2843 }
2844
2845 pub fn scale_size(mut self, s: crate::scale::size::ScaleSizeContinuous) -> Self {
2846 self.scales.push(Box::new(s));
2847 self
2848 }
2849
2850 pub fn scale_size_area(mut self, max_size: f64) -> Self {
2854 self.scales.push(Box::new(
2855 crate::scale::size::ScaleSizeContinuous::new().area(max_size),
2856 ));
2857 self
2858 }
2859
2860 pub fn scale_radius(self, min: f64, max: f64) -> Self {
2863 self.scale_size(crate::scale::size::ScaleSizeContinuous::new().with_range(min, max))
2864 }
2865
2866 pub fn scale_size_binned(self, n: usize) -> Self {
2868 self.scale_color(crate::scale::values::ScaleValueBinned::new(
2869 crate::aes::Aesthetic::Size,
2870 n,
2871 ))
2872 }
2873
2874 pub fn scale_alpha_binned(self, n: usize) -> Self {
2876 self.scale_color(crate::scale::values::ScaleValueBinned::new(
2877 crate::aes::Aesthetic::Alpha,
2878 n,
2879 ))
2880 }
2881
2882 pub fn scale_linewidth_binned(self, n: usize) -> Self {
2884 self.scale_color(crate::scale::values::ScaleValueBinned::new(
2885 crate::aes::Aesthetic::Linewidth,
2886 n,
2887 ))
2888 }
2889
2890 pub fn scale_shape_binned(self, n: usize) -> Self {
2892 self.scale_color(crate::scale::values::ScaleValueBinned::new(
2893 crate::aes::Aesthetic::Shape,
2894 n,
2895 ))
2896 }
2897
2898 pub fn scale_linetype_binned(self, n: usize) -> Self {
2900 self.scale_color(crate::scale::values::ScaleValueBinned::new(
2901 crate::aes::Aesthetic::Linetype,
2902 n,
2903 ))
2904 }
2905
2906 pub fn scale_size_manual(self, values: Vec<(&str, f64)>) -> Self {
2908 self.scale_color(crate::scale::values::ScaleValueManual::new(
2909 crate::aes::Aesthetic::Size,
2910 values,
2911 ))
2912 }
2913
2914 pub fn scale_alpha_manual(self, values: Vec<(&str, f64)>) -> Self {
2916 self.scale_color(crate::scale::values::ScaleValueManual::new(
2917 crate::aes::Aesthetic::Alpha,
2918 values,
2919 ))
2920 }
2921
2922 pub fn scale_linewidth_manual(self, values: Vec<(&str, f64)>) -> Self {
2924 self.scale_color(crate::scale::values::ScaleValueManual::new(
2925 crate::aes::Aesthetic::Linewidth,
2926 values,
2927 ))
2928 }
2929
2930 pub fn scale_size_identity(self) -> Self {
2932 self.scale_color(crate::scale::values::ScaleValueIdentity::new(
2933 crate::aes::Aesthetic::Size,
2934 ))
2935 }
2936
2937 pub fn scale_alpha_identity(self) -> Self {
2939 self.scale_color(crate::scale::values::ScaleValueIdentity::new(
2940 crate::aes::Aesthetic::Alpha,
2941 ))
2942 }
2943
2944 pub fn scale_linewidth_identity(self) -> Self {
2947 self.scale_color(crate::scale::values::ScaleValueIdentity::new(
2948 crate::aes::Aesthetic::Linewidth,
2949 ))
2950 }
2951
2952 pub fn scale_shape_identity(self) -> Self {
2955 self.scale_color(crate::scale::values::ScaleValueIdentity::new(
2956 crate::aes::Aesthetic::Shape,
2957 ))
2958 }
2959
2960 pub fn scale_alpha(mut self, s: crate::scale::alpha::ScaleAlphaContinuous) -> Self {
2961 self.scales.push(Box::new(s));
2962 self
2963 }
2964
2965 pub fn scale_linewidth(mut self, s: crate::scale::linewidth::ScaleLinewidthContinuous) -> Self {
2969 self.scales.push(Box::new(s));
2970 self
2971 }
2972
2973 pub fn xlim(self, min: f64, max: f64) -> Self {
2974 self.scale_x_continuous(ScaleContinuous::new().with_limits(min, max))
2975 }
2976
2977 pub fn ylim(self, min: f64, max: f64) -> Self {
2978 self.scale_y_continuous(ScaleContinuous::new().with_limits(min, max))
2979 }
2980
2981 pub fn scale_x_log10(self) -> Self {
2982 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log10))
2983 }
2984
2985 pub fn scale_y_log10(self) -> Self {
2986 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log10))
2987 }
2988
2989 pub fn scale_x_sqrt(self) -> Self {
2990 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Sqrt))
2991 }
2992
2993 pub fn scale_y_sqrt(self) -> Self {
2994 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Sqrt))
2995 }
2996
2997 pub fn scale_x_log2(self) -> Self {
2998 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log2))
2999 }
3000
3001 pub fn scale_y_log2(self) -> Self {
3002 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log2))
3003 }
3004
3005 pub fn scale_x_ln(self) -> Self {
3006 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Ln))
3007 }
3008
3009 pub fn scale_y_ln(self) -> Self {
3010 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Ln))
3011 }
3012
3013 pub fn scale_x_logit(self) -> Self {
3015 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Logit))
3016 }
3017
3018 pub fn scale_y_logit(self) -> Self {
3019 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Logit))
3020 }
3021
3022 pub fn scale_x_probit(self) -> Self {
3024 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Probit))
3025 }
3026
3027 pub fn scale_y_probit(self) -> Self {
3028 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Probit))
3029 }
3030
3031 pub fn scale_x_pseudo_log(self) -> Self {
3033 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::PseudoLog))
3034 }
3035
3036 pub fn scale_y_pseudo_log(self) -> Self {
3037 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::PseudoLog))
3038 }
3039
3040 pub fn scale_x_reciprocal(self) -> Self {
3042 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reciprocal))
3043 }
3044
3045 pub fn scale_y_reciprocal(self) -> Self {
3046 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reciprocal))
3047 }
3048
3049 pub fn scale_x_exp(self) -> Self {
3051 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Exp))
3052 }
3053
3054 pub fn scale_y_exp(self) -> Self {
3055 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Exp))
3056 }
3057
3058 pub fn scale_x_time(self) -> Self {
3062 self.scale_x_continuous(ScaleContinuous::time())
3063 }
3064
3065 pub fn scale_y_time(self) -> Self {
3067 self.scale_y_continuous(ScaleContinuous::time())
3068 }
3069
3070 pub fn scale_x_binned(self, n: usize) -> Self {
3074 self.scale_x_continuous(ScaleContinuous::binned(n))
3075 }
3076
3077 pub fn scale_y_binned(self, n: usize) -> Self {
3079 self.scale_y_continuous(ScaleContinuous::binned(n))
3080 }
3081
3082 pub fn scale_x_boxcox(self, lambda: f64) -> Self {
3083 self.scale_x_continuous(
3084 ScaleContinuous::new().with_transform(ScaleTransform::BoxCox(lambda)),
3085 )
3086 }
3087
3088 pub fn scale_y_boxcox(self, lambda: f64) -> Self {
3089 self.scale_y_continuous(
3090 ScaleContinuous::new().with_transform(ScaleTransform::BoxCox(lambda)),
3091 )
3092 }
3093
3094 pub fn facet_wrap(mut self, var: &str, ncol: Option<usize>) -> Self {
3097 self.facet = Facet::Wrap {
3098 var: var.to_string(),
3099 ncol,
3100 scales: FacetScales::Fixed,
3101 labeller: FacetLabeller::default(),
3102 levels: None,
3103 vertical: false,
3104 as_table: true,
3105 strip_position: crate::facet::StripPosition::Top,
3106 space: FacetSpace::Fixed,
3107 };
3108 self
3109 }
3110
3111 pub fn facet_wrap_free(mut self, var: &str, ncol: Option<usize>, scales: FacetScales) -> Self {
3112 self.facet = Facet::Wrap {
3113 var: var.to_string(),
3114 ncol,
3115 scales,
3116 labeller: FacetLabeller::default(),
3117 levels: None,
3118 vertical: false,
3119 as_table: true,
3120 strip_position: crate::facet::StripPosition::Top,
3121 space: FacetSpace::Fixed,
3122 };
3123 self
3124 }
3125
3126 pub fn facet_wrap_labeller(
3127 mut self,
3128 var: &str,
3129 ncol: Option<usize>,
3130 labeller: FacetLabeller,
3131 ) -> Self {
3132 self.facet = Facet::Wrap {
3133 var: var.to_string(),
3134 ncol,
3135 scales: FacetScales::Fixed,
3136 labeller,
3137 levels: None,
3138 vertical: false,
3139 as_table: true,
3140 strip_position: crate::facet::StripPosition::Top,
3141 space: FacetSpace::Fixed,
3142 };
3143 self
3144 }
3145
3146 pub fn facet_wrap_dir(mut self, vertical: bool, as_table: bool) -> Self {
3150 if let Facet::Wrap {
3151 vertical: v,
3152 as_table: a,
3153 ..
3154 } = &mut self.facet
3155 {
3156 *v = vertical;
3157 *a = as_table;
3158 }
3159 self
3160 }
3161
3162 pub fn facet_axes(mut self, axes: crate::facet::FacetAxes) -> Self {
3165 self.facet_axes = axes;
3166 self
3167 }
3168
3169 pub fn facet_labeller(mut self, l: FacetLabeller) -> Self {
3173 match &mut self.facet {
3174 Facet::Wrap { labeller, .. } | Facet::Grid { labeller, .. } => *labeller = l,
3175 Facet::None => {}
3176 }
3177 self
3178 }
3179
3180 pub fn facet_wrap_space(mut self, space: FacetSpace) -> Self {
3184 if let Facet::Wrap { space: s, .. } = &mut self.facet {
3185 *s = space;
3186 }
3187 self
3188 }
3189
3190 pub fn facet_strip_position(mut self, position: crate::facet::StripPosition) -> Self {
3194 if let Facet::Wrap { strip_position, .. } = &mut self.facet {
3195 *strip_position = position;
3196 }
3197 self
3198 }
3199
3200 pub fn facet_grid_levels<S: AsRef<str>>(
3204 mut self,
3205 rows: Option<&[S]>,
3206 cols: Option<&[S]>,
3207 ) -> Self {
3208 let dedup = |l: &[S]| {
3209 let mut seen = Vec::<String>::new();
3210 for s in l {
3211 if !seen.iter().any(|x| x == s.as_ref()) {
3212 seen.push(s.as_ref().to_string());
3213 }
3214 }
3215 seen
3216 };
3217 if let Facet::Grid {
3218 row_levels,
3219 col_levels,
3220 ..
3221 } = &mut self.facet
3222 {
3223 *row_levels = rows.map(dedup);
3224 *col_levels = cols.map(dedup);
3225 }
3226 self
3227 }
3228
3229 pub fn facet_margins(mut self, on: bool) -> Self {
3233 if let Facet::Grid { margins, .. } = &mut self.facet {
3234 *margins = on;
3235 }
3236 self
3237 }
3238
3239 pub fn facet_switch(mut self, switch: crate::facet::FacetSwitch) -> Self {
3243 if let Facet::Grid { switch: s, .. } = &mut self.facet {
3244 *s = switch;
3245 }
3246 self
3247 }
3248
3249 pub fn facet_levels<S: AsRef<str>>(mut self, levels: &[S]) -> Self {
3256 if let Facet::Wrap { levels: l, .. } = &mut self.facet {
3257 let mut seen = Vec::<String>::new();
3258 for s in levels {
3259 if !seen.iter().any(|x| x == s.as_ref()) {
3260 seen.push(s.as_ref().to_string());
3261 }
3262 }
3263 *l = Some(seen);
3264 }
3265 self
3266 }
3267
3268 pub fn facet_grid(mut self, row: Option<&str>, col: Option<&str>) -> Self {
3269 self.facet = Facet::Grid {
3270 row_var: row.map(String::from),
3271 col_var: col.map(String::from),
3272 scales: FacetScales::Fixed,
3273 labeller: FacetLabeller::default(),
3274 space: FacetSpace::Fixed,
3275 switch: crate::facet::FacetSwitch::None,
3276 row_levels: None,
3277 col_levels: None,
3278 margins: false,
3279 };
3280 self
3281 }
3282
3283 pub fn facet_grid_free(
3284 mut self,
3285 row: Option<&str>,
3286 col: Option<&str>,
3287 scales: FacetScales,
3288 ) -> Self {
3289 self.facet = Facet::Grid {
3290 row_var: row.map(String::from),
3291 col_var: col.map(String::from),
3292 scales,
3293 labeller: FacetLabeller::default(),
3294 space: FacetSpace::Fixed,
3295 switch: crate::facet::FacetSwitch::None,
3296 row_levels: None,
3297 col_levels: None,
3298 margins: false,
3299 };
3300 self
3301 }
3302
3303 pub fn facet_grid_multi(
3307 mut self,
3308 row: Option<&str>,
3309 cols: &[&str],
3310 scales: FacetScales,
3311 space: FacetSpace,
3312 ) -> Self {
3313 let col_var = if cols.len() > 1 {
3314 let n = self.data.nrows();
3316 let mut combined = Vec::with_capacity(n);
3317 for i in 0..n {
3318 let parts: Vec<String> = cols
3319 .iter()
3320 .map(|c| {
3321 self.data
3322 .column(c)
3323 .and_then(|col| col.get(i))
3324 .map(|v| v.to_group_key())
3325 .unwrap_or_default()
3326 })
3327 .collect();
3328 combined.push(crate::data::Value::Str(parts.join(" . ")));
3329 }
3330 let name = "__facet_cols__".to_string();
3331 self.data.add_column(name.clone(), combined);
3332 Some(name)
3333 } else {
3334 cols.first().map(|s| s.to_string())
3335 };
3336 self.facet = Facet::Grid {
3337 row_var: row.map(String::from),
3338 col_var,
3339 scales,
3340 labeller: FacetLabeller::default(),
3341 space,
3342 switch: crate::facet::FacetSwitch::None,
3343 row_levels: None,
3344 col_levels: None,
3345 margins: false,
3346 };
3347 self
3348 }
3349
3350 pub fn facet_grid_space(
3353 mut self,
3354 row: Option<&str>,
3355 col: Option<&str>,
3356 scales: FacetScales,
3357 space: FacetSpace,
3358 ) -> Self {
3359 self.facet = Facet::Grid {
3360 row_var: row.map(String::from),
3361 col_var: col.map(String::from),
3362 scales,
3363 labeller: FacetLabeller::default(),
3364 space,
3365 switch: crate::facet::FacetSwitch::None,
3366 row_levels: None,
3367 col_levels: None,
3368 margins: false,
3369 };
3370 self
3371 }
3372
3373 pub fn facet_grid_labeller(
3374 mut self,
3375 row: Option<&str>,
3376 col: Option<&str>,
3377 labeller: FacetLabeller,
3378 ) -> Self {
3379 self.facet = Facet::Grid {
3380 row_var: row.map(String::from),
3381 col_var: col.map(String::from),
3382 scales: FacetScales::Fixed,
3383 labeller,
3384 space: FacetSpace::Fixed,
3385 switch: crate::facet::FacetSwitch::None,
3386 row_levels: None,
3387 col_levels: None,
3388 margins: false,
3389 };
3390 self
3391 }
3392
3393 pub fn coord_flip(mut self) -> Self {
3396 self.coord = Box::new(CoordFlip);
3397 self
3398 }
3399
3400 pub fn coord_fixed(mut self, ratio: f64) -> Self {
3401 self.coord = Box::new(CoordFixed::new(ratio));
3402 self
3403 }
3404
3405 #[cfg(feature = "sf")]
3409 pub fn coord_sf(mut self) -> Self {
3410 self.coord = Box::new(crate::coord::sf::CoordSf::new());
3411 self
3412 }
3413
3414 #[cfg(feature = "sf")]
3419 pub fn coord_sf_with(mut self, coord: crate::coord::sf::CoordSf) -> Self {
3420 self.coord = Box::new(coord);
3421 self
3422 }
3423
3424 pub fn svg_root_data(mut self, on: bool) -> Self {
3431 self.svg_root_data = on;
3432 self
3433 }
3434
3435 pub fn svg_attr(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
3445 self.root_attrs.push((name.into(), value.into()));
3446 self
3447 }
3448
3449 pub fn svg_attrs(mut self, attrs: impl IntoIterator<Item = (String, String)>) -> Self {
3451 self.root_attrs.extend(attrs);
3452 self
3453 }
3454
3455 pub fn svg_warnings_attr(mut self, on: bool) -> Self {
3460 self.svg_warnings_attr = on;
3461 self
3462 }
3463
3464 pub fn svg_semantic_classes(mut self, on: bool) -> Self {
3483 self.svg_classes = on;
3484 self
3485 }
3486
3487 pub fn svg_formatted_values(mut self, on: bool) -> Self {
3488 self.svg_formatted_values = on;
3489 self
3490 }
3491
3492 pub fn svg_title(mut self, title: impl Into<String>) -> Self {
3502 self.svg_title = Some(title.into());
3503 self
3504 }
3505
3506 pub fn svg_desc(mut self, desc: impl Into<String>) -> Self {
3514 self.svg_desc = Some(desc.into());
3515 self
3516 }
3517
3518 pub fn coord_trans(mut self, x: Option<ScaleTransform>, y: Option<ScaleTransform>) -> Self {
3523 self.coord = Box::new(crate::coord::trans::CoordTrans::new(x, y));
3524 self
3525 }
3526
3527 pub fn coord_transform(self, x: Option<ScaleTransform>, y: Option<ScaleTransform>) -> Self {
3529 self.coord_trans(x, y)
3530 }
3531
3532 pub fn coord_quickmap(mut self) -> Self {
3535 self.coord = Box::new(crate::coord::map::CoordMap::new(
3536 crate::coord::map::MapProjection::Quick,
3537 ));
3538 self
3539 }
3540
3541 pub fn coord_map(mut self) -> Self {
3545 self.coord = Box::new(crate::coord::map::CoordMap::new(
3546 crate::coord::map::MapProjection::Mercator,
3547 ));
3548 self
3549 }
3550
3551 pub fn coord_cartesian_with(mut self, coord: CoordCartesian) -> Self {
3553 self.coord = Box::new(coord);
3554 self
3555 }
3556
3557 pub fn coord_clip(mut self, on: bool) -> Self {
3561 self.clip = on;
3562 self
3563 }
3564
3565 pub fn coord_reverse(mut self, x: bool, y: bool) -> Self {
3567 self.coord = Box::new(CoordCartesian::new().reverse(x, y));
3568 self
3569 }
3570
3571 pub fn coord_radial(mut self, start: f64, end: f64, inner_radius: f64) -> Self {
3576 let mut c = CoordPolar::new();
3577 c.start = start;
3578 c.span = end - start;
3579 c.inner_radius = inner_radius.clamp(0.0, 0.99);
3580 self.coord = Box::new(c);
3581 self
3582 }
3583
3584 pub fn coord_trans_y(self, y: ScaleTransform) -> Self {
3586 self.coord_trans(None, Some(y))
3587 }
3588
3589 pub fn coord_trans_x(self, x: ScaleTransform) -> Self {
3591 self.coord_trans(Some(x), None)
3592 }
3593
3594 pub fn coord_cartesian_zoom(
3596 mut self,
3597 xlim: Option<(f64, f64)>,
3598 ylim: Option<(f64, f64)>,
3599 ) -> Self {
3600 let mut c = CoordCartesian::new();
3601 if let Some((min, max)) = xlim {
3602 c = c.xlim(min, max);
3603 }
3604 if let Some((min, max)) = ylim {
3605 c = c.ylim(min, max);
3606 }
3607 self.coord = Box::new(c);
3608 self
3609 }
3610
3611 pub fn coord_polar(mut self) -> Self {
3612 self.coord = Box::new(CoordPolar::new());
3613 self
3614 }
3615
3616 pub fn coord_radar(mut self) -> Self {
3620 self.coord = Box::new(crate::coord::radar::CoordRadar::new());
3621 self
3622 }
3623
3624 pub fn coord_radar_with(mut self, coord: crate::coord::radar::CoordRadar) -> Self {
3625 self.coord = Box::new(coord);
3626 self
3627 }
3628
3629 pub fn coord_polar_with(mut self, coord: CoordPolar) -> Self {
3630 self.coord = Box::new(coord);
3631 self
3632 }
3633
3634 pub fn theme(mut self, theme: Theme) -> Self {
3639 self.apply_preset(theme);
3640 self
3641 }
3642
3643 fn apply_preset(&mut self, theme: Theme) {
3644 let primary = self.theme.primary;
3645 self.theme = theme;
3646 if self.theme.primary.is_none() {
3647 self.theme.primary = primary;
3648 }
3649 }
3650
3651 pub fn axis_text_x_angle(mut self, degrees: f64) -> Self {
3655 self.theme.axis_text_x.angle = degrees;
3656 self
3657 }
3658
3659 pub fn axis_text_y_angle(mut self, degrees: f64) -> Self {
3661 self.theme.axis_text_y.angle = degrees;
3662 self
3663 }
3664
3665 pub fn axis_text_x_dodge(mut self, n: usize) -> Self {
3668 self.theme.axis_text_x_dodge = n.max(1);
3669 self
3670 }
3671
3672 pub fn aspect_ratio(mut self, ratio: f64) -> Self {
3675 self.theme.aspect_ratio = Some(ratio);
3676 self
3677 }
3678
3679 pub fn panel_ontop(mut self) -> Self {
3681 self.theme.panel_ontop = true;
3682 self
3683 }
3684
3685 pub fn axis_minor_ticks(mut self) -> Self {
3687 self.theme.axis_minor_ticks = true;
3688 self
3689 }
3690
3691 pub fn axis_text_x_fit(mut self, fit: crate::theme::AxisLabelFit) -> Self {
3696 self.theme.axis_text_x_fit = fit;
3697 self
3698 }
3699
3700 pub fn axis_text_x_check_overlap(mut self, on: bool) -> Self {
3703 self.theme.axis_text_x_check_overlap = on;
3704 self
3705 }
3706
3707 pub fn title_position(mut self, pos: crate::theme::TitlePosition) -> Self {
3710 self.theme.title_position = pos;
3711 self
3712 }
3713
3714 pub fn tag_position(mut self, pos: crate::theme::TagPosition) -> Self {
3716 self.theme.tag_position = pos;
3717 self
3718 }
3719
3720 pub fn legend_direction(mut self, dir: crate::theme::LegendDirection) -> Self {
3722 self.theme.legend_direction = Some(dir);
3723 self
3724 }
3725
3726 pub fn legend_position_inside(mut self, x: f64, y: f64) -> Self {
3733 self.theme.legend_position = crate::theme::LegendPosition::Inside(x, y);
3734 self
3735 }
3736
3737 pub fn legend_position(mut self, pos: crate::theme::LegendPosition) -> Self {
3739 self.theme.legend_position = pos;
3740 self
3741 }
3742
3743 pub fn legend_bottom_when_narrow(mut self, share: f64) -> Self {
3750 self.legend_bottom_share = Some(share);
3751 self
3752 }
3753
3754 pub fn legend_inside_auto(self) -> Self {
3765 self.legend_inside_auto_with(&crate::theme::LegendCorner::ALL, None)
3766 }
3767
3768 pub fn legend_inside_auto_with(
3773 mut self,
3774 corners: &[crate::theme::LegendCorner],
3775 fallback: Option<crate::theme::LegendPosition>,
3776 ) -> Self {
3777 use crate::theme::LegendPosition as P;
3778 let mut c = [None; 4];
3779 for (slot, corner) in c.iter_mut().zip(corners) {
3780 *slot = Some(*corner);
3781 }
3782 let fallback = match fallback {
3783 Some(P::Top) => Some(LegendSide::Top),
3784 Some(P::Right) => Some(LegendSide::Right),
3785 Some(P::Bottom) => Some(LegendSide::Bottom),
3786 Some(P::Left) => Some(LegendSide::Left),
3787 _ => None,
3788 };
3789 self.legend_auto = Some(LegendAuto {
3790 corners: c,
3791 fallback,
3792 });
3793 self
3794 }
3795
3796 pub fn primary_color(mut self, color: (u8, u8, u8)) -> Self {
3797 self.theme.primary = Some(color);
3798 self
3799 }
3800
3801 pub fn theme_minimal(mut self) -> Self {
3802 self.apply_preset(crate::theme::presets::theme_minimal());
3803 self
3804 }
3805
3806 pub fn theme_test(mut self) -> Self {
3808 self.apply_preset(crate::theme::presets::theme_test());
3809 self
3810 }
3811
3812 pub fn theme_bw(mut self) -> Self {
3813 self.apply_preset(crate::theme::presets::theme_bw());
3814 self
3815 }
3816
3817 pub fn theme_gray(mut self) -> Self {
3818 self.apply_preset(crate::theme::presets::theme_gray());
3819 self
3820 }
3821
3822 pub fn theme_classic(mut self) -> Self {
3823 self.apply_preset(crate::theme::presets::theme_classic());
3824 self
3825 }
3826
3827 pub fn theme_pubr(mut self) -> Self {
3829 self.apply_preset(crate::theme::presets::theme_pubr());
3830 self
3831 }
3832
3833 pub fn theme_linedraw(mut self) -> Self {
3834 self.apply_preset(crate::theme::presets::theme_linedraw());
3835 self
3836 }
3837
3838 pub fn theme_light(mut self) -> Self {
3839 self.apply_preset(crate::theme::presets::theme_light());
3840 self
3841 }
3842
3843 pub fn theme_dark(mut self) -> Self {
3844 self.apply_preset(crate::theme::presets::theme_dark());
3845 self
3846 }
3847
3848 pub fn theme_void(mut self) -> Self {
3849 self.apply_preset(crate::theme::presets::theme_void());
3850 self
3851 }
3852
3853 pub fn theme_update(mut self, update: crate::theme::ThemeUpdate) -> Self {
3856 self.theme = self.theme.update(update);
3857 self
3858 }
3859
3860 pub fn theme_replace(self, update: crate::theme::ThemeUpdate) -> Self {
3865 self.theme_update(update)
3866 }
3867
3868 pub fn theme_with(mut self, f: impl FnOnce(&mut Theme)) -> Self {
3872 f(&mut self.theme);
3873 self
3874 }
3875
3876 pub fn guides(mut self, mut guide: crate::guide::config::GuideLegend) -> Self {
3880 if guide.hidden.is_empty() {
3884 guide.hidden = std::mem::take(&mut self.guide_legend.hidden);
3885 }
3886 if guide.titles.is_empty() {
3887 guide.titles = std::mem::take(&mut self.guide_legend.titles);
3888 }
3889 if guide.reversed.is_empty() {
3890 guide.reversed = std::mem::take(&mut self.guide_legend.reversed);
3891 }
3892 if guide.colourbars.is_empty() {
3893 guide.colourbars = std::mem::take(&mut self.guide_legend.colourbars);
3894 }
3895 if guide.overrides.is_empty() {
3896 guide.overrides = std::mem::take(&mut self.guide_legend.overrides);
3897 }
3898 if guide.bins.is_empty() {
3899 guide.bins = std::mem::take(&mut self.guide_legend.bins);
3900 }
3901 if guide.plain_keys.is_empty() {
3902 guide.plain_keys = std::mem::take(&mut self.guide_legend.plain_keys);
3903 }
3904 if guide.custom.is_empty() {
3905 guide.custom = std::mem::take(&mut self.guide_legend.custom);
3906 }
3907 if guide.positions.is_empty() {
3908 guide.positions = std::mem::take(&mut self.guide_legend.positions);
3909 }
3910 self.guide_legend = guide;
3911 self
3912 }
3913
3914 pub fn labs(mut self, labels: Labels) -> Self {
3917 if labels.title.is_some() {
3918 self.labels.title = labels.title;
3919 }
3920 if labels.subtitle.is_some() {
3921 self.labels.subtitle = labels.subtitle;
3922 }
3923 if labels.x.is_some() {
3924 self.labels.x = labels.x;
3925 }
3926 if labels.y.is_some() {
3927 self.labels.y = labels.y;
3928 }
3929 if labels.caption.is_some() {
3930 self.labels.caption = labels.caption;
3931 }
3932 if labels.tag.is_some() {
3933 self.labels.tag = labels.tag;
3934 }
3935 self
3936 }
3937
3938 pub fn title(mut self, title: &str) -> Self {
3939 self.labels.title = Some(title.to_string());
3940 self
3941 }
3942
3943 pub fn tag(mut self, tag: &str) -> Self {
3946 self.labels.tag = Some(tag.to_string());
3947 self
3948 }
3949
3950 pub fn subtitle(mut self, subtitle: &str) -> Self {
3951 self.labels.subtitle = Some(subtitle.to_string());
3952 self
3953 }
3954
3955 pub fn xlab(mut self, label: &str) -> Self {
3956 self.labels.x = Some(label.to_string());
3957 self
3958 }
3959
3960 pub fn ylab(mut self, label: &str) -> Self {
3961 self.labels.y = Some(label.to_string());
3962 self
3963 }
3964
3965 pub fn caption(mut self, caption: &str) -> Self {
3966 self.labels.caption = Some(caption.to_string());
3967 self
3968 }
3969
3970 pub fn annotate(mut self, annotation: Annotation) -> Self {
3974 self.annotations.push(annotation);
3975 self
3976 }
3977
3978 pub fn annotate_text(self, label: &str, x: f64, y: f64) -> Self {
3980 self.annotate(Annotation::text(label, x, y))
3981 }
3982
3983 pub fn annotate_rect(self, xmin: f64, xmax: f64, ymin: f64, ymax: f64) -> Self {
3985 self.annotate(Annotation::rect(xmin, xmax, ymin, ymax))
3986 }
3987
3988 pub fn annotate_segment(self, x: f64, y: f64, xend: f64, yend: f64) -> Self {
3990 self.annotate(Annotation::segment(x, y, xend, yend))
3991 }
3992
3993 pub fn annotation_logticks(self, sides: &str) -> Self {
3996 self.annotate(Annotation::logticks(sides))
3997 }
3998
3999 pub fn annotation_raster(
4002 self,
4003 image: Vec<u8>,
4004 xmin: f64,
4005 xmax: f64,
4006 ymin: f64,
4007 ymax: f64,
4008 ) -> Self {
4009 self.annotate(Annotation::raster(image, xmin, xmax, ymin, ymax))
4010 }
4011
4012 #[cfg(feature = "png")]
4015 pub fn annotation_raster_rgba(
4016 self,
4017 (width, height): (u32, u32),
4018 rgba: &[u8],
4019 (xmin, xmax, ymin, ymax): (f64, f64, f64, f64),
4020 ) -> Self {
4021 use image::ImageEncoder;
4022 let mut png = Vec::new();
4023 let ok = image::codecs::png::PngEncoder::new(&mut png)
4024 .write_image(rgba, width, height, image::ColorType::Rgba8)
4025 .is_ok();
4026 if !ok {
4027 return self;
4028 }
4029 self.annotation_raster(png, xmin, xmax, ymin, ymax)
4030 }
4031
4032 pub fn annotation_custom(
4036 self,
4037 inset: GGPlot,
4038 xmin: f64,
4039 xmax: f64,
4040 ymin: f64,
4041 ymax: f64,
4042 ) -> Self {
4043 self.annotate(Annotation::inset(inset, xmin, xmax, ymin, ymax))
4044 }
4045
4046 pub fn locale(mut self, locale: crate::locale::Locale) -> Self {
4069 self.locale = Some(locale);
4070 self
4071 }
4072
4073 pub fn try_build(self) -> Result<crate::build::BuiltPlot, GGError> {
4077 PlotBuilder::build(self)
4078 }
4079
4080 pub fn build(self) -> crate::build::BuiltPlot {
4084 self.try_build().expect("plot build failed")
4085 }
4086
4087 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
4091 pub fn save(self, path: &str) -> Result<(), GGError> {
4092 self.save_with_size(path, 800, 600)
4093 }
4094
4095 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
4097 pub fn save_with_size(self, path: &str, w: u32, h: u32) -> Result<(), GGError> {
4098 let ext = path.rsplit('.').next().unwrap_or("svg").to_lowercase();
4100 #[cfg(feature = "pdf")]
4101 if ext == "pdf" {
4102 let bytes = self.render_pdf_with_size(w, h)?;
4103 return std::fs::write(path, bytes).map_err(|e| GGError::Render(e.into()));
4104 }
4105 let (built, layout) = self.prepare(w, h)?;
4106
4107 match ext.as_str() {
4108 "svg" => {
4109 let backend = plotters::prelude::SVGBackend::new(path, (w, h));
4110 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
4111 }
4112 "png" | "bmp" | "gif" | "jpeg" | "jpg" | "tiff" => {
4113 let backend = plotters::prelude::BitMapBackend::new(path, (w, h));
4114 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
4115 }
4116 _ => {
4117 return Err(GGError::UnsupportedFormat(ext));
4118 }
4119 }
4120
4121 Ok(())
4122 }
4123
4124 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
4130 pub fn render_svg(self) -> Result<String, GGError> {
4131 self.render_svg_with_size(800, 600)
4132 }
4133
4134 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
4138 pub fn render_svg_with_size(self, w: u32, h: u32) -> Result<String, GGError> {
4139 let (built, layout) = self.prepare(w, h)?;
4140 let mut buf = String::new();
4141 {
4142 let backend = plotters::prelude::SVGBackend::with_string(&mut buf, (w, h));
4143 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
4144 }
4145 Ok(buf)
4146 }
4147
4148 pub fn render_svg_native(self) -> Result<String, GGError> {
4152 self.render_svg_native_with_size(800, 600)
4153 }
4154
4155 pub fn render_svg_native_with_size(self, w: u32, h: u32) -> Result<String, GGError> {
4163 Ok(self.render_native(w, h)?.0.finish())
4164 }
4165
4166 pub fn render_svg_native_with_warnings(
4171 self,
4172 w: u32,
4173 h: u32,
4174 ) -> Result<(String, Vec<String>), GGError> {
4175 let (backend, warnings, _) = self.render_native(w, h)?;
4176 Ok((backend.finish(), warnings))
4177 }
4178
4179 pub fn render_svg_native_at(self, x: f64, y: f64, w: u32, h: u32) -> Result<String, GGError> {
4191 Ok(self.render_native(w, h)?.0.finish_fragment(x, y))
4192 }
4193
4194 pub fn render_svg_area_with_size(self, w: u32, h: u32) -> Result<(String, [f64; 4]), GGError> {
4198 let (backend, _, pa) = self.render_native(w, h)?;
4199 Ok((backend.finish(), [pa.x, pa.y, pa.width, pa.height]))
4200 }
4201
4202 fn render_native(
4206 self,
4207 w: u32,
4208 h: u32,
4209 ) -> Result<
4210 (
4211 crate::render::svg_backend::SvgBackend,
4212 Vec<String>,
4213 crate::render::Rect,
4214 ),
4215 GGError,
4216 > {
4217 let svg_root_data = self.svg_root_data;
4218 let root_attrs = self.root_attrs.clone();
4219 let svg_warnings_attr = self.svg_warnings_attr;
4220 let svg_formatted_values = self.svg_formatted_values;
4221 let svg_title = self.svg_title.clone();
4222 let svg_desc = self.svg_desc.clone();
4223 let (built, layout) = self.prepare(w, h)?;
4224 let pa = layout.plot_area.clone();
4225 let mut backend = crate::render::svg_backend::SvgBackend::new(w, h, pa.clone());
4226 backend.set_formatted_values(svg_formatted_values);
4227 backend.set_svg_title(svg_title.clone());
4228 backend.set_svg_desc(svg_desc.clone());
4229 let existing_root_attrs = if svg_root_data {
4230 let attrs = crate::render::svg_backend::root_data_attrs(&built);
4231 backend.set_root_attrs(attrs.clone());
4232 let mut reserved = attrs;
4236 for name in ["data-plot", "data-viewport", "data-panels"] {
4239 reserved.push((name.to_string(), String::new()));
4240 }
4241 reserved
4242 } else {
4243 backend.without_plot_attr();
4244 Vec::new()
4245 };
4246 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
4247 let mut warnings = built.warnings;
4248 warnings.extend(backend.take_warnings());
4249
4250 let mut reserved = existing_root_attrs;
4251 if svg_warnings_attr {
4252 reserved.push(("data-warnings".to_string(), String::new()));
4253 }
4254 if svg_title.is_some() || svg_desc.is_some() {
4259 reserved.push(("role".to_string(), String::new()));
4260 }
4261 if svg_title.is_some() {
4262 reserved.push(("aria-labelledby".to_string(), String::new()));
4263 }
4264 if svg_desc.is_some() {
4265 reserved.push(("aria-describedby".to_string(), String::new()));
4266 }
4267 let extra = crate::render::svg_backend::validate_root_attrs(
4268 &root_attrs,
4269 &reserved,
4270 "plot",
4271 &mut warnings,
4272 );
4273 backend.extend_root_attrs(extra);
4274 if svg_warnings_attr {
4275 backend.extend_root_attrs(vec![(
4276 "data-warnings".to_string(),
4277 crate::render::svg_backend::warnings_json(&warnings),
4278 )]);
4279 }
4280 Ok((backend, warnings, pa))
4281 }
4282
4283 #[cfg(feature = "canvas")]
4288 pub fn render_rgba_with_size(self, w: u32, h: u32) -> Result<(u32, u32, Vec<u8>), GGError> {
4289 let (built, layout) = self.prepare(w, h)?;
4290 let mut backend =
4291 crate::render::pixel_backend::PixelBackend::new(w, h, layout.plot_area.clone());
4292 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
4293 let (ow, oh) = backend.dimensions();
4294 Ok((ow, oh, backend.into_rgba()))
4295 }
4296
4297 #[cfg(feature = "pdf")]
4301 pub fn render_pdf_with_size(self, w: u32, h: u32) -> Result<Vec<u8>, GGError> {
4302 let (built, layout) = self.prepare(w, h)?;
4303 let mut backend =
4304 crate::render::pdf_backend::PdfBackend::new(w, h, layout.plot_area.clone());
4305 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
4306 backend.finish().map_err(GGError::Render)
4307 }
4308
4309 #[cfg(feature = "pdf")]
4311 pub fn render_pdf(self) -> Result<Vec<u8>, GGError> {
4312 self.render_pdf_with_size(800, 600)
4313 }
4314
4315 #[cfg(feature = "canvas")]
4319 pub fn render_rgba_area_with_size(
4320 self,
4321 w: u32,
4322 h: u32,
4323 ) -> Result<(Vec<u8>, [f64; 4]), GGError> {
4324 let (built, layout) = self.prepare(w, h)?;
4325 let pa = layout.plot_area.clone();
4326 let mut backend = crate::render::pixel_backend::PixelBackend::new(w, h, pa.clone());
4327 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
4328 Ok((backend.into_rgba(), [pa.x, pa.y, pa.width, pa.height]))
4329 }
4330
4331 #[cfg(feature = "canvas")]
4335 pub fn render_png_raster_with_size(self, w: u32, h: u32) -> Result<Vec<u8>, GGError> {
4336 let (built, layout) = self.prepare(w, h)?;
4337 let mut backend =
4338 crate::render::pixel_backend::PixelBackend::new(w, h, layout.plot_area.clone());
4339 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
4340 backend.into_png().map_err(GGError::Render)
4341 }
4342
4343 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
4350 pub fn render_png(self) -> Result<Vec<u8>, GGError> {
4351 self.render_png_with_size(800, 600)
4352 }
4353
4354 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
4357 pub fn render_png_with_size(self, w: u32, h: u32) -> Result<Vec<u8>, GGError> {
4358 let (built, layout) = self.prepare(w, h)?;
4359
4360 let mut rgb = vec![0u8; (w as usize) * (h as usize) * 3];
4363 {
4364 let backend = plotters::prelude::BitMapBackend::with_buffer(&mut rgb, (w, h));
4365 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
4366 }
4367
4368 let img = image::RgbImage::from_raw(w, h, rgb).ok_or_else(|| {
4369 GGError::Render(RenderError::BackendError(
4370 "PNG buffer size mismatch".to_string(),
4371 ))
4372 })?;
4373 let mut out = std::io::Cursor::new(Vec::new());
4374 img.write_to(&mut out, image::ImageOutputFormat::Png)
4375 .map_err(|e| GGError::Render(RenderError::BackendError(format!("{:?}", e))))?;
4376 Ok(out.into_inner())
4377 }
4378
4379 pub(crate) fn prepare(
4381 self,
4382 w: u32,
4383 h: u32,
4384 ) -> Result<(crate::build::BuiltPlot, PlotLayout), GGError> {
4385 let (mut built, meta) = self.build_for_render()?;
4386 let layout = Self::layout_built(&mut built, &meta, w, h);
4387 Ok((built, layout))
4388 }
4389
4390 pub(crate) fn build_for_render(self) -> Result<(crate::build::BuiltPlot, RenderMeta), GGError> {
4393 let plot = self;
4394
4395 let has_title = plot.labels.title.is_some();
4396 let has_subtitle = plot.labels.subtitle.is_some();
4397 let has_caption = plot.labels.caption.is_some();
4398 let has_legend = plot.has_legend_mapping();
4399 let legend_bottom_share = plot.legend_bottom_share;
4400 let legend_auto = plot.legend_auto;
4401 let x_label = plot.labels.x.clone();
4402 let y_label = plot.labels.y.clone();
4403 let guide_titles = plot.guide_legend.titles.clone();
4404
4405 let mut built = PlotBuilder::build(plot)?;
4406
4407 for (aes, title) in &guide_titles {
4409 if let Some(s) = built.scales.get_mut(aes) {
4410 s.set_name(title);
4411 }
4412 }
4413
4414 built.theme.resolve_inheritance();
4416
4417 if built.facet.is_none() && built.theme.aspect_ratio.is_none() {
4422 if let Some(a) = built
4423 .coord
4424 .fixed_aspect()
4425 .filter(|a| a.is_finite() && *a > 0.0)
4426 {
4427 built.theme.aspect_ratio = Some(a);
4428 }
4429 }
4430
4431 if let Some(ref label) = x_label {
4433 if let Some(s) = built.scales.get_mut(&crate::aes::Aesthetic::X) {
4434 s.set_name(label);
4435 }
4436 }
4437 if let Some(ref label) = y_label {
4438 if let Some(s) = built.scales.get_mut(&crate::aes::Aesthetic::Y) {
4439 s.set_name(label);
4440 }
4441 }
4442
4443 Ok((
4444 built,
4445 RenderMeta {
4446 has_title,
4447 has_subtitle,
4448 has_caption,
4449 has_legend,
4450 legend_bottom_share,
4451 legend_auto,
4452 },
4453 ))
4454 }
4455
4456 pub(crate) fn layout_built(
4459 built: &mut crate::build::BuiltPlot,
4460 meta: &RenderMeta,
4461 w: u32,
4462 h: u32,
4463 ) -> PlotLayout {
4464 match meta.legend_auto {
4465 Some(auto) if meta.has_legend && built.panels.is_empty() => {
4466 Self::layout_legend_auto(built, meta, auto, w, h)
4467 }
4468 _ => Self::layout_built_inner(built, meta, w, h),
4469 }
4470 }
4471
4472 fn layout_legend_auto(
4475 built: &mut crate::build::BuiltPlot,
4476 meta: &RenderMeta,
4477 auto: LegendAuto,
4478 w: u32,
4479 h: u32,
4480 ) -> PlotLayout {
4481 use crate::render::probe::Probe;
4482 use crate::theme::LegendPosition as P;
4483 let total = crate::render::Rect {
4484 x: 0.0,
4485 y: 0.0,
4486 width: w as f64,
4487 height: h as f64,
4488 };
4489 let (theme0, n_warnings) = (built.theme.clone(), built.warnings.len());
4492 let reset = |built: &mut crate::build::BuiltPlot, pos: P| {
4493 built.theme = theme0.clone();
4494 built.theme.legend_position = pos;
4495 built.warnings.truncate(n_warnings);
4496 };
4497
4498 reset(built, P::Inside(1.0, 0.0));
4499 let layout = Self::layout_built_inner(built, meta, w, h);
4500 let pa = layout.plot_area.clone();
4501 let mut marks = Probe::new(pa.clone(), total.clone());
4502 for layer in built.layers.iter().filter(|l| l.data.nrows() > 0) {
4503 let _ = layer.geom.draw(
4504 &layer.data,
4505 built.coord.as_ref(),
4506 &built.scales,
4507 &built.theme,
4508 &mut marks,
4509 );
4510 }
4511 for corner in auto.corners.iter().flatten() {
4512 built.theme.legend_position = corner.inside();
4513 let mut legend = Probe::new(pa.clone(), total.clone());
4514 let drawn = crate::guide::legend::draw_legend_planned(
4515 &built.scales,
4516 &built.theme,
4517 &pa,
4518 pa.width,
4519 &mut legend,
4520 &built.guide_legend,
4521 &built.suppressed_aes,
4522 &built.legend_plans,
4523 );
4524 let Some((x0, y0, x1, y1)) = legend.extent().filter(|_| drawn.is_ok()) else {
4525 continue;
4526 };
4527 const PAD: f64 = 2.0;
4528 if !marks.hits((x0 - PAD, y0 - PAD, x1 + PAD, y1 + PAD)) {
4529 built.legend_at = Some(format!("inside-{}", corner.name()));
4530 return layout;
4531 }
4532 }
4533
4534 let sides = match auto.fallback {
4537 Some(side) => vec![side],
4538 None => vec![LegendSide::Top, LegendSide::Right],
4539 };
4540 let data_area = |built: &crate::build::BuiltPlot, layout: &PlotLayout| {
4541 let r = built
4542 .coord
4543 .data_rect(&layout.plot_area)
4544 .unwrap_or_else(|| layout.plot_area.clone());
4545 r.width.max(0.0) * r.height.max(0.0)
4546 };
4547 let mut best = (sides[0], f64::MIN);
4548 for &side in &sides {
4549 reset(built, side.position());
4550 let trial = Self::layout_built_inner(built, meta, w, h);
4551 let area = data_area(built, &trial);
4552 if area > best.1 {
4553 best = (side, area);
4554 }
4555 }
4556 reset(built, best.0.position());
4557 let layout = Self::layout_built_inner(built, meta, w, h);
4558 built.legend_at = Some(
4559 match built.theme.legend_position {
4560 P::Top => "top",
4561 P::Right => "right",
4562 P::Bottom => "bottom",
4563 _ => "left",
4564 }
4565 .to_string(),
4566 );
4567 layout
4568 }
4569
4570 fn layout_built_inner(
4571 built: &mut crate::build::BuiltPlot,
4572 meta: &RenderMeta,
4573 w: u32,
4574 h: u32,
4575 ) -> PlotLayout {
4576 let RenderMeta {
4577 has_title,
4578 has_subtitle,
4579 has_caption,
4580 has_legend,
4581 legend_bottom_share,
4582 legend_auto: _,
4583 } = *meta;
4584 let x_axis_top = built
4585 .scales
4586 .get(&crate::aes::Aesthetic::X)
4587 .map(|s| s.axis_position_opposite())
4588 .unwrap_or(false);
4589
4590 if let Some(share) = legend_bottom_share {
4593 if has_legend
4594 && matches!(
4595 built.theme.legend_position,
4596 crate::theme::LegendPosition::Right
4597 )
4598 {
4599 let panel_width = |pos| {
4600 let mut theme = built.theme.clone();
4601 theme.legend_position = pos;
4602 PlotLayout::compute_with_extras(
4603 w as f64,
4604 h as f64,
4605 &theme,
4606 has_title,
4607 has_subtitle,
4608 has_caption,
4609 has_legend,
4610 x_axis_top,
4611 None,
4612 None,
4613 crate::render::layout::LayoutExtras::default(),
4614 )
4615 .plot_area
4616 .width
4617 };
4618 let free = panel_width(crate::theme::LegendPosition::None);
4621 if panel_width(crate::theme::LegendPosition::Right) < (1.0 - share) * free {
4622 built.theme.legend_position = crate::theme::LegendPosition::Bottom;
4623 }
4624 }
4625 }
4626
4627 let flipped = built.coord.is_flipped();
4631 let h_aes = if flipped {
4632 crate::aes::Aesthetic::Y
4633 } else {
4634 crate::aes::Aesthetic::X
4635 };
4636 let v_aes = if flipped {
4637 crate::aes::Aesthetic::X
4638 } else {
4639 crate::aes::Aesthetic::Y
4640 };
4641
4642 let drawn_x_labels: Vec<(f64, String)> = built
4650 .scales
4651 .get(&h_aes)
4652 .map(|hs| {
4653 hs.breaks()
4654 .into_iter()
4655 .filter(|(_, label)| !label.is_empty())
4656 .collect()
4657 })
4658 .unwrap_or_default();
4659 let h_is_discrete = built
4660 .scales
4661 .get(&h_aes)
4662 .map(|hs| hs.is_discrete())
4663 .unwrap_or(false);
4664
4665 if built.theme.axis_text_x.visible
4678 && built.theme.axis_text_x.angle.abs() < 1.0
4679 && h_is_discrete
4680 && !drawn_x_labels.is_empty()
4681 {
4682 let font = built.theme.axis_text_x.size;
4683 let max_w = drawn_x_labels
4684 .iter()
4685 .map(|(_, l)| crate::render::text::text_width(l, font))
4686 .fold(0.0_f64, f64::max);
4687 let n = drawn_x_labels.len() as f64;
4688 let spacing = 0.9 * w as f64 / n; if max_w > spacing {
4690 let vertical = max_w * std::f64::consts::FRAC_1_SQRT_2 > spacing;
4694 built.theme.axis_text_x.angle = if vertical { 270.0 } else { -45.0 };
4695 }
4696 }
4697
4698 let x_label_height = if built.theme.axis_text_x.visible
4713 && built.theme.axis_text_x.angle.abs() > 10.0
4714 && !drawn_x_labels.is_empty()
4715 {
4716 let font = built.theme.axis_text_x.size;
4717 let angle = built.theme.axis_text_x.angle;
4718 let dir = if x_axis_top { -1.0 } else { 1.0 };
4719 let (rise, fall) = crate::render::text::rotated_label_rise_fall(
4720 drawn_x_labels.iter().map(|(_, l)| l.as_str()),
4721 font,
4722 angle,
4723 crate::render::text::rotated_anchor_frac(angle, dir),
4724 );
4725 Some(built.theme.legend_spacing / 2.0 + font / 2.0 + rise + fall)
4726 } else {
4727 None
4728 };
4729
4730 let y_label_width = if built.theme.axis_text_y.visible {
4734 built.scales.get(&v_aes).map(|vs| {
4735 crate::guide::axis::y_label_reserve(&built.theme, &vs.breaks()).min(0.35 * w as f64)
4736 })
4737 } else {
4738 None
4739 };
4740
4741 let mut extras = crate::render::layout::LayoutExtras {
4754 extra_legend_sides: crate::guide::legend::extra_legend_sides(
4755 &built.scales,
4756 &built.suppressed_aes,
4757 &built.guide_legend,
4758 &built.theme.legend_position,
4759 ),
4760 ..Default::default()
4761 };
4762 if let (Some(vs), Some(sec)) = (
4766 built.scales.get(&crate::aes::Aesthetic::Y),
4767 built.scales.sec_axis(&crate::aes::Aesthetic::Y),
4768 ) {
4769 let theme = &built.theme;
4770 let max_ch = match sec.own_ticks(vs) {
4771 Some(t) => t.iter().map(|(_, l)| l.chars().count()).max(),
4772 None => vs.breaks().iter().map(|(_, l)| l.chars().count() + 2).max(),
4773 }
4774 .unwrap_or(0);
4775 let text = if theme.axis_text_y.visible {
4776 (max_ch as f64 * theme.axis_text_y.size * 0.6).max(theme.axis_text_y.size * 3.5)
4777 } else {
4778 0.0
4779 };
4780 let title = if !sec.name.is_empty() && theme.axis_title_y.visible {
4781 theme.axis_title_y.size * 1.5
4782 } else {
4783 0.0
4784 };
4785 extras.right += theme.axis_ticks_length + theme.legend_spacing + text + title;
4786 }
4787 if let Some(sec) = built
4789 .scales
4790 .get(&h_aes)
4791 .filter(|s| !s.axis_position_opposite())
4792 .and_then(|s| s.sec_axis())
4793 {
4794 extras.top += crate::guide::axis::sec_x_axis_height(&built.theme, sec);
4795 }
4796 let can_reserve = built.facet.is_none()
4797 && built.theme.axis_text_x.visible
4798 && built.theme.axis_text_x_fit == crate::theme::AxisLabelFit::Reserve
4799 && !built.coord.is_polar()
4800 && built.coord.supports_axis_reserve();
4801 if can_reserve {
4802 if let Some(hs) = built.scales.get(&h_aes) {
4803 let breaks = hs.breaks();
4804 if let (Some(first), Some(last)) = (breaks.first(), breaks.last()) {
4805 let angle = built.theme.axis_text_x.angle;
4806 let anchor = if angle.abs() > 10.0 {
4807 let dir = if x_axis_top { -1.0 } else { 1.0 };
4808 crate::render::text::rotated_anchor_frac(angle, dir)
4809 } else {
4810 0.5
4811 };
4812 let size = built.theme.axis_text_x.size;
4813 const EDGE: f64 = 1.0;
4814 for _ in 0..2 {
4815 let layout = PlotLayout::compute_with_extras(
4816 w as f64,
4817 h as f64,
4818 &built.theme,
4819 has_title,
4820 has_subtitle,
4821 has_caption,
4822 has_legend,
4823 x_axis_top,
4824 y_label_width,
4825 x_label_height,
4826 extras,
4827 );
4828 let area = &layout.plot_area;
4829 let edge_y = area.y + area.height;
4830 let to_point = |pos: f64| if flipped { (0.0, pos) } else { (pos, 0.0) };
4831 let px_first = built.coord.transform(to_point(first.0), area).0;
4832 let px_last = built.coord.transform(to_point(last.0), area).0;
4833 let bbox_first = crate::render::text::label_bbox(
4834 &first.1, size, px_first, edge_y, angle, anchor,
4835 );
4836 let bbox_last = crate::render::text::label_bbox(
4837 &last.1, size, px_last, edge_y, angle, anchor,
4838 );
4839 let deficit_left = (EDGE - bbox_first[0]).max(0.0);
4840 let deficit_right = (bbox_last[2] - (w as f64 - EDGE)).max(0.0);
4841 if deficit_left <= 0.0 && deficit_right <= 0.0 {
4842 break;
4843 }
4844 let (p_first, p_last) = (first.0, last.0);
4853 if deficit_left > 0.0 && deficit_right > 0.0 {
4854 let (a, b, c, d) = (1.0 - p_first, p_first, 1.0 - p_last, p_last);
4859 let det = a * d - b * c;
4860 if det.abs() > 0.01 {
4861 extras.left +=
4862 ((deficit_left * d + deficit_right * b) / det).max(0.0);
4863 extras.right +=
4864 ((deficit_right * a + deficit_left * c) / det).max(0.0);
4865 } else {
4866 extras.left += deficit_left / (1.0 - p_first).max(0.05);
4870 extras.right += deficit_right / p_last.max(0.05);
4871 }
4872 } else if deficit_left > 0.0 {
4873 extras.left += deficit_left / (1.0 - p_first).max(0.05);
4874 } else if deficit_right > 0.0 {
4875 extras.right += deficit_right / p_last.max(0.05);
4876 }
4877 const MIN_PANEL_WIDTH: f64 = 50.0;
4892 let cap = (w as f64 - MIN_PANEL_WIDTH).max(0.0);
4893 if extras.left + extras.right > cap {
4894 let scale = if extras.left + extras.right > 0.0 {
4895 cap / (extras.left + extras.right)
4896 } else {
4897 0.0
4898 };
4899 extras.left *= scale;
4900 extras.right *= scale;
4901 }
4902 }
4903 }
4904 }
4905 }
4906
4907 if has_legend
4914 && !matches!(
4915 built.theme.legend_position,
4916 crate::theme::LegendPosition::None
4917 )
4918 {
4919 let legend_aes =
4920 crate::guide::legend::legend_scales_for(&built.scales, &built.suppressed_aes);
4921 extras.legend_max_key_size = legend_aes
4925 .iter()
4926 .filter_map(|aes| {
4927 let scale = built.scales.get(aes)?;
4928 let breaks = scale.breaks();
4929 Some(crate::guide::legend::size_key_diameter(
4930 aes,
4931 &built.scales,
4932 scale,
4933 &breaks,
4934 ))
4935 })
4936 .fold(0.0_f64, f64::max);
4937 let has_wrap_guide = legend_aes.iter().any(|a| {
4948 let is_discrete = built
4949 .scales
4950 .get(a)
4951 .map(|s| s.is_discrete())
4952 .unwrap_or(false);
4953 is_discrete || !crate::guide::legend::is_colorbar_aesthetic(a)
4954 });
4955 if has_wrap_guide {
4956 let layout0 = PlotLayout::compute_with_extras(
4957 w as f64,
4958 h as f64,
4959 &built.theme,
4960 has_title,
4961 has_subtitle,
4962 has_caption,
4963 has_legend,
4964 x_axis_top,
4965 y_label_width,
4966 x_label_height,
4967 extras,
4968 );
4969 let (legend_x0, _, mut is_horizontal) = crate::guide::legend::legend_position(
4979 &built.theme,
4980 &layout0.plot_area,
4981 extras.legend_extra_rows,
4982 (0.0, 0.0),
4983 0.0,
4984 &layout0.total,
4985 );
4986 if let Some(dir) = built.theme.legend_direction {
4987 is_horizontal = matches!(dir, crate::theme::LegendDirection::Horizontal);
4988 }
4989 let avail_width =
4990 (layout0.plot_area.x + layout0.plot_area.width - legend_x0).max(0.0);
4991 let mut legend_warnings = Vec::new();
4992 let mut plans = crate::guide::legend::plan_all_legends(
4993 &built.scales,
4994 &built.guide_legend,
4995 &built.theme,
4996 &built.suppressed_aes,
4997 avail_width,
4998 layout0.plot_area.height,
4999 is_horizontal,
5000 &mut legend_warnings,
5001 );
5002 built.warnings.extend(legend_warnings);
5003
5004 if !plans.is_empty() {
5005 extras.legend_extra_rows = if is_horizontal {
5011 plans
5012 .values()
5013 .map(|p| p.rows.saturating_sub(1))
5014 .max()
5015 .unwrap_or(0)
5016 } else {
5017 plans.values().map(|p| p.rows.saturating_sub(1)).sum()
5018 };
5019 extras.legend_extra_width = plans
5026 .values()
5027 .map(|p| p.cols.saturating_sub(1) as f64 * p.col_pitch)
5028 .fold(0.0_f64, f64::max);
5029
5030 if !is_horizontal {
5042 let final_layout = PlotLayout::compute_with_extras(
5043 w as f64,
5044 h as f64,
5045 &built.theme,
5046 has_title,
5047 has_subtitle,
5048 has_caption,
5049 has_legend,
5050 x_axis_top,
5051 y_label_width,
5052 x_label_height,
5053 extras,
5054 );
5055 let (legend_x_final, _, _) = crate::guide::legend::legend_position(
5061 &built.theme,
5062 &final_layout.plot_area,
5063 extras.legend_extra_rows,
5064 (0.0, 0.0),
5065 0.0,
5066 &final_layout.total,
5067 );
5068 let swatch_and_gap =
5069 built.theme.legend_key_width + built.theme.legend_spacing;
5070 let text_size = built.theme.legend_text.size;
5071 fn right_edge_of(
5077 legend_x: f64,
5078 swatch_and_gap: f64,
5079 text_size: f64,
5080 plan: &crate::guide::legend::LegendPlan,
5081 breaks: &[(f64, String)],
5082 ) -> f64 {
5083 plan.entries
5084 .iter()
5085 .filter_map(|e| breaks.get(e.break_idx).map(|(_, l)| (e, l)))
5086 .map(|(e, label)| {
5087 let text =
5088 e.label_override.as_deref().unwrap_or(label.as_str());
5089 legend_x
5090 + e.x_offset
5091 + swatch_and_gap
5092 + crate::render::text::text_width(text, text_size)
5093 })
5094 .fold(0.0_f64, f64::max)
5095 }
5096
5097 let mut updates: Vec<(
5098 crate::aes::Aesthetic,
5099 crate::guide::legend::LegendPlan,
5100 )> = Vec::new();
5101 let mut reduced_aes: Vec<crate::aes::Aesthetic> = Vec::new();
5108 for (aes, plan) in &plans {
5109 if plan.cols <= 1 {
5110 continue;
5111 }
5112 let Some(scale) = built.scales.get(aes) else {
5113 continue;
5114 };
5115 let breaks = scale.breaks();
5116 if right_edge_of(
5117 legend_x_final,
5118 swatch_and_gap,
5119 text_size,
5120 plan,
5121 &breaks,
5122 ) <= w as f64
5123 {
5124 continue; }
5126
5127 let n = breaks.len();
5130 let mut reduced: Vec<crate::guide::legend::LegendPlan> = Vec::new();
5131 for c in (1..plan.cols).rev() {
5132 let mut candidate_guide = built.guide_legend.clone();
5133 candidate_guide.ncol = Some(c);
5134 candidate_guide.nrow = None;
5135 let mut tmp_warnings = Vec::new();
5136 let candidate_guide =
5137 candidate_guide.validated(n, &mut tmp_warnings);
5138 if let Some(cand) = crate::guide::legend::plan_legend(
5139 &breaks,
5140 &candidate_guide,
5141 &built.theme,
5142 avail_width,
5143 layout0.plot_area.height,
5144 false,
5145 ) {
5146 reduced.push(cand);
5147 }
5148 }
5149 if let Some(fits) = reduced.iter().find(|c| {
5150 right_edge_of(legend_x_final, swatch_and_gap, text_size, c, &breaks)
5151 <= w as f64
5152 }) {
5153 extras.legend_extra_rows =
5154 extras.legend_extra_rows.max(fits.rows.saturating_sub(1));
5155 updates.push((aes.clone(), fits.clone()));
5156 reduced_aes.push(aes.clone());
5157 continue;
5158 }
5159
5160 let base = reduced.last().cloned().unwrap_or_else(|| plan.clone());
5165 extras.legend_extra_rows =
5166 extras.legend_extra_rows.max(base.rows.saturating_sub(1));
5167 let mut truncated = base.clone();
5168 for e in &mut truncated.entries {
5169 let Some((_, label)) = breaks.get(e.break_idx) else {
5170 continue;
5171 };
5172 let avail = (w as f64
5173 - (legend_x_final + e.x_offset + swatch_and_gap))
5174 .max(0.0);
5175 if let Some(short) =
5176 crate::render::text::truncate_to_width(label, avail, text_size)
5177 {
5178 e.label_override = Some(short);
5179 }
5180 }
5181
5182 let truncated_edge = right_edge_of(
5186 legend_x_final,
5187 swatch_and_gap,
5188 text_size,
5189 &truncated,
5190 &breaks,
5191 );
5192 if truncated_edge > w as f64 {
5193 built.warnings.push(format!(
5194 "legend: the {}-column grid still doesn't fit the {w}px chart (needs about {} px)",
5195 truncated.cols,
5196 truncated_edge.ceil() as i64
5197 ));
5198 }
5199 updates.push((aes.clone(), truncated));
5200 }
5201 for (aes, new_plan) in &updates {
5202 plans.insert(aes.clone(), new_plan.clone());
5203 }
5204
5205 if !reduced_aes.is_empty() {
5246 let original_reserve = extras.legend_extra_width;
5247 let tighter_reserve = plans
5248 .values()
5249 .map(|p| p.cols.saturating_sub(1) as f64 * p.col_pitch)
5250 .fold(0.0_f64, f64::max);
5251 if tighter_reserve < original_reserve {
5252 let mut retry_extras = extras;
5253 retry_extras.legend_extra_width = tighter_reserve;
5254 let retry_layout = PlotLayout::compute_with_extras(
5255 w as f64,
5256 h as f64,
5257 &built.theme,
5258 has_title,
5259 has_subtitle,
5260 has_caption,
5261 has_legend,
5262 x_axis_top,
5263 y_label_width,
5264 x_label_height,
5265 retry_extras,
5266 );
5267 let (retry_x, _, _) = crate::guide::legend::legend_position(
5273 &built.theme,
5274 &retry_layout.plot_area,
5275 retry_extras.legend_extra_rows,
5276 (0.0, 0.0),
5277 0.0,
5278 &retry_layout.total,
5279 );
5280 let all_still_fit = plans.iter().all(|(aes, plan)| {
5281 let Some(scale) = built.scales.get(aes) else {
5282 return true;
5283 };
5284 let breaks = scale.breaks();
5285 right_edge_of(retry_x, swatch_and_gap, text_size, plan, &breaks)
5286 <= w as f64
5287 });
5288 if all_still_fit {
5289 extras.legend_extra_width = tighter_reserve;
5290 }
5291 }
5292 }
5293 }
5294 for (aes, plan) in &plans {
5295 if let Some(ov) = &plan.overflow {
5296 let n = built
5297 .scales
5298 .get(aes)
5299 .map(|s| s.breaks().len())
5300 .unwrap_or(ov.dropped);
5301 let shown = n.saturating_sub(ov.dropped);
5302 built.warnings.push(format!(
5303 "legend: {} of {n} entries don't fit the chart; the legend shows {shown} and \"+{} more\"",
5304 ov.dropped, ov.dropped
5305 ));
5306 }
5307 }
5308 }
5309 built.legend_plans = plans;
5315 }
5316 }
5317
5318 if has_legend
5321 && matches!(
5322 built.theme.legend_position,
5323 crate::theme::LegendPosition::Left | crate::theme::LegendPosition::Right
5324 )
5325 && !matches!(
5326 built.theme.legend_direction,
5327 Some(crate::theme::LegendDirection::Horizontal)
5328 )
5329 {
5330 let key_w = built.theme.legend_key_width.max(extras.legend_max_key_size);
5331 let extra =
5332 crate::guide::legend::legend_scales_for(&built.scales, &built.suppressed_aes)
5333 .iter()
5334 .filter(|aes| {
5335 crate::guide::legend::is_colorbar_aesthetic(aes)
5336 && built.scales.get(aes).is_some_and(|s| !s.is_discrete())
5337 })
5338 .filter_map(|aes| built.guide_legend.colourbar_for(aes).bar_width)
5339 .map(|w| (w - key_w).max(0.0))
5340 .fold(0.0_f64, f64::max);
5341 extras.legend_extra_width = extras.legend_extra_width.max(extra);
5342 let text_col = key_w + built.theme.legend_spacing + built.theme.legend_text.size * 6.0;
5344 let custom = built
5345 .guide_legend
5346 .custom
5347 .iter()
5348 .map(|g| (g.width - text_col).max(0.0))
5349 .fold(0.0_f64, f64::max);
5350 extras.legend_extra_width = extras.legend_extra_width.max(custom);
5351 }
5352
5353 if has_legend
5364 && !matches!(
5365 built.theme.legend_position,
5366 crate::theme::LegendPosition::None
5367 )
5368 {
5369 let is_horizontal = match built.theme.legend_direction {
5370 Some(dir) => matches!(dir, crate::theme::LegendDirection::Horizontal),
5371 None => matches!(
5372 built.theme.legend_position,
5373 crate::theme::LegendPosition::Top | crate::theme::LegendPosition::Bottom
5374 ),
5375 };
5376 if is_horizontal {
5377 let legend_aes =
5378 crate::guide::legend::legend_scales_for(&built.scales, &built.suppressed_aes);
5379 let continuous_colourbar = legend_aes.iter().find_map(|aes| {
5380 if !matches!(
5381 aes,
5382 crate::aes::Aesthetic::Color | crate::aes::Aesthetic::Fill
5383 ) {
5384 return None;
5385 }
5386 let scale = built.scales.get(aes)?;
5387 if scale.is_discrete() {
5388 return None;
5389 }
5390 Some(scale)
5391 });
5392 if let Some(scale) = continuous_colourbar {
5393 let title = built
5394 .guide_legend
5395 .title
5396 .as_deref()
5397 .unwrap_or_else(|| scale.name());
5398 let bar_height = crate::guide::legend::continuous_horizontal_bar_height(
5399 &built.theme,
5400 !title.is_empty(),
5401 &built.guide_legend.colourbar_for(&scale.aesthetic()),
5402 );
5403 let key_h = built
5404 .theme
5405 .legend_key_height
5406 .max(extras.legend_max_key_size);
5407 extras.continuous_horizontal_legend_extra_height =
5408 (bar_height - key_h).max(0.0);
5409 }
5410 let key_h = built
5412 .theme
5413 .legend_key_height
5414 .max(extras.legend_max_key_size);
5415 let custom = built
5416 .guide_legend
5417 .custom
5418 .iter()
5419 .map(|g| (g.title_offset(&built.theme) + g.height - key_h).max(0.0))
5420 .fold(0.0_f64, f64::max);
5421 extras.continuous_horizontal_legend_extra_height =
5422 extras.continuous_horizontal_legend_extra_height.max(custom);
5423 }
5424 }
5425
5426 PlotLayout::compute_with_extras(
5427 w as f64,
5428 h as f64,
5429 &built.theme,
5430 has_title,
5431 has_subtitle,
5432 has_caption,
5433 has_legend,
5434 x_axis_top,
5435 y_label_width,
5436 x_label_height,
5437 extras,
5438 )
5439 }
5440
5441 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
5444 fn render_into<DB>(
5445 area: plotters::drawing::DrawingArea<DB, plotters::coord::Shift>,
5446 built: &crate::build::BuiltPlot,
5447 layout: &PlotLayout,
5448 ) -> Result<(), GGError>
5449 where
5450 DB: plotters::prelude::DrawingBackend,
5451 DB::ErrorType: 'static,
5452 {
5453 area.fill(&plotters::prelude::WHITE)
5454 .map_err(|e| GGError::Render(RenderError::BackendError(format!("{:?}", e))))?;
5455 let mut adapter = PlottersAdapter::new(&area, layout.plot_area.clone());
5456 PlotRenderer::render(built, &mut adapter).map_err(GGError::Render)?;
5457 area.present()
5458 .map_err(|e| GGError::Render(RenderError::BackendError(format!("{:?}", e))))?;
5459 Ok(())
5460 }
5461
5462 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
5465 pub fn ggsave(
5466 self,
5467 path: &str,
5468 width_inches: f64,
5469 height_inches: f64,
5470 dpi: f64,
5471 ) -> Result<(), GGError> {
5472 let w = (width_inches * dpi) as u32;
5473 let h = (height_inches * dpi) as u32;
5474 self.save_with_size(path, w, h)
5475 }
5476
5477 fn has_legend_mapping(&self) -> bool {
5492 use crate::guide::legend::is_legend_aesthetic;
5497 let plot_level = self
5498 .mapping
5499 .mappings
5500 .iter()
5501 .any(|m| is_legend_aesthetic(&m.aesthetic));
5502 !self.guide_legend.custom.is_empty()
5504 || plot_level
5505 || self.layers.iter().any(|layer| {
5506 if layer.show_legend == Some(false) {
5507 return false;
5508 }
5509 let effective = if layer.geom.inherit_aes() {
5510 self.mapping.merge(&layer.mapping)
5511 } else {
5512 layer.mapping.clone()
5513 };
5514 effective
5515 .mappings
5516 .iter()
5517 .any(|m| is_legend_aesthetic(&m.aesthetic))
5518 })
5519 }
5520}
5521
5522#[derive(Clone, Copy, Debug)]
5524pub(crate) struct RenderMeta {
5525 pub(crate) has_title: bool,
5526 pub(crate) has_subtitle: bool,
5527 pub(crate) has_caption: bool,
5528 pub(crate) has_legend: bool,
5529 pub(crate) legend_bottom_share: Option<f64>,
5530 pub(crate) legend_auto: Option<LegendAuto>,
5531}
5532
5533#[derive(Clone, Copy, Debug)]
5535pub(crate) struct LegendAuto {
5536 corners: [Option<crate::theme::LegendCorner>; 4],
5537 fallback: Option<LegendSide>,
5538}
5539
5540#[derive(Clone, Copy, Debug)]
5542enum LegendSide {
5543 Top,
5544 Right,
5545 Bottom,
5546 Left,
5547}
5548
5549impl LegendSide {
5550 fn position(self) -> crate::theme::LegendPosition {
5551 use crate::theme::LegendPosition as P;
5552 match self {
5553 LegendSide::Top => P::Top,
5554 LegendSide::Right => P::Right,
5555 LegendSide::Bottom => P::Bottom,
5556 LegendSide::Left => P::Left,
5557 }
5558 }
5559}
5560
5561#[derive(Debug)]
5563#[non_exhaustive]
5564pub enum GGError {
5565 Render(RenderError),
5566 UnsupportedFormat(String),
5567 Io(std::io::Error),
5568 ValidationError(String),
5569}
5570
5571impl std::fmt::Display for GGError {
5572 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5573 match self {
5574 GGError::Render(e) => write!(f, "Render error: {e}"),
5575 GGError::UnsupportedFormat(ext) => write!(f, "Unsupported output format: {ext}"),
5576 GGError::Io(e) => write!(f, "IO error: {e}"),
5577 GGError::ValidationError(msg) => write!(f, "Validation error: {msg}"),
5578 }
5579 }
5580}
5581
5582impl std::error::Error for GGError {}
5583
5584fn distiller(
5586 aes: crate::aes::Aesthetic,
5587 palette: &crate::scale::palettes::PaletteName,
5588 direction: i32,
5589) -> crate::scale::gradient_n::ScaleColorGradientN {
5590 let mut colors = crate::scale::palettes::palette(palette).to_vec();
5591 if direction < 0 {
5592 colors.reverse();
5593 }
5594 let n = colors.len().max(2) - 1;
5595 let stops = colors
5596 .into_iter()
5597 .enumerate()
5598 .map(|(i, c)| (i as f64 / n as f64, c))
5599 .collect();
5600 crate::scale::gradient_n::ScaleColorGradientN::new(aes, stops)
5601}