thomasp85 / ggforce

Accelerating ggplot2
https://ggforce.data-imaginist.com
Other
916 stars 105 forks source link

[feature request] geom_subplot #147

Open mkoohafkan opened 5 years ago

mkoohafkan commented 5 years ago

ggsubplot has been deprecated for years, but tidyverse support for list columns and custom annotations in ggplot2 make it pretty easy to mimic its functionality. However, there is some boilerplate logic that I could see fitting into a new geom, i.e. geom_subplot().

First, some examples on how to embed plots in a plot:

# simple example (unlikely use case -- could instead use facet_grid) 
library(dplyr)
library(purrr)
library(ggplot2)

titanic = as.data.frame(Titanic, responseName = "value") %>%
  group_nest(Class, Sex) %>%
  mutate(
    Class = factor(Class),
    Sex = factor(Sex),
    X = as.integer(Class),
    Y = as.integer(Sex),
    plot = map(data, 
      ~ggplot(.x) + geom_col(aes(x = Survived, y = value))
    ),
    annotation = pmap(list(X, Y, plot),
      ~ annotation_custom(ggplotGrob(..3),
        xmin = ..1 - 0.4, xmax = ..1 + 0.4,
        ymin = ..2 - 0.4, ymax = ..2 + 0.4))
  )
ggplot(titanic) + aes(x = Class, y = Sex) + geom_point() + pull(titanic, annotation)

plot1

# mapping example (more likely use case)
library(dplyr)
library(purrr)
library(ggplot2)
library(sf)

nc <- st_read(system.file("shape/nc.shp", package = "sf"))
data(Crime, package = "Ecdat")

ncdat = nc %>%
  st_transform(3857) %>%
  bind_cols(as_tibble(st_coordinates(st_centroid(.))))

crimedat = Crime %>% 
  group_nest(county) %>%
  inner_join(select(st_drop_geometry(ncdat), X, Y, CRESS_ID), by = c("county" = "CRESS_ID")) %>%
  mutate(
    plot = map(data, ~ggplot(.x) + aes(x = year, y = crmrte) + geom_line(color = "red") + theme_void()),
    annotation = pmap(list(X, Y, plot), ~ annotation_custom(ggplotGrob(..3),
      xmin = ..1 - 8000 , xmax = ..1 + 8000,
      ymin = ..2 - 8000 , ymax = ..2 + 8000)) 
  )

ggplot(ncdat) + geom_sf() + pull(crimedat, annotation)

plot2

And here's a more sophisticated example (link to blog plost with code).

plot3

I'm thinking a geom_subplot() could handle the last step of transforming a list of plots into custom annotations, replacing the final call to pmap and manual addition of the annotation list to the base plot in the above examples. In other words, the geom would take a dataframe with a list column containing ggplot objects and map them onto the "base" plot. This would provide maximum flexibility for users generating the suplots themselves and avoid a lot of the messy aesthetics that was in ggsubplot. The new geom would accept subplot locations, dimensions, and the subplots themselves (i.e. geom_subplot(aes(x, y, height, width, plot))). At the same time, the new geom could provide helper arguments to

I've been learning more about extending ggplot2 and would be interested in helping develop this functionality, but I don't think I have the necessary expertise to develop this on my own. I also would prefer to contribute to ggforce rather than try to maintain a separate package, since ggforce clearly has a well-developed underlying framework for developing new geoms.

mkoohafkan commented 4 years ago

I have developed a new geometry geom_subfig() and am currently hosting it in an experimental package ggsubplot2. I would be interested in contributing this to ggforce rather than maintaining a separate package if there is interest.

library(dplyr)
library(purrr)
library(ggplot2)
#  remotes::install_github("mkoohafkan/ggsubplot2")
library(ggsubplot2)

d1 = mtcars %>%
    group_nest(gear, cyl) %>%
    mutate(plot = map(data,
        ~ ggplot(.x, aes(x = mpg)) +
            geom_density() +
            theme_bw(base_size = 4)
    ))

ggplot(d1, aes(x = gear, y = cyl, plot = plot)) +
    geom_subfig(width = 0.75, height = 0.75)

image

dlmolloy commented 4 years ago

Was hoping to use this for a project, but the map function seems to crash whenever I apply it to my data. The steps creating plots for each location may need work.

mkoohafkan commented 4 years ago

@dlmolloy post your issue (with sample data) to the ggsubplot2 issues page and I'll see if I can help. This thread is generally about integrating or developing a subplot geom in ggforce.

thomasp85 commented 7 months ago

I have been away from the repo. Are you still interested in submitting this into ggforce?