library(tidyverse)
ggplot(cars) + 
  aes(dist, speed) + 
  geom_point(size = 7) + 
  aes(color = speed) + 
  scale_color_viridis_c(limits = c(0,26)) + 
  scale_x_continuous(limits = c(0,125)) +
  scale_y_continuous(limits = c(0,25))

data_filter <- function(keep) {
  structure(list(keep_specification = rlang::enquo(keep)), 
            class = "wipeobs")
}

ggplot_add.wipeobs <- function(object, plot, object_name) {
  
  new_data <- dplyr::filter(plot$data, 
                            !! object$keep_specification)
  plot$data <- new_data
  plot

  }

last_plot() + 
  data_filter(keep = dist > 60)

ggplot(cars) + 
  aes(dist, speed) + 
  geom_point(size = 7) + 
  aes(color = speed)

data_replace <- function(data) {
  structure(list(new_data_specification = data), 
            class = "wipedata")
}

ggplot_add.wipedata <- function(object, plot, object_name) {
  
  plot$data <- object$new_data_specification
  plot

  }


last_plot() + 
  data_replace(data = cars %>% filter(dist > 50))

drob_funs <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2024/2024-07-09/drob_funs.csv')

drob_funs %>% 
  ggplot() + 
  aes(y = funs) + 
  aes(y = fct_infreq(funs)) +
  aes(y = fct_infreq(funs) %>% fct_rev()) +
  geom_bar() ->
p; p

p + 
  data_replace(drob_funs %>% 
             group_by(funs) %>% 
             filter(n() > 500))

p + 
  data_filter(pkgs == "ggplot")

p + 
  data_filter(pkgs == "dplyr")

p + 
  data_filter(pkgs == "tidyr")

p + 
  data_filter(pkgs == "base")

# might not work
data_group <- function(group) {
  structure(list(group_specification = rlang::enquo(group)),
            class = "data_grouping")
}

ggplot_add.data_grouping <- function(object, plot, object_name) {

  new_data <- dplyr::group_by(plot$data,
                            !! object$group_specification)
  plot$data <- new_data
  plot

}

p +
  data_group() +
  data_filter(n() > 500)

data_mutate <- function(.value, .by) {
  structure(list(sum_specification = rlang::enquo(.value),
                 by_specification = rlang::enquo(.by)),
            class = "data_summary")
  
}

ggplot_add.data_summary <- function(object, plot, object_name) {

  
  new_data <- dplyr::mutate(plot$data, .value =
                            !! object$sum_specification, 
                            .by = !! object$by_specification)
    message("New variable named '.value' created")

  plot$data <- new_data
  plot

  
  }


p + 
  data_mutate(.value = n(), 
              .by = funs) +
  data_filter(.value > 500)

drob_funs %>% 
  ggplot() + 
  aes(id = funs) + 
  ggcirclepack::geom_circlepack() + 
  ggcirclepack::geom_circlepack_text() + 
  coord_equal() +
  aes(fill = I("grey")) ->
plot_all

plot_all + 
  data_filter(pkgs == "ggplot")

plot_all + 
  data_filter(pkgs == "base")

plot_all + 
  data_filter(pkgs == "tidyr")

plot_all + 
  data_filter(pkgs == "dplyr")

plot_all + 
  data_filter(pkgs == "stringr")

library(tidyverse)

drob_funs <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2024/2024-07-09/drob_funs.csv')

data_mutate_filter <- function(.value, .by, keep) {
  structure(list(sum_specification = rlang::enquo(.value),
                 by_specification = rlang::enquo(.by),
                 keep_specifiction = rlang::enquo(keep)),
            class = "data_mutatefilter")
  
}

ggplot_add.data_mutatefilter <- function(object, plot, object_name) {

  
  new_data <- dplyr::mutate(plot$data, .value =
                            !! object$sum_specification, 
                            .by = !! object$by_specification) %>% 
    dplyr::filter(!! object$keep_specifiction)
    message("New variable named '.value' created")

  plot$data <- new_data
  plot

  
  }


drob_funs %>% 
  ggplot() + 
  aes(id = paste(funs, pkgs)) + 
  ggcirclepack::geom_circlepack() + 
  ggcirclepack::geom_circlepack_text(aes(label = funs)) + 
  coord_equal() +
  aes(fill = pkgs) + 
  guides(fill = "none")

last_plot() +
  data_mutate_filter(.value = n(),       
                     .by = c(funs, pkgs), 
                     keep = .value >= 200) 

last_plot() +
  aes(group = pkgs) 

# ggcirclepack:::StatCirclepack$compute_panel
# 
# StatCirclepack <- ggcirclepack:::StatCirclepack
# StatCirclepack$compute_panel <- function (data, scales, npoints = 50, fun = sum) 
# {
#     if (is.null(data$slice)) {
#         data$slice <- TRUE
#     }
#     data <- data %>% dplyr::filter(.data$slice)
#     grp_cols <- c("id", "fill", "alpha", "colour", "linewidth", 
#         "label", "size", "linetype", "render")
#     data <- data %>% group_by(group_by(pick(any_of(grp_cols))))
#     if (is.null(data$area)) {
#         data$area <- 1
#     }
#     if (is.null(data$wt)) {
#         data$wt <- 1
#     }
#     data <- data %>% summarize(area = fun(.data$area * .data$wt), 
#         .groups = "drop")
#     data <- data %>% arrange(id)
#     if (is.null(data$within)) {
#         data$within <- 1
#     }
#     data <- data %>% group_by(.data$within) %>% mutate(prop = .data$area/sum(.data$area)) %>% 
#         mutate(percent = round(.data$prop * 100))
#     data$id = 1:nrow(data)
#     data %>% pull(area) %>% packcircles::circleProgressiveLayout(sizetype = "area") %>% 
#         packcircles::circleLayoutVertices(npoints = npoints) %>% 
#         left_join(data, by = join_by(id))
# }

Closing remarks, Other Relevant Work, Caveats

Intro Thoughts

Status Quo

library(tidyverse)

ggplot(cars) + 
  aes(dist, speed) + 
  geom_point(size = 7) + 
  aes(color = speed) + 
  scale_color_viridis_c(limits = c(0,26)) + 
  scale_x_continuous(limits = c(0,125)) +
  scale_y_continuous(limits = c(0,25))

# last_plot() %>% `%+%`(cars)
# 
# update_data <- `%+%`

# last_plot() |>
#   update_data(cars %>% filter(dist > 20))

last_plot_update_data <- function(p = last_plot(), data){
  
  p$data <- data

  p

}


last_plot_update_data(data = cars %>% filter(speed > 10))

last_plot_filter_data <- function(p = last_plot(), keep){
  
  p$data <- p$data %>% filter({{keep}})
  
  p
  
}


last_plot_filter_data(keep = dist > 40)

#The {magrittr} piping with . returns a function (of the 'functional sequence' subclass), so that kicks off the 'function as data' clause of the data documention.

#You could probably do something like the following to allow that in data_replace() too:
library(tidyverse)

ggplot_add.wipedata <- function(object, plot, object_name) {
  new <- object$new_data_specifiction
  if (is.function(new)) {
    new <- new(plot$data)
  }
  plot$data <- new
  plot
}

data_replace <- function(data) {
  structure(list(new_data_specification = data), 
            class = "wipedata")
}

circle_packing_data <- data.frame(x = abs(rnorm(100)), id = 1:100) 

circle_packing_data %>% 
ggplot(data = .) +
  aes(area = x, id = id) + 
  ggcirclepack::geom_circlepack() 

last_plot() +
  data_replace(data = circle_packing_data %>% mutate(x = sort(x)))
## Error in panels[[1]]: subscript out of bounds
last_plot() +
  data_replace(data = . %>% mutate(x = sort(x)))
## Error in panels[[1]]: subscript out of bounds
ggplot_add.wipedata <- function(object, plot, object_name) {

  plot$data <- object$new_data_specification
  plot

  }

last_plot() + 
  data_replace(data = circle_packing_data %>% mutate(x = sort(x)))

last_plot() + 
  data_replace(data = circle_packing_data %>% mutate(x = rev(sort(x))))

last_plot() %+% 
  (. %>% mutate(x = sort(x)))
## Error in `ggplot_add()`:
## ! Can't add `(. %>% mutate(x = sort(x)))` to a <ggplot> object
## ℹ Did you forget to add parentheses, as in `(. %>% mutate(x = sort(x)))()`?