jaromil
jaromil

Reputation: 41

Creating subplot (facets) with custom x,y position of the subplots in ggplot2

How can we custom the position of the panels/subplot in ggplot2?

Concretely I have a grouped times series and I want to produce 1 subplot per time series with custom positions of the subplot, not necessarily in a grid.

The facet_grid() or facet_wrap() functions do not provide a full customization of the position of the panel as it uses grid.

library(tidyverse)

df = data.frame(group = LETTERS[1:5],
                x = c(1,2,3,1.5,2.5),
                y =c(2,1,2,3,3),
                stringsAsFactors = F)%>%
  group_by(group)%>%
  expand_grid(time = 1:20)%>%
  ungroup()%>%
  mutate(dv = rnorm(n()))%>%
  arrange(group,time)

## plot in grid          
df%>%                  
ggplot()+
  geom_line(aes(x=time,y=dv))+
  facet_grid(~group)

## plot with custom x, y position
## Is there an equivalent of facet_custom()?             
df%>%                  
ggplot()+
  geom_line(aes(x=time,y=dv))+
  facet_custom(~group, x.subplot = x, y.subplot = y)

FYI: This dataset is only an example. My data are EEG data where each group represents an electrode (up to 64) and I want to plot the EEG signals of each electrode accordingly to the position of the electrode on the head.

Upvotes: 2

Views: 384

Answers (1)

tjebo
tjebo

Reputation: 23747

Well, I guess this would not really be a 'facet plot' any more. I therefore don't think there is a specific function out there.

But you can use the fantastic patchwork package for that, in particular the layout option in wrap_plots.

As the main package author Thomas describes in the vignette, the below option using area() may be a bit verbose, but it would give you full programmatic options about positioning all your plots.

library(tidyverse)
library(patchwork)

mydf <- data.frame(
  group = LETTERS[1:5],
  x = c(1, 2, 3, 1.5, 2.5),
  y = c(2, 1, 2, 3, 3),
  stringsAsFactors = F
) %>%
  group_by(group) %>%
  expand_grid(time = 1:20) %>%
  ungroup() %>%
  mutate(dv = rnorm(n())) %>%
  arrange(group, time)

## plot in grid
mylist <- 
  mydf %>% 
  split(., .$group) 

p_list <- 
  map(1:length(mylist), function(i){
  ggplot(mylist[[i]]) +
    geom_line(aes(x = time, y = dv)) +
    ggtitle(names(mylist)[i]) 
  }
  )

layout <- c(
  area(t = 1, l = 1, b = 2, r = 2),
  area(t = 2, l = 3, b = 3, r = 4),
  area(t = 3, l = 5, b = 4, r = 6),
  area(t = 4, l = 3, b = 5, r = 4),
  area(t = 5, l = 1, b = 6, r = 2)
)

wrap_plots(p_list, design = layout)
#> result not shown, it's the same as below

For a more programmatic approach, one option is to create the required "patch_area" object manually.

t = 1:5
b = t+1
l = c(1,3,5,3,1)
r = l+1

list_area <- list(t = t, b = b, l = l, r = r)

class(list_area) <- "patch_area"

wrap_plots(p_list, design = list_area)

Created on 2020-04-22 by the reprex package (v0.3.0)

Upvotes: 2

Related Questions