@@ -498,6 +498,285 @@ S7::method(mark_rule, plotit_class) <- function(
498498 )
499499}
500500
501+ # ---- mark_path ----
502+ # ' Path layer
503+ # '
504+ # ' Adds a path layer connecting observations in their original order.
505+ # ' Use for trajectories, time-ordered connected points, or custom
506+ # ' drawing orders.
507+ # '
508+ # ' @param plot A plotit object
509+ # ' @param mapping Optional new aesthetics
510+ # ' @param data Optional data for this layer
511+ # ' @param position Position adjustment.
512+ # ' @param rasterize If `TRUE`, rasterize via `ggrastr::rasterise()`.
513+ # ' @param rasterize_dpi DPI for rasterization (default 300).
514+ # ' @param rasterize_dev Graphics device for rasterization (default `"cairo"`).
515+ # ' @param ... Other arguments passed to `geom_path`
516+ # ' @return Modified plotit object
517+ # ' @references
518+ # ' AntV G2: \href{https://g2.antv.antgroup.com/en/api/mark/path}{Path}
519+ # ' @examples
520+ # ' df <- data.frame(x = 1:10, y = cumsum(runif(10, -1, 1)))
521+ # ' plotit(df, encode(x = x, y = y)) |> mark_path()
522+ # ' @export
523+ mark_path <- S7 :: new_generic(
524+ " mark_path" , " plot" ,
525+ function (plot , mapping = NULL , data = NULL , position = NULL , ... ,
526+ rasterize = FALSE , rasterize_dpi = 300 , rasterize_dev = " cairo" ) {
527+ S7 :: S7_dispatch()
528+ }
529+ )
530+ ._register_mark_method(mark_path , ggplot2 :: geom_path )
531+
532+ # ---- mark_polygon ----
533+ # ' Polygon layer
534+ # '
535+ # ' Adds a filled polygon layer. Each group forms one polygon;
536+ # ' subgroups are separated by `NA` rows or the `group` aesthetic.
537+ # '
538+ # ' @param plot A plotit object
539+ # ' @param mapping Optional new aesthetics
540+ # ' @param data Optional data for this layer
541+ # ' @param position Position adjustment.
542+ # ' @param rasterize If `TRUE`, rasterize via `ggrastr::rasterise()`.
543+ # ' @param rasterize_dpi DPI for rasterization (default 300).
544+ # ' @param rasterize_dev Graphics device for rasterization (default `"cairo"`).
545+ # ' @param ... Other arguments passed to `geom_polygon`
546+ # ' @return Modified plotit object
547+ # ' @references
548+ # ' AntV G2: \href{https://g2.antv.antgroup.com/en/api/mark/polygon}{Polygon}
549+ # ' @examples
550+ # ' tri <- data.frame(x = c(0, 1, 0.5), y = c(0, 0, 1))
551+ # ' plotit(tri, encode(x = x, y = y)) |> mark_polygon(fill = "skyblue")
552+ # ' @export
553+ mark_polygon <- S7 :: new_generic(
554+ " mark_polygon" , " plot" ,
555+ function (plot , mapping = NULL , data = NULL , position = NULL , ... ,
556+ rasterize = FALSE , rasterize_dpi = 300 , rasterize_dev = " cairo" ) {
557+ S7 :: S7_dispatch()
558+ }
559+ )
560+ ._register_mark_method(mark_polygon , ggplot2 :: geom_polygon )
561+
562+ # ---- mark_smooth ----
563+ # ' Smoothed conditional mean layer
564+ # '
565+ # ' Adds a smoothed conditional mean line with a confidence band.
566+ # ' Aids the eye in seeing patterns in the presence of overplotting.
567+ # '
568+ # ' @param plot A plotit object
569+ # ' @param mapping Optional new aesthetics
570+ # ' @param data Optional data for this layer
571+ # ' @param position Position adjustment.
572+ # ' @param method Smoothing method: `"auto"` (loess for n<1000, gam otherwise),
573+ # ' `"lm"`, `"glm"`, `"gam"`, or `"loess"`.
574+ # ' @param formula Formula to use in the smoothing function.
575+ # ' @param se If `TRUE` (default), display confidence interval around smooth.
576+ # ' @param rasterize If `TRUE`, rasterize via `ggrastr::rasterise()`.
577+ # ' @param rasterize_dpi DPI for rasterization (default 300).
578+ # ' @param rasterize_dev Graphics device for rasterization (default `"cairo"`).
579+ # ' @param ... Other arguments passed to `geom_smooth`
580+ # ' @return Modified plotit object
581+ # ' @references
582+ # ' Vega-Lite: achieved via \code{layer(point) + layer(line) + transform(regression)}
583+ # '
584+ # ' AntV G2: achieved via transform pipeline
585+ # ' @examples
586+ # ' plotit(mtcars, encode(x = wt, y = mpg)) |> mark_smooth()
587+ # ' @export
588+ mark_smooth <- S7 :: new_generic(
589+ " mark_smooth" , " plot" ,
590+ function (plot , mapping = NULL , data = NULL , position = NULL , ... ,
591+ method = NULL , formula = NULL , se = NULL ,
592+ rasterize = FALSE , rasterize_dpi = 300 , rasterize_dev = " cairo" ) {
593+ S7 :: S7_dispatch()
594+ }
595+ )
596+
597+ # ' @export
598+ S7 :: method(mark_smooth , plotit_class ) <- function (
599+ plot , mapping = NULL , data = NULL , position = NULL , ... ,
600+ method = NULL , formula = NULL , se = NULL ,
601+ rasterize = FALSE , rasterize_dpi = 300 , rasterize_dev = " cairo" ) {
602+ params <- rlang :: list2(... )
603+ params $ method <- method
604+ params $ formula <- formula
605+ params $ se <- se
606+ do.call(function (... ) {
607+ ._mark_impl(plot , mapping , data , position , ggplot2 :: geom_smooth ,
608+ rasterize , rasterize_dpi , rasterize_dev , ... )
609+ }, params )
610+ }
611+
612+ # ---- mark_hex ----
613+ # ' Hexagonal heatmap layer
614+ # '
615+ # ' Divides the x-y plane into hexagonal bins and fills each by the
616+ # ' count (or other aggregation) of observations in that bin.
617+ # ' Ideal for visualizing overplotting in large datasets.
618+ # '
619+ # ' @param plot A plotit object
620+ # ' @param mapping Optional new aesthetics
621+ # ' @param data Optional data for this layer
622+ # ' @param position Position adjustment.
623+ # ' @param bins Number of bins along both axes (default 30).
624+ # ' @param rasterize If `TRUE`, rasterize via `ggrastr::rasterise()`.
625+ # ' @param rasterize_dpi DPI for rasterization (default 300).
626+ # ' @param rasterize_dev Graphics device for rasterization (default `"cairo"`).
627+ # ' @param ... Other arguments passed to `geom_hex`
628+ # ' @return Modified plotit object
629+ # ' @references
630+ # ' AntV G2: \href{https://g2.antv.antgroup.com/en/api/mark/heatmap}{Heatmap} (corelib)
631+ # ' @examples
632+ # ' plotit(diamonds[sample(nrow(diamonds), 1000), ],
633+ # ' encode(x = carat, y = price)) |> mark_hex(bins = 20)
634+ # ' @export
635+ mark_hex <- S7 :: new_generic(
636+ " mark_hex" , " plot" ,
637+ function (plot , mapping = NULL , data = NULL , position = NULL , ... ,
638+ bins = NULL ,
639+ rasterize = FALSE , rasterize_dpi = 300 , rasterize_dev = " cairo" ) {
640+ S7 :: S7_dispatch()
641+ }
642+ )
643+
644+ # ' @export
645+ S7 :: method(mark_hex , plotit_class ) <- function (
646+ plot , mapping = NULL , data = NULL , position = NULL , ... ,
647+ bins = NULL ,
648+ rasterize = FALSE , rasterize_dpi = 300 , rasterize_dev = " cairo" ) {
649+ params <- rlang :: list2(... )
650+ params $ bins <- bins
651+ do.call(function (... ) {
652+ ._mark_impl(plot , mapping , data , position , ggplot2 :: geom_hex ,
653+ rasterize , rasterize_dpi , rasterize_dev , ... )
654+ }, params )
655+ }
656+
657+ # ---- mark_density_2d ----
658+ # ' 2D density contour layer
659+ # '
660+ # ' Adds 2D kernel density estimate contours. Use `filled = TRUE`
661+ # ' for filled density bands via [ggplot2::geom_density_2d_filled].
662+ # '
663+ # ' @param plot A plotit object
664+ # ' @param mapping Optional new aesthetics
665+ # ' @param data Optional data for this layer
666+ # ' @param position Position adjustment.
667+ # ' @param filled If `TRUE`, use filled density contours.
668+ # ' @param bins Number of contour bins (for filled mode).
669+ # ' @param rasterize If `TRUE`, rasterize via `ggrastr::rasterise()`.
670+ # ' @param rasterize_dpi DPI for rasterization (default 300).
671+ # ' @param rasterize_dev Graphics device for rasterization (default `"cairo"`).
672+ # ' @param ... Other arguments passed to the underlying geom
673+ # ' @return Modified plotit object
674+ # ' @references
675+ # ' AntV G2: \href{https://g2.antv.antgroup.com/en/api/mark/density}{Density} (corelib, contour mode)
676+ # ' @examples
677+ # ' plotit(iris, encode(x = Sepal.Width, y = Sepal.Length)) |>
678+ # ' mark_density_2d()
679+ # ' @export
680+ mark_density_2d <- S7 :: new_generic(
681+ " mark_density_2d" , " plot" ,
682+ function (plot , mapping = NULL , data = NULL , position = NULL , ... ,
683+ filled = FALSE , bins = NULL ,
684+ rasterize = FALSE , rasterize_dpi = 300 , rasterize_dev = " cairo" ) {
685+ S7 :: S7_dispatch()
686+ }
687+ )
688+
689+ # ' @export
690+ S7 :: method(mark_density_2d , plotit_class ) <- function (
691+ plot , mapping = NULL , data = NULL , position = NULL , ... ,
692+ filled = FALSE , bins = NULL ,
693+ rasterize = FALSE , rasterize_dpi = 300 , rasterize_dev = " cairo" ) {
694+ geom_fun <- if (filled ) ggplot2 :: geom_density_2d_filled else ggplot2 :: geom_density_2d
695+ dots <- rlang :: list2(... )
696+ if (! is.null(bins )) dots $ bins <- bins
697+ # Only clear default_color when the layer provides colour/fill
698+ if (! is.null(mapping ) && (! is.null(mapping $ colour ) || ! is.null(mapping $ fill ))) {
699+ plot <- ._clear_default_color(plot , mapping )
700+ }
701+ pos <- position
702+ if (is.null(pos ) && ! is.null(plot @ meta @ dodge ) && plot @ meta @ dodge > 0 ) {
703+ pos <- ggplot2 :: position_dodge(plot @ meta @ dodge )
704+ }
705+ geom <- if (is.null(pos )) {
706+ do.call(geom_fun , c(list (mapping = mapping , data = data ), dots ))
707+ } else {
708+ do.call(geom_fun , c(list (mapping = mapping , data = data , position = pos ), dots ))
709+ }
710+ .add_geom(plot , geom ,
711+ rasterize = rasterize , rasterize_dpi = rasterize_dpi ,
712+ rasterize_dev = rasterize_dev
713+ )
714+ }
715+
716+ # ---- mark_corr ----
717+ # ' Correlation matrix heatmap
718+ # '
719+ # ' Computes a correlation matrix from numeric data columns, optionally
720+ # ' reorders by hierarchical clustering, and renders it as a tile heatmap.
721+ # '
722+ # ' @param plot A plotit object. Numeric columns are extracted from the
723+ # ' plot data for correlation computation.
724+ # ' @param method Correlation method: `"pearson"` (default), `"spearman"`,
725+ # ' or `"kendall"`.
726+ # ' @param reorder If `TRUE` (default), reorder rows and columns by
727+ # ' hierarchical clustering.
728+ # ' @param rasterize If `TRUE`, rasterize via `ggrastr::rasterise()`.
729+ # ' @param rasterize_dpi DPI for rasterization (default 300).
730+ # ' @param rasterize_dev Graphics device for rasterization (default `"cairo"`).
731+ # ' @param ... Other arguments passed to `geom_tile`
732+ # ' @return Modified plotit object
733+ # ' @references
734+ # ' AntV G2: \href{https://g2.antv.antgroup.com/en/api/mark/cell}{Cell} (correlation matrix expression)
735+ # ' @examples
736+ # ' plotit(mtcars, encode()) |> mark_corr()
737+ # ' @export
738+ mark_corr <- S7 :: new_generic(
739+ " mark_corr" , " plot" ,
740+ function (plot , method = c(" pearson" , " spearman" , " kendall" ),
741+ reorder = TRUE , ... ,
742+ rasterize = FALSE , rasterize_dpi = 300 , rasterize_dev = " cairo" ) {
743+ S7 :: S7_dispatch()
744+ }
745+ )
746+
747+ # ' @export
748+ S7 :: method(mark_corr , plotit_class ) <- function (
749+ plot , method = c(" pearson" , " spearman" , " kendall" ),
750+ reorder = TRUE , ... ,
751+ rasterize = FALSE , rasterize_dpi = 300 , rasterize_dev = " cairo" ) {
752+ method <- match.arg(method )
753+ # Extract numeric columns from plot data
754+ raw_data <- plot @ gg $ data
755+ num_cols <- vapply(raw_data , is.numeric , logical (1 ))
756+ if (sum(num_cols ) < 2 ) {
757+ cli :: cli_abort(" {.fn mark_corr} requires at least 2 numeric columns." )
758+ }
759+ mat <- stats :: cor(raw_data [, num_cols , drop = FALSE ], method = method )
760+ # Hierarchical clustering reorder
761+ if (reorder ) {
762+ ord <- stats :: hclust(stats :: as.dist(1 - abs(mat )))$ order
763+ mat <- mat [ord , ord ]
764+ }
765+ # Melt to long form
766+ df <- expand.grid(
767+ Var1 = factor (rownames(mat ), levels = rownames(mat )),
768+ Var2 = factor (colnames(mat ), levels = colnames(mat ))
769+ )
770+ df $ value <- as.vector(mat )
771+ # Build tile
772+ mapping <- encode(x = Var1 , y = Var2 , fill = value )
773+ geom <- ggplot2 :: geom_tile(mapping = mapping , data = df , ... )
774+ .add_geom(plot , geom ,
775+ rasterize = rasterize , rasterize_dpi = rasterize_dpi ,
776+ rasterize_dev = rasterize_dev
777+ )
778+ }
779+
501780# ---- mark_bar (hand-written: geom_col vs geom_bar dispatch) ----
502781# ' Bar layer
503782# '
0 commit comments