I am plotting multiple graphs using facet_wrap() from the ggplot2 package in R. When facetting by multiple variables, the result includes both labels in the strip text. How can I remove one?
In this toy example from the mpg dataset, how to keep the cyl labels only? Thanks
ggplot(mpg, aes(displ, hwy)) +
geom_point() +
facet_wrap(c("cyl", "drv"))
The biggest concern with this is as #aelwan mentioned several plots will have the same strip labels but are not the same. Ignoring this issue, I believe the best way to proceed is by creating a new cross variable between cyl and drv.
So if you just want one row for the strip labels you can for example:
ggplot(mpg %>% mutate(cyl_drv = paste0(cyl, '-', drv)), aes(displ, hwy)) +
geom_point() +
facet_wrap(~ cyl_drv)
You can then change the labels if you need as follows:
ggplot(mpg %>% mutate(cyl_drv = paste0(cyl, '-', drv)), aes(displ, hwy)) +
geom_point() +
facet_wrap(~ cyl_drv, labeller = as_labeller(c(`4-4`="4", `4-f`="4", `5-f`=5, `6-4`=6, `6-f`=6, `6-r`=6, `8-4`=8, `8-f`=8, `8-r`=8)))
Another (admittedly not great) way to change it is as follows (which I suspect there is a better way to do):
library(ggplot2)
library(ggExtra)
library(grid)
library(gtable)
gg <- ggplot(mpg, aes(displ, hwy)) +
geom_point() +
facet_wrap(~ cyl * drv)
g1 <- ggplot(mpg, aes(displ, hwy)) +
geom_point() +
facet_wrap(~ cyl)
gtab <- ggplotGrob(gg)
gtab$grobs[[47]] <- ggplotGrob(g1)$grobs[[23]]
gtab$grobs[[48]] <- ggplotGrob(g1)$grobs[[23]]
gtab$grobs[[49]] <- ggplotGrob(g1)$grobs[[23]]
gtab$grobs[[50]] <- ggplotGrob(g1)$grobs[[22]]
gtab$grobs[[51]] <- ggplotGrob(g1)$grobs[[22]]
gtab$grobs[[52]] <- ggplotGrob(g1)$grobs[[22]]
gtab$grobs[[53]] <- ggplotGrob(g1)$grobs[[24]]
gtab$grobs[[54]] <- ggplotGrob(g1)$grobs[[24]]
gtab$grobs[[55]] <- ggplotGrob(g1)$grobs[[25]]
grid.draw(gtab)
Related
I'm trying to develop a function that will create a plot from just a few arguments. I need it to be flexible, so that I can input an unknown number of variables to facet the graph by. I've used all the quoting/unquoting methods I can find: {{ }}, .data[], !!!, inject, and more. I think part of the problem is that facet_grid calls it's variables within vars(), which is not cooperating with these operators. I have also tried passing the variables that I want to facet by into the function using dots, and by a named argument that takes a vector.
It seems to me that the best option here, based on this article (https://adv-r.hadley.nz/quasiquotation.html) is the unquote-splice operator. It seems to me like one of these should work, but neither does:
make_graph <- function (factor.by){
ggplot(mpg, aes(cyl, cty)) +
geom_col() +
facet_grid(cols = vars(!!!factor.by))
}
make_graph(factor.by = c("manufacturer", "model"))
make_graph_2 <- function (...){
ggplot(mpg, aes(cyl, cty)) +
geom_col() +
facet_grid(cols = vars(...))
}
make_graph_2("manufactuer", "model")
I would really appreciate any help figuring out how to make this work! I'm pretty new to programming with R, and I've been stuck on this issue for a long time. Thank you so much!
Some options:
Ellipses:
make_graph <- function(...) {
ggplot(mpg, aes(cyl, cty)) +
geom_col() +
facet_grid(cols = vars(...))
}
make_graph(manufacturer, model)
Programmatic formula:
make_graph <- function(factor.by) {
ggplot(mpg, aes(cyl, cty)) +
geom_col() +
facet_grid(rows = as.formula(paste0(". ~ ", paste(factor.by, collapse = "+"))))
}
make_graph(factor.by = c("manufacturer", "model"))
Using ensyms (thank you #stefan!), for a variadic function:
make_graph <- function(...) {
ggplot(mpg, aes(cyl, cty)) +
geom_col() +
facet_grid(cols = vars(!!!rlang::ensyms(...)))
}
make_graph("manufacturer", "model")
Using syms for a single-argument function:
make_graph <- function(factor.by) {
ggplot(mpg, aes(cyl, cty)) +
geom_col() +
facet_grid(cols = vars(!!!rlang::syms(factor.by)))
}
make_graph(c("manufacturer", "model"))
I have multivariate longitudinal samples that I am plotting in a large facet_grid, specifically using facet_grid so that when I don't have a certain time point for a certain sample it still keeps everything in a nicely ordered grid. I am trying to add some sort of indicator to empty facets to show that they don't have data (rather than just having no dots show up), because sometimes the empty facet is a result of not having collected that sample yet. What I have been able to get is a label that shows up in every facet that DOES have data, but I can't seem to figure out how to get a label that shows up in every facet that does NOT have data. It would be even better if I could add a red X through select facets, or some other indication of "No Data Available", rather than a text label, if you have suggestions about that as well.
ggplot(mpg, aes(displ, cty)) + geom_point() +
facet_grid(vars(drv), vars(cyl)) + geom_text(x = 5, y = 20, label = "Blah")
You could add rows for the missing combinations with a full_join. These new rows will have no data, so nothing will be plotted, but you can add an additional column with the message that geom_text will use:
library(tidyverse)
theme_set(theme_bw())
mpg %>%
full_join(crossing(drv=unique(mpg$drv), cyl=unique(mpg$cyl))) %>%
mutate(empty=ifelse(is.na(model), "No data available", NA_character_),
x=mean(range(displ, na.rm=TRUE)),
y=mean(range(cty, na.rm=TRUE))) %>%
ggplot(aes(displ, cty)) +
geom_point() +
facet_grid(vars(drv), vars(cyl)) +
geom_text(aes(x, y, label=empty), colour="red", size=3)
For an "X", change the empty text to "X" and plot it with a large size. For example:
mpg %>%
full_join(crossing(drv=unique(mpg$drv), cyl=unique(mpg$cyl))) %>%
mutate(empty=ifelse(is.na(model), "X", NA_character_),
x=mean(range(displ, na.rm=TRUE)),
y=mean(range(cty, na.rm=TRUE))) %>%
ggplot(aes(displ, cty)) +
geom_point() +
geom_text(aes(x, y, label=empty), colour="red", size=20) +
facet_grid(vars(drv), vars(cyl))
Or we could use geom_segment:
mpg %>%
full_join(crossing(drv=unique(mpg$drv), cyl=unique(mpg$cyl))) %>%
ggplot(aes(displ, cty)) +
geom_point() +
geom_segment(data=. %>% filter(is.na(model)),
x=min(mpg$displ), xend=max(mpg$displ),
y=min(mpg$cty), yend=max(mpg$cty),
colour="red") +
geom_segment(data=. %>% filter(is.na(model)),
x=min(mpg$displ), xend=max(mpg$displ),
y=max(mpg$cty), yend=min(mpg$cty),
colour="red") +
facet_grid(vars(drv), vars(cyl))
The above can be done with a single call to geom_segment, but it requires (AFAICT) a more complex data prep:
mpg %>%
full_join(crossing(drv=unique(mpg$drv), cyl=unique(mpg$cyl))) %>%
ggplot(aes(displ, cty)) +
geom_point() +
geom_segment(data=. %>%
filter(is.na(model)) %>%
select(-displ, -cty) %>%
crossing(
displ=range(mpg$displ),
cty=range(mpg$cty)
),
aes(xend=rev(displ), yend=rev(cty)), colour="red") +
facet_grid(vars(drv), vars(cyl))
I'm trying to put expressions into facet labels using label_parsed but with no success:
library(ggplot2)
mpg3 <- mpg
levels(mpg3$drv)[levels(mpg3$drv)=="4"] <- "4^{wd}"
levels(mpg3$drv)[levels(mpg3$drv)=="f"] <- "- Front %.% e^{pi * i}"
levels(mpg3$drv)[levels(mpg3$drv)=="r"] <- "4^{wd} - Front"
ggplot(mpg3, aes(x=displ, y=hwy)) + geom_point() +
facet_grid(. ~ drv, labeller = label_parsed)
The plot that I get lacks expressions - facet labels contain the original levels of drv variable.
If I type levels(mpg3$drv) I get character(0).
There are two problems - firstly mpg$drv is character, not factor, and secondly, you need to set the factor labels, not the levels. I think this is what you want...
mpg3 <- mpg
mpg3$drv <- factor(mpg3$drv,
levels=c("4","f","r"),
labels=c("4^{wd}","- Front %.% e^{pi * i}","4^{wd} - Front"))
ggplot(mpg3, aes(x=displ, y=hwy)) +
geom_point() +
facet_grid(. ~ drv, labeller = label_parsed)
I am trying to learn ggplot2 and have made below plots:
Using this code:
library(ggplot2); library(gridExtra)
gg <- ggplot(mydata,aes(x=Level))
plot1 <- gg + geom_line(aes(y=Experience,colour="xp"),size=1) +
labs(title="xp")
g <- ggplot(mydata,aes(x=Level))
plot2 <- g + geom_line(aes(y=Experience,colour="xp"),size=1) + geom_line(aes(y=Accu,colour="accu"),size=1) +
labs(title="xp vs Accumulated")
grid.arrange(plot1,plot2,ncol=2)
Where mydata is a data frame containing 3 columns (Level, xp and accu) and 30 rows.
What I am wondering is:
How to get the y-axis on the left-hand plot to have the same form as the
right-hand plot.
How to make the color of "xp" the same in both plots
without removing the descriptions of what the lines represent.
How about this (with some random data)?
library(ggplot2)
library(gridExtra)
library(scales)
gg <- ggplot(mydata,aes(x=Level))
plot1 <- gg + geom_line(aes(y=Experience,colour="xp"),size=1) +
labs(title="xp") + scale_y_continuous(labels = comma) +
scale_colour_manual(values = c("red"))
g <- ggplot(mydata,aes(x=Level))
plot2 <- g + geom_line(aes(y=Experience,colour="xp"),size=1) +
geom_line(aes(y=Accu,colour="accu"),size=1) +
labs(title="xp vs Accumulated") + scale_y_continuous(labels = comma) +
scale_colour_manual(values = c("blue", "red"))
grid.arrange(plot1,plot2,ncol=2)
Specifically, this is in a facet_grid. Have googled extensively for similar questions but not clear on the syntax or where it goes. What I want is for every number on the y-axes to have two digits after the decimal, even if the trailing one is 0. Is this a parameter in scale_y_continuous or element_text or...?
row1 <- ggplot(sector_data[sector_data$sector %in% pages[[x]],], aes(date,price)) + geom_line() +
geom_hline(yintercept=0,size=0.3,color="gray50") +
facet_grid( ~ sector) +
scale_x_date( breaks='1 year', minor_breaks = '1 month') +
scale_y_continuous( labels = ???) +
theme(panel.grid.major.x = element_line(size=1.5),
axis.title.x=element_blank(),
axis.text.x=element_blank(),
axis.title.y=element_blank(),
axis.text.y=element_text(size=8),
axis.ticks=element_blank()
)
From the help for ?scale_y_continuous, the argument 'labels' can be a function:
labels One of:
NULL for no labels
waiver() for the default labels computed by the transformation object
A character vector giving labels (must be same length as breaks)
A function that takes the breaks as input and returns labels as output
We will use the last option, a function that takes breaks as an argument and returns a number with 2 decimal places.
#Our transformation function
scaleFUN <- function(x) sprintf("%.2f", x)
#Plot
library(ggplot2)
p <- ggplot(mpg, aes(displ, cty)) + geom_point()
p <- p + facet_grid(. ~ cyl)
p + scale_y_continuous(labels=scaleFUN)
The "scales" package has some nice functions for formatting the axes. One of these functions is number_format(). So you don't have to define your function first.
library(ggplot2)
# building on Pierre's answer
p <- ggplot(mpg, aes(displ, cty)) + geom_point()
p <- p + facet_grid(. ~ cyl)
# here comes the difference
p + scale_y_continuous(
labels = scales::number_format(accuracy = 0.01))
# the function offers some other nice possibilities, such as controlling your decimal
# mark, here ',' instead of '.'
p + scale_y_continuous(
labels = scales::number_format(accuracy = 0.01,
decimal.mark = ','))
The scales package has been updated, and number_format() has been retired. Use label_number(). This can also be applied to percentages and other continuous scales (ex: label_percent(); https://scales.r-lib.org/reference/label_percent.html).
#updating Rtists answer with latest syntax from scales
library(ggplot2); library(scales)
p <- ggplot(mpg, aes(displ, cty)) + geom_point()
p <- p + facet_grid(. ~ cyl)
# number_format() is retired; use label_number() instead
p + scale_y_continuous(
labels = label_number(accuracy = 0.01)
)
# for whole numbers use accuracy = 1
p + scale_y_continuous(
labels = label_number(accuracy = 1)
)
Several people have suggested the scales package, but you could just do pretty much the same with base R as well, here by using the format() function.
require(ggplot2)
ggplot(iris, aes(y = Sepal.Length, x = Sepal.Width)) +
geom_point() +
scale_y_continuous(labels = function(x) format(x, nsmall = 2)) +
facet_wrap(~Species)