问题
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