'How to use a variable to specify column name in ggplot
I have a ggplot command
ggplot( rates.by.groups, aes(x=name, y=rate, colour=majr, group=majr) )
inside a function. But I would like to be able to use a parameter of the function to pick out the column to use as colour and group. I.e. I would like something like this
f <- function( column ) {
...
ggplot( rates.by.groups, aes(x=name, y=rate, colour= ??? , group=??? ) )
}
So that the column used in the ggplot is determined by the parameter. E.g. for f("majr") we get the effect of
ggplot( rates.by.groups, aes(x=name, y=rate, colour=majr, group=majr) )
but for f("gender") we get the effect of
ggplot( rates.by.groups, aes(x=name, y=rate, colour=gender, group=gender) )
Some things I tried:
ggplot( rates.by.groups, aes(x=name, y=rate, colour= columnName , group=columnName ) )
did not work. Nor did
e <- environment()
ggplot( rates.by.groups, aes(x=name, y=rate, colour= columnName , group=columnName ), environment=e )
Solution 1:[1]
You can use aes_string
:
f <- function( column ) {
...
ggplot( rates.by.groups, aes_string(x="name", y="rate", colour= column,
group=column ) )
}
as long as you pass the column to the function as a string (f("majr")
rather than f(majr)
). Also note that we changed the other columns, "name"
and "rate"
, to be strings.
If for whatever reason you'd rather not use aes_string
, you could change it to (the somewhat more cumbersome):
ggplot( rates.by.groups, aes(x=name, y=rate, colour= get(column),
group=get(column) ) )
Solution 2:[2]
From the release notes of ggplot2 V3.0.0
:
aes() now supports quasiquotation so that you can use !!, !!!, and :=. This replaces aes_() and aes_string() which are now soft-deprecated (but will remain around for a long time).
The idiomatic way now would be to convert to a symbol the string that the variable contains, using sym()
(which is almost the same as base aliases as.name()
/ as.symbol()
), and unquote it using !!
Simulating OP's data we can do :
library(tidyverse)
rates.by.groups <- data.frame(
name = LETTERS[1:3],
rate = 1:3,
mjr = LETTERS[c(4,4,5)],
gender = c("M","F","F")
)
f <- function(column) {
column <- sym(column)
ggplot(rates.by.groups,
aes(x = name,
y = rate,
fill = !!column,
group = !!column)) +
geom_col()
}
f("gender")
f("mjr")
x <- "gender"
f(x)
If we'd rather feed raw names to the function we can do:
f2 <- function(column) {
column <- ensym(column)
ggplot(rates.by.groups,
aes(x = name,
y = rate,
fill = !!column,
group = !!column)) +
geom_col()
}
It will work with names a.k.a. symbols AND with string literals
f2(gender)
f2(mjr)
f2("gender")
f2("mjr")
As Lionel says about ensym()
:
it's meant to mimic the syntax of arguments where you can supply both in the LHS, e.g. list(bare = 1, "quoted" = 2)
A note on enquo()
enquo()
quotes the expression (not necessarily a symbol) fed to the argument, it doesn't convert a string literal to a symbol as ensym()
does so it might be less adapted here, but we can do :
f3 <- function(column) {
column <- enquo(column)
ggplot(rates.by.groups,
aes(x = name,
y = rate,
fill = !!column,
group = !!column)) +
geom_col()
}
f3(gender)
f2(mjr)
Solution 3:[3]
Another option (ggplot2 > 3.0.0
) is to use the tidy evaluation pronoun .data
to slice the chosen variable/column from the rates.by.groups
data frame.
See also this answer
library(ggplot2)
theme_set(theme_classic(base_size = 14))
# created by @Moody_Mudskipper
rates.by.groups <- data.frame(
name = LETTERS[1:3],
rate = 1:3,
mjr = LETTERS[c(4, 4, 5)],
gender = c("M", "F", "F")
)
f1 <- function(df, column) {
gg <- ggplot(df,
aes(x = name,
y = rate,
fill = .data[[column]],
group = .data[[column]])) +
geom_col() +
labs(fill = column)
return(gg)
}
plot_list <- lapply(list("gender", "mjr"), function(x){ f1(rates.by.groups, x) })
plot_list
#> [[1]]
#>
#> [[2]]
# combine all plots
library(egg)
ggarrange(plots = plot_list,
nrow = 2,
labels = c('A)', 'B)'))
Created on 2019-04-04 by the reprex package (v0.2.1.9000)
Solution 4:[4]
Try using aes_string
instead of aes
.
Solution 5:[5]
Do two things
- Turn the column name into a symbol with
sym()
- Prepend
!!
to the symbol when you want to use it
Example
my_col <- sym("Petal.Length")
iris %>%
ggplot(aes(x = Sepal.Length, y = !!my_col)) +
geom_point()
Solution 6:[6]
Using aes_string
does fix this problem, but does face an issue when adding error bars geom_errorbar
. Below is a simple solution.
#Identify your variables using the names of your columns indie your dataset
xaxis <- "Independent"
yaxis <- "Dependent"
sd <- "error"
#Specify error bar range (in 'a-b' not 'a'-'b')
range <- c(yaxis, sd) #using c(X, y) allows use of quotation marks inside formula
yerrbar <- aes_string(ymin=paste(range, collapse='-'),
ymax=paste(range, collapse='+'))
#Build the plot
ggplot(data=Dataset, aes_string(x=xaxis, y=yaxis)) +
geom_errorbar(mapping=yerrbar, width=15, colour="#73777a", size = 0.5) +
geom_point (shape=21)
Bonus, you can also add facets to your plot using these lines inside the ggplot:
facet_grid(formula(paste(Variable1, "~", Variable2)))
This script was modified from this original post: ggplot2 - Error bars using a custom function
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | David Robinson |
Solution 2 | |
Solution 3 | |
Solution 4 | MDe |
Solution 5 | |
Solution 6 | Marty999 |