I'm struggling combining the use of variables' labels (provided by the expsspackage) in a ggplot2plot from a function I've written to repeat it several times.
In other words, the following code works as expected.
data(mtcars)
library(expss)
library(ggplot2)
mtcars <- apply_labels(mtcars,
mpg = "MPG",
cyl = "CYL",
wt = "WEIGHT")
use_labels(mtcars, {
# from the example of the package's vignette
ggplot(..data) +
geom_point(aes(y = mpg, x = wt))
})
If I want to write a function like
myplot <- function(x,y) {
ggplot(data=mtcars) +
geom_point(aes(y = {{y}}, x = {{x}}))
}
myplot(mpg, cyl)
myplot(mpg, wt)
This works as appropriate as well.
But if I use
myplot <- function(x,y) {
use_labels(data=mtcars, {
ggplot(..data) +
geom_point(aes(y = y, x = x))
})
}
myplot("mpg", "cyl")
This does not work anymore, i.e. the plot is not correct and the labels are not shown.
I've tried
myplot <- function(x,y) {
use_labels(data=mtcars, {
ggplot(data=mtcars) +
geom_point(aes(y = mtcars[[y]], x = mtcars[[x]]))
})
}
myplot("mpg", "cyl")
Then the plot is correct, but the labels are not shown...
Much easier solution: the ggeasy package (https://rdrr.io/cran/ggeasy/man/easy_labs.html)
The following works perfectly:
myplot <- function(x,y) {
ggplot(data=mtcars) +
geom_point(aes(y = {{y}}, x = {{x}}))+
ggeasy::easy_labs(teach=TRUE)
}
myplot(mpg, cyl)
Related
How can you specify a facet parameter that is optional for facet_wrap(), without a weird additional label showing up?
For facet_wrap(), it works as expected when facets are specified. But if it's NULL, there is a weird (all) facet. Is it possible to get rid of that facet label without adding another parameter to the function?
foo_wrap <- function(x) {
ggplot(mtcars) +
aes(x = mpg, y = disp) +
geom_point() +
facet_wrap(vars({{ x }}))
}
foo_wrap (cyl) # cylinder facets
foo_wrap (NULL) # how to get rid of "(all)"?
How can you get rid of "(all)"?
Adding these examples as references in case people find this by searching
Below is an example function with optional facets for facet_grid(), where it works as expected:
foo_grid <- function(x) {
ggplot(mtcars) +
aes(x = mpg, y = disp) +
geom_point() +
facet_grid(rows=NULL, cols=vars({{ x }}))
}
foo_grid (cyl) # cylinder facets
foo_grid (NULL) # no facets, as expected
Here is an example with hard coded rows facetting. Note that you need to call vars():
foo_grid_am <- function(x) {
ggplot(mtcars) +
aes(x = mpg, y = disp) +
geom_point() +
facet_grid(rows=vars(am), cols=vars({{ x }}))
}
foo_grid_am (cyl) # automatic-manual x cylinder facets
One option would be to add a conditional facet layer where I use rlang::quo_is_null(rlang::enquo(x)) to check whether a faceting variable was provided or not:
Note: I made NULL the default.
library(ggplot2)
library(rlang)
foo_wrap <- function(x = NULL) {
facet_layer <- if (!rlang::quo_is_null(rlang::enquo(x))) facet_wrap(vars({{ x }}))
ggplot(mtcars) +
aes(x = mpg, y = disp) +
geom_point() +
facet_layer
}
foo_wrap(cyl)
foo_wrap(NULL)
I'm trying to plot the line graph for X=date Y=column which is XS1-XS10.
I use the lapply with a next function
plot_data_column = function (column) {
ggplot(data= excess_return, aes(y=column,x=date)) +
geom_line()+
geom_hline(yintercept = mean(excess_return$column), color="red")+
ggtitle(column)+
theme_minimal()
}
and then use lapply to plug in the columns of the dataset into the ggplot.
ggplots = lapply(excess_return[,1:10], plot_data_column)
My problem occurs with geom_hline which doesn't recognize the column and ggtitle(column).
P.s I have tried also like this
ggplots = lapply(colnames(excess_return[,1:10]), plot_data_column)
I wonder why R doesn't accept the XS1 as it were written manually by me?
because this code perfectly works.
ggplot(data= excess_return, aes(y=XS1,x=date)) +
geom_line()+
geom_hline(yintercept = mean(excess_return$XS1), color="red")+
theme_minimal()
The only thing what i want to is to iterate the XS1 to XS10.
Thank you for support
you can adapt this to your data strucutre:
plot_data_column = function (.data, .column) {
ggplot2::ggplot(data= .data, ggplot2::aes(y=!!dplyr::sym(.column),x = Petal.Width)) +
ggplot2::geom_line() +
ggplot2::geom_hline(yintercept = .data %>%
dplyr::pull(!!dplyr::sym(.column)) %>%
mean(),
color="red")+
ggplot2::ggtitle(.column) +
ggplot2::theme_minimal()
}
plots <- names(iris)[1:3] %>%
purrr::map(~plot_data_column(.data = iris, .column = .x))
You need to change the names(iris)[1:3] to your names names(excess_return)[1:10] and x = Petal.Width to x = date.
Another option:
library(tidyverse)
custom_ggplot_function <- function(var, var_name) {
ggplot(mtcars, aes(x = disp, y = var)) +
geom_line() +
geom_hline(yintercept = mean(var), color = "red") +
labs(y = var_name) +
ggtitle(var_name) +
theme_minimal()
}
mtcars %>%
select(mpg, cyl, disp) %>%
map2(.y = names(.), ~ custom_ggplot_function(.x, .y))
I am trying to write a function that creates a barplot but I have trouble getting the fill aesthetic right.
If I use fill = !!x leads to Quosures can only be unquoted within a quasiquotation context.
and fill = x leads to Aesthetics must be either length 1 or the same as the data (4): fill
My Code:
genBar <- function(data, x, y) {
x <- enquo(x)
y <- enquo(y)
plot <- ggplot(data) +
geom_bar(aes(!!x, !!y),
stat = 'identity',
fill = <help>)
return(plot)
}
fill should be inside aes. Try :
library(ggplot2)
genBar <- function(data, x, y) {
plot <- ggplot(data) +
geom_bar(aes({{x}}, {{y}}, fill = {{x}}),
stat = 'identity')
return(plot)
}
genBar(mtcars, cyl, mpg)
If you want to pass column names as string use .data pronoun.
genBar <- function(data, x, y) {
plot <- ggplot(data) +
geom_bar(aes(.data[[x]], .data[[y]], fill = .data[[x]]),
stat = 'identity')
return(plot)
}
genBar(mtcars, "cyl", "mpg")
Are you looking for something like this?
library(dplyr)
library(ggplot2)
genBar <- function(data, x, y) {
x <- enquo(x)
y <- enquo(y)
plot <- ggplot(data) +
geom_bar(aes(!!x, !!y, fill = !!x),
stat = 'identity')
return(plot)
}
iris %>%
group_by(Species) %>%
summarize(Size = mean(Petal.Length)) %>%
genBar(Species, Size)
Created on 2020-12-04 by the reprex package (v0.3.0)
I'm plotting data marked up using haven semantics, i.e. variables and values have labels defined via attributes.
Often, these labels are also what I want in my axis titles and ticks.
library(ggplot2)
mtcars$mpg = haven::labelled(mtcars$mpg, labels = c("low" = 10, "high" = 30))
attributes(mtcars$mpg)$label = "miles per gallon"
ggplot(mtcars, aes(mpg, cyl)) + geom_point() +
scale_x_continuous(attributes(mtcars$mpg)$label,
breaks = attributes(mtcars$mpg)$labels,
labels = names(attributes(mtcars$mpg)$labels))
Could I write a helper that replaces that laborious scale_x_continuous statement with something that can more easily be iterated? E.g. something like
scale_x_continuous(label_from_attr, breaks = breaks_from_attr, labels = value_labels_from_attr). Or maybe even + add_labels_from_attributes() to replace the whole thing?
I'm aware that I can write/use helpers like Hmisc::label to slightly shorten the attribute-code above, but that's not what I want here.
I don't have a good scale, but you can use a function like this:
label_x <- function(p) {
b <- ggplot_build(p)
x <- b$plot$data[[b$plot$labels$x]]
p + scale_x_continuous(
attributes(x)$label,
breaks = attributes(x)$labels,
labels = names(attributes(x)$labels)
)
}
Then use as (+ won't do):
p <- ggplot(mtcars, aes(mpg, cyl)) + geom_point()
label_x(p)
Alternatively, use a pipe:
mtcars %>% { ggplot(., aes(mpg, cyl)) + geom_point() } %>% label_x()
Old solution
use_labelled <- function(l, axis = "x") {
if (axis == "x") {
scale_x_continuous(attributes(l)$label,
breaks = attributes(l)$labels,
labels = names(attributes(l)$labels))
}
if (axis == "y") {
scale_y_continuous(attributes(l)$label,
breaks = attributes(l)$labels,
labels = names(attributes(l)$labels))
}
}
Then you just give:
ggplot(mtcars, aes(mpg, cyl)) + geom_point() + use_labelled(mtcars$cyl)
Or for the y-axis:
ggplot(mtcars, aes(cyl, mpg)) + geom_point() + use_labelled(mtcars$cyl, "y")
Another approach is to write a wrapper for ggplot() that has its own class. Then attributes have full visibility when the corresponding print method is called. See ?ag.print from package 'yamlet' (0.2.1).
library(ggplot2)
library(yamlet)
library(magrittr)
mtcars$disp %<>% structure(label = 'displacement', unit = 'cu. in.')
mtcars$mpg %<>% structure(label = 'mileage', unit = 'miles/gallon')
mtcars$am %<>% factor(levels = c(0,1), labels = c('automatic','manual'))
mtcars$am %<>% structure(label = 'transmission')
agplot(mtcars, aes(disp, mpg, color = am)) + geom_point()
If I try to manually compose some elements of a ggplot2 plot, it works just fine:
> p <- ggplot(aes(x = mpg, y = hp), data = mtcars)
> p + geom_vline(xintercept = 20) + geom_point(data = mtcars)
But if I try to bundle some of the composition into a function, I get an error:
> myFunction <- function() {
+ return(
+ geom_vline(xintercept = 20) + geom_point(data = mtcars)
+ )
+ }
> p <- ggplot(aes(x = mpg, y = hp), data = mtcars)
> p + myFunction()
Error in geom_vline(xintercept = 20) + geom_point(data = mtcars) :
non-numeric argument to binary operator
Am I missing something in ggplot2 notation for properly combining ggplot2 elements within a function body?
ggplot2 supports "list" of the elements:
myFunction <- function()
list(geom_vline(xintercept = 20),
geom_point(data = mtcars))
p <- ggplot(aes(x = mpg, y = hp), data = mtcars)
p + myFunction()
you can keep in a list any piece that ggplot2 function returns, including labs(), opts(), etc, and then use "+" for bind ggplot2 base layer and the piece in the list.
Probably this feature is not widely known , but is very useful when anyone want to re-use a piece of elements.