1#[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
2use plotters::prelude::IntoDrawingArea;
3
4use crate::aes::Aes;
5use crate::annotate::Annotation;
6use crate::build::PlotBuilder;
7use crate::coord::cartesian::CoordCartesian;
8use crate::coord::fixed::CoordFixed;
9use crate::coord::flip::CoordFlip;
10use crate::coord::polar::CoordPolar;
11use crate::coord::Coord;
12use crate::data::{DataFrame, GGData, Value};
13use crate::facet::{Facet, FacetLabeller, FacetScales, FacetSpace};
14use crate::geom::area::GeomArea;
15use crate::geom::bar::GeomBar;
16use crate::geom::bin2d::GeomBin2d;
17use crate::geom::blank::GeomBlank;
18use crate::geom::boxplot::GeomBoxplot;
19use crate::geom::col::GeomCol;
20use crate::geom::contour::GeomContour;
21use crate::geom::count::GeomCount;
22use crate::geom::crossbar::GeomCrossbar;
23use crate::geom::curve::GeomCurve;
24use crate::geom::density::GeomDensity;
25use crate::geom::density2d::GeomDensity2d;
26use crate::geom::dotplot::GeomDotplot;
27use crate::geom::errorbar::GeomErrorbar;
28use crate::geom::freqpoly::GeomFreqpoly;
29use crate::geom::hex::GeomHex;
30use crate::geom::histogram::GeomHistogram;
31use crate::geom::jitter::GeomJitter;
32use crate::geom::line::GeomLine;
33use crate::geom::linerange::GeomLinerange;
34use crate::geom::path::GeomPath;
35use crate::geom::point::GeomPoint;
36use crate::geom::pointrange::GeomPointrange;
37use crate::geom::polygon::GeomPolygon;
38use crate::geom::qq::{GeomQQ, GeomQQLine};
39use crate::geom::rect::GeomRect;
40use crate::geom::refline::{GeomAbline, GeomHline, GeomVline};
41use crate::geom::ribbon::GeomRibbon;
42use crate::geom::rug::GeomRug;
43use crate::geom::segment::GeomSegment;
44use crate::geom::smooth::GeomSmooth;
45use crate::geom::spoke::GeomSpoke;
46use crate::geom::step::GeomStep;
47use crate::geom::text::{GeomLabel, GeomText};
48use crate::geom::tile::GeomTile;
49use crate::geom::violin::GeomViolin;
50use crate::geom::{Geom, GeomParams};
51use crate::position::Position;
52use crate::render::layout::PlotLayout;
53#[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
54use crate::render::plotters_backend::PlottersAdapter;
55use crate::render::renderer::PlotRenderer;
56use crate::render::RenderError;
57use crate::scale::continuous::ScaleContinuous;
58use crate::scale::transform::ScaleTransform;
59use crate::scale::Scale;
60use crate::stat::Stat;
61use crate::theme::Theme;
62
63mod stat_layers;
66
67#[derive(Clone, Debug, Default)]
69pub struct Labels {
70 pub title: Option<String>,
71 pub subtitle: Option<String>,
72 pub x: Option<String>,
73 pub y: Option<String>,
74 pub caption: Option<String>,
75 pub tag: Option<String>,
77}
78
79pub struct Layer {
81 pub data: Option<DataFrame>,
82 pub mapping: Aes,
83 pub geom: Box<dyn Geom>,
84 pub stat: Box<dyn Stat>,
85 pub position: Box<dyn Position>,
86 pub params: GeomParams,
87 pub show_legend: Option<bool>,
88 pub explicit_style: bool,
91 pub tooltip_template: Option<String>,
94}
95
96pub struct GGPlot {
98 pub(crate) data: DataFrame,
99 pub(crate) mapping: Aes,
100 pub(crate) layers: Vec<Layer>,
101 pub(crate) scales: Vec<Box<dyn Scale>>,
102 pub(crate) coord: Box<dyn Coord>,
103 pub(crate) theme: Theme,
104 pub(crate) labels: Labels,
105 pub(crate) facet: Facet,
106 pub(crate) annotations: Vec<Annotation>,
107 pub(crate) guide_legend: crate::guide::config::GuideLegend,
108 pub(crate) warnings: Vec<String>,
111 pub(crate) default_aspect_ratio: Option<f64>,
114 pub(crate) locale: Option<crate::locale::Locale>,
116 pub(crate) svg_root_data: bool,
121 pub(crate) root_attrs: Vec<(String, String)>,
124 pub(crate) svg_warnings_attr: bool,
128 pub(crate) svg_formatted_values: bool,
132}
133
134impl GGPlot {
135 pub fn new(data: impl GGData) -> Self {
142 GGPlot {
143 data: data.into_dataframe(),
144 mapping: Aes::default(),
145 layers: Vec::new(),
146 scales: Vec::new(),
147 coord: Box::new(CoordCartesian::new()),
148 theme: Theme::default(),
149 labels: Labels::default(),
150 facet: Facet::default(),
151 annotations: Vec::new(),
152 guide_legend: crate::guide::config::GuideLegend::default(),
153 warnings: Vec::new(),
154 default_aspect_ratio: None,
155 locale: None,
156 svg_root_data: true,
157 root_attrs: Vec::new(),
158 svg_warnings_attr: false,
159 svg_formatted_values: false,
160 }
161 }
162
163 pub fn aes(mut self, mapping: Aes) -> Self {
165 self.warnings.extend(mapping.warnings.iter().cloned());
166 self.mapping = mapping;
167 self
168 }
169
170 pub fn geom_point(self) -> Self {
173 self.add_geom(GeomPoint::default())
174 }
175
176 pub fn geom_point_with(self, geom: GeomPoint) -> Self {
177 self.add_geom_with(geom)
178 }
179
180 pub fn geom_line(self) -> Self {
181 self.add_geom(GeomLine::default())
182 }
183
184 pub fn geom_line_with(self, geom: GeomLine) -> Self {
185 self.add_geom_with(geom)
186 }
187
188 pub fn geom_bar(self) -> Self {
189 self.add_geom(GeomBar::default())
190 }
191
192 pub fn geom_bar_with(self, geom: GeomBar) -> Self {
193 self.add_geom_with(geom)
194 }
195
196 pub fn geom_histogram(self) -> Self {
197 self.add_geom(GeomHistogram::default())
198 }
199
200 pub fn geom_histogram_with(self, geom: GeomHistogram) -> Self {
201 self.add_geom_with(geom)
202 }
203
204 pub fn geom_boxplot(self) -> Self {
205 self.add_geom(GeomBoxplot::default())
206 }
207
208 pub fn geom_boxplot_with(self, geom: GeomBoxplot) -> Self {
209 self.add_geom_with(geom)
210 }
211
212 pub fn geom_smooth(self) -> Self {
213 self.add_geom(GeomSmooth::default())
214 }
215
216 pub fn geom_smooth_with(self, geom: GeomSmooth) -> Self {
217 self.add_geom_with(geom)
218 }
219
220 pub fn geom_col(self) -> Self {
221 self.add_geom(GeomCol::default())
222 }
223
224 pub fn geom_col_with(self, geom: GeomCol) -> Self {
225 self.add_geom_with(geom)
226 }
227
228 pub fn geom_hline(self, yintercept: f64) -> Self {
232 self.add_refline(
233 GeomHline::new(yintercept),
234 false,
235 &[("yintercept", yintercept)],
236 )
237 }
238
239 pub fn geom_hline_with(self, geom: GeomHline) -> Self {
241 let y = geom.yintercept;
242 self.add_refline(geom, true, &[("yintercept", y)])
243 }
244
245 pub fn geom_hline_aes(self, mapping: Aes) -> Self {
269 self.add_geom(GeomHline::mapped()).layer_aes(mapping)
270 }
271
272 pub fn geom_hline_aes_with(self, geom: GeomHline, mapping: Aes) -> Self {
274 self.add_geom_with(geom).layer_aes(mapping)
275 }
276
277 pub fn geom_vline(self, xintercept: f64) -> Self {
280 self.add_refline(
281 GeomVline::new(xintercept),
282 false,
283 &[("xintercept", xintercept)],
284 )
285 }
286
287 pub fn geom_vline_with(self, geom: GeomVline) -> Self {
289 let x = geom.xintercept;
290 self.add_refline(geom, true, &[("xintercept", x)])
291 }
292
293 pub fn geom_vline_aes(self, mapping: Aes) -> Self {
296 self.add_geom(GeomVline::mapped()).layer_aes(mapping)
297 }
298
299 pub fn geom_vline_aes_with(self, geom: GeomVline, mapping: Aes) -> Self {
301 self.add_geom_with(geom).layer_aes(mapping)
302 }
303
304 pub fn geom_abline(self, slope: f64, intercept: f64) -> Self {
307 self.add_refline(
308 GeomAbline::new(slope, intercept),
309 false,
310 &[("slope", slope), ("intercept", intercept)],
311 )
312 }
313
314 pub fn geom_abline_with(self, geom: GeomAbline) -> Self {
316 let (b, a) = (geom.slope, geom.intercept);
317 self.add_refline(geom, true, &[("slope", b), ("intercept", a)])
318 }
319
320 pub fn geom_abline_aes(self, mapping: Aes) -> Self {
323 self.add_geom(GeomAbline::mapped()).layer_aes(mapping)
324 }
325
326 pub fn geom_abline_aes_with(self, geom: GeomAbline, mapping: Aes) -> Self {
328 self.add_geom_with(geom).layer_aes(mapping)
329 }
330
331 fn add_refline(
334 self,
335 geom: impl Geom + 'static,
336 explicit: bool,
337 values: &[(&str, f64)],
338 ) -> Self {
339 let mut data = DataFrame::new();
340 let mut mapping = Aes::new();
341 for (col, v) in values {
342 data.add_column(col.to_string(), vec![Value::Float(*v)]);
343 mapping = match *col {
344 "xintercept" => mapping.xintercept(col),
345 "yintercept" => mapping.yintercept(col),
346 "slope" => mapping.slope(col),
347 _ => mapping.intercept(col),
348 };
349 }
350 let plot = if explicit {
351 self.add_geom_with(geom)
352 } else {
353 self.add_geom(geom)
354 };
355 plot.layer_aes(mapping).layer_data(data)
356 }
357
358 pub fn geom_text(self) -> Self {
359 self.add_geom(GeomText::default())
360 }
361
362 pub fn geom_text_with(self, geom: GeomText) -> Self {
363 self.add_geom_with(geom)
364 }
365
366 #[cfg(feature = "ggpubr")]
371 pub fn stat_cor(self) -> Self {
372 self.geom_text().stat(crate::stat::cor::StatCor::default())
373 }
374
375 #[cfg(feature = "ggpubr")]
378 pub fn stat_cor_with(self, stat: crate::stat::cor::StatCor) -> Self {
379 self.geom_text().stat(stat)
380 }
381
382 #[cfg(feature = "ggpubr")]
387 pub fn stat_compare_means(self) -> Self {
388 self.geom_text()
389 .stat(crate::stat::compare_means::StatCompareMeans::default())
390 }
391
392 #[cfg(feature = "ggpubr")]
395 pub fn stat_compare_means_with(
396 self,
397 stat: crate::stat::compare_means::StatCompareMeans,
398 ) -> Self {
399 self.geom_text().stat(stat)
400 }
401
402 #[cfg(feature = "ggpubr")]
408 pub fn stat_compare_means_pairwise(self, comparisons: &[(&str, &str)]) -> Self {
409 self.stat_compare_means_pairwise_with(
410 crate::stat::compare_means::CompareMethod::Auto,
411 comparisons,
412 )
413 }
414
415 #[cfg(feature = "ggpubr")]
418 pub fn stat_compare_means_pairwise_with(
419 self,
420 method: crate::stat::compare_means::CompareMethod,
421 comparisons: &[(&str, &str)],
422 ) -> Self {
423 let col_for = |a: crate::aes::Aesthetic| {
425 self.mapping
426 .mappings
427 .iter()
428 .find(|m| m.aesthetic == a)
429 .map(|m| m.column.clone())
430 };
431 let (xcol, ycol) = match (
432 col_for(crate::aes::Aesthetic::X),
433 col_for(crate::aes::Aesthetic::Y),
434 ) {
435 (Some(x), Some(y)) => (x, y),
436 _ => return self,
437 };
438 let (xc, yc) = match (self.data.column(&xcol), self.data.column(&ycol)) {
439 (Some(x), Some(y)) => (x, y),
440 _ => return self,
441 };
442
443 let mut groups: Vec<(String, Vec<f64>)> = Vec::new();
445 let mut ymax = f64::NEG_INFINITY;
446 let mut ymin = f64::INFINITY;
447 for (xv, yv) in xc.iter().zip(yc.iter()) {
448 let y = match yv.as_f64() {
449 Some(y) if y.is_finite() => y,
450 _ => continue,
451 };
452 ymax = ymax.max(y);
453 ymin = ymin.min(y);
454 let key = xv.to_group_key();
455 if let Some(g) = groups.iter_mut().find(|(k, _)| *k == key) {
456 g.1.push(y);
457 } else {
458 groups.push((key, vec![y]));
459 }
460 }
461 if groups.len() < 2 {
462 return self;
463 }
464 let step = if ymax > ymin {
465 (ymax - ymin) * 0.12
466 } else {
467 1.0
468 };
469
470 let (mut xmin_v, mut xmax_v, mut y_v, mut label_v) =
472 (Vec::new(), Vec::new(), Vec::new(), Vec::new());
473 let mut placed = 0usize;
474 for (a, b) in comparisons {
475 let ga = groups.iter().find(|(k, _)| k == a).map(|g| &g.1);
476 let gb = groups.iter().find(|(k, _)| k == b).map(|g| &g.1);
477 let (ga, gb) = match (ga, gb) {
478 (Some(x), Some(y)) if x.len() >= 2 && y.len() >= 2 => (x, y),
479 _ => continue,
480 };
481 let p = match crate::stat::compare_means::pairwise_p(method, ga, gb) {
482 Some(p) => p,
483 None => continue,
484 };
485 xmin_v.push(Value::Str((*a).to_string()));
486 xmax_v.push(Value::Str((*b).to_string()));
487 y_v.push(Value::Float(ymax + step * (placed as f64 + 1.0)));
488 label_v.push(Value::Str(crate::stat::cor::format_p_value(p)));
489 placed += 1;
490 }
491 if xmin_v.is_empty() {
492 return self;
493 }
494
495 let data = vec![
496 ("xmin".to_string(), xmin_v),
497 ("xmax".to_string(), xmax_v),
498 ("y".to_string(), y_v),
499 ("label".to_string(), label_v),
500 ];
501 self.add_geom(crate::geom::bracket::GeomBracket::default())
502 .layer_data(data)
503 .layer_aes(Aes::new().xmin("xmin").xmax("xmax").y("y").label("label"))
504 }
505
506 pub fn geom_bracket(self, xmin: &str, xmax: &str, y: f64, label: &str) -> Self {
511 self.geom_bracket_many(
512 crate::geom::bracket::GeomBracket::default(),
513 &[(xmin, xmax, y, label)],
514 )
515 }
516
517 pub fn geom_bracket_many(
521 self,
522 geom: crate::geom::bracket::GeomBracket,
523 brackets: &[(&str, &str, f64, &str)],
524 ) -> Self {
525 let xmin = brackets
526 .iter()
527 .map(|b| Value::Str(b.0.to_string()))
528 .collect::<Vec<_>>();
529 let xmax = brackets
530 .iter()
531 .map(|b| Value::Str(b.1.to_string()))
532 .collect::<Vec<_>>();
533 let y = brackets
534 .iter()
535 .map(|b| Value::Float(b.2))
536 .collect::<Vec<_>>();
537 let label = brackets
538 .iter()
539 .map(|b| Value::Str(b.3.to_string()))
540 .collect::<Vec<_>>();
541 let data = vec![
542 ("xmin".to_string(), xmin),
543 ("xmax".to_string(), xmax),
544 ("y".to_string(), y),
545 ("label".to_string(), label),
546 ];
547 self.add_geom(geom)
548 .layer_data(data)
549 .layer_aes(Aes::new().xmin("xmin").xmax("xmax").y("y").label("label"))
550 }
551
552 pub fn geom_bracket_table(
561 mut self,
562 table: impl GGData,
563 spec: crate::geom::bracket::BracketTable,
564 ) -> Self {
565 let table = table.into_dataframe();
566 let col_for = |a: crate::aes::Aesthetic| {
567 self.mapping
568 .mappings
569 .iter()
570 .find(|m| m.aesthetic == a)
571 .map(|m| m.column.clone())
572 };
573 let x_levels: Vec<String> = col_for(crate::aes::Aesthetic::X)
576 .and_then(|c| self.data.column(&c))
577 .filter(|col| col.iter().any(|v| matches!(v, Value::Str(_))))
578 .map(|col| {
579 let mut seen = std::collections::HashSet::new();
580 col.iter()
581 .filter(|v| !v.is_na())
582 .map(|v| v.to_group_key())
583 .filter(|k| seen.insert(k.clone()))
584 .collect()
585 })
586 .unwrap_or_default();
587 let y_range = col_for(crate::aes::Aesthetic::Y)
588 .and_then(|c| self.data.column(&c))
589 .and_then(|col| {
590 let (lo, hi) = col
591 .iter()
592 .filter_map(|v| v.as_f64())
593 .filter(|v| v.is_finite())
594 .fold((f64::INFINITY, f64::NEG_INFINITY), |(lo, hi), v| {
595 (lo.min(v), hi.max(v))
596 });
597 (lo <= hi).then_some((lo, hi))
598 });
599 let mut warnings = Vec::new();
600 let resolved = spec.resolve(&table, &x_levels, y_range, &mut warnings);
601 self.warnings.extend(warnings);
602 match resolved {
603 Some(data) => self
604 .add_geom(crate::geom::bracket::GeomBracket::from(spec.geom))
605 .layer_data(data)
606 .layer_aes(Aes::new().xmin("xmin").xmax("xmax").y("y").label("label")),
607 None => self,
608 }
609 }
610
611 pub fn geom_text_repel(self) -> Self {
616 self.add_geom(crate::geom::repel::GeomTextRepel::default())
617 }
618
619 pub fn geom_text_repel_with(self, geom: crate::geom::repel::GeomTextRepel) -> Self {
622 self.add_geom_with(geom)
623 }
624
625 pub fn geom_label_repel(self) -> Self {
628 self.add_geom(crate::geom::repel::GeomLabelRepel::default())
629 }
630
631 pub fn geom_label_repel_with(self, geom: crate::geom::repel::GeomLabelRepel) -> Self {
633 self.add_geom_with(geom)
634 }
635
636 pub fn geom_label(self) -> Self {
637 self.add_geom(GeomLabel::default())
638 }
639
640 pub fn geom_label_with(self, geom: GeomLabel) -> Self {
641 self.add_geom_with(geom)
642 }
643
644 pub fn geom_area(self) -> Self {
645 self.add_geom(GeomArea::default())
646 }
647
648 pub fn geom_area_with(self, geom: GeomArea) -> Self {
649 self.add_geom_with(geom)
650 }
651
652 pub fn geom_ribbon(self) -> Self {
653 self.add_geom(GeomRibbon::default())
654 }
655
656 pub fn geom_ribbon_with(self, geom: GeomRibbon) -> Self {
657 self.add_geom_with(geom)
658 }
659
660 pub fn geom_errorbar(self) -> Self {
661 self.add_geom(GeomErrorbar::default())
662 }
663
664 pub fn geom_errorbar_with(self, geom: GeomErrorbar) -> Self {
665 self.add_geom_with(geom)
666 }
667
668 pub fn geom_segment(self) -> Self {
669 self.add_geom(GeomSegment::default())
670 }
671
672 pub fn geom_segment_with(self, geom: GeomSegment) -> Self {
673 self.add_geom_with(geom)
674 }
675
676 pub fn geom_density(self) -> Self {
677 self.add_geom(GeomDensity::default())
678 }
679
680 pub fn geom_density_with(self, geom: GeomDensity) -> Self {
681 self.add_geom_with(geom)
682 }
683
684 pub fn geom_rug(self) -> Self {
685 self.add_geom(GeomRug::default())
686 }
687
688 pub fn geom_rug_with(self, geom: GeomRug) -> Self {
689 self.add_geom_with(geom)
690 }
691
692 pub fn geom_jitter(self) -> Self {
693 self.add_geom(GeomJitter::default())
694 }
695
696 pub fn geom_jitter_with(self, geom: GeomJitter) -> Self {
697 self.add_geom_with(geom)
698 }
699
700 pub fn geom_path(self) -> Self {
701 self.add_geom(GeomPath::default())
702 }
703
704 pub fn geom_path_with(self, geom: GeomPath) -> Self {
705 self.add_geom_with(geom)
706 }
707
708 pub fn stat_ellipse(self) -> Self {
710 self.geom_path()
711 .stat(crate::stat::ellipse::StatEllipse::default())
712 }
713
714 pub fn stat_ellipse_level(self, level: f64) -> Self {
716 self.geom_path()
717 .stat(crate::stat::ellipse::StatEllipse::new(level))
718 }
719
720 #[cfg(feature = "regression")]
723 pub fn stat_quantile(mut self, taus: &[f64]) -> Self {
724 for &tau in taus {
725 self = self
726 .geom_path()
727 .stat(crate::stat::quantile::StatQuantile::new(tau));
728 }
729 self
730 }
731
732 #[cfg(feature = "regression")]
734 pub fn geom_quantile(self) -> Self {
735 self.stat_quantile(&[0.25, 0.5, 0.75])
736 }
737
738 pub fn geom_step(self) -> Self {
739 self.add_geom(GeomStep::default())
740 }
741
742 pub fn geom_step_with(self, geom: GeomStep) -> Self {
743 self.add_geom_with(geom)
744 }
745
746 pub fn geom_freqpoly(self) -> Self {
747 self.add_geom(GeomFreqpoly::default())
748 }
749
750 pub fn geom_freqpoly_with(self, geom: GeomFreqpoly) -> Self {
751 self.add_geom_with(geom)
752 }
753
754 pub fn geom_linerange(self) -> Self {
755 self.add_geom(GeomLinerange::default())
756 }
757
758 pub fn geom_linerange_with(self, geom: GeomLinerange) -> Self {
759 self.add_geom_with(geom)
760 }
761
762 pub fn geom_pointrange(self) -> Self {
763 self.add_geom(GeomPointrange::default())
764 }
765
766 pub fn geom_pointrange_with(self, geom: GeomPointrange) -> Self {
767 self.add_geom_with(geom)
768 }
769
770 pub fn geom_crossbar(self) -> Self {
771 self.add_geom(GeomCrossbar::default())
772 }
773
774 pub fn geom_crossbar_with(self, geom: GeomCrossbar) -> Self {
775 self.add_geom_with(geom)
776 }
777
778 pub fn geom_spoke(self) -> Self {
779 self.add_geom(GeomSpoke::default())
780 }
781
782 pub fn geom_spoke_with(self, geom: GeomSpoke) -> Self {
783 self.add_geom_with(geom)
784 }
785
786 pub fn geom_rect(self) -> Self {
787 self.add_geom(GeomRect::default())
788 }
789
790 pub fn geom_rect_with(self, geom: GeomRect) -> Self {
791 self.add_geom_with(geom)
792 }
793
794 pub fn geom_tile(self) -> Self {
795 self.add_geom(GeomTile::default())
796 }
797
798 pub fn geom_tile_with(self, geom: GeomTile) -> Self {
799 self.add_geom_with(geom)
800 }
801
802 pub fn geom_raster(self) -> Self {
804 self.add_geom(crate::geom::raster::GeomRaster::default())
805 }
806
807 pub fn geom_raster_with(self, geom: crate::geom::raster::GeomRaster) -> Self {
808 self.add_geom_with(geom)
809 }
810
811 pub fn geom_polygon(self) -> Self {
812 self.add_geom(GeomPolygon::default())
813 }
814
815 pub fn geom_polygon_with(self, geom: GeomPolygon) -> Self {
816 self.add_geom_with(geom)
817 }
818
819 #[cfg(feature = "sf")]
821 pub fn geom_sf(self) -> Self {
822 self.add_geom(crate::geom::sf::GeomSf::default())
823 }
824
825 #[cfg(feature = "sf")]
826 pub fn geom_sf_with(self, geom: crate::geom::sf::GeomSf) -> Self {
827 self.add_geom_with(geom)
828 }
829
830 pub fn geom_curve(self) -> Self {
831 self.add_geom(GeomCurve::default())
832 }
833
834 pub fn geom_curve_with(self, geom: GeomCurve) -> Self {
835 self.add_geom_with(geom)
836 }
837
838 pub fn geom_violin(self) -> Self {
839 self.add_geom(GeomViolin::default())
840 }
841
842 pub fn geom_violin_with(self, geom: GeomViolin) -> Self {
843 self.add_geom_with(geom)
844 }
845
846 pub fn geom_dotplot(self) -> Self {
847 self.add_geom(GeomDotplot::default())
848 }
849
850 pub fn geom_dotplot_with(self, geom: GeomDotplot) -> Self {
851 self.add_geom_with(geom)
852 }
853
854 pub fn geom_qq(self) -> Self {
855 self.add_geom(GeomQQ::default())
856 }
857
858 pub fn geom_qq_with(self, geom: GeomQQ) -> Self {
859 self.add_geom_with(geom)
860 }
861
862 pub fn geom_qq_line(self) -> Self {
863 self.add_geom(GeomQQLine::default())
864 }
865
866 pub fn geom_qq_line_with(self, geom: GeomQQLine) -> Self {
867 self.add_geom_with(geom)
868 }
869
870 pub fn geom_bin2d(self) -> Self {
871 self.add_geom(GeomBin2d::default())
872 }
873
874 pub fn geom_bin2d_with(self, geom: GeomBin2d) -> Self {
875 self.add_geom_with(geom)
876 }
877
878 pub fn geom_hex(self) -> Self {
879 self.add_geom(GeomHex::default())
880 }
881
882 pub fn geom_hex_with(self, geom: GeomHex) -> Self {
883 self.add_geom_with(geom)
884 }
885
886 pub fn geom_count(self) -> Self {
887 self.add_geom(GeomCount::default())
888 }
889
890 pub fn geom_count_with(self, geom: GeomCount) -> Self {
891 self.add_geom_with(geom)
892 }
893
894 pub fn geom_contour(self) -> Self {
895 self.add_geom(GeomContour::default())
896 }
897
898 pub fn geom_contour_with(self, geom: GeomContour) -> Self {
899 self.add_geom_with(geom)
900 }
901
902 pub fn geom_contour_filled(self) -> Self {
905 self.add_geom(GeomPolygon {
906 line_width: 0.0,
907 alpha: 1.0,
908 ..GeomPolygon::default()
909 })
910 .stat(crate::stat::contour_filled::StatContourFilled::default())
911 }
912
913 pub fn geom_density2d(self) -> Self {
914 self.add_geom(GeomDensity2d::default())
915 }
916
917 pub fn geom_density2d_with(self, geom: GeomDensity2d) -> Self {
918 self.add_geom_with(geom)
919 }
920
921 pub fn geom_candlestick(self) -> Self {
924 self.add_geom(crate::geom::candlestick::GeomCandlestick::default())
925 }
926
927 pub fn geom_candlestick_with(self, geom: crate::geom::candlestick::GeomCandlestick) -> Self {
928 self.add_geom_with(geom)
929 }
930
931 pub fn geom_ohlc(self) -> Self {
934 self.add_geom(crate::geom::candlestick::GeomOhlc::default())
935 }
936
937 pub fn geom_ohlc_with(self, geom: crate::geom::candlestick::GeomOhlc) -> Self {
938 self.add_geom_with(geom)
939 }
940
941 pub fn geom_calendar(self) -> Self {
952 self.geom_calendar_with(
953 GeomTile {
954 color: (255, 255, 255),
955 line_width: 1.5,
956 ..Default::default()
957 },
958 false,
959 )
960 }
961
962 pub fn geom_calendar_with(mut self, tile: GeomTile, monday_first: bool) -> Self {
965 use crate::stat::calendar::{
966 day_number, month_boundaries, month_breaks, month_breaks_localized, weekday_labels,
967 CalendarGrid, StatCalendar, MAX_CALENDAR_YEARS,
968 };
969 let grid = self
970 .mapping
971 .get_mapping(&crate::aes::Aesthetic::X)
972 .and_then(|c| self.data.column(c))
973 .and_then(|col| {
974 CalendarGrid::from_days(col.iter().filter_map(day_number), monday_first)
975 });
976 let Some((grid, clipped)) = grid else {
977 return self.add_geom_with(tile).stat(StatCalendar {
979 grid: None,
980 monday_first,
981 });
982 };
983 if clipped {
984 self.warnings.push(format!(
985 "geom_calendar: dates more than {MAX_CALENDAR_YEARS} years before the newest were dropped"
986 ));
987 }
988 let (xb, _) = month_breaks(&grid);
989 let yb = if monday_first {
991 vec![6.0, 4.0, 2.0]
992 } else {
993 vec![5.0, 3.0, 1.0]
994 };
995 let segs = month_boundaries(&grid);
996 let col = |f: fn(&(f64, f64, f64, f64)) -> f64| -> Vec<Value> {
997 segs.iter().map(|s| Value::Float(f(s))).collect()
998 };
999 let boundaries = vec![
1000 ("x".to_string(), col(|s| s.0)),
1001 ("y".to_string(), col(|s| s.1)),
1002 ("xend".to_string(), col(|s| s.2)),
1003 ("yend".to_string(), col(|s| s.3)),
1004 ];
1005 self.default_aspect_ratio = Some(7.0 / grid.n_weeks().max(1) as f64);
1006 let plot = self
1007 .add_geom_with(tile)
1008 .stat(StatCalendar {
1009 grid: Some(grid),
1010 monday_first,
1011 })
1012 .scale_x_continuous(
1013 ScaleContinuous::new()
1014 .with_breaks(xb)
1015 .with_localized_labels(move |l| month_breaks_localized(&grid, l).1)
1017 .with_expand(0.0, 0.0),
1018 )
1019 .scale_y_continuous(
1020 ScaleContinuous::new()
1021 .with_breaks(yb)
1022 .with_localized_labels(weekday_labels)
1023 .with_expand(0.0, 0.0),
1024 );
1025 if segs.is_empty() {
1026 return plot;
1027 }
1028 plot.add_geom_with(crate::geom::segment::GeomCalendarBorder)
1030 .layer_data(boundaries)
1031 .layer_aes(Aes::new().x("x").y("y").xend("xend").yend("yend"))
1032 .show_legend(false)
1033 }
1034
1035 pub fn geom_blank(self) -> Self {
1036 self.add_geom(GeomBlank)
1037 }
1038
1039 fn add_geom_with(self, geom: impl Geom + 'static) -> Self {
1042 let mut plot = self.add_geom(geom);
1043 if let Some(layer) = plot.layers.last_mut() {
1044 layer.explicit_style = true;
1045 }
1046 plot
1047 }
1048
1049 fn add_geom(mut self, geom: impl Geom + 'static) -> Self {
1050 let stat = geom.default_stat();
1051 let position = geom.default_position();
1052 let params = geom.default_params();
1053 self.layers.push(Layer {
1054 data: None,
1055 mapping: Aes::default(),
1056 geom: Box::new(geom),
1057 stat,
1058 position,
1059 params,
1060 show_legend: None,
1061 explicit_style: false,
1062 tooltip_template: None,
1063 });
1064 self
1065 }
1066
1067 pub fn stat(mut self, stat: impl Stat + 'static) -> Self {
1071 if let Some(layer) = self.layers.last_mut() {
1072 layer.stat = Box::new(stat);
1073 }
1074 self
1075 }
1076
1077 pub fn position(mut self, pos: impl Position + 'static) -> Self {
1079 if let Some(layer) = self.layers.last_mut() {
1080 layer.position = Box::new(pos);
1081 }
1082 self
1083 }
1084
1085 pub fn layer_data(mut self, data: impl GGData) -> Self {
1087 if let Some(layer) = self.layers.last_mut() {
1088 layer.data = Some(data.into_dataframe());
1089 }
1090 self
1091 }
1092
1093 pub fn layer_aes(mut self, mapping: Aes) -> Self {
1095 self.warnings.extend(mapping.warnings.iter().cloned());
1096 if let Some(layer) = self.layers.last_mut() {
1097 layer.mapping = mapping;
1098 }
1099 self
1100 }
1101
1102 pub fn tooltip(mut self, template: &str) -> Self {
1113 if let Some(layer) = self.layers.last_mut() {
1114 layer.tooltip_template = Some(template.to_string());
1115 }
1116 self
1117 }
1118
1119 pub fn show_legend(mut self, show: bool) -> Self {
1122 if let Some(layer) = self.layers.last_mut() {
1123 layer.show_legend = Some(show);
1124 }
1125 self
1126 }
1127
1128 pub fn decorative(mut self) -> Self {
1155 if let Some(layer) = self.layers.last_mut() {
1156 let geom = std::mem::replace(&mut layer.geom, Box::new(GeomBlank));
1157 layer.geom = Box::new(crate::geom::decorative::Decorative(geom));
1158 if layer.show_legend.is_none() {
1159 layer.show_legend = Some(false);
1160 }
1161 }
1162 self
1163 }
1164
1165 pub fn scale_x_continuous(mut self, s: ScaleContinuous) -> Self {
1168 let s = s.for_aesthetic(crate::aes::Aesthetic::X);
1169 self.scales.push(Box::new(s));
1170 self
1171 }
1172
1173 pub fn scale_y_continuous(mut self, s: ScaleContinuous) -> Self {
1174 let s = s.for_aesthetic(crate::aes::Aesthetic::Y);
1175 self.scales.push(Box::new(s));
1176 self
1177 }
1178
1179 pub fn scale_x_discrete(mut self, s: crate::scale::discrete::ScaleDiscrete) -> Self {
1180 let s = s.for_aesthetic(crate::aes::Aesthetic::X);
1181 self.scales.push(Box::new(s));
1182 self
1183 }
1184
1185 pub fn scale_y_discrete(mut self, s: crate::scale::discrete::ScaleDiscrete) -> Self {
1186 let s = s.for_aesthetic(crate::aes::Aesthetic::Y);
1187 self.scales.push(Box::new(s));
1188 self
1189 }
1190
1191 pub fn scale_color(mut self, s: impl Scale + 'static) -> Self {
1192 self.scales.push(Box::new(s));
1193 self
1194 }
1195
1196 pub fn scale_fill(mut self, s: impl Scale + 'static) -> Self {
1197 self.scales.push(Box::new(s));
1198 self
1199 }
1200
1201 pub fn scale_color_manual(self, values: Vec<(&str, crate::scale::color::RGBAColor)>) -> Self {
1202 let s = crate::scale::manual::ScaleManual::new(crate::aes::Aesthetic::Color, values);
1203 self.scale_color(s)
1204 }
1205
1206 pub fn scale_fill_manual(self, values: Vec<(&str, crate::scale::color::RGBAColor)>) -> Self {
1207 let s = crate::scale::manual::ScaleManual::new(crate::aes::Aesthetic::Fill, values);
1208 self.scale_fill(s)
1209 }
1210
1211 pub fn scale_colour_identity(self) -> Self {
1214 let s = crate::scale::identity::ScaleColorIdentity::new(crate::aes::Aesthetic::Color);
1215 self.scale_color(s)
1216 }
1217
1218 pub fn scale_color_identity(self) -> Self {
1220 self.scale_colour_identity()
1221 }
1222
1223 pub fn scale_fill_identity(self) -> Self {
1226 let s = crate::scale::identity::ScaleColorIdentity::new(crate::aes::Aesthetic::Fill);
1227 self.scale_fill(s)
1228 }
1229
1230 pub fn scale_color_viridis(self) -> Self {
1231 use crate::scale::color::ScaleColorDiscrete;
1232 use crate::scale::palettes::PaletteName;
1233 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Color)
1234 .with_named_palette(&PaletteName::Viridis);
1235 self.scale_color(s)
1236 }
1237
1238 pub fn scale_color_brewer(self, name: crate::scale::palettes::PaletteName) -> Self {
1239 use crate::scale::color::ScaleColorDiscrete;
1240 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Color).with_named_palette(&name);
1241 self.scale_color(s)
1242 }
1243
1244 pub fn scale_color_gradient(
1245 self,
1246 low: crate::scale::color::RGBAColor,
1247 high: crate::scale::color::RGBAColor,
1248 ) -> Self {
1249 use crate::scale::color::ScaleColorContinuous;
1250 let s = ScaleColorContinuous::new(crate::aes::Aesthetic::Color).with_colors(low, high);
1251 self.scale_color(s)
1252 }
1253
1254 pub fn scale_fill_gradient(
1255 self,
1256 low: crate::scale::color::RGBAColor,
1257 high: crate::scale::color::RGBAColor,
1258 ) -> Self {
1259 use crate::scale::color::ScaleColorContinuous;
1260 let s = ScaleColorContinuous::new(crate::aes::Aesthetic::Fill).with_colors(low, high);
1261 self.scale_fill(s)
1262 }
1263
1264 pub fn scale_color_gradient2(
1265 self,
1266 low: crate::scale::color::RGBAColor,
1267 mid: crate::scale::color::RGBAColor,
1268 high: crate::scale::color::RGBAColor,
1269 ) -> Self {
1270 use crate::scale::gradient::ScaleColorGradient2;
1271 let s = ScaleColorGradient2::new(crate::aes::Aesthetic::Color).with_colors(low, mid, high);
1272 self.scale_color(s)
1273 }
1274
1275 pub fn scale_fill_gradient2(
1276 self,
1277 low: crate::scale::color::RGBAColor,
1278 mid: crate::scale::color::RGBAColor,
1279 high: crate::scale::color::RGBAColor,
1280 ) -> Self {
1281 use crate::scale::gradient::ScaleColorGradient2;
1282 let s = ScaleColorGradient2::new(crate::aes::Aesthetic::Fill).with_colors(low, mid, high);
1283 self.scale_fill(s)
1284 }
1285
1286 pub fn scale_fill_viridis(self) -> Self {
1287 use crate::scale::color::ScaleColorDiscrete;
1288 use crate::scale::palettes::PaletteName;
1289 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill)
1290 .with_named_palette(&PaletteName::Viridis);
1291 self.scale_fill(s)
1292 }
1293
1294 pub fn scale_color_viridis_c(self) -> Self {
1296 use crate::scale::gradient_n::ScaleColorGradientN;
1297 let s = ScaleColorGradientN::viridis(crate::aes::Aesthetic::Color);
1298 self.scale_color(s)
1299 }
1300
1301 pub fn scale_fill_viridis_c(self) -> Self {
1303 use crate::scale::gradient_n::ScaleColorGradientN;
1304 let s = ScaleColorGradientN::viridis(crate::aes::Aesthetic::Fill);
1305 self.scale_fill(s)
1306 }
1307
1308 pub fn scale_color_gradientn(self, stops: Vec<(f64, crate::scale::color::RGBAColor)>) -> Self {
1310 use crate::scale::gradient_n::ScaleColorGradientN;
1311 let s = ScaleColorGradientN::new(crate::aes::Aesthetic::Color, stops);
1312 self.scale_color(s)
1313 }
1314
1315 pub fn scale_fill_gradientn(self, stops: Vec<(f64, crate::scale::color::RGBAColor)>) -> Self {
1317 use crate::scale::gradient_n::ScaleColorGradientN;
1318 let s = ScaleColorGradientN::new(crate::aes::Aesthetic::Fill, stops);
1319 self.scale_fill(s)
1320 }
1321
1322 pub fn scale_color_steps(
1325 self,
1326 low: crate::scale::color::RGBAColor,
1327 high: crate::scale::color::RGBAColor,
1328 n_bins: usize,
1329 ) -> Self {
1330 let s = crate::scale::steps::ScaleColorSteps::two(
1331 crate::aes::Aesthetic::Color,
1332 (low.r, low.g, low.b),
1333 (high.r, high.g, high.b),
1334 n_bins,
1335 );
1336 self.scale_color(s)
1337 }
1338
1339 pub fn scale_color_stepsn(
1341 self,
1342 stops: Vec<crate::scale::color::RGBAColor>,
1343 n_bins: usize,
1344 ) -> Self {
1345 let s = crate::scale::steps::ScaleColorSteps::new(
1346 crate::aes::Aesthetic::Color,
1347 stops.iter().map(|c| (c.r, c.g, c.b)).collect(),
1348 n_bins,
1349 );
1350 self.scale_color(s)
1351 }
1352
1353 pub fn scale_color_fermenter(
1355 self,
1356 name: crate::scale::palettes::PaletteName,
1357 n_bins: usize,
1358 ) -> Self {
1359 let stops = crate::scale::palettes::palette(&name)
1360 .iter()
1361 .map(|c| (c.r, c.g, c.b))
1362 .collect();
1363 let s =
1364 crate::scale::steps::ScaleColorSteps::new(crate::aes::Aesthetic::Color, stops, n_bins);
1365 self.scale_color(s)
1366 }
1367
1368 pub fn scale_fill_steps(
1370 self,
1371 low: crate::scale::color::RGBAColor,
1372 high: crate::scale::color::RGBAColor,
1373 n_bins: usize,
1374 ) -> Self {
1375 let s = crate::scale::steps::ScaleColorSteps::two(
1376 crate::aes::Aesthetic::Fill,
1377 (low.r, low.g, low.b),
1378 (high.r, high.g, high.b),
1379 n_bins,
1380 );
1381 self.scale_fill(s)
1382 }
1383
1384 pub fn scale_fill_fermenter(
1386 self,
1387 name: crate::scale::palettes::PaletteName,
1388 n_bins: usize,
1389 ) -> Self {
1390 let stops = crate::scale::palettes::palette(&name)
1391 .iter()
1392 .map(|c| (c.r, c.g, c.b))
1393 .collect();
1394 let s =
1395 crate::scale::steps::ScaleColorSteps::new(crate::aes::Aesthetic::Fill, stops, n_bins);
1396 self.scale_fill(s)
1397 }
1398
1399 pub fn scale_fill_discrete_sorted(self) -> Self {
1404 use crate::scale::color::ScaleColorDiscrete;
1405 self.scale_fill(ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill).sorted())
1406 }
1407
1408 pub fn scale_color_discrete_sorted(self) -> Self {
1411 use crate::scale::color::ScaleColorDiscrete;
1412 self.scale_color(ScaleColorDiscrete::new(crate::aes::Aesthetic::Color).sorted())
1413 }
1414
1415 pub fn scale_fill_brewer(self, name: crate::scale::palettes::PaletteName) -> Self {
1416 use crate::scale::color::ScaleColorDiscrete;
1417 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill).with_named_palette(&name);
1418 self.scale_fill(s)
1419 }
1420
1421 pub fn scale_linetype_manual(
1422 self,
1423 values: Vec<(&str, crate::render::backend::Linetype)>,
1424 ) -> Self {
1425 let s = crate::scale::linetype_manual::ScaleLinetypeManual::new(values);
1426 self.scale_color(s)
1427 }
1428
1429 pub fn scale_shape_manual(
1430 self,
1431 values: Vec<(&str, crate::render::backend::PointShape)>,
1432 ) -> Self {
1433 let s = crate::scale::shape_manual::ScaleShapeManual::new(values);
1434 self.scale_color(s)
1435 }
1436
1437 pub fn scale_color_grey(self) -> Self {
1438 let s = crate::scale::grey::ScaleColorGrey::new(crate::aes::Aesthetic::Color);
1439 self.scale_color(s)
1440 }
1441
1442 pub fn scale_fill_grey(self) -> Self {
1443 let s = crate::scale::grey::ScaleColorGrey::new(crate::aes::Aesthetic::Fill);
1444 self.scale_fill(s)
1445 }
1446
1447 pub fn scale_color_grey_with(self, s: crate::scale::grey::ScaleColorGrey) -> Self {
1448 self.scale_color(s)
1449 }
1450
1451 pub fn scale_fill_grey_with(self, s: crate::scale::grey::ScaleColorGrey) -> Self {
1452 self.scale_fill(s)
1453 }
1454
1455 pub fn scale_x_reverse(self) -> Self {
1456 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reverse))
1457 }
1458
1459 pub fn scale_y_reverse(self) -> Self {
1460 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reverse))
1461 }
1462
1463 pub fn scale_x_datetime(mut self, s: crate::scale::datetime::ScaleDateTime) -> Self {
1464 let s = s.for_aesthetic(crate::aes::Aesthetic::X);
1465 self.scales.push(Box::new(s));
1466 self
1467 }
1468
1469 pub fn scale_y_datetime(mut self, s: crate::scale::datetime::ScaleDateTime) -> Self {
1470 let s = s.for_aesthetic(crate::aes::Aesthetic::Y);
1471 self.scales.push(Box::new(s));
1472 self
1473 }
1474
1475 pub fn scale_size(mut self, s: crate::scale::size::ScaleSizeContinuous) -> Self {
1476 self.scales.push(Box::new(s));
1477 self
1478 }
1479
1480 pub fn scale_size_area(mut self, max_size: f64) -> Self {
1484 self.scales.push(Box::new(
1485 crate::scale::size::ScaleSizeContinuous::new().area(max_size),
1486 ));
1487 self
1488 }
1489
1490 pub fn scale_alpha(mut self, s: crate::scale::alpha::ScaleAlphaContinuous) -> Self {
1491 self.scales.push(Box::new(s));
1492 self
1493 }
1494
1495 pub fn scale_linewidth(mut self, s: crate::scale::linewidth::ScaleLinewidthContinuous) -> Self {
1499 self.scales.push(Box::new(s));
1500 self
1501 }
1502
1503 pub fn xlim(self, min: f64, max: f64) -> Self {
1504 self.scale_x_continuous(ScaleContinuous::new().with_limits(min, max))
1505 }
1506
1507 pub fn ylim(self, min: f64, max: f64) -> Self {
1508 self.scale_y_continuous(ScaleContinuous::new().with_limits(min, max))
1509 }
1510
1511 pub fn scale_x_log10(self) -> Self {
1512 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log10))
1513 }
1514
1515 pub fn scale_y_log10(self) -> Self {
1516 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log10))
1517 }
1518
1519 pub fn scale_x_sqrt(self) -> Self {
1520 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Sqrt))
1521 }
1522
1523 pub fn scale_y_sqrt(self) -> Self {
1524 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Sqrt))
1525 }
1526
1527 pub fn scale_x_log2(self) -> Self {
1528 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log2))
1529 }
1530
1531 pub fn scale_y_log2(self) -> Self {
1532 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log2))
1533 }
1534
1535 pub fn scale_x_ln(self) -> Self {
1536 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Ln))
1537 }
1538
1539 pub fn scale_y_ln(self) -> Self {
1540 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Ln))
1541 }
1542
1543 pub fn scale_x_logit(self) -> Self {
1545 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Logit))
1546 }
1547
1548 pub fn scale_y_logit(self) -> Self {
1549 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Logit))
1550 }
1551
1552 pub fn scale_x_probit(self) -> Self {
1554 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Probit))
1555 }
1556
1557 pub fn scale_y_probit(self) -> Self {
1558 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Probit))
1559 }
1560
1561 pub fn scale_x_pseudo_log(self) -> Self {
1563 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::PseudoLog))
1564 }
1565
1566 pub fn scale_y_pseudo_log(self) -> Self {
1567 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::PseudoLog))
1568 }
1569
1570 pub fn scale_x_reciprocal(self) -> Self {
1572 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reciprocal))
1573 }
1574
1575 pub fn scale_y_reciprocal(self) -> Self {
1576 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reciprocal))
1577 }
1578
1579 pub fn scale_x_exp(self) -> Self {
1581 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Exp))
1582 }
1583
1584 pub fn scale_y_exp(self) -> Self {
1585 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Exp))
1586 }
1587
1588 pub fn scale_x_boxcox(self, lambda: f64) -> Self {
1590 self.scale_x_continuous(
1591 ScaleContinuous::new().with_transform(ScaleTransform::BoxCox(lambda)),
1592 )
1593 }
1594
1595 pub fn scale_y_boxcox(self, lambda: f64) -> Self {
1596 self.scale_y_continuous(
1597 ScaleContinuous::new().with_transform(ScaleTransform::BoxCox(lambda)),
1598 )
1599 }
1600
1601 pub fn facet_wrap(mut self, var: &str, ncol: Option<usize>) -> Self {
1604 self.facet = Facet::Wrap {
1605 var: var.to_string(),
1606 ncol,
1607 scales: FacetScales::Fixed,
1608 labeller: FacetLabeller::default(),
1609 };
1610 self
1611 }
1612
1613 pub fn facet_wrap_free(mut self, var: &str, ncol: Option<usize>, scales: FacetScales) -> Self {
1614 self.facet = Facet::Wrap {
1615 var: var.to_string(),
1616 ncol,
1617 scales,
1618 labeller: FacetLabeller::default(),
1619 };
1620 self
1621 }
1622
1623 pub fn facet_wrap_labeller(
1624 mut self,
1625 var: &str,
1626 ncol: Option<usize>,
1627 labeller: FacetLabeller,
1628 ) -> Self {
1629 self.facet = Facet::Wrap {
1630 var: var.to_string(),
1631 ncol,
1632 scales: FacetScales::Fixed,
1633 labeller,
1634 };
1635 self
1636 }
1637
1638 pub fn facet_grid(mut self, row: Option<&str>, col: Option<&str>) -> Self {
1639 self.facet = Facet::Grid {
1640 row_var: row.map(String::from),
1641 col_var: col.map(String::from),
1642 scales: FacetScales::Fixed,
1643 labeller: FacetLabeller::default(),
1644 space: FacetSpace::Fixed,
1645 };
1646 self
1647 }
1648
1649 pub fn facet_grid_free(
1650 mut self,
1651 row: Option<&str>,
1652 col: Option<&str>,
1653 scales: FacetScales,
1654 ) -> Self {
1655 self.facet = Facet::Grid {
1656 row_var: row.map(String::from),
1657 col_var: col.map(String::from),
1658 scales,
1659 labeller: FacetLabeller::default(),
1660 space: FacetSpace::Fixed,
1661 };
1662 self
1663 }
1664
1665 pub fn facet_grid_multi(
1669 mut self,
1670 row: Option<&str>,
1671 cols: &[&str],
1672 scales: FacetScales,
1673 space: FacetSpace,
1674 ) -> Self {
1675 let col_var = if cols.len() > 1 {
1676 let n = self.data.nrows();
1678 let mut combined = Vec::with_capacity(n);
1679 for i in 0..n {
1680 let parts: Vec<String> = cols
1681 .iter()
1682 .map(|c| {
1683 self.data
1684 .column(c)
1685 .and_then(|col| col.get(i))
1686 .map(|v| v.to_group_key())
1687 .unwrap_or_default()
1688 })
1689 .collect();
1690 combined.push(crate::data::Value::Str(parts.join(" . ")));
1691 }
1692 let name = "__facet_cols__".to_string();
1693 self.data.add_column(name.clone(), combined);
1694 Some(name)
1695 } else {
1696 cols.first().map(|s| s.to_string())
1697 };
1698 self.facet = Facet::Grid {
1699 row_var: row.map(String::from),
1700 col_var,
1701 scales,
1702 labeller: FacetLabeller::default(),
1703 space,
1704 };
1705 self
1706 }
1707
1708 pub fn facet_grid_space(
1711 mut self,
1712 row: Option<&str>,
1713 col: Option<&str>,
1714 scales: FacetScales,
1715 space: FacetSpace,
1716 ) -> Self {
1717 self.facet = Facet::Grid {
1718 row_var: row.map(String::from),
1719 col_var: col.map(String::from),
1720 scales,
1721 labeller: FacetLabeller::default(),
1722 space,
1723 };
1724 self
1725 }
1726
1727 pub fn facet_grid_labeller(
1728 mut self,
1729 row: Option<&str>,
1730 col: Option<&str>,
1731 labeller: FacetLabeller,
1732 ) -> Self {
1733 self.facet = Facet::Grid {
1734 row_var: row.map(String::from),
1735 col_var: col.map(String::from),
1736 scales: FacetScales::Fixed,
1737 labeller,
1738 space: FacetSpace::Fixed,
1739 };
1740 self
1741 }
1742
1743 pub fn coord_flip(mut self) -> Self {
1746 self.coord = Box::new(CoordFlip);
1747 self
1748 }
1749
1750 pub fn coord_fixed(mut self, ratio: f64) -> Self {
1751 self.coord = Box::new(CoordFixed::new(ratio));
1752 self
1753 }
1754
1755 #[cfg(feature = "sf")]
1759 pub fn coord_sf(mut self) -> Self {
1760 self.coord = Box::new(crate::coord::sf::CoordSf::new());
1761 self
1762 }
1763
1764 #[cfg(feature = "sf")]
1769 pub fn coord_sf_with(mut self, coord: crate::coord::sf::CoordSf) -> Self {
1770 self.coord = Box::new(coord);
1771 self
1772 }
1773
1774 pub fn svg_root_data(mut self, on: bool) -> Self {
1781 self.svg_root_data = on;
1782 self
1783 }
1784
1785 pub fn svg_attr(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
1795 self.root_attrs.push((name.into(), value.into()));
1796 self
1797 }
1798
1799 pub fn svg_attrs(mut self, attrs: impl IntoIterator<Item = (String, String)>) -> Self {
1801 self.root_attrs.extend(attrs);
1802 self
1803 }
1804
1805 pub fn svg_warnings_attr(mut self, on: bool) -> Self {
1810 self.svg_warnings_attr = on;
1811 self
1812 }
1813
1814 pub fn svg_formatted_values(mut self, on: bool) -> Self {
1823 self.svg_formatted_values = on;
1824 self
1825 }
1826
1827 pub fn coord_trans(mut self, x: Option<ScaleTransform>, y: Option<ScaleTransform>) -> Self {
1832 self.coord = Box::new(crate::coord::trans::CoordTrans::new(x, y));
1833 self
1834 }
1835
1836 pub fn coord_trans_y(self, y: ScaleTransform) -> Self {
1838 self.coord_trans(None, Some(y))
1839 }
1840
1841 pub fn coord_trans_x(self, x: ScaleTransform) -> Self {
1843 self.coord_trans(Some(x), None)
1844 }
1845
1846 pub fn coord_cartesian_zoom(
1848 mut self,
1849 xlim: Option<(f64, f64)>,
1850 ylim: Option<(f64, f64)>,
1851 ) -> Self {
1852 let mut c = CoordCartesian::new();
1853 if let Some((min, max)) = xlim {
1854 c = c.xlim(min, max);
1855 }
1856 if let Some((min, max)) = ylim {
1857 c = c.ylim(min, max);
1858 }
1859 self.coord = Box::new(c);
1860 self
1861 }
1862
1863 pub fn coord_polar(mut self) -> Self {
1864 self.coord = Box::new(CoordPolar::new());
1865 self
1866 }
1867
1868 pub fn coord_radar(mut self) -> Self {
1872 self.coord = Box::new(crate::coord::radar::CoordRadar::new());
1873 self
1874 }
1875
1876 pub fn coord_radar_with(mut self, coord: crate::coord::radar::CoordRadar) -> Self {
1877 self.coord = Box::new(coord);
1878 self
1879 }
1880
1881 pub fn coord_polar_with(mut self, coord: CoordPolar) -> Self {
1882 self.coord = Box::new(coord);
1883 self
1884 }
1885
1886 pub fn theme(mut self, theme: Theme) -> Self {
1891 self.apply_preset(theme);
1892 self
1893 }
1894
1895 fn apply_preset(&mut self, theme: Theme) {
1896 let primary = self.theme.primary;
1897 self.theme = theme;
1898 if self.theme.primary.is_none() {
1899 self.theme.primary = primary;
1900 }
1901 }
1902
1903 pub fn axis_text_x_angle(mut self, degrees: f64) -> Self {
1907 self.theme.axis_text_x.angle = degrees;
1908 self
1909 }
1910
1911 pub fn axis_text_y_angle(mut self, degrees: f64) -> Self {
1913 self.theme.axis_text_y.angle = degrees;
1914 self
1915 }
1916
1917 pub fn axis_text_x_dodge(mut self, n: usize) -> Self {
1920 self.theme.axis_text_x_dodge = n.max(1);
1921 self
1922 }
1923
1924 pub fn aspect_ratio(mut self, ratio: f64) -> Self {
1927 self.theme.aspect_ratio = Some(ratio);
1928 self
1929 }
1930
1931 pub fn panel_ontop(mut self) -> Self {
1933 self.theme.panel_ontop = true;
1934 self
1935 }
1936
1937 pub fn axis_minor_ticks(mut self) -> Self {
1939 self.theme.axis_minor_ticks = true;
1940 self
1941 }
1942
1943 pub fn axis_text_x_fit(mut self, fit: crate::theme::AxisLabelFit) -> Self {
1948 self.theme.axis_text_x_fit = fit;
1949 self
1950 }
1951
1952 pub fn axis_text_x_check_overlap(mut self, on: bool) -> Self {
1955 self.theme.axis_text_x_check_overlap = on;
1956 self
1957 }
1958
1959 pub fn title_position(mut self, pos: crate::theme::TitlePosition) -> Self {
1962 self.theme.title_position = pos;
1963 self
1964 }
1965
1966 pub fn tag_position(mut self, pos: crate::theme::TagPosition) -> Self {
1968 self.theme.tag_position = pos;
1969 self
1970 }
1971
1972 pub fn legend_direction(mut self, dir: crate::theme::LegendDirection) -> Self {
1974 self.theme.legend_direction = Some(dir);
1975 self
1976 }
1977
1978 pub fn legend_position_inside(mut self, x: f64, y: f64) -> Self {
1985 self.theme.legend_position = crate::theme::LegendPosition::Inside(x, y);
1986 self
1987 }
1988
1989 pub fn legend_position(mut self, pos: crate::theme::LegendPosition) -> Self {
1991 self.theme.legend_position = pos;
1992 self
1993 }
1994
1995 pub fn primary_color(mut self, color: (u8, u8, u8)) -> Self {
1996 self.theme.primary = Some(color);
1997 self
1998 }
1999
2000 pub fn theme_minimal(mut self) -> Self {
2001 self.apply_preset(crate::theme::presets::theme_minimal());
2002 self
2003 }
2004
2005 pub fn theme_bw(mut self) -> Self {
2006 self.apply_preset(crate::theme::presets::theme_bw());
2007 self
2008 }
2009
2010 pub fn theme_gray(mut self) -> Self {
2011 self.apply_preset(crate::theme::presets::theme_gray());
2012 self
2013 }
2014
2015 pub fn theme_classic(mut self) -> Self {
2016 self.apply_preset(crate::theme::presets::theme_classic());
2017 self
2018 }
2019
2020 pub fn theme_pubr(mut self) -> Self {
2022 self.apply_preset(crate::theme::presets::theme_pubr());
2023 self
2024 }
2025
2026 pub fn theme_linedraw(mut self) -> Self {
2027 self.apply_preset(crate::theme::presets::theme_linedraw());
2028 self
2029 }
2030
2031 pub fn theme_light(mut self) -> Self {
2032 self.apply_preset(crate::theme::presets::theme_light());
2033 self
2034 }
2035
2036 pub fn theme_dark(mut self) -> Self {
2037 self.apply_preset(crate::theme::presets::theme_dark());
2038 self
2039 }
2040
2041 pub fn theme_void(mut self) -> Self {
2042 self.apply_preset(crate::theme::presets::theme_void());
2043 self
2044 }
2045
2046 pub fn theme_update(mut self, update: crate::theme::ThemeUpdate) -> Self {
2049 self.theme = self.theme.update(update);
2050 self
2051 }
2052
2053 pub fn guides(mut self, guide: crate::guide::config::GuideLegend) -> Self {
2057 self.guide_legend = guide;
2058 self
2059 }
2060
2061 pub fn labs(mut self, labels: Labels) -> Self {
2064 if labels.title.is_some() {
2065 self.labels.title = labels.title;
2066 }
2067 if labels.subtitle.is_some() {
2068 self.labels.subtitle = labels.subtitle;
2069 }
2070 if labels.x.is_some() {
2071 self.labels.x = labels.x;
2072 }
2073 if labels.y.is_some() {
2074 self.labels.y = labels.y;
2075 }
2076 if labels.caption.is_some() {
2077 self.labels.caption = labels.caption;
2078 }
2079 if labels.tag.is_some() {
2080 self.labels.tag = labels.tag;
2081 }
2082 self
2083 }
2084
2085 pub fn title(mut self, title: &str) -> Self {
2086 self.labels.title = Some(title.to_string());
2087 self
2088 }
2089
2090 pub fn tag(mut self, tag: &str) -> Self {
2093 self.labels.tag = Some(tag.to_string());
2094 self
2095 }
2096
2097 pub fn subtitle(mut self, subtitle: &str) -> Self {
2098 self.labels.subtitle = Some(subtitle.to_string());
2099 self
2100 }
2101
2102 pub fn xlab(mut self, label: &str) -> Self {
2103 self.labels.x = Some(label.to_string());
2104 self
2105 }
2106
2107 pub fn ylab(mut self, label: &str) -> Self {
2108 self.labels.y = Some(label.to_string());
2109 self
2110 }
2111
2112 pub fn caption(mut self, caption: &str) -> Self {
2113 self.labels.caption = Some(caption.to_string());
2114 self
2115 }
2116
2117 pub fn annotate(mut self, annotation: Annotation) -> Self {
2121 self.annotations.push(annotation);
2122 self
2123 }
2124
2125 pub fn annotate_text(self, label: &str, x: f64, y: f64) -> Self {
2127 self.annotate(Annotation::text(label, x, y))
2128 }
2129
2130 pub fn annotate_rect(self, xmin: f64, xmax: f64, ymin: f64, ymax: f64) -> Self {
2132 self.annotate(Annotation::rect(xmin, xmax, ymin, ymax))
2133 }
2134
2135 pub fn annotate_segment(self, x: f64, y: f64, xend: f64, yend: f64) -> Self {
2137 self.annotate(Annotation::segment(x, y, xend, yend))
2138 }
2139
2140 pub fn locale(mut self, locale: crate::locale::Locale) -> Self {
2163 self.locale = Some(locale);
2164 self
2165 }
2166
2167 pub fn try_build(self) -> Result<crate::build::BuiltPlot, GGError> {
2171 PlotBuilder::build(self)
2172 }
2173
2174 pub fn build(self) -> crate::build::BuiltPlot {
2178 self.try_build().expect("plot build failed")
2179 }
2180
2181 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
2185 pub fn save(self, path: &str) -> Result<(), GGError> {
2186 self.save_with_size(path, 800, 600)
2187 }
2188
2189 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
2191 pub fn save_with_size(self, path: &str, w: u32, h: u32) -> Result<(), GGError> {
2192 let (built, layout) = self.prepare(w, h)?;
2193
2194 let ext = path.rsplit('.').next().unwrap_or("svg").to_lowercase();
2196
2197 match ext.as_str() {
2198 "svg" => {
2199 let backend = plotters::prelude::SVGBackend::new(path, (w, h));
2200 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
2201 }
2202 "png" | "bmp" | "gif" | "jpeg" | "jpg" | "tiff" => {
2203 let backend = plotters::prelude::BitMapBackend::new(path, (w, h));
2204 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
2205 }
2206 _ => {
2207 return Err(GGError::UnsupportedFormat(ext));
2208 }
2209 }
2210
2211 Ok(())
2212 }
2213
2214 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
2220 pub fn render_svg(self) -> Result<String, GGError> {
2221 self.render_svg_with_size(800, 600)
2222 }
2223
2224 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
2228 pub fn render_svg_with_size(self, w: u32, h: u32) -> Result<String, GGError> {
2229 let (built, layout) = self.prepare(w, h)?;
2230 let mut buf = String::new();
2231 {
2232 let backend = plotters::prelude::SVGBackend::with_string(&mut buf, (w, h));
2233 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
2234 }
2235 Ok(buf)
2236 }
2237
2238 pub fn render_svg_native(self) -> Result<String, GGError> {
2242 self.render_svg_native_with_size(800, 600)
2243 }
2244
2245 pub fn render_svg_native_with_size(self, w: u32, h: u32) -> Result<String, GGError> {
2253 Ok(self.render_native(w, h)?.0.finish())
2254 }
2255
2256 pub fn render_svg_native_with_warnings(
2261 self,
2262 w: u32,
2263 h: u32,
2264 ) -> Result<(String, Vec<String>), GGError> {
2265 let (backend, warnings, _) = self.render_native(w, h)?;
2266 Ok((backend.finish(), warnings))
2267 }
2268
2269 pub fn render_svg_native_at(self, x: f64, y: f64, w: u32, h: u32) -> Result<String, GGError> {
2281 Ok(self.render_native(w, h)?.0.finish_fragment(x, y))
2282 }
2283
2284 pub fn render_svg_area_with_size(self, w: u32, h: u32) -> Result<(String, [f64; 4]), GGError> {
2288 let (backend, _, pa) = self.render_native(w, h)?;
2289 Ok((backend.finish(), [pa.x, pa.y, pa.width, pa.height]))
2290 }
2291
2292 fn render_native(
2296 self,
2297 w: u32,
2298 h: u32,
2299 ) -> Result<
2300 (
2301 crate::render::svg_backend::SvgBackend,
2302 Vec<String>,
2303 crate::render::Rect,
2304 ),
2305 GGError,
2306 > {
2307 let svg_root_data = self.svg_root_data;
2308 let root_attrs = self.root_attrs.clone();
2309 let svg_warnings_attr = self.svg_warnings_attr;
2310 let svg_formatted_values = self.svg_formatted_values;
2311 let (built, layout) = self.prepare(w, h)?;
2312 let pa = layout.plot_area.clone();
2313 let mut backend = crate::render::svg_backend::SvgBackend::new(w, h, pa.clone());
2314 backend.set_formatted_values(svg_formatted_values);
2315 let existing_root_attrs = if svg_root_data {
2316 let attrs = crate::render::svg_backend::root_data_attrs(&built);
2317 backend.set_root_attrs(attrs.clone());
2318 let mut reserved = attrs;
2322 reserved.push(("data-plot".to_string(), String::new()));
2323 reserved
2324 } else {
2325 backend.without_plot_attr();
2326 Vec::new()
2327 };
2328 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
2329 let mut warnings = built.warnings;
2330 warnings.extend(backend.take_warnings());
2331
2332 let mut reserved = existing_root_attrs;
2333 if svg_warnings_attr {
2334 reserved.push(("data-warnings".to_string(), String::new()));
2335 }
2336 let extra = crate::render::svg_backend::validate_root_attrs(
2337 &root_attrs,
2338 &reserved,
2339 "plot",
2340 &mut warnings,
2341 );
2342 backend.extend_root_attrs(extra);
2343 if svg_warnings_attr {
2344 backend.extend_root_attrs(vec![(
2345 "data-warnings".to_string(),
2346 crate::render::svg_backend::warnings_json(&warnings),
2347 )]);
2348 }
2349 Ok((backend, warnings, pa))
2350 }
2351
2352 #[cfg(feature = "canvas")]
2357 pub fn render_rgba_with_size(self, w: u32, h: u32) -> Result<(u32, u32, Vec<u8>), GGError> {
2358 let (built, layout) = self.prepare(w, h)?;
2359 let mut backend =
2360 crate::render::pixel_backend::PixelBackend::new(w, h, layout.plot_area.clone());
2361 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
2362 let (ow, oh) = backend.dimensions();
2363 Ok((ow, oh, backend.into_rgba()))
2364 }
2365
2366 #[cfg(feature = "canvas")]
2370 pub fn render_rgba_area_with_size(
2371 self,
2372 w: u32,
2373 h: u32,
2374 ) -> Result<(Vec<u8>, [f64; 4]), GGError> {
2375 let (built, layout) = self.prepare(w, h)?;
2376 let pa = layout.plot_area.clone();
2377 let mut backend = crate::render::pixel_backend::PixelBackend::new(w, h, pa.clone());
2378 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
2379 Ok((backend.into_rgba(), [pa.x, pa.y, pa.width, pa.height]))
2380 }
2381
2382 #[cfg(feature = "canvas")]
2386 pub fn render_png_raster_with_size(self, w: u32, h: u32) -> Result<Vec<u8>, GGError> {
2387 let (built, layout) = self.prepare(w, h)?;
2388 let mut backend =
2389 crate::render::pixel_backend::PixelBackend::new(w, h, layout.plot_area.clone());
2390 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
2391 backend.into_png().map_err(GGError::Render)
2392 }
2393
2394 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
2401 pub fn render_png(self) -> Result<Vec<u8>, GGError> {
2402 self.render_png_with_size(800, 600)
2403 }
2404
2405 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
2408 pub fn render_png_with_size(self, w: u32, h: u32) -> Result<Vec<u8>, GGError> {
2409 let (built, layout) = self.prepare(w, h)?;
2410
2411 let mut rgb = vec![0u8; (w as usize) * (h as usize) * 3];
2414 {
2415 let backend = plotters::prelude::BitMapBackend::with_buffer(&mut rgb, (w, h));
2416 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
2417 }
2418
2419 let img = image::RgbImage::from_raw(w, h, rgb).ok_or_else(|| {
2420 GGError::Render(RenderError::BackendError(
2421 "PNG buffer size mismatch".to_string(),
2422 ))
2423 })?;
2424 let mut out = std::io::Cursor::new(Vec::new());
2425 img.write_to(&mut out, image::ImageOutputFormat::Png)
2426 .map_err(|e| GGError::Render(RenderError::BackendError(format!("{:?}", e))))?;
2427 Ok(out.into_inner())
2428 }
2429
2430 pub(crate) fn prepare(
2432 self,
2433 w: u32,
2434 h: u32,
2435 ) -> Result<(crate::build::BuiltPlot, PlotLayout), GGError> {
2436 let (mut built, meta) = self.build_for_render()?;
2437 let layout = Self::layout_built(&mut built, &meta, w, h);
2438 Ok((built, layout))
2439 }
2440
2441 pub(crate) fn build_for_render(self) -> Result<(crate::build::BuiltPlot, RenderMeta), GGError> {
2444 let plot = self;
2445
2446 let has_title = plot.labels.title.is_some();
2447 let has_subtitle = plot.labels.subtitle.is_some();
2448 let has_caption = plot.labels.caption.is_some();
2449 let has_legend = plot.has_legend_mapping();
2450 let x_label = plot.labels.x.clone();
2451 let y_label = plot.labels.y.clone();
2452
2453 let mut built = PlotBuilder::build(plot)?;
2454
2455 built.theme.resolve_inheritance();
2457
2458 if let Some(ref label) = x_label {
2460 if let Some(s) = built.scales.get_mut(&crate::aes::Aesthetic::X) {
2461 s.set_name(label);
2462 }
2463 }
2464 if let Some(ref label) = y_label {
2465 if let Some(s) = built.scales.get_mut(&crate::aes::Aesthetic::Y) {
2466 s.set_name(label);
2467 }
2468 }
2469
2470 Ok((
2471 built,
2472 RenderMeta {
2473 has_title,
2474 has_subtitle,
2475 has_caption,
2476 has_legend,
2477 },
2478 ))
2479 }
2480
2481 pub(crate) fn layout_built(
2484 built: &mut crate::build::BuiltPlot,
2485 meta: &RenderMeta,
2486 w: u32,
2487 h: u32,
2488 ) -> PlotLayout {
2489 let RenderMeta {
2490 has_title,
2491 has_subtitle,
2492 has_caption,
2493 has_legend,
2494 } = *meta;
2495 let x_axis_top = built
2496 .scales
2497 .get(&crate::aes::Aesthetic::X)
2498 .map(|s| s.axis_position_opposite())
2499 .unwrap_or(false);
2500
2501 let flipped = built.coord.is_flipped();
2505 let h_aes = if flipped {
2506 crate::aes::Aesthetic::Y
2507 } else {
2508 crate::aes::Aesthetic::X
2509 };
2510 let v_aes = if flipped {
2511 crate::aes::Aesthetic::X
2512 } else {
2513 crate::aes::Aesthetic::Y
2514 };
2515
2516 let drawn_x_labels: Vec<(f64, String)> = built
2524 .scales
2525 .get(&h_aes)
2526 .map(|hs| {
2527 hs.breaks()
2528 .into_iter()
2529 .filter(|(_, label)| !label.is_empty())
2530 .collect()
2531 })
2532 .unwrap_or_default();
2533 let h_is_discrete = built
2534 .scales
2535 .get(&h_aes)
2536 .map(|hs| hs.is_discrete())
2537 .unwrap_or(false);
2538
2539 if built.theme.axis_text_x.visible
2552 && built.theme.axis_text_x.angle.abs() < 1.0
2553 && h_is_discrete
2554 && !drawn_x_labels.is_empty()
2555 {
2556 let font = built.theme.axis_text_x.size;
2557 let max_w = drawn_x_labels
2558 .iter()
2559 .map(|(_, l)| crate::render::text::text_width(l, font))
2560 .fold(0.0_f64, f64::max);
2561 let n = drawn_x_labels.len() as f64;
2562 let spacing = 0.9 * w as f64 / n; if max_w > spacing {
2564 let vertical = max_w * std::f64::consts::FRAC_1_SQRT_2 > spacing;
2568 built.theme.axis_text_x.angle = if vertical { 270.0 } else { -45.0 };
2569 }
2570 }
2571
2572 let x_label_height = if built.theme.axis_text_x.visible
2587 && built.theme.axis_text_x.angle.abs() > 10.0
2588 && !drawn_x_labels.is_empty()
2589 {
2590 let font = built.theme.axis_text_x.size;
2591 let angle = built.theme.axis_text_x.angle;
2592 let dir = if x_axis_top { -1.0 } else { 1.0 };
2593 let (rise, fall) = crate::render::text::rotated_label_rise_fall(
2594 drawn_x_labels.iter().map(|(_, l)| l.as_str()),
2595 font,
2596 angle,
2597 crate::render::text::rotated_anchor_frac(angle, dir),
2598 );
2599 Some(built.theme.legend_spacing / 2.0 + font / 2.0 + rise + fall)
2600 } else {
2601 None
2602 };
2603
2604 let y_label_width = if built.theme.axis_text_y.visible {
2608 built.scales.get(&v_aes).map(|vs| {
2609 let max_ch = vs
2610 .breaks()
2611 .iter()
2612 .map(|(_, l)| l.chars().count())
2613 .max()
2614 .unwrap_or(0);
2615 let measured = max_ch as f64 * built.theme.axis_text_y.size * 0.6 + 4.0;
2616 let default = built.theme.axis_text_y.size * 3.5 + 4.0;
2617 measured.max(default).min(0.35 * w as f64)
2618 })
2619 } else {
2620 None
2621 };
2622
2623 let mut extras = crate::render::layout::LayoutExtras::default();
2634 let can_reserve = built.facet.is_none()
2635 && built.theme.axis_text_x.visible
2636 && built.theme.axis_text_x_fit == crate::theme::AxisLabelFit::Reserve
2637 && !built.coord.is_polar()
2638 && built.coord.supports_axis_reserve();
2639 if can_reserve {
2640 if let Some(hs) = built.scales.get(&h_aes) {
2641 let breaks = hs.breaks();
2642 if let (Some(first), Some(last)) = (breaks.first(), breaks.last()) {
2643 let angle = built.theme.axis_text_x.angle;
2644 let anchor = if angle.abs() > 10.0 {
2645 let dir = if x_axis_top { -1.0 } else { 1.0 };
2646 crate::render::text::rotated_anchor_frac(angle, dir)
2647 } else {
2648 0.5
2649 };
2650 let size = built.theme.axis_text_x.size;
2651 const EDGE: f64 = 1.0;
2652 for _ in 0..2 {
2653 let layout = PlotLayout::compute_with_extras(
2654 w as f64,
2655 h as f64,
2656 &built.theme,
2657 has_title,
2658 has_subtitle,
2659 has_caption,
2660 has_legend,
2661 x_axis_top,
2662 y_label_width,
2663 x_label_height,
2664 extras,
2665 );
2666 let area = &layout.plot_area;
2667 let edge_y = area.y + area.height;
2668 let to_point = |pos: f64| if flipped { (0.0, pos) } else { (pos, 0.0) };
2669 let px_first = built.coord.transform(to_point(first.0), area).0;
2670 let px_last = built.coord.transform(to_point(last.0), area).0;
2671 let bbox_first = crate::render::text::label_bbox(
2672 &first.1, size, px_first, edge_y, angle, anchor,
2673 );
2674 let bbox_last = crate::render::text::label_bbox(
2675 &last.1, size, px_last, edge_y, angle, anchor,
2676 );
2677 let deficit_left = (EDGE - bbox_first[0]).max(0.0);
2678 let deficit_right = (bbox_last[2] - (w as f64 - EDGE)).max(0.0);
2679 if deficit_left <= 0.0 && deficit_right <= 0.0 {
2680 break;
2681 }
2682 let (p_first, p_last) = (first.0, last.0);
2691 if deficit_left > 0.0 && deficit_right > 0.0 {
2692 let (a, b, c, d) = (1.0 - p_first, p_first, 1.0 - p_last, p_last);
2697 let det = a * d - b * c;
2698 if det.abs() > 0.01 {
2699 extras.left +=
2700 ((deficit_left * d + deficit_right * b) / det).max(0.0);
2701 extras.right +=
2702 ((deficit_right * a + deficit_left * c) / det).max(0.0);
2703 } else {
2704 extras.left += deficit_left / (1.0 - p_first).max(0.05);
2708 extras.right += deficit_right / p_last.max(0.05);
2709 }
2710 } else if deficit_left > 0.0 {
2711 extras.left += deficit_left / (1.0 - p_first).max(0.05);
2712 } else if deficit_right > 0.0 {
2713 extras.right += deficit_right / p_last.max(0.05);
2714 }
2715 const MIN_PANEL_WIDTH: f64 = 50.0;
2730 let cap = (w as f64 - MIN_PANEL_WIDTH).max(0.0);
2731 if extras.left + extras.right > cap {
2732 let scale = if extras.left + extras.right > 0.0 {
2733 cap / (extras.left + extras.right)
2734 } else {
2735 0.0
2736 };
2737 extras.left *= scale;
2738 extras.right *= scale;
2739 }
2740 }
2741 }
2742 }
2743 }
2744
2745 if has_legend
2752 && !matches!(
2753 built.theme.legend_position,
2754 crate::theme::LegendPosition::None
2755 )
2756 {
2757 let legend_aes =
2758 crate::guide::legend::legend_scales_for(&built.scales, &built.suppressed_aes);
2759 let has_discrete_guide = legend_aes.iter().any(|a| {
2760 built
2761 .scales
2762 .get(a)
2763 .map(|s| s.is_discrete())
2764 .unwrap_or(false)
2765 });
2766 if has_discrete_guide {
2767 let layout0 = PlotLayout::compute_with_extras(
2768 w as f64,
2769 h as f64,
2770 &built.theme,
2771 has_title,
2772 has_subtitle,
2773 has_caption,
2774 has_legend,
2775 x_axis_top,
2776 y_label_width,
2777 x_label_height,
2778 extras,
2779 );
2780 let (legend_x0, _, mut is_horizontal) =
2781 crate::guide::legend::legend_position(&built.theme, &layout0.plot_area);
2782 if let Some(dir) = built.theme.legend_direction {
2783 is_horizontal = matches!(dir, crate::theme::LegendDirection::Horizontal);
2784 }
2785 let avail_width =
2786 (layout0.plot_area.x + layout0.plot_area.width - legend_x0).max(0.0);
2787 let mut legend_warnings = Vec::new();
2788 let mut plans = crate::guide::legend::plan_all_legends(
2789 &built.scales,
2790 &built.guide_legend,
2791 &built.theme,
2792 &built.suppressed_aes,
2793 avail_width,
2794 layout0.plot_area.height,
2795 is_horizontal,
2796 &mut legend_warnings,
2797 );
2798 built.warnings.extend(legend_warnings);
2799
2800 if !plans.is_empty() {
2801 extras.legend_extra_rows = if is_horizontal {
2807 plans
2808 .values()
2809 .map(|p| p.rows.saturating_sub(1))
2810 .max()
2811 .unwrap_or(0)
2812 } else {
2813 plans.values().map(|p| p.rows.saturating_sub(1)).sum()
2814 };
2815 extras.legend_extra_width = plans
2822 .values()
2823 .map(|p| p.cols.saturating_sub(1) as f64 * p.col_pitch)
2824 .fold(0.0_f64, f64::max);
2825
2826 if !is_horizontal {
2838 let final_layout = PlotLayout::compute_with_extras(
2839 w as f64,
2840 h as f64,
2841 &built.theme,
2842 has_title,
2843 has_subtitle,
2844 has_caption,
2845 has_legend,
2846 x_axis_top,
2847 y_label_width,
2848 x_label_height,
2849 extras,
2850 );
2851 let (legend_x_final, _, _) = crate::guide::legend::legend_position(
2852 &built.theme,
2853 &final_layout.plot_area,
2854 );
2855 let swatch_and_gap =
2856 built.theme.legend_key_width + built.theme.legend_spacing;
2857 let text_size = built.theme.legend_text.size;
2858 let right_edge_of =
2859 |plan: &crate::guide::legend::LegendPlan, breaks: &[(f64, String)]| {
2860 plan.entries
2861 .iter()
2862 .filter_map(|e| breaks.get(e.break_idx).map(|(_, l)| (e, l)))
2863 .map(|(e, label)| {
2864 let text =
2865 e.label_override.as_deref().unwrap_or(label.as_str());
2866 legend_x_final
2867 + e.x_offset
2868 + swatch_and_gap
2869 + crate::render::text::text_width(text, text_size)
2870 })
2871 .fold(0.0_f64, f64::max)
2872 };
2873
2874 let mut updates: Vec<(
2875 crate::aes::Aesthetic,
2876 crate::guide::legend::LegendPlan,
2877 )> = Vec::new();
2878 for (aes, plan) in &plans {
2879 if plan.cols <= 1 {
2880 continue;
2881 }
2882 let Some(scale) = built.scales.get(aes) else {
2883 continue;
2884 };
2885 let breaks = scale.breaks();
2886 if right_edge_of(plan, &breaks) <= w as f64 {
2887 continue; }
2889
2890 let n = breaks.len();
2893 let mut reduced: Vec<crate::guide::legend::LegendPlan> = Vec::new();
2894 for c in (1..plan.cols).rev() {
2895 let mut candidate_guide = built.guide_legend.clone();
2896 candidate_guide.ncol = Some(c);
2897 candidate_guide.nrow = None;
2898 let mut tmp_warnings = Vec::new();
2899 let candidate_guide =
2900 candidate_guide.validated(n, &mut tmp_warnings);
2901 if let Some(cand) = crate::guide::legend::plan_legend(
2902 &breaks,
2903 &candidate_guide,
2904 &built.theme,
2905 avail_width,
2906 layout0.plot_area.height,
2907 false,
2908 ) {
2909 reduced.push(cand);
2910 }
2911 }
2912 if let Some(fits) = reduced
2913 .iter()
2914 .find(|c| right_edge_of(c, &breaks) <= w as f64)
2915 {
2916 extras.legend_extra_rows =
2917 extras.legend_extra_rows.max(fits.rows.saturating_sub(1));
2918 updates.push((aes.clone(), fits.clone()));
2919 continue;
2920 }
2921
2922 let base = reduced.last().cloned().unwrap_or_else(|| plan.clone());
2927 extras.legend_extra_rows =
2928 extras.legend_extra_rows.max(base.rows.saturating_sub(1));
2929 let mut truncated = base.clone();
2930 for e in &mut truncated.entries {
2931 let Some((_, label)) = breaks.get(e.break_idx) else {
2932 continue;
2933 };
2934 let avail = (w as f64
2935 - (legend_x_final + e.x_offset + swatch_and_gap))
2936 .max(0.0);
2937 if let Some(short) =
2938 crate::render::text::truncate_to_width(label, avail, text_size)
2939 {
2940 e.label_override = Some(short);
2941 }
2942 }
2943
2944 if right_edge_of(&truncated, &breaks) > w as f64 {
2948 built.warnings.push(format!(
2949 "legend: the {}-column grid still doesn't fit the {w}px chart (needs about {} px)",
2950 truncated.cols,
2951 right_edge_of(&truncated, &breaks).ceil() as i64
2952 ));
2953 }
2954 updates.push((aes.clone(), truncated));
2955 }
2956 for (aes, new_plan) in updates {
2957 plans.insert(aes, new_plan);
2958 }
2959 }
2996 for (aes, plan) in &plans {
2997 if let Some(ov) = &plan.overflow {
2998 let n = built
2999 .scales
3000 .get(aes)
3001 .map(|s| s.breaks().len())
3002 .unwrap_or(ov.dropped);
3003 let shown = n.saturating_sub(ov.dropped);
3004 built.warnings.push(format!(
3005 "legend: {} of {n} entries don't fit the chart; the legend shows {shown} and \"+{} more\"",
3006 ov.dropped, ov.dropped
3007 ));
3008 }
3009 }
3010 }
3011 built.legend_plans = plans;
3017 }
3018 }
3019
3020 PlotLayout::compute_with_extras(
3021 w as f64,
3022 h as f64,
3023 &built.theme,
3024 has_title,
3025 has_subtitle,
3026 has_caption,
3027 has_legend,
3028 x_axis_top,
3029 y_label_width,
3030 x_label_height,
3031 extras,
3032 )
3033 }
3034
3035 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
3038 fn render_into<DB>(
3039 area: plotters::drawing::DrawingArea<DB, plotters::coord::Shift>,
3040 built: &crate::build::BuiltPlot,
3041 layout: &PlotLayout,
3042 ) -> Result<(), GGError>
3043 where
3044 DB: plotters::prelude::DrawingBackend,
3045 DB::ErrorType: 'static,
3046 {
3047 area.fill(&plotters::prelude::WHITE)
3048 .map_err(|e| GGError::Render(RenderError::BackendError(format!("{:?}", e))))?;
3049 let mut adapter = PlottersAdapter::new(&area, layout.plot_area.clone());
3050 PlotRenderer::render(built, &mut adapter).map_err(GGError::Render)?;
3051 area.present()
3052 .map_err(|e| GGError::Render(RenderError::BackendError(format!("{:?}", e))))?;
3053 Ok(())
3054 }
3055
3056 #[cfg(all(feature = "plotters", not(target_arch = "wasm32")))]
3059 pub fn ggsave(
3060 self,
3061 path: &str,
3062 width_inches: f64,
3063 height_inches: f64,
3064 dpi: f64,
3065 ) -> Result<(), GGError> {
3066 let w = (width_inches * dpi) as u32;
3067 let h = (height_inches * dpi) as u32;
3068 self.save_with_size(path, w, h)
3069 }
3070
3071 fn has_legend_mapping(&self) -> bool {
3072 self.mapping.mappings.iter().any(|m| {
3073 matches!(
3074 m.aesthetic,
3075 crate::aes::Aesthetic::Color
3076 | crate::aes::Aesthetic::Fill
3077 | crate::aes::Aesthetic::Shape
3078 | crate::aes::Aesthetic::Linetype
3079 | crate::aes::Aesthetic::Size
3080 | crate::aes::Aesthetic::Alpha
3081 )
3082 })
3083 }
3084}
3085
3086#[derive(Clone, Copy, Debug)]
3088pub(crate) struct RenderMeta {
3089 pub(crate) has_title: bool,
3090 pub(crate) has_subtitle: bool,
3091 pub(crate) has_caption: bool,
3092 pub(crate) has_legend: bool,
3093}
3094
3095#[derive(Debug)]
3097pub enum GGError {
3098 Render(RenderError),
3099 UnsupportedFormat(String),
3100 Io(std::io::Error),
3101 ValidationError(String),
3102}
3103
3104impl std::fmt::Display for GGError {
3105 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3106 match self {
3107 GGError::Render(e) => write!(f, "Render error: {e}"),
3108 GGError::UnsupportedFormat(ext) => write!(f, "Unsupported output format: {ext}"),
3109 GGError::Io(e) => write!(f, "IO error: {e}"),
3110 GGError::ValidationError(msg) => write!(f, "Validation error: {msg}"),
3111 }
3112 }
3113}
3114
3115impl std::error::Error for GGError {}