1use plotters::prelude::IntoDrawingArea;
2
3use crate::aes::Aes;
4use crate::annotate::Annotation;
5use crate::build::PlotBuilder;
6use crate::coord::cartesian::CoordCartesian;
7use crate::coord::fixed::CoordFixed;
8use crate::coord::flip::CoordFlip;
9use crate::coord::polar::CoordPolar;
10use crate::coord::Coord;
11use crate::data::{DataFrame, GGData};
12use crate::facet::{Facet, FacetLabeller, FacetScales, FacetSpace};
13use crate::geom::area::GeomArea;
14use crate::geom::bar::GeomBar;
15use crate::geom::bin2d::GeomBin2d;
16use crate::geom::blank::GeomBlank;
17use crate::geom::boxplot::GeomBoxplot;
18use crate::geom::col::GeomCol;
19use crate::geom::contour::GeomContour;
20use crate::geom::count::GeomCount;
21use crate::geom::crossbar::GeomCrossbar;
22use crate::geom::curve::GeomCurve;
23use crate::geom::density::GeomDensity;
24use crate::geom::density2d::GeomDensity2d;
25use crate::geom::dotplot::GeomDotplot;
26use crate::geom::errorbar::GeomErrorbar;
27use crate::geom::freqpoly::GeomFreqpoly;
28use crate::geom::hex::GeomHex;
29use crate::geom::histogram::GeomHistogram;
30use crate::geom::jitter::GeomJitter;
31use crate::geom::line::GeomLine;
32use crate::geom::linerange::GeomLinerange;
33use crate::geom::path::GeomPath;
34use crate::geom::point::GeomPoint;
35use crate::geom::pointrange::GeomPointrange;
36use crate::geom::polygon::GeomPolygon;
37use crate::geom::qq::{GeomQQ, GeomQQLine};
38use crate::geom::rect::GeomRect;
39use crate::geom::refline::{GeomAbline, GeomHline, GeomVline};
40use crate::geom::ribbon::GeomRibbon;
41use crate::geom::rug::GeomRug;
42use crate::geom::segment::GeomSegment;
43use crate::geom::smooth::GeomSmooth;
44use crate::geom::spoke::GeomSpoke;
45use crate::geom::step::GeomStep;
46use crate::geom::text::{GeomLabel, GeomText};
47use crate::geom::tile::GeomTile;
48use crate::geom::violin::GeomViolin;
49use crate::geom::{Geom, GeomParams};
50use crate::position::Position;
51use crate::render::layout::PlotLayout;
52use crate::render::plotters_backend::PlottersAdapter;
53use crate::render::renderer::PlotRenderer;
54use crate::render::RenderError;
55use crate::scale::continuous::ScaleContinuous;
56use crate::scale::transform::ScaleTransform;
57use crate::scale::Scale;
58use crate::stat::Stat;
59use crate::theme::Theme;
60
61#[derive(Clone, Debug, Default)]
63pub struct Labels {
64 pub title: Option<String>,
65 pub subtitle: Option<String>,
66 pub x: Option<String>,
67 pub y: Option<String>,
68 pub caption: Option<String>,
69 pub tag: Option<String>,
71}
72
73pub struct Layer {
75 pub data: Option<DataFrame>,
76 pub mapping: Aes,
77 pub geom: Box<dyn Geom>,
78 pub stat: Box<dyn Stat>,
79 pub position: Box<dyn Position>,
80 pub params: GeomParams,
81 pub show_legend: Option<bool>,
82}
83
84pub struct GGPlot {
86 pub(crate) data: DataFrame,
87 pub(crate) mapping: Aes,
88 pub(crate) layers: Vec<Layer>,
89 pub(crate) scales: Vec<Box<dyn Scale>>,
90 pub(crate) coord: Box<dyn Coord>,
91 pub(crate) theme: Theme,
92 pub(crate) labels: Labels,
93 pub(crate) facet: Facet,
94 pub(crate) annotations: Vec<Annotation>,
95 pub(crate) guide_legend: crate::guide::config::GuideLegend,
96}
97
98impl GGPlot {
99 pub fn new(data: impl GGData) -> Self {
101 GGPlot {
102 data: data.into_dataframe(),
103 mapping: Aes::default(),
104 layers: Vec::new(),
105 scales: Vec::new(),
106 coord: Box::new(CoordCartesian::new()),
107 theme: Theme::default(),
108 labels: Labels::default(),
109 facet: Facet::default(),
110 annotations: Vec::new(),
111 guide_legend: crate::guide::config::GuideLegend::default(),
112 }
113 }
114
115 pub fn aes(mut self, mapping: Aes) -> Self {
117 self.mapping = mapping;
118 self
119 }
120
121 pub fn geom_point(self) -> Self {
124 self.add_geom(GeomPoint::default())
125 }
126
127 pub fn geom_point_with(self, geom: GeomPoint) -> Self {
128 self.add_geom(geom)
129 }
130
131 pub fn geom_line(self) -> Self {
132 self.add_geom(GeomLine::default())
133 }
134
135 pub fn geom_line_with(self, geom: GeomLine) -> Self {
136 self.add_geom(geom)
137 }
138
139 pub fn geom_bar(self) -> Self {
140 self.add_geom(GeomBar::default())
141 }
142
143 pub fn geom_bar_with(self, geom: GeomBar) -> Self {
144 self.add_geom(geom)
145 }
146
147 pub fn geom_histogram(self) -> Self {
148 self.add_geom(GeomHistogram::default())
149 }
150
151 pub fn geom_histogram_with(self, geom: GeomHistogram) -> Self {
152 self.add_geom(geom)
153 }
154
155 pub fn geom_boxplot(self) -> Self {
156 self.add_geom(GeomBoxplot::default())
157 }
158
159 pub fn geom_boxplot_with(self, geom: GeomBoxplot) -> Self {
160 self.add_geom(geom)
161 }
162
163 pub fn geom_smooth(self) -> Self {
164 self.add_geom(GeomSmooth::default())
165 }
166
167 pub fn geom_smooth_with(self, geom: GeomSmooth) -> Self {
168 self.add_geom(geom)
169 }
170
171 pub fn geom_col(self) -> Self {
172 self.add_geom(GeomCol::default())
173 }
174
175 pub fn geom_col_with(self, geom: GeomCol) -> Self {
176 self.add_geom(geom)
177 }
178
179 pub fn geom_hline(self, yintercept: f64) -> Self {
180 self.add_geom(GeomHline::new(yintercept))
181 }
182
183 pub fn geom_hline_with(self, geom: GeomHline) -> Self {
185 self.add_geom(geom)
186 }
187
188 pub fn geom_vline(self, xintercept: f64) -> Self {
189 self.add_geom(GeomVline::new(xintercept))
190 }
191
192 pub fn geom_vline_with(self, geom: GeomVline) -> Self {
194 self.add_geom(geom)
195 }
196
197 pub fn geom_abline(self, slope: f64, intercept: f64) -> Self {
198 self.add_geom(GeomAbline::new(slope, intercept))
199 }
200
201 pub fn geom_abline_with(self, geom: GeomAbline) -> Self {
203 self.add_geom(geom)
204 }
205
206 pub fn geom_text(self) -> Self {
207 self.add_geom(GeomText::default())
208 }
209
210 pub fn geom_text_with(self, geom: GeomText) -> Self {
211 self.add_geom(geom)
212 }
213
214 pub fn geom_label(self) -> Self {
215 self.add_geom(GeomLabel::default())
216 }
217
218 pub fn geom_label_with(self, geom: GeomLabel) -> Self {
219 self.add_geom(geom)
220 }
221
222 pub fn geom_area(self) -> Self {
223 self.add_geom(GeomArea::default())
224 }
225
226 pub fn geom_area_with(self, geom: GeomArea) -> Self {
227 self.add_geom(geom)
228 }
229
230 pub fn geom_ribbon(self) -> Self {
231 self.add_geom(GeomRibbon::default())
232 }
233
234 pub fn geom_ribbon_with(self, geom: GeomRibbon) -> Self {
235 self.add_geom(geom)
236 }
237
238 pub fn geom_errorbar(self) -> Self {
239 self.add_geom(GeomErrorbar::default())
240 }
241
242 pub fn geom_errorbar_with(self, geom: GeomErrorbar) -> Self {
243 self.add_geom(geom)
244 }
245
246 pub fn geom_segment(self) -> Self {
247 self.add_geom(GeomSegment::default())
248 }
249
250 pub fn geom_segment_with(self, geom: GeomSegment) -> Self {
251 self.add_geom(geom)
252 }
253
254 pub fn geom_density(self) -> Self {
255 self.add_geom(GeomDensity::default())
256 }
257
258 pub fn geom_density_with(self, geom: GeomDensity) -> Self {
259 self.add_geom(geom)
260 }
261
262 pub fn geom_rug(self) -> Self {
263 self.add_geom(GeomRug::default())
264 }
265
266 pub fn geom_rug_with(self, geom: GeomRug) -> Self {
267 self.add_geom(geom)
268 }
269
270 pub fn geom_jitter(self) -> Self {
271 self.add_geom(GeomJitter::default())
272 }
273
274 pub fn geom_jitter_with(self, geom: GeomJitter) -> Self {
275 self.add_geom(geom)
276 }
277
278 pub fn geom_path(self) -> Self {
279 self.add_geom(GeomPath::default())
280 }
281
282 pub fn geom_path_with(self, geom: GeomPath) -> Self {
283 self.add_geom(geom)
284 }
285
286 pub fn stat_ellipse(self) -> Self {
288 self.geom_path()
289 .stat(crate::stat::ellipse::StatEllipse::default())
290 }
291
292 pub fn stat_ellipse_level(self, level: f64) -> Self {
294 self.geom_path()
295 .stat(crate::stat::ellipse::StatEllipse::new(level))
296 }
297
298 #[cfg(feature = "regression")]
301 pub fn stat_quantile(mut self, taus: &[f64]) -> Self {
302 for &tau in taus {
303 self = self
304 .geom_path()
305 .stat(crate::stat::quantile::StatQuantile::new(tau));
306 }
307 self
308 }
309
310 #[cfg(feature = "regression")]
312 pub fn geom_quantile(self) -> Self {
313 self.stat_quantile(&[0.25, 0.5, 0.75])
314 }
315
316 pub fn geom_step(self) -> Self {
317 self.add_geom(GeomStep::default())
318 }
319
320 pub fn geom_step_with(self, geom: GeomStep) -> Self {
321 self.add_geom(geom)
322 }
323
324 pub fn geom_freqpoly(self) -> Self {
325 self.add_geom(GeomFreqpoly::default())
326 }
327
328 pub fn geom_freqpoly_with(self, geom: GeomFreqpoly) -> Self {
329 self.add_geom(geom)
330 }
331
332 pub fn geom_linerange(self) -> Self {
333 self.add_geom(GeomLinerange::default())
334 }
335
336 pub fn geom_linerange_with(self, geom: GeomLinerange) -> Self {
337 self.add_geom(geom)
338 }
339
340 pub fn geom_pointrange(self) -> Self {
341 self.add_geom(GeomPointrange::default())
342 }
343
344 pub fn geom_pointrange_with(self, geom: GeomPointrange) -> Self {
345 self.add_geom(geom)
346 }
347
348 pub fn geom_crossbar(self) -> Self {
349 self.add_geom(GeomCrossbar::default())
350 }
351
352 pub fn geom_crossbar_with(self, geom: GeomCrossbar) -> Self {
353 self.add_geom(geom)
354 }
355
356 pub fn geom_spoke(self) -> Self {
357 self.add_geom(GeomSpoke::default())
358 }
359
360 pub fn geom_spoke_with(self, geom: GeomSpoke) -> Self {
361 self.add_geom(geom)
362 }
363
364 pub fn geom_rect(self) -> Self {
365 self.add_geom(GeomRect::default())
366 }
367
368 pub fn geom_rect_with(self, geom: GeomRect) -> Self {
369 self.add_geom(geom)
370 }
371
372 pub fn geom_tile(self) -> Self {
373 self.add_geom(GeomTile::default())
374 }
375
376 pub fn geom_tile_with(self, geom: GeomTile) -> Self {
377 self.add_geom(geom)
378 }
379
380 pub fn geom_raster(self) -> Self {
382 self.add_geom(crate::geom::raster::GeomRaster::default())
383 }
384
385 pub fn geom_raster_with(self, geom: crate::geom::raster::GeomRaster) -> Self {
386 self.add_geom(geom)
387 }
388
389 pub fn geom_polygon(self) -> Self {
390 self.add_geom(GeomPolygon::default())
391 }
392
393 pub fn geom_polygon_with(self, geom: GeomPolygon) -> Self {
394 self.add_geom(geom)
395 }
396
397 #[cfg(feature = "sf")]
399 pub fn geom_sf(self) -> Self {
400 self.add_geom(crate::geom::sf::GeomSf::default())
401 }
402
403 #[cfg(feature = "sf")]
404 pub fn geom_sf_with(self, geom: crate::geom::sf::GeomSf) -> Self {
405 self.add_geom(geom)
406 }
407
408 pub fn geom_curve(self) -> Self {
409 self.add_geom(GeomCurve::default())
410 }
411
412 pub fn geom_curve_with(self, geom: GeomCurve) -> Self {
413 self.add_geom(geom)
414 }
415
416 pub fn geom_violin(self) -> Self {
417 self.add_geom(GeomViolin::default())
418 }
419
420 pub fn geom_violin_with(self, geom: GeomViolin) -> Self {
421 self.add_geom(geom)
422 }
423
424 pub fn geom_dotplot(self) -> Self {
425 self.add_geom(GeomDotplot::default())
426 }
427
428 pub fn geom_dotplot_with(self, geom: GeomDotplot) -> Self {
429 self.add_geom(geom)
430 }
431
432 pub fn geom_qq(self) -> Self {
433 self.add_geom(GeomQQ::default())
434 }
435
436 pub fn geom_qq_with(self, geom: GeomQQ) -> Self {
437 self.add_geom(geom)
438 }
439
440 pub fn geom_qq_line(self) -> Self {
441 self.add_geom(GeomQQLine::default())
442 }
443
444 pub fn geom_qq_line_with(self, geom: GeomQQLine) -> Self {
445 self.add_geom(geom)
446 }
447
448 pub fn geom_bin2d(self) -> Self {
449 self.add_geom(GeomBin2d::default())
450 }
451
452 pub fn geom_bin2d_with(self, geom: GeomBin2d) -> Self {
453 self.add_geom(geom)
454 }
455
456 pub fn geom_hex(self) -> Self {
457 self.add_geom(GeomHex::default())
458 }
459
460 pub fn geom_hex_with(self, geom: GeomHex) -> Self {
461 self.add_geom(geom)
462 }
463
464 pub fn geom_count(self) -> Self {
465 self.add_geom(GeomCount::default())
466 }
467
468 pub fn geom_count_with(self, geom: GeomCount) -> Self {
469 self.add_geom(geom)
470 }
471
472 pub fn geom_contour(self) -> Self {
473 self.add_geom(GeomContour::default())
474 }
475
476 pub fn geom_contour_with(self, geom: GeomContour) -> Self {
477 self.add_geom(geom)
478 }
479
480 pub fn geom_contour_filled(self) -> Self {
483 self.add_geom(GeomPolygon {
484 line_width: 0.0,
485 alpha: 1.0,
486 ..GeomPolygon::default()
487 })
488 .stat(crate::stat::contour_filled::StatContourFilled::default())
489 }
490
491 pub fn geom_density2d(self) -> Self {
492 self.add_geom(GeomDensity2d::default())
493 }
494
495 pub fn geom_density2d_with(self, geom: GeomDensity2d) -> Self {
496 self.add_geom(geom)
497 }
498
499 pub fn geom_blank(self) -> Self {
500 self.add_geom(GeomBlank)
501 }
502
503 fn add_geom(mut self, geom: impl Geom + 'static) -> Self {
504 let stat = geom.default_stat();
505 let position = geom.default_position();
506 let params = geom.default_params();
507 self.layers.push(Layer {
508 data: None,
509 mapping: Aes::default(),
510 geom: Box::new(geom),
511 stat,
512 position,
513 params,
514 show_legend: None,
515 });
516 self
517 }
518
519 pub fn stat(mut self, stat: impl Stat + 'static) -> Self {
523 if let Some(layer) = self.layers.last_mut() {
524 layer.stat = Box::new(stat);
525 }
526 self
527 }
528
529 pub fn position(mut self, pos: impl Position + 'static) -> Self {
531 if let Some(layer) = self.layers.last_mut() {
532 layer.position = Box::new(pos);
533 }
534 self
535 }
536
537 pub fn layer_data(mut self, data: impl GGData) -> Self {
539 if let Some(layer) = self.layers.last_mut() {
540 layer.data = Some(data.into_dataframe());
541 }
542 self
543 }
544
545 pub fn layer_aes(mut self, mapping: Aes) -> Self {
547 if let Some(layer) = self.layers.last_mut() {
548 layer.mapping = mapping;
549 }
550 self
551 }
552
553 pub fn show_legend(mut self, show: bool) -> Self {
556 if let Some(layer) = self.layers.last_mut() {
557 layer.show_legend = Some(show);
558 }
559 self
560 }
561
562 pub fn scale_x_continuous(mut self, s: ScaleContinuous) -> Self {
565 let s = s.for_aesthetic(crate::aes::Aesthetic::X);
566 self.scales.push(Box::new(s));
567 self
568 }
569
570 pub fn scale_y_continuous(mut self, s: ScaleContinuous) -> Self {
571 let s = s.for_aesthetic(crate::aes::Aesthetic::Y);
572 self.scales.push(Box::new(s));
573 self
574 }
575
576 pub fn scale_x_discrete(mut self, s: crate::scale::discrete::ScaleDiscrete) -> Self {
577 let s = s.for_aesthetic(crate::aes::Aesthetic::X);
578 self.scales.push(Box::new(s));
579 self
580 }
581
582 pub fn scale_y_discrete(mut self, s: crate::scale::discrete::ScaleDiscrete) -> Self {
583 let s = s.for_aesthetic(crate::aes::Aesthetic::Y);
584 self.scales.push(Box::new(s));
585 self
586 }
587
588 pub fn scale_color(mut self, s: impl Scale + 'static) -> Self {
589 self.scales.push(Box::new(s));
590 self
591 }
592
593 pub fn scale_fill(mut self, s: impl Scale + 'static) -> Self {
594 self.scales.push(Box::new(s));
595 self
596 }
597
598 pub fn scale_color_manual(self, values: Vec<(&str, crate::scale::color::RGBAColor)>) -> Self {
599 let s = crate::scale::manual::ScaleManual::new(crate::aes::Aesthetic::Color, values);
600 self.scale_color(s)
601 }
602
603 pub fn scale_fill_manual(self, values: Vec<(&str, crate::scale::color::RGBAColor)>) -> Self {
604 let s = crate::scale::manual::ScaleManual::new(crate::aes::Aesthetic::Fill, values);
605 self.scale_fill(s)
606 }
607
608 pub fn scale_color_viridis(self) -> Self {
609 use crate::scale::color::ScaleColorDiscrete;
610 use crate::scale::palettes::PaletteName;
611 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Color)
612 .with_named_palette(&PaletteName::Viridis);
613 self.scale_color(s)
614 }
615
616 pub fn scale_color_brewer(self, name: crate::scale::palettes::PaletteName) -> Self {
617 use crate::scale::color::ScaleColorDiscrete;
618 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Color).with_named_palette(&name);
619 self.scale_color(s)
620 }
621
622 pub fn scale_color_gradient(
623 self,
624 low: crate::scale::color::RGBAColor,
625 high: crate::scale::color::RGBAColor,
626 ) -> Self {
627 use crate::scale::color::ScaleColorContinuous;
628 let s = ScaleColorContinuous::new(crate::aes::Aesthetic::Color).with_colors(low, high);
629 self.scale_color(s)
630 }
631
632 pub fn scale_fill_gradient(
633 self,
634 low: crate::scale::color::RGBAColor,
635 high: crate::scale::color::RGBAColor,
636 ) -> Self {
637 use crate::scale::color::ScaleColorContinuous;
638 let s = ScaleColorContinuous::new(crate::aes::Aesthetic::Fill).with_colors(low, high);
639 self.scale_fill(s)
640 }
641
642 pub fn scale_color_gradient2(
643 self,
644 low: crate::scale::color::RGBAColor,
645 mid: crate::scale::color::RGBAColor,
646 high: crate::scale::color::RGBAColor,
647 ) -> Self {
648 use crate::scale::gradient::ScaleColorGradient2;
649 let s = ScaleColorGradient2::new(crate::aes::Aesthetic::Color).with_colors(low, mid, high);
650 self.scale_color(s)
651 }
652
653 pub fn scale_fill_gradient2(
654 self,
655 low: crate::scale::color::RGBAColor,
656 mid: crate::scale::color::RGBAColor,
657 high: crate::scale::color::RGBAColor,
658 ) -> Self {
659 use crate::scale::gradient::ScaleColorGradient2;
660 let s = ScaleColorGradient2::new(crate::aes::Aesthetic::Fill).with_colors(low, mid, high);
661 self.scale_fill(s)
662 }
663
664 pub fn scale_fill_viridis(self) -> Self {
665 use crate::scale::color::ScaleColorDiscrete;
666 use crate::scale::palettes::PaletteName;
667 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill)
668 .with_named_palette(&PaletteName::Viridis);
669 self.scale_fill(s)
670 }
671
672 pub fn scale_color_viridis_c(self) -> Self {
674 use crate::scale::gradient_n::ScaleColorGradientN;
675 let s = ScaleColorGradientN::viridis(crate::aes::Aesthetic::Color);
676 self.scale_color(s)
677 }
678
679 pub fn scale_fill_viridis_c(self) -> Self {
681 use crate::scale::gradient_n::ScaleColorGradientN;
682 let s = ScaleColorGradientN::viridis(crate::aes::Aesthetic::Fill);
683 self.scale_fill(s)
684 }
685
686 pub fn scale_color_gradientn(self, stops: Vec<(f64, crate::scale::color::RGBAColor)>) -> Self {
688 use crate::scale::gradient_n::ScaleColorGradientN;
689 let s = ScaleColorGradientN::new(crate::aes::Aesthetic::Color, stops);
690 self.scale_color(s)
691 }
692
693 pub fn scale_fill_gradientn(self, stops: Vec<(f64, crate::scale::color::RGBAColor)>) -> Self {
695 use crate::scale::gradient_n::ScaleColorGradientN;
696 let s = ScaleColorGradientN::new(crate::aes::Aesthetic::Fill, stops);
697 self.scale_fill(s)
698 }
699
700 pub fn scale_color_steps(
703 self,
704 low: crate::scale::color::RGBAColor,
705 high: crate::scale::color::RGBAColor,
706 n_bins: usize,
707 ) -> Self {
708 let s = crate::scale::steps::ScaleColorSteps::two(
709 crate::aes::Aesthetic::Color,
710 (low.r, low.g, low.b),
711 (high.r, high.g, high.b),
712 n_bins,
713 );
714 self.scale_color(s)
715 }
716
717 pub fn scale_color_stepsn(
719 self,
720 stops: Vec<crate::scale::color::RGBAColor>,
721 n_bins: usize,
722 ) -> Self {
723 let s = crate::scale::steps::ScaleColorSteps::new(
724 crate::aes::Aesthetic::Color,
725 stops.iter().map(|c| (c.r, c.g, c.b)).collect(),
726 n_bins,
727 );
728 self.scale_color(s)
729 }
730
731 pub fn scale_color_fermenter(
733 self,
734 name: crate::scale::palettes::PaletteName,
735 n_bins: usize,
736 ) -> Self {
737 let stops = crate::scale::palettes::palette(&name)
738 .iter()
739 .map(|c| (c.r, c.g, c.b))
740 .collect();
741 let s =
742 crate::scale::steps::ScaleColorSteps::new(crate::aes::Aesthetic::Color, stops, n_bins);
743 self.scale_color(s)
744 }
745
746 pub fn scale_fill_steps(
748 self,
749 low: crate::scale::color::RGBAColor,
750 high: crate::scale::color::RGBAColor,
751 n_bins: usize,
752 ) -> Self {
753 let s = crate::scale::steps::ScaleColorSteps::two(
754 crate::aes::Aesthetic::Fill,
755 (low.r, low.g, low.b),
756 (high.r, high.g, high.b),
757 n_bins,
758 );
759 self.scale_fill(s)
760 }
761
762 pub fn scale_fill_fermenter(
764 self,
765 name: crate::scale::palettes::PaletteName,
766 n_bins: usize,
767 ) -> Self {
768 let stops = crate::scale::palettes::palette(&name)
769 .iter()
770 .map(|c| (c.r, c.g, c.b))
771 .collect();
772 let s =
773 crate::scale::steps::ScaleColorSteps::new(crate::aes::Aesthetic::Fill, stops, n_bins);
774 self.scale_fill(s)
775 }
776
777 pub fn scale_fill_brewer(self, name: crate::scale::palettes::PaletteName) -> Self {
778 use crate::scale::color::ScaleColorDiscrete;
779 let s = ScaleColorDiscrete::new(crate::aes::Aesthetic::Fill).with_named_palette(&name);
780 self.scale_fill(s)
781 }
782
783 pub fn scale_linetype_manual(
784 self,
785 values: Vec<(&str, crate::render::backend::Linetype)>,
786 ) -> Self {
787 let s = crate::scale::linetype_manual::ScaleLinetypeManual::new(values);
788 self.scale_color(s)
789 }
790
791 pub fn scale_shape_manual(
792 self,
793 values: Vec<(&str, crate::render::backend::PointShape)>,
794 ) -> Self {
795 let s = crate::scale::shape_manual::ScaleShapeManual::new(values);
796 self.scale_color(s)
797 }
798
799 pub fn scale_color_grey(self) -> Self {
800 let s = crate::scale::grey::ScaleColorGrey::new(crate::aes::Aesthetic::Color);
801 self.scale_color(s)
802 }
803
804 pub fn scale_fill_grey(self) -> Self {
805 let s = crate::scale::grey::ScaleColorGrey::new(crate::aes::Aesthetic::Fill);
806 self.scale_fill(s)
807 }
808
809 pub fn scale_color_grey_with(self, s: crate::scale::grey::ScaleColorGrey) -> Self {
810 self.scale_color(s)
811 }
812
813 pub fn scale_fill_grey_with(self, s: crate::scale::grey::ScaleColorGrey) -> Self {
814 self.scale_fill(s)
815 }
816
817 pub fn scale_x_reverse(self) -> Self {
818 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reverse))
819 }
820
821 pub fn scale_y_reverse(self) -> Self {
822 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reverse))
823 }
824
825 pub fn scale_x_datetime(mut self, s: crate::scale::datetime::ScaleDateTime) -> Self {
826 let s = s.for_aesthetic(crate::aes::Aesthetic::X);
827 self.scales.push(Box::new(s));
828 self
829 }
830
831 pub fn scale_y_datetime(mut self, s: crate::scale::datetime::ScaleDateTime) -> Self {
832 let s = s.for_aesthetic(crate::aes::Aesthetic::Y);
833 self.scales.push(Box::new(s));
834 self
835 }
836
837 pub fn scale_size(mut self, s: crate::scale::size::ScaleSizeContinuous) -> Self {
838 self.scales.push(Box::new(s));
839 self
840 }
841
842 pub fn scale_alpha(mut self, s: crate::scale::alpha::ScaleAlphaContinuous) -> Self {
843 self.scales.push(Box::new(s));
844 self
845 }
846
847 pub fn xlim(self, min: f64, max: f64) -> Self {
848 self.scale_x_continuous(ScaleContinuous::new().with_limits(min, max))
849 }
850
851 pub fn ylim(self, min: f64, max: f64) -> Self {
852 self.scale_y_continuous(ScaleContinuous::new().with_limits(min, max))
853 }
854
855 pub fn scale_x_log10(self) -> Self {
856 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log10))
857 }
858
859 pub fn scale_y_log10(self) -> Self {
860 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log10))
861 }
862
863 pub fn scale_x_sqrt(self) -> Self {
864 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Sqrt))
865 }
866
867 pub fn scale_y_sqrt(self) -> Self {
868 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Sqrt))
869 }
870
871 pub fn scale_x_log2(self) -> Self {
872 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log2))
873 }
874
875 pub fn scale_y_log2(self) -> Self {
876 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Log2))
877 }
878
879 pub fn scale_x_ln(self) -> Self {
880 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Ln))
881 }
882
883 pub fn scale_y_ln(self) -> Self {
884 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Ln))
885 }
886
887 pub fn scale_x_logit(self) -> Self {
889 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Logit))
890 }
891
892 pub fn scale_y_logit(self) -> Self {
893 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Logit))
894 }
895
896 pub fn scale_x_probit(self) -> Self {
898 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Probit))
899 }
900
901 pub fn scale_y_probit(self) -> Self {
902 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Probit))
903 }
904
905 pub fn scale_x_pseudo_log(self) -> Self {
907 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::PseudoLog))
908 }
909
910 pub fn scale_y_pseudo_log(self) -> Self {
911 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::PseudoLog))
912 }
913
914 pub fn scale_x_reciprocal(self) -> Self {
916 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reciprocal))
917 }
918
919 pub fn scale_y_reciprocal(self) -> Self {
920 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Reciprocal))
921 }
922
923 pub fn scale_x_exp(self) -> Self {
925 self.scale_x_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Exp))
926 }
927
928 pub fn scale_y_exp(self) -> Self {
929 self.scale_y_continuous(ScaleContinuous::new().with_transform(ScaleTransform::Exp))
930 }
931
932 pub fn scale_x_boxcox(self, lambda: f64) -> Self {
934 self.scale_x_continuous(
935 ScaleContinuous::new().with_transform(ScaleTransform::BoxCox(lambda)),
936 )
937 }
938
939 pub fn scale_y_boxcox(self, lambda: f64) -> Self {
940 self.scale_y_continuous(
941 ScaleContinuous::new().with_transform(ScaleTransform::BoxCox(lambda)),
942 )
943 }
944
945 pub fn facet_wrap(mut self, var: &str, ncol: Option<usize>) -> Self {
948 self.facet = Facet::Wrap {
949 var: var.to_string(),
950 ncol,
951 scales: FacetScales::Fixed,
952 labeller: FacetLabeller::default(),
953 };
954 self
955 }
956
957 pub fn facet_wrap_free(mut self, var: &str, ncol: Option<usize>, scales: FacetScales) -> Self {
958 self.facet = Facet::Wrap {
959 var: var.to_string(),
960 ncol,
961 scales,
962 labeller: FacetLabeller::default(),
963 };
964 self
965 }
966
967 pub fn facet_wrap_labeller(
968 mut self,
969 var: &str,
970 ncol: Option<usize>,
971 labeller: FacetLabeller,
972 ) -> Self {
973 self.facet = Facet::Wrap {
974 var: var.to_string(),
975 ncol,
976 scales: FacetScales::Fixed,
977 labeller,
978 };
979 self
980 }
981
982 pub fn facet_grid(mut self, row: Option<&str>, col: Option<&str>) -> Self {
983 self.facet = Facet::Grid {
984 row_var: row.map(String::from),
985 col_var: col.map(String::from),
986 scales: FacetScales::Fixed,
987 labeller: FacetLabeller::default(),
988 space: FacetSpace::Fixed,
989 };
990 self
991 }
992
993 pub fn facet_grid_free(
994 mut self,
995 row: Option<&str>,
996 col: Option<&str>,
997 scales: FacetScales,
998 ) -> Self {
999 self.facet = Facet::Grid {
1000 row_var: row.map(String::from),
1001 col_var: col.map(String::from),
1002 scales,
1003 labeller: FacetLabeller::default(),
1004 space: FacetSpace::Fixed,
1005 };
1006 self
1007 }
1008
1009 pub fn facet_grid_multi(
1013 mut self,
1014 row: Option<&str>,
1015 cols: &[&str],
1016 scales: FacetScales,
1017 space: FacetSpace,
1018 ) -> Self {
1019 let col_var = if cols.len() > 1 {
1020 let n = self.data.nrows();
1022 let mut combined = Vec::with_capacity(n);
1023 for i in 0..n {
1024 let parts: Vec<String> = cols
1025 .iter()
1026 .map(|c| {
1027 self.data
1028 .column(c)
1029 .and_then(|col| col.get(i))
1030 .map(|v| v.to_group_key())
1031 .unwrap_or_default()
1032 })
1033 .collect();
1034 combined.push(crate::data::Value::Str(parts.join(" . ")));
1035 }
1036 let name = "__facet_cols__".to_string();
1037 self.data.add_column(name.clone(), combined);
1038 Some(name)
1039 } else {
1040 cols.first().map(|s| s.to_string())
1041 };
1042 self.facet = Facet::Grid {
1043 row_var: row.map(String::from),
1044 col_var,
1045 scales,
1046 labeller: FacetLabeller::default(),
1047 space,
1048 };
1049 self
1050 }
1051
1052 pub fn facet_grid_space(
1055 mut self,
1056 row: Option<&str>,
1057 col: Option<&str>,
1058 scales: FacetScales,
1059 space: FacetSpace,
1060 ) -> Self {
1061 self.facet = Facet::Grid {
1062 row_var: row.map(String::from),
1063 col_var: col.map(String::from),
1064 scales,
1065 labeller: FacetLabeller::default(),
1066 space,
1067 };
1068 self
1069 }
1070
1071 pub fn facet_grid_labeller(
1072 mut self,
1073 row: Option<&str>,
1074 col: Option<&str>,
1075 labeller: FacetLabeller,
1076 ) -> Self {
1077 self.facet = Facet::Grid {
1078 row_var: row.map(String::from),
1079 col_var: col.map(String::from),
1080 scales: FacetScales::Fixed,
1081 labeller,
1082 space: FacetSpace::Fixed,
1083 };
1084 self
1085 }
1086
1087 pub fn coord_flip(mut self) -> Self {
1090 self.coord = Box::new(CoordFlip);
1091 self
1092 }
1093
1094 pub fn coord_fixed(mut self, ratio: f64) -> Self {
1095 self.coord = Box::new(CoordFixed::new(ratio));
1096 self
1097 }
1098
1099 #[cfg(feature = "sf")]
1103 pub fn coord_sf(mut self) -> Self {
1104 self.coord = Box::new(crate::coord::sf::CoordSf::new());
1105 self
1106 }
1107
1108 pub fn coord_trans(mut self, x: Option<ScaleTransform>, y: Option<ScaleTransform>) -> Self {
1113 self.coord = Box::new(crate::coord::trans::CoordTrans::new(x, y));
1114 self
1115 }
1116
1117 pub fn coord_trans_y(self, y: ScaleTransform) -> Self {
1119 self.coord_trans(None, Some(y))
1120 }
1121
1122 pub fn coord_trans_x(self, x: ScaleTransform) -> Self {
1124 self.coord_trans(Some(x), None)
1125 }
1126
1127 pub fn coord_cartesian_zoom(
1129 mut self,
1130 xlim: Option<(f64, f64)>,
1131 ylim: Option<(f64, f64)>,
1132 ) -> Self {
1133 let mut c = CoordCartesian::new();
1134 if let Some((min, max)) = xlim {
1135 c = c.xlim(min, max);
1136 }
1137 if let Some((min, max)) = ylim {
1138 c = c.ylim(min, max);
1139 }
1140 self.coord = Box::new(c);
1141 self
1142 }
1143
1144 pub fn coord_polar(mut self) -> Self {
1145 self.coord = Box::new(CoordPolar::new());
1146 self
1147 }
1148
1149 pub fn coord_polar_with(mut self, coord: CoordPolar) -> Self {
1150 self.coord = Box::new(coord);
1151 self
1152 }
1153
1154 pub fn theme(mut self, theme: Theme) -> Self {
1157 self.theme = theme;
1158 self
1159 }
1160
1161 pub fn axis_text_x_angle(mut self, degrees: f64) -> Self {
1165 self.theme.axis_text_x.angle = degrees;
1166 self
1167 }
1168
1169 pub fn axis_text_y_angle(mut self, degrees: f64) -> Self {
1171 self.theme.axis_text_y.angle = degrees;
1172 self
1173 }
1174
1175 pub fn axis_text_x_dodge(mut self, n: usize) -> Self {
1178 self.theme.axis_text_x_dodge = n.max(1);
1179 self
1180 }
1181
1182 pub fn aspect_ratio(mut self, ratio: f64) -> Self {
1185 self.theme.aspect_ratio = Some(ratio);
1186 self
1187 }
1188
1189 pub fn panel_ontop(mut self) -> Self {
1191 self.theme.panel_ontop = true;
1192 self
1193 }
1194
1195 pub fn axis_minor_ticks(mut self) -> Self {
1197 self.theme.axis_minor_ticks = true;
1198 self
1199 }
1200
1201 pub fn title_position(mut self, pos: crate::theme::TitlePosition) -> Self {
1204 self.theme.title_position = pos;
1205 self
1206 }
1207
1208 pub fn tag_position(mut self, pos: crate::theme::TagPosition) -> Self {
1210 self.theme.tag_position = pos;
1211 self
1212 }
1213
1214 pub fn legend_direction(mut self, dir: crate::theme::LegendDirection) -> Self {
1216 self.theme.legend_direction = Some(dir);
1217 self
1218 }
1219
1220 pub fn legend_position_inside(mut self, x: f64, y: f64) -> Self {
1227 self.theme.legend_position = crate::theme::LegendPosition::Inside(x, y);
1228 self
1229 }
1230
1231 pub fn primary_color(mut self, color: (u8, u8, u8)) -> Self {
1232 self.theme.primary = Some(color);
1233 self
1234 }
1235
1236 pub fn theme_minimal(mut self) -> Self {
1237 self.theme = crate::theme::presets::theme_minimal();
1238 self
1239 }
1240
1241 pub fn theme_bw(mut self) -> Self {
1242 self.theme = crate::theme::presets::theme_bw();
1243 self
1244 }
1245
1246 pub fn theme_gray(mut self) -> Self {
1247 self.theme = crate::theme::presets::theme_gray();
1248 self
1249 }
1250
1251 pub fn theme_classic(mut self) -> Self {
1252 self.theme = crate::theme::presets::theme_classic();
1253 self
1254 }
1255
1256 pub fn theme_linedraw(mut self) -> Self {
1257 self.theme = crate::theme::presets::theme_linedraw();
1258 self
1259 }
1260
1261 pub fn theme_light(mut self) -> Self {
1262 self.theme = crate::theme::presets::theme_light();
1263 self
1264 }
1265
1266 pub fn theme_dark(mut self) -> Self {
1267 self.theme = crate::theme::presets::theme_dark();
1268 self
1269 }
1270
1271 pub fn theme_void(mut self) -> Self {
1272 self.theme = crate::theme::presets::theme_void();
1273 self
1274 }
1275
1276 pub fn theme_update(mut self, update: crate::theme::ThemeUpdate) -> Self {
1279 self.theme = self.theme.update(update);
1280 self
1281 }
1282
1283 pub fn guides(mut self, guide: crate::guide::config::GuideLegend) -> Self {
1287 self.guide_legend = guide;
1288 self
1289 }
1290
1291 pub fn labs(mut self, labels: Labels) -> Self {
1294 if labels.title.is_some() {
1295 self.labels.title = labels.title;
1296 }
1297 if labels.subtitle.is_some() {
1298 self.labels.subtitle = labels.subtitle;
1299 }
1300 if labels.x.is_some() {
1301 self.labels.x = labels.x;
1302 }
1303 if labels.y.is_some() {
1304 self.labels.y = labels.y;
1305 }
1306 if labels.caption.is_some() {
1307 self.labels.caption = labels.caption;
1308 }
1309 if labels.tag.is_some() {
1310 self.labels.tag = labels.tag;
1311 }
1312 self
1313 }
1314
1315 pub fn title(mut self, title: &str) -> Self {
1316 self.labels.title = Some(title.to_string());
1317 self
1318 }
1319
1320 pub fn tag(mut self, tag: &str) -> Self {
1323 self.labels.tag = Some(tag.to_string());
1324 self
1325 }
1326
1327 pub fn subtitle(mut self, subtitle: &str) -> Self {
1328 self.labels.subtitle = Some(subtitle.to_string());
1329 self
1330 }
1331
1332 pub fn xlab(mut self, label: &str) -> Self {
1333 self.labels.x = Some(label.to_string());
1334 self
1335 }
1336
1337 pub fn ylab(mut self, label: &str) -> Self {
1338 self.labels.y = Some(label.to_string());
1339 self
1340 }
1341
1342 pub fn caption(mut self, caption: &str) -> Self {
1343 self.labels.caption = Some(caption.to_string());
1344 self
1345 }
1346
1347 pub fn annotate(mut self, annotation: Annotation) -> Self {
1351 self.annotations.push(annotation);
1352 self
1353 }
1354
1355 pub fn annotate_text(self, label: &str, x: f64, y: f64) -> Self {
1357 self.annotate(Annotation::text(label, x, y))
1358 }
1359
1360 pub fn annotate_rect(self, xmin: f64, xmax: f64, ymin: f64, ymax: f64) -> Self {
1362 self.annotate(Annotation::rect(xmin, xmax, ymin, ymax))
1363 }
1364
1365 pub fn annotate_segment(self, x: f64, y: f64, xend: f64, yend: f64) -> Self {
1367 self.annotate(Annotation::segment(x, y, xend, yend))
1368 }
1369
1370 pub fn try_build(self) -> Result<crate::build::BuiltPlot, GGError> {
1374 PlotBuilder::build(self)
1375 }
1376
1377 pub fn build(self) -> crate::build::BuiltPlot {
1381 self.try_build().expect("plot build failed")
1382 }
1383
1384 pub fn save(self, path: &str) -> Result<(), GGError> {
1386 self.save_with_size(path, 800, 600)
1387 }
1388
1389 pub fn save_with_size(self, path: &str, w: u32, h: u32) -> Result<(), GGError> {
1391 let (built, layout) = self.prepare(w, h)?;
1392
1393 let ext = path.rsplit('.').next().unwrap_or("svg").to_lowercase();
1395
1396 match ext.as_str() {
1397 "svg" => {
1398 let backend = plotters::prelude::SVGBackend::new(path, (w, h));
1399 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
1400 }
1401 "png" | "bmp" | "gif" | "jpeg" | "jpg" | "tiff" => {
1402 let backend = plotters::prelude::BitMapBackend::new(path, (w, h));
1403 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
1404 }
1405 _ => {
1406 return Err(GGError::UnsupportedFormat(ext));
1407 }
1408 }
1409
1410 Ok(())
1411 }
1412
1413 pub fn render_svg(self) -> Result<String, GGError> {
1418 self.render_svg_with_size(800, 600)
1419 }
1420
1421 pub fn render_svg_with_size(self, w: u32, h: u32) -> Result<String, GGError> {
1423 let (built, layout) = self.prepare(w, h)?;
1424 let mut buf = String::new();
1425 {
1426 let backend = plotters::prelude::SVGBackend::with_string(&mut buf, (w, h));
1427 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
1428 }
1429 Ok(buf)
1430 }
1431
1432 pub fn render_svg_native(self) -> Result<String, GGError> {
1436 self.render_svg_native_with_size(800, 600)
1437 }
1438
1439 pub fn render_svg_native_with_size(self, w: u32, h: u32) -> Result<String, GGError> {
1441 let (built, layout) = self.prepare(w, h)?;
1442 let mut backend =
1443 crate::render::svg_backend::SvgBackend::new(w, h, layout.plot_area.clone());
1444 PlotRenderer::render(&built, &mut backend).map_err(GGError::Render)?;
1445 Ok(backend.finish())
1446 }
1447
1448 pub fn render_png(self) -> Result<Vec<u8>, GGError> {
1453 self.render_png_with_size(800, 600)
1454 }
1455
1456 pub fn render_png_with_size(self, w: u32, h: u32) -> Result<Vec<u8>, GGError> {
1458 let (built, layout) = self.prepare(w, h)?;
1459
1460 let mut rgb = vec![0u8; (w as usize) * (h as usize) * 3];
1463 {
1464 let backend = plotters::prelude::BitMapBackend::with_buffer(&mut rgb, (w, h));
1465 Self::render_into(backend.into_drawing_area(), &built, &layout)?;
1466 }
1467
1468 let img = image::RgbImage::from_raw(w, h, rgb).ok_or_else(|| {
1469 GGError::Render(RenderError::BackendError(
1470 "PNG buffer size mismatch".to_string(),
1471 ))
1472 })?;
1473 let mut out = std::io::Cursor::new(Vec::new());
1474 img.write_to(&mut out, image::ImageOutputFormat::Png)
1475 .map_err(|e| GGError::Render(RenderError::BackendError(format!("{:?}", e))))?;
1476 Ok(out.into_inner())
1477 }
1478
1479 fn prepare(self, w: u32, h: u32) -> Result<(crate::build::BuiltPlot, PlotLayout), GGError> {
1481 let plot = self;
1482
1483 let has_title = plot.labels.title.is_some();
1484 let has_subtitle = plot.labels.subtitle.is_some();
1485 let has_caption = plot.labels.caption.is_some();
1486 let has_legend = plot.has_legend_mapping();
1487 let x_label = plot.labels.x.clone();
1488 let y_label = plot.labels.y.clone();
1489
1490 let mut built = PlotBuilder::build(plot)?;
1491
1492 built.theme.resolve_inheritance();
1494
1495 if let Some(ref label) = x_label {
1497 if let Some(s) = built.scales.get_mut(&crate::aes::Aesthetic::X) {
1498 s.set_name(label);
1499 }
1500 }
1501 if let Some(ref label) = y_label {
1502 if let Some(s) = built.scales.get_mut(&crate::aes::Aesthetic::Y) {
1503 s.set_name(label);
1504 }
1505 }
1506
1507 let x_axis_top = built
1508 .scales
1509 .get(&crate::aes::Aesthetic::X)
1510 .map(|s| s.axis_position_opposite())
1511 .unwrap_or(false);
1512
1513 let layout = PlotLayout::compute_full(
1514 w as f64,
1515 h as f64,
1516 &built.theme,
1517 has_title,
1518 has_subtitle,
1519 has_caption,
1520 has_legend,
1521 x_axis_top,
1522 );
1523
1524 Ok((built, layout))
1525 }
1526
1527 fn render_into<DB>(
1529 area: plotters::drawing::DrawingArea<DB, plotters::coord::Shift>,
1530 built: &crate::build::BuiltPlot,
1531 layout: &PlotLayout,
1532 ) -> Result<(), GGError>
1533 where
1534 DB: plotters::prelude::DrawingBackend,
1535 DB::ErrorType: 'static,
1536 {
1537 area.fill(&plotters::prelude::WHITE)
1538 .map_err(|e| GGError::Render(RenderError::BackendError(format!("{:?}", e))))?;
1539 let mut adapter = PlottersAdapter::new(&area, layout.plot_area.clone());
1540 PlotRenderer::render(built, &mut adapter).map_err(GGError::Render)?;
1541 area.present()
1542 .map_err(|e| GGError::Render(RenderError::BackendError(format!("{:?}", e))))?;
1543 Ok(())
1544 }
1545
1546 pub fn ggsave(
1548 self,
1549 path: &str,
1550 width_inches: f64,
1551 height_inches: f64,
1552 dpi: f64,
1553 ) -> Result<(), GGError> {
1554 let w = (width_inches * dpi) as u32;
1555 let h = (height_inches * dpi) as u32;
1556 self.save_with_size(path, w, h)
1557 }
1558
1559 fn has_legend_mapping(&self) -> bool {
1560 self.mapping.mappings.iter().any(|m| {
1561 matches!(
1562 m.aesthetic,
1563 crate::aes::Aesthetic::Color
1564 | crate::aes::Aesthetic::Fill
1565 | crate::aes::Aesthetic::Shape
1566 | crate::aes::Aesthetic::Linetype
1567 | crate::aes::Aesthetic::Size
1568 | crate::aes::Aesthetic::Alpha
1569 )
1570 })
1571 }
1572}
1573
1574#[derive(Debug)]
1576pub enum GGError {
1577 Render(RenderError),
1578 UnsupportedFormat(String),
1579 Io(std::io::Error),
1580 ValidationError(String),
1581}
1582
1583impl std::fmt::Display for GGError {
1584 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1585 match self {
1586 GGError::Render(e) => write!(f, "Render error: {e}"),
1587 GGError::UnsupportedFormat(ext) => write!(f, "Unsupported output format: {ext}"),
1588 GGError::Io(e) => write!(f, "IO error: {e}"),
1589 GGError::ValidationError(msg) => write!(f, "Validation error: {msg}"),
1590 }
1591 }
1592}
1593
1594impl std::error::Error for GGError {}