Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove unnecessary y-axis points with facet_wrap and geom_segment

Tags:

r

ggplot2

I'm mapping y-axis points to the x-axis using geom_segment() and then using facet_wrap to separate data into two plots; however, the y-axis points are showing up on both plots.

How can I have only the necessary y-axis points pertaining to each facet_wrap?

Sample Code

dat <- structure(list(temp = c(1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 
4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5), rev = c(-5, 
-11, -20, -29, -40, -9, -20, -32, -45, -57, -12, -24, -37, -50, 
-62, -7, -20, -36, -52, -67, -5, -13, -23, -35, -47, -12, -24, 
-36, -48, -58), type = c("Type 1", "Type 1", "Type 1", "Type 1", 
"Type 1", "Type 1", "Type 1", "Type 1", "Type 1", "Type 1", "Type 1", 
"Type 1", "Type 1", "Type 1", "Type 1", "Type 2", "Type 2", "Type 2", 
"Type 2", "Type 2", "Type 2", "Type 2", "Type 2", "Type 2", "Type 2", 
"Type 2", "Type 2", "Type 2", "Type 2", "Type 2"), model = c("A", 
"A", "A", "A", "A", "B", "B", "B", "B", "B", "C", "C", "C", "C", 
"C", "A", "A", "A", "A", "A", "B", "B", "B", "B", "B", "C", "C", 
"C", "C", "C")), .Names = c("temp", "rev", "type", "model"), row.names = c(NA, 
-30L), class = "data.frame")

p1 <- ggplot(dat, aes(temp, rev, color = model)) + 
  geom_line() + geom_point() + geom_segment(aes(x = 0, xend = temp, yend = rev), linetype = "dashed", color = "grey") + 
  facet_wrap(~type, scales = "free") + scale_y_continuous(breaks = dat$rev)
p1

Plot

enter image description here

like image 427
Vedda Avatar asked Nov 20 '25 01:11

Vedda


2 Answers

I made up dummy data because for some reason pasting your dput into my console made it unhappy.

library(dplyr)

df <- expand.grid(temp = 1:5, model = LETTERS[1:3], type = 1:2) %>% 
  group_by(model, type) %>% 
  mutate(rev = -sort(sample.int(20, length(temp)))) 

# this is equivalent to your data as-is, structurewise

df.labeled <- df %>% 
  ungroup() %>% group_by(type, rev) %>% 
  mutate(label = c(rev[1], rep(NA, length(rev) - 1)))

Here I created a group for each y value that shows up in each group panel. Then I create a label column which consists of 1 observation of that y value, padded with NAs. So if a panel would have had two models that each had a rev of -5, now it would be -5, NA instead of -5, -5. Why I'm doing this will become clearer below.


ggplot(df.labeled, aes(temp, rev, color = model)) + 
  geom_segment(aes(xend = 0, yend = rev), linetype = "dashed", color = "grey") +
  geom_text(aes(label = label, x = -0.1), colour = "black", hjust = 1) +
  geom_vline(xintercept = 0) +
  geom_point() + geom_line() + facet_grid(~type) + 
  scale_y_continuous(breaks = NULL) + 
  scale_x_continuous(limits = c(-0.5, NA)) +
  theme_bw() + theme(panel.grid = element_blank())

enter image description here

If I had left in the duplicates (here would have been -7, -15 for type 1 and -11 for type 2), the geom_text would have been a messy bolded blur. Duplicated text labels don't render well in ggplot2. Since it's not really possible to do it the way you wanted, here we're just making a fake scale for each panel. If you don't like the fact that there's an extra line on the y-axis to the left of the numbers, that can be gotten rid of:

  ... + 
  theme(panel.grid = element_blank(),
        panel.border = element_blank(),
        axis.line.x = element_line())

enter image description here

like image 99
Brian Avatar answered Nov 22 '25 17:11

Brian


We can split the data frame by the type, create separated plot, and then use grid.arrange from the gridExtra package to combine two plots.

library(ggplot2)
library(gridExtra)

# Split the data
dat_list <- split(dat, dat$type)

# Use lapply to create plot for both subset
p_list <- lapply(dat_list, function(x){

  p1 <- ggplot(x, aes(temp, rev, color = model)) + 
    geom_line() + 
    geom_point() + 
    geom_segment(aes(x = 0, xend = temp, yend = rev), linetype = "dashed", color = "grey") + 
    scale_y_continuous(breaks = x$rev) +
    facet_wrap(~type, scales = "free")
  return(p1)
})

# Plot the data
grid.arrange(grobs = p_list, nrow = 1)

Update

Another option is to use the cowplot package. This seems to be a way to create a common legend.

library(cowplot)

# Get the common legend, p_list is from the previous example
legend_both <- get_legend(p_list[[1]])

# Plot the plots and the common legend together
# Use rel_widths to set the column width
plot_grid(p_list[[1]] + theme(legend.position = "none"),
          p_list[[2]] + theme(legend.position = "none"),
          legend_both, 
          nrow = 1,
          rel_widths = c(2, 2, 1))
like image 39
www Avatar answered Nov 22 '25 18:11

www



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!