I am working with the R programming language. I made the following graph using the built-in "mtcars" dataset:
library(ggplot2)
a = ggplot(data=mtcars, aes(x=wt, y=mpg)) + geom_point() + ggtitle("mtcars: wt vs mpg")
Question: Now, I am trying to customize the title, but I want the title to "contain a variable reference", for example:
b = ggplot(data=mtcars, aes(x=wt, y=mpg)) + geom_point() + ggtitle("mtcars: wt vs mpg - average mpg = mean(mtcars$mpg)")
But this command literally just prints the code I wrote:
I know that the "mean" command runs by itself:
mean(mtcars$mpg)
[1] 20.09062
But can someone please help me change this code:
ggplot(data=mtcars, aes(x=wt, y=mpg)) + geom_point() + ggtitle("mtcars: wt vs mpg - average mpg = mean(mtcars$mpg)")
So that it produces something like this (note: here, I manually wrote the "mean" by hand):
Thanks
You can do this using paste().
ggplot(data=mtcars, aes(x=wt, y=mpg)) + geom_point() + ggtitle(paste0("mtcars: wt vs mpg - average mpg = ", mean(mtcars$mpg)))
If you need to you can add more text and variables with commas like so:
ggtitle(paste0('text ', var1, 'text2 etc ', var2, var3, 'text3'))
Note that paste0 is a variant of paste that concatenates things with no space or separator in between.
An option with glue
library(ggplot2)
library(glue)
ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point() +
ggtitle(glue("mtcars: wt vs mpg - average mpg = {mean(mtcars$mpg)}"))
We could also use str_c from stringr package which is part of tidyverse package. str_c is equivalent to paste0
library(tidyverse)
ggplot(data=mtcars, aes(x=wt, y=mpg)) + geom_point() + ggtitle(str_c("mtcars: wt vs mpg - average mpg = ", mean(mtcars$mpg)))
Related
I want to make a function that uses ggplot and facet_wrap and passes the function variables to facet by.
I can do the following using quoted arguments.
library(tidyverse)
my_grid_plot <- function(facet_by){
ggplot(mtcars, aes(wt, disp)) +
geom_point() +
facet_wrap(facet_by)
}
my_grid_plot(facet_by = 'am')
my_grid_plot(facet_by = 'vs')
my_grid_plot(facet_by = c('am', 'vs'))
However, I would like to do this using unquoted arguments, e.g.
# does not work yet; this is what I want
my_grid_plot(facet_by = am)
my_grid_plot(facet_by = vs)
my_grid_plot(facet_by = c(am, vs))
I know I can use vars with facet_wrap, e.g.
ggplot(mtcars, aes(wt, disp)) +
geom_point() +
facet_wrap(vars(am, vs))
And so I could do something like this
my_grid_plot2 <- function(facet_by){
ggplot(mtcars, aes(wt, disp)) +
geom_point() +
facet_wrap(vars({{facet_by}}))
}
# works fine
my_grid_plot2(am)
my_grid_plot2(vs)
But that won't work if facet_by is a vector.
# does not work; obscure error
my_grid_plot2(c(am, vs))
So is there a way to get what I want above, i.e. where facet_by takes a single variable name of vector of names?
I don't know if this is the right or best way, and it seems a bit hacky, but I think it does the job. Inspired by https://stackoverflow.com/a/57709169/1009979
my_grid_plot3 <- function(facet_by){
by_expr <- enexpr(facet_by)
if(length(by_expr) == 1) {
args_vars <- as.list(by_expr)
} else {
args_vars <- as.list(by_expr)[-1]
}
quoted_args_vars <- sapply(args_vars, quo_name)
ggplot(mtcars, aes(wt, disp)) +
geom_point() +
facet_wrap(quoted_args_vars)
}
# this works
my_grid_plot3(am)
my_grid_plot3(vs)
my_grid_plot3(c(am, vs))
One option is to let tidyselect do the heavy lifting:
my_grid_plot2 <- function(facet_by){
by <- rlang::enexpr(facet_by) %>%
tidyselect::eval_select(mtcars)
ggplot(mtcars, aes(wt, disp)) +
geom_point() +
facet_wrap(names(by))
}
## All of the following now work as expected
my_grid_plot2(am)
my_grid_plot2(vs)
my_grid_plot2(c(am, vs))
my_grid_plot2('am')
my_grid_plot2('vs')
my_grid_plot2(c('am', 'vs'))
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 want to add label with mathematical expressions in two line with facet_grid for two grids (See MWE). I can get that in one line, wonder to get in two lines (Beta in one line and Gamma in second line in second graph).
library(ggplot2)
p1 <- ggplot(mtcars, aes(x = mpg, y = wt)) + geom_point()
p1 + facet_grid(
facets = gear ~ vs + am
, labeller = label_both
)
p1 + facet_grid(
facets = gear ~ vs + am
, labeller =
label_bquote(
rows = alpha:.(gear)
, cols = list(beta:.(vs), gamma:.(am))
)
)
You can use atop() instead of list():
library(ggplot2)
ggplot(mtcars, aes(mpg, wt)) +
geom_point() +
facet_grid(gear ~ vs + am,
labeller = label_bquote(
rows = alpha:.(gear),
cols = atop(beta:.(vs), gamma:.(am))))
atop() is a brute force approach as it puts "x over y (no horizontal bar)"
Consider the simple example:
library(ggplot2)
head(mtcars)
# create the plot
ggplot(mtcars, aes(factor(cyl))) + geom_bar() + theme_bw() +
theme(strip.text.x = element_text(size = 20, face="bold"))+
xlab("number of cyl") + ylab("Count")
Now we can obtain the average $mpg per cyl with:
aggregate(mpg ~ cyl, data = mtcars, FUN=mean)
How can I put these average values into the x-axis so that they appear below the corresponding cyl. Can one draw a table and somehow write that this is the ...average mpg per cyl...
Here is a simple way to do it by rewriting the factor level names:
(Note that this is safe only as long as aggregate generates it table in the same order as the factor level names and without any gaps - which seems like it should be the case, but one would have to investigate to make sure. It might be safer to code it as a loop and look at the level names to make sure they match up correctly)
library(ggplot2)
head(mtcars)
adf <- aggregate(mpg ~ cyl, data = mtcars, FUN=mean)
mtcars$fcyl <- factor(mtcars$cyl)
levels(mtcars$fcyl) <- sprintf("%d \n %.1f",adf$cyl,adf$mpg)
# create the plot
ggplot(mtcars, aes(fcyl)) + geom_bar() + theme_bw() +
theme(strip.text.x = element_text(size = 20, face="bold"))+
xlab("number of cyl") + ylab("Count")
yielding:
Code below plots random effects from a mixed effects model:
mtcarsSub <- mtcars[,c("wt", "drat", "cyl")]
library(lme4)
mtcarsME <- lmer(drat ~ (1|cyl) + wt, data=mtcarsSub)
mtcarsSub$fixed.effect <- predict(mtcarsME)
library(plyr)
l_ply(list(4, 6, 8), function(x) mtcarsSub[[ paste0("random.effect.cyl", x) ]] <<- mtcarsSub$fixed.effect + ranef(mtcarsME)$cyl[as.character(x),])
library(ggplot2)
ggplot(mtcarsSub, aes(wt, drat, color=factor(cyl))) +
geom_point() +
geom_line(aes(wt, fixed.effect), color="black", size=2) +
geom_line(aes(wt, random.effect.cyl4), size=2) +
geom_line(aes(wt, random.effect.cyl6), size=2) +
geom_line(aes(wt, random.effect.cyl8), size=2)
How can I programatically make each random effect line the same colour as the colours displayed for cyl? Therefore, the random effect line for level 4 of cyl should be red, level 6 of cyl should be green and level 8 of cyl should be blue. I dont want to specify color="red" etc in geom_line().
I would suggest to make new data frame for the random effects. For this I use function ldply() and the function you made to calculate random effects for each level. Additionally in this new data frame added column wt and cyl. wt will contain all wt values from mtcarsSub data frame repeated for each level. cyl will contain values 4, 6 and 8.
mt.rand<-ldply(list(4,6,8), function(x) data.frame(
wt=mtcarsSub$wt,
cyl=x,
rand=mtcarsSub$fixed.effect + ranef(mtcarsME)$cyl[as.character(x),]))
Now for the plotting use new data frame in one geom_line() call. As the new data frame also has cyl column it will be assigned the colors as for points.
ggplot(mtcarsSub, aes(wt, drat, color=factor(cyl))) +
geom_point() +
geom_line(aes(wt, fixed.effect), color="black", size=2)+
geom_line(data=mt.rand,aes(wt,rand),size=2)