Unlist column names and using it in facet_grid - r

I have a long list of column names that I want to use it in the facet_grid. I would like to select some column names and put + as facet_grid function require.
I have tried this with mtcars but couldn't figure it out why unlist or paste are not working.
names=paste(unlist(names(mtcars)[c(1,3,5)]),sep='+')
library(ggplot2)
ggplot(mtcars, aes("", hp)) +
geom_boxplot(width=0.7, position=position_dodge(0.7)) +
theme_bw() +
facet_grid(. ~ names,switch = 'both',labeller = label_both)
Error in combine_vars(data, params$plot_env, cols, drop = params$drop)
: At least one layer must contain all variables used for facetting

You can use a string inside facet_grid, but you have to provide the whole formula (including the tilde) as a string.
names <- paste(c(". ~ ", names(mtcars)[c(1,3,5)]), collapse='+')
ggplot(mtcars, aes("", hp)) +
geom_boxplot(width=0.7, position=position_dodge(0.7)) +
theme_bw() +
facet_grid(names, switch = 'both', labeller = label_both)

Related

R - when using facet_wrap, access the factor within the current facet

Consider the following (nonsensical, but working) plot:
ggplot(mtcars,
aes(x = as.factor(cyl), y = hp)) +
geom_boxplot() +
facet_wrap( ~ am) +
geom_text(label = "test")
I'd like to pass the value of am within each facet to the label argument of geom_text. So all the labels within the left facet would read "0", all the labels within the right facet would read "1".
How could I achieve this? Simply passing am doesn't work, and neither does .$am.
Sure, just provide the label inside mapping, like this:
... +
geom_text(aes(label = am))
You could pass it as a vector like this:
library(ggplot2)
ggplot(mtcars, aes(x = as.factor(cyl), y = hp)) +
geom_boxplot() +
facet_wrap( ~ am) +
geom_text(label = mtcars$am)
Created on 2022-11-03 with reprex v2.0.2

changing the facet_wrap labels using labeller in ggplot2

In my ggplot below, I'm trying to change the 10 facet labels of facet_wrap using labeller(sch.id=paste0("sch.id:", unique(ten$sch.id))).
However, the plot shows NA instead of the correct facet labels, I wonder what the fix is?
library(ggplot2)
hsb <- read.csv('https://raw.githubusercontent.com/rnorouzian/e/master/hsb.csv')
ten <- subset(hsb, sch.id %in% unique(sch.id)[1:10])
p <- ten %>% ggplot() + aes(ses, math) + geom_point() +
facet_wrap(~sch.id) + geom_smooth(method = "lm", se = FALSE)
p + facet_wrap(~sch.id, labeller = labeller(sch.id=paste0("sch.id:", unique(ten$sch.id)))) ## HERE ##
The problem seems to be that you are passing a variable to the labeller function but facet_wrap already passes its own faceting variable. A conflict occurs and the result are NA's.
The solution is to create a labeller function as a function of a variable x (or any other name as long as it's not the faceting variables' names) and then coerce to labeller with as_labeller.
Note that there is no need for unique, just like there is no need for it in the facet_wrap formula.
p <- ten %>% ggplot() + aes(ses, math) + geom_point() +
geom_smooth(method = "lm", formula = y ~ x, se = FALSE)
cust_labeller <- function(x) paste0("sch.id:", x)
p + facet_wrap(~ sch.id,
labeller = as_labeller(cust_labeller)) ## HERE ##
I think the easiest way would be to change sch.id before plotting.
library(ggplot2)
ten$sch.id <- paste0("sch.id:", ten$sch.id)
ggplot(ten) + aes(ses, math) +
geom_point() +
geom_smooth(method = "lm", se = FALSE) +
facet_wrap(~sch.id)
If you don't want to modify your data and want to use the labeller argument you can create a named vector and use it in labeller.
cust_label <- setNames(paste0("sch.id:", unique(ten$sch.id)), unique(ten$sch.id))
ggplot(ten) + aes(ses, math) +
geom_point() +
geom_smooth(method = "lm", se = FALSE) +
facet_wrap(~sch.id, labeller = as_labeller(cust_label))

R facet labels with expressions using label_parsed

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)

Label with mathematical expressions in two line with facet_grid for two grids in ggplot2

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)"

Boxplot show the value of mean

In this boxplot we can see the mean but how can we have also the number value on the plot for every mean of every box plot?
ggplot(data=PlantGrowth, aes(x=group, y=weight, fill=group)) + geom_boxplot() +
stat_summary(fun.y=mean, colour="darkred", geom="point",
shape=18, size=3,show_guide = FALSE)
First, you can calculate the group means with aggregate:
means <- aggregate(weight ~ group, PlantGrowth, mean)
This dataset can be used with geom_text:
library(ggplot2)
ggplot(data=PlantGrowth, aes(x=group, y=weight, fill=group)) + geom_boxplot() +
stat_summary(fun=mean, colour="darkred", geom="point",
shape=18, size=3, show.legend=FALSE) +
geom_text(data = means, aes(label = weight, y = weight + 0.08))
Here, + 0.08 is used to place the label above the point representing the mean.
An alternative version without ggplot2:
means <- aggregate(weight ~ group, PlantGrowth, mean)
boxplot(weight ~ group, PlantGrowth)
points(1:3, means$weight, col = "red")
text(1:3, means$weight + 0.08, labels = means$weight)
You can use the output value from stat_summary()
ggplot(data=PlantGrowth, aes(x=group, y=weight, fill=group))
+ geom_boxplot()
+ stat_summary(fun.y=mean, colour="darkred", geom="point", hape=18, size=3,show_guide = FALSE)
+ stat_summary(fun.y=mean, colour="red", geom="text", show_guide = FALSE,
vjust=-0.7, aes( label=round(..y.., digits=1)))
You can also use a function within stat_summary to calculate the mean and the hjust argument to place the text, you need a additional function but no additional data frame:
fun_mean <- function(x){
return(data.frame(y=mean(x),label=mean(x,na.rm=T)))}
ggplot(PlantGrowth,aes(x=group,y=weight)) +
geom_boxplot(aes(fill=group)) +
stat_summary(fun.y = mean, geom="point",colour="darkred", size=3) +
stat_summary(fun.data = fun_mean, geom="text", vjust=-0.7)
The Magrittr way
I know there is an accepted answer already, but I wanted to show one cool way to do it in single command with the help of magrittr package.
PlantGrowth %$% # open dataset and make colnames accessible with '$'
split(weight,group) %T>% # split by group and side-pipe it into boxplot
boxplot %>% # plot
lapply(mean) %>% # data from split can still be used thanks to side-pipe '%T>%'
unlist %T>% # convert to atomic and side-pipe it to points
points(pch=18) %>% # add points for means to the boxplot
text(x=.+0.06,labels=.) # use the values to print text
This code will produce a boxplot with means printed as points and values:
I split the command on multiple lines so I can comment on what each part does, but it can also be entered as a oneliner. You can learn more about this in my gist.

Resources