Add titles to ggplots created with map() - r

What's the easiest way to add titles to each ggplot that I've created below using the map function? I want the titles to reflect the name of each data frame - i.e. 4, 6, 8 (cylinders).
Thanks :)
mtcars_split <-
mtcars %>%
split(mtcars$cyl)
plots <-
mtcars_split %>%
map(~ ggplot(data=.,mapping = aes(y=mpg,x=wt)) +
geom_jitter()
# + ggtitle(....))
plots

Use map2 with names.
plots <- map2(
mtcars_split,
names(mtcars_split),
~ggplot(data = .x, mapping = aes(y = mpg, x = wt)) +
geom_jitter() +
ggtitle(.y)
)
Edit: alistaire pointed out this is the same as imap
plots <- imap(
mtcars_split,
~ggplot(data = .x, mapping = aes(y = mpg, x = wt)) +
geom_jitter() +
ggtitle(.y)
)

Perhaps you'd be interested in using facet_wrap instead
ggplot(mtcars, aes(y=mpg, x=wt)) + geom_jitter() + facet_wrap(~cyl)

You can use purrr::map2():
mtcars_split <- mtcars %>% split(mtcars$cyl)
plots <- map2(mtcars_split, titles,
~ ggplot(data=.x, aes(mpg,wt)) + geom_jitter() + ggtitle(.y)
)
EDIT
Sorry duplicated with Paul's answer.

Related

Same y-axis range with ggarrange if I am already using facets and cannot use them again

my question is basically a follow-up to this question. However, the problem is that in the said question the answer completely bypasses the fact that ggarrange is used and instead transfers the whole issue to be handled by the facets functionality of ggplot.
This doesn't work for me since I already am using facets in the sub-plots and I cannot use them again.
Here is some example code. I am wondering how to achieve that the two plots which are joined with ggarrange have the same range of y-axis (of course, not setting the limits manually).
mtcars %>%
group_split(vs) %>%
map(~ggplot(., aes(x = mpg, y = wt)) +
geom_point() +
facet_grid(rows = vars(am), cols = vars(gear))) %>%
ggarrange(plotlist = .)
As you can see, the left image's y-axis ranges from 2 to 5, while the right plot's y-axis ranges from 1.5 to 3.5. How can I make them be the same?
I'm once again arguing for abandoning the 'ggarrange' approach, this time in favour of the {patchwork} package, which allows you to apply an operation to all previous plots. In this case, we can use & scale_y_continuous(limits = ...) to set the limits for all plots.
library(ggplot2)
library(dplyr)
library(purrr)
library(patchwork)
mtcars %>%
group_split(vs) %>%
map(~ggplot(., aes(x = mpg, y = wt)) +
geom_point() +
facet_grid(rows = vars(am), cols = vars(gear))) %>%
wrap_plots() &
scale_y_continuous(limits = range(mtcars$wt))
Created on 2022-12-08 by the reprex package (v2.0.0)
One option would be to compute and add the range of your x and y variables to your dataset before splitting, which could then be used to set the limits.
library(dplyr)
library(ggplot2)
library(ggpubr)
library(purrr)
mtcars %>%
mutate(across(c(mpg, wt), list(range = ~list(range(.x))))) %>%
group_split(vs) %>%
map(~ggplot(., aes(x = mpg, y = wt)) +
geom_point() +
scale_x_continuous(limits = .$mpg_range[[1]]) +
scale_y_continuous(limits = .$wt_range[[1]]) +
facet_grid(rows = vars(am), cols = vars(gear))) %>%
ggarrange(plotlist = .)

lapply function to create many plots in Ggplot

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

Shorthand functions for multiple geoms in ggplot2

I would like to create shorthand notations or functions that combines multiple geoms for ggplot.
For example, instead of
mtcars %>%
ggplot(aes(x = cyl, y = mpg)) +
geom_point() +
geom_smooth(method = "lm") +
ggpubr::stat_cor()
I would like to be able to create a function to combine the geoms like so
lm_and_cor <- function() {
geom_smooth(method = "lm", se = FALSE) +
stat_cor()
}
mtcars %>%
ggplot(aes(x = cyl, y = mpg)) +
geom_point() +
lm_and_cor()
I am aware that I can create functions that does all of the plotting, basically
plot_data <- function(x) {
x %>%
ggplot(aes(x = cyl, y = mpg)) +
geom_point() +
geom_smooth(method = "lm") +
ggpubr::stat_cor()
}
which to be fair does what I want, to some degree. However, I would instead like to combine multiple geoms in a single function, as the underlying geom (e.g. point, lines, etc.) will not always be the same. Is this doable, and is it feasible?
With ggplot2 you can use list of elements:
lm_and_cor <- function()
list(geom_smooth(method = "lm", se = FALSE),
ggpubr::stat_cor()
)
mtcars %>%
ggplot(aes(x = cyl, y = mpg)) +
geom_point() +
lm_and_cor()
Output:
Do you mean something like this?
You can store multiple geom in a list object.
Edit: I misunderstand the question. This should meet the expectation.
data(iris)
library(ggplot2)
x <- list(geom_point(), geom_line())
ggplot(iris, aes(Sepal.Length, Sepal.Width)) + x
Or if you want to make a function to plot by column use this {{variable}}.
library(dplyr)
plotting <- function(data, x, y){
data %>%
ggplot(aes({{x}}, {{y}})) +
geom_point() +
geom_smooth(method = "lm")}
plotting(iris, Sepal.Length, Sepal.Width)

unable to set xlim and ylim using min() and max() in ggplot

I am missing something crucial here and can't see it.
Why does min and max not work to set the axis limits?
mtcars %>%
select(mpg, cyl, disp, wt) %>%
filter(complete.cases(disp)) %>%
ggplot() +
geom_point(aes(x=mpg, y=disp, colour=cyl), size=3) +
xlim(min(mpg, na.rm=TRUE),max(mpg, na.rm=TRUE)) +
ylim(min(disp, na.rm=TRUE),max(disp, na.rm=TRUE)) +
scale_colour_gradient(low="red",high="green", name = "cyl")
This works:
mtcars %>%
select(mpg, cyl, disp, wt) %>%
filter(complete.cases(disp)) %>%
ggplot() +
geom_point(aes(x=mpg, y=disp, colour=cyl), size=3) +
# xlim(min(mpg, na.rm=TRUE),max(mpg, na.rm=TRUE)) +
# ylim(min(disp, na.rm=TRUE),max(disp, na.rm=TRUE)) +
scale_colour_gradient(low="red",high="green", name = "cyl")
ggplot cannot access the column values in the way that dplyr can.
You need to add in the data:
mtcars %>%
select(mpg, cyl, disp, wt) %>%
filter(complete.cases(disp)) %>%
ggplot() +
geom_point(aes(x=mpg, y=disp, colour=cyl), size=3) +
xlim(min(mtcars$mpg, na.rm=TRUE),max(mtcars$mpg, na.rm=TRUE)) +
ylim(min(mtcars$disp, na.rm=TRUE),max(mtcars$disp, na.rm=TRUE)) +
scale_colour_gradient(low="red",high="green", name = "cyl")
You can't reference column names in ggplot objects except inside aes() and in a formula or vars() in a facet_* function. But the helper function expand_scale is there to help you expand the scales in a more controlled way.
For example:
# add 1 unit to the x-scale in each direction
scale_x_continuous(expand = expand_scale(add = 1))
# have the scale exactly fit the data, no padding
scale_x_continuous(expand = expand_scale(0, 0))
# extend the scale by 10% in each direction
scale_x_continuous(expand = expand_scale(mult = .1))
See ?scale_x_continuous and especially ?expand_scale for details. It's also possible to selectively pad just the top or just the bottom of each scale, there are examples in ?expand_scale.

ggplot using purrr map() to plot same x with multiple y's

I want to create multiple plots that have the same x but different y's using purrr package methodology. That is, I would like to use the map() or walk() functions to perform this.
Using mtcars dataset for simplicity.
ggplot(data = mtcars, aes(x = hp, y = mpg)) + geom_point()
ggplot(data = mtcars, aes(x = hp, y = cyl)) + geom_point()
ggplot(data = mtcars, aes(x = hp, y = disp)) + geom_point()
edit
So far I have tried
y <- list("mpg", "cyl", "disp")
mtcars %>% map(y, ggplot(., aes(hp, y)) + geom_point()
This is one possibility
ys <- c("mpg","cyl","disp")
ys %>% map(function(y)
ggplot(mtcars, aes(hp)) + geom_point(aes_string(y=y)))
It's just like any other map function, you just need to configure your aesthetics properly in the function.
I've made a bit more general function for this, because it's part of EDA protocol (Zuur et al., 2010). This article from Ariel Muldoon helped me.
plotlist <- function(data, resp, efflist) {
require(ggplot2)
require(purrr)
y <- enquo(resp)
map(efflist, function(x)
ggplot(data, aes(!!sym(x), !!y)) +
geom_point(alpha = 0.25, color = "darkgreen") +
ylab(NULL)
)
}
where:
data is your dataframe
resp is response variable
efflist is a char of effects (independent variables)
Of course, you may change the geom and/or aesthetics as it needs. The function returns a list of plots which you can pass to e.g. cowplot or gridExtra as in example:
library(gridExtra)
library(dplyr) # just for pipes
plotlist(mtcars, hp, c("mpg","cyl","disp")) %>%
grid.arrange(grobs = ., left = "HP")

Resources