Manual breaks of facet_wrap() in ggplot2

落爺英雄遲暮 提交于 2021-02-08 05:05:59

问题


Problem

I am trying to understand how to provide y-axis breaks manually to facets, generated by the facet_wrap() function in ggplot2 in R.

Minimal reproducible example

Disclaimer: I have borrowed the following example from the R studio community

With the following code, you can specify the y-axis breaks based on the y-axis values in de dataset.

library(ggplot2)
diamonds2 <- subset(diamonds, !(cut == "Fair" & price > 5000))

my_breaks <- function(x) { if (max(x) < 6000) seq(0, 5000, 1000) else seq(0, 15000, 5000) }

ggplot(data = diamonds2, aes(x = carat, y = price)) +
  facet_wrap(~ cut, scales = "free_y") +
  geom_point() +
  scale_y_continuous(breaks = my_breaks)

Question

I would like to be able to specify the breaks manually, based on the facet (in this case: based on the 'cut' of the diamonds). For example, I would like to set the breaks for the 'Fair' cut to seq(1000, 2500, 5000), the breaks for the 'Good' cut to seq(1500, 3000, 4500, 6000, ..., 15000) and the rest to seq(0,15000, 5000).

Attempt

I thought that adapting the my_breaks function with an if-else-ladder, specifying the 'cut' would solve the problem, however, it doesn't:

my_breaks <- function(x) { 
  if (cut == "Fair") {seq(0, 5000, 1000) }
  else if (cut == "Good") {seq(1500,15000, 1500)}
  else { seq(0, 15000, 5000) }
}

It provides the error:

Error in cut == "Fair" : comparison (1) is possible only for atomic and list types

Is there another approach to manually provide the breaks to different facets?


回答1:


Try defining each facet manually by filtering the data and then "patch" the plot up using patchwork package

library(ggplot2)
library(patchwork)

my_plot <- function(df, var, sc) {
  ggplot(data = df, aes(x = carat, y = price)) +
  facet_grid(~ {{var}}) +
  geom_point() +
  coord_cartesian(ylim = {{sc}})
}

diamonds2 <- subset(diamonds, !(cut == "Fair" & price > 5000))

p1 <- diamonds2 %>% filter(cut == "Fair") %>% my_plot(var = "Fair",  sc = c(0, 5000))
p2 <- diamonds2 %>% filter(cut == "Good") %>% my_plot(var = "Good",  sc = c(0, 15000))
p3 <- diamonds2 %>% filter(cut == "Very Good") %>% my_plot(var = "Very Good",  sc = c(0, 1000))
p4 <- diamonds2 %>% filter(cut == "Premium") %>% my_plot(var = "Premium",  sc = c(0, 500))
p5 <- diamonds2 %>% filter(cut == "Ideal") %>% my_plot(var = "Ideal",  sc = c(0, 20000))

p1+p2+p3+p3+p4+plot_layout(ncol = 3)

edit: I realized it was the y-axis breaks to be set pr. facet. In that case

my_plot <- function(df, var, my_breaks) {
  ggplot(data = df, aes(x = carat, y = price)) +
  facet_grid(~ {{var}}) +
  geom_point() +
  scale_y_continuous(breaks = {{my_breaks}})
}

library(ggplot2)
diamonds2 <- subset(diamonds, !(cut == "Fair" & price > 5000))

p1 <- diamonds2 %>% filter(cut == "Fair") %>% my_plot(var = "Fair",  my_breaks = seq(0, 5000, 1000))
p2 <- diamonds2 %>% filter(cut == "Good") %>% my_plot(var = "Good",  my_breaks = seq(1500,15000, 1500))
p3 <- diamonds2 %>% filter(cut == "Very Good") %>% my_plot(var = "Very Good",  my_breaks =seq(1500,15000, 5000))
p4 <- diamonds2 %>% filter(cut == "Premium") %>% my_plot(var = "Premium",  my_breaks = seq(1500,15000, 5000))
p5 <- diamonds2 %>% filter(cut == "Ideal") %>% my_plot(var = "Ideal",  my_breaks = seq(1500,15000, 5000))

p1+p2+p3+p3+p4+plot_layout(ncol = 3)

Edit2: A leaner way to do this using purrr

library(ggplot2)
library(patchwork)
library(purrr)
facets = diamonds2 %>% distinct(cut) %>% pull()
my_breaks = list(seq(0, 5000, 1000), seq(1500,15000, 1500), seq(1500,15000, 5000),
                 seq(1500,15000, 5000), seq(1500,15000, 5000))

plt_list <- purrr::map2(facets, my_breaks, ~my_plot(diamonds2, .x, .y))

Reduce('+', plt_list) + plot_layout(ncol = 3)


来源:https://stackoverflow.com/questions/60337130/manual-breaks-of-facet-wrap-in-ggplot2

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!