'Is there a way to use different y-values per facet in R?

I'm relatively new to R and I'm struggling to figure out a way to get a set of plots with different y values. Below is a simplified version of the dataset I'm working on.

Cell x y1 y2 y3 y4
A 1 0.5 0.7 0.9 1.1
A 2 0.6 0.8 1.0 1.2
A 3 0.7 0.9 1.1 1.3
B 1 0.5 2.9 4.0 3.1
B 2 0.6 3.0 4.1 3.2
B 3 0.7 3.1 4.2 3.3

As it stands now, what I have is the code below

ggplot(ETO2, aes(x = x, y = y1) +
geom_line() +
facet_wrap(~Cell) 

Is there a simple way to plot different y-values per facet? For example I would want data with Cell=A to plot y1 over x and for data with Cell=B i'd want it to plot y3 over x. Preferably i would like to see the plots as one output. Note that in my actual data sets, there are a lot more cell lines, and it would also be nice to easily switch the columns for the y-values.

Thank you so much, and I hope I explained my intention as clear as possible. If not, please feel free to ask more.



Solution 1:[1]

Create a dictionary dict specifying which y column to plot in which cell, merge it with ETO2, create a new y variable and plot.

This approach is quite flexible as it is not restricted to 2 cells. dict can have any number of rows. Also, if any cells in ETO2 are not to be associated with a facet then simply omit such cells from dict. Also it provides for labelling each facet with both the cell and ordinate for clarity on what is shown in each facet.

Although get(ycol) is shorter cur_data()[[ycol]] or c_across(all_of(ycol)) would also work in the mutate below.

library(dplyr)
library(ggplot2)

dict <- data.frame(Cell = c("A", "B"), ycol = c("y1", "y3"))

ETO2 %>%
  inner_join(dict, by = "Cell") %>%
  rowwise %>% 
  mutate(Cell = paste(Cell, ycol, sep = "-"), y = get(ycol)) %>%
  ungroup %>%
  ggplot(aes(x, y)) +
    geom_line() +
    facet_wrap(~ Cell)

screenshot

Note

ETO2 <- structure(list(Cell = c("A", "A", "A", "B", "B", "B"), x = c(1L, 
2L, 3L, 1L, 2L, 3L), y1 = c(0.5, 0.6, 0.7, 0.5, 0.6, 0.7), y2 = c(0.7, 
0.8, 0.9, 2.9, 3, 3.1), y3 = c(0.9, 1, 1.1, 4, 4.1, 4.2), y4 = c(1.1, 
1.2, 1.3, 3.1, 3.2, 3.3)), class = "data.frame", row.names = c(NA, 
-6L))

Solution 2:[2]

In general, "no", but you can create a new variable that takes from y1 or y3 depending on the Cell. If it's just two values, then ifelse will suffice,

ETO2$y0 <- ifelse(ETO2$Cell == "A", ETO2$y1, ETO2$y3)

If there are more, though, you may prefer dplyr::case_when or data.table::fcase.

From here, just choose the new variable y0 instead:

ggplot(ETO2, aes(x = x, y = y0)) +
 geom_line() +
 facet_wrap(~Cell) 

Solution 3:[3]

Another solution would be to produce two plots by filtering ET02 on values of column Cell, then joining to have a single output. You can easily switch for various columns as y axis in this way

library(ggplot2)
library(tidyverse)
library(patchwork) # package for joining ggplot2 plots in different ways

ETO2 %>%  
  filter(Cell == "A") %>% # select only rows with "A" value in Cell
  ggplot(., aes(x = x, y = y1)) + # plot over desired y
           geom_line() -> p1

ETO2 %>%  
  filter(Cell == "B") %>% # select only rows with "B" value in Cell
  ggplot(., aes(x = x, y = y3)) + # plot over desired y
  geom_line() -> p2

p1 + p2 # side by side
p1 / p2 # top and bottom

In case you would like to have the same ranges of y axis with different values, you can set ylim()

p1 + ylim(0,5) -> p1_lim
p2 + ylim(0,5) -> p2_lim

p1_lim + p2_lim 

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 r2evans
Solution 3 Svito