I have a list of ggplot2 plots, and I want to add the same title (Cars to each element of the list
library(ggplot2)
l <- list(
ggplot(data = mtcars, aes(x = mpg, y = cyl, col = am)) + geom_point(),
ggplot(data = mtcars, aes(x = mpg, y = disp, col = am)) + geom_point(),
ggplot(data = mtcars, aes(x = mpg, y = hp, col = am)) + geom_point()
)
Now I can refer to each element and add the title as follows
l[[1]] + ggtitle("Cars")
l[[2]] + ggtitle("Cars")
l[[3]] + ggtitle("Cars")
But is there a way to add the title to all elements in the list at once?
(Note: For one layer, this is rather silly, but I can extend such an example to multiple layers.)
User H 1 answered the question. As ggplot2 is different due to the layering, I was unsure if lapply() would work in this case. I now learned that the pipe symbol, + is a function to be applied over.
But adding a title and positioning the legend at the bottom has the desired effect:
q <- lapply(l, function(x) x + ggtitle("Cars") + theme(legend.position = "bottom"))
multiplot( plotlist = q, cols = 2)
where the code for multiplot() is found here.
Related
I have a set data that I need to add to levels of labels. One on a single chart within the facet grid, and one from a small dataframe with entries for for each chart.
In the example below you'll see that I can add to a single chart no problem but when I try to add from the df I get the error -
Error in FUN(X[[i]], ...) : object 'wt' not found
Preparation:
library(ggplot2)
p <- ggplot(mtcars, aes(mpg, wt)) + geom_line()
p <- p + facet_grid(. ~ cyl)
ann_text <- data.frame(mpg = 30,wt = 5,lab = "Text",
cyl = factor(8,levels = c("4","6","8")))
dfl <- data.frame(name = c('Jim',"Bob", "Sue"), r = c(-0.2, 0.5, -0.4))
Single Label:
p + geom_text(data = ann_text,label = "Text")
Multiple Labels:
p + geom_text(data = ann_text,label = "Text") +
geom_text(data = dfl, mpg = 30,wt = 5, aes(label = r))
The method I'm using is trying to recreate other examples I've found here on SO and elsewhere but I seem to be missing something.
It's not working in your second code because in the second geom_text, your mpg and wt in not in aes(). Also, these two variables are absent in your dfl.
If you wish to have better control of the labelling of your r variable, you can create extra columns in dfl specifying the x and y location of the label, and use these variables in geom_text(aes()).
Note that I have modified the y position in the second geom_text to avoid overlapping "0,2" with "Text".
library(ggplot2)
p <- ggplot(mtcars, aes(mpg, wt)) + geom_line()
p <- p + facet_grid(. ~ cyl)
ann_text <- data.frame(mpg = 30,wt = 5,lab = "Text",
cyl = factor(8,levels = c("4","6","8")))
dfl <- data.frame(name = c('Jim',"Bob", "Sue"), r = c(-0.2, 0.5, -0.4))
p + geom_text(data = ann_text,label = "Text") +
geom_text(data = dfl, aes(30, 4, label = r), check_overlap = T)
Created on 2022-05-06 by the reprex package (v2.0.1)
I know how to modify titles in ggplot without altering the original data. Suppose I have the following data frame and I want to change the labels. Then, I would do so in the following way
df <- data.frame(x = 1:4, y = 1:4, label = c(c("params[1]", "params[2]", "params[3]",
"params[4]")))
params_names <- list(
'params[1]'= "beta[11]",
'params[2]'= "beta[22]",
'params[3]'= "beta[33]",
'params[4]'= "beta[44]"
)
param_labeller <- function(variable, value){
params_names[value]
}
ggplot(df, aes(x=x,y=y)) +
geom_point() +
facet_grid(~label, labeller = param_labeller)
If I wanted to display the subscripts, I would just do this
ggplot(df, aes(x=x,y=y)) +
geom_point() +
facet_grid(~label, labeller = label_parsed)
How do I apply both operations at the same time?
I don't know exactly if this conflicts with you not wanting to "alter" the original data, but you add the labelling information to the factor itself:
df$label2 <- factor(df$label,
labels = c("beta[4]", "beta[24]", "beta[42]", "beta[43]"))
ggplot(df, aes(x = x, y = y)) +
geom_point() +
facet_grid( ~ label2, labeller = label_parsed)
This produces the following plot:
Plot with formatted facet labels
I am trying to write a function to plot graphs in a grid. I am using ggplot and facet grid. I am unable to pass the argument for facet grid. I wonder if anybody can point me in the right direction.
The data example:
Year = as.factor(rep(c("01", "02"), each = 4, times = 1))
Group = as.factor(rep(c("G1", "G2"), each = 2, times = 2))
Gender = as.factor(rep(c("Male", "Female"), times = 4))
Percentage = as.integer(c("80","20","50","50","45","55","15","85"))
df1 = data.frame (Year, Group, Gender, Percentage)
The code for the grid plot without function is:
p = ggplot(data=df1, aes(x=Year, y=Percentage, fill = Gender)) + geom_bar(stat = "identity")
p = p + facet_grid(~ Group, scales = 'free')
p
This produces a plot like the ones I want to do. However, when I put it into a function:
MyGridPlot <- function (df, x_axis, y_axis, bar_fill, fgrid){
p = ggplot(data=df1, aes(x=x_axis, y=y_axis, fill = bar_fill)) + geom_bar(stat = "identity")
p = p + facet_grid(~ fgrid, scales = 'free')
return(p)
}
And then run:
MyGridPlot(df1, df1Year, df1$Percentage, df1$Gender, df1$Group)
It comes up with the error:
Error: At least one layer must contain all faceting variables: `fgrid`.
* Plot is missing `fgrid`
* Layer 1 is missing `fgrid
I have tried using aes_string, which works for the x, y and fill but not for the grid.
MyGridPlot <- function (df, x_axis, y_axis, bar_fill, fgrid){
p = ggplot(data=df1, aes_string(x=x_axis, y=y_axis, fill = bar_fill)) + geom_bar(stat = "identity")
p = p + facet_grid(~ fgrid, scales = 'free')
return(p)
}
and then run:
MyGridPlot(df1, Year, Percentage, Gender, Group)
This produces the same error. If I delete the facet grid, both function code runs well, though no grid :-(
Thanks a lot for helping this beginner.
Gustavo
Your problem is that in your function, ggplot is looking for variable names (x_axis, y_axis, etc), but you're giving it objects (df1$year...).
There are a couple ways you could deal with this. Maybe the simplest would be to rewrite the function so that it expects objects. For example:
MyGridPlot <- function(x_axis, y_axis, bar_fill, fgrid){ # Note no df parameter here
df1 <- data.frame(x_axis = x_axis, y_axis = y_axis, bar_fill = bar_fill, fgrid = fgrid) # Create a data frame from inputs
p = ggplot(data=df1, aes(x=x_axis, y=y_axis, fill = bar_fill)) + geom_bar(stat = "identity")
p = p + facet_grid(~ fgrid, scales = 'free')
return(p)
}
MyGridPlot(Year, Percentage, Gender, Group)
Alternatively, you could set up the function with a data frame and variable names. There isn't really much reason to do this if you're working with individual objects the way you are here, but if you're working with a data frame, it might make your life easier:
MyGridPlot <- function(df, x_var, y_var, fill_var, grid_var){
# Need to "tell" R to treat parameters as variable names.
df <- df %>% mutate(x_var = UQ(enquo(x_var)), y_var = UQ(enquo(y_var)), fill_var = UQ(enquo(fill_var)), grid_var = UQ(enquo(grid_var)))
p = ggplot(data = df, aes(x = x_var, y = y_var, fill = fill_var)) + geom_bar(stat = "identity")
p = p + facet_grid(~grid_var, scales = 'free')
return(p)
}
MyGridPlot(df1, Year, Percentage, Gender, Group)
I am starting to get familiar with gganimate, but I want to extend my gifs further.
For instance, I can throw a frame on one variable in gganimate but what if I want to animate the process of adding entirely new layers/geoms/variables?
Here's a standard gganimate example:
library(tidyverse)
library(gganimate)
p <- ggplot(mtcars, aes(x = hp, y = mpg, frame = cyl)) +
geom_point()
gg_animate(p)
But what if I want the gif to animate:
# frame 1
ggplot(mtcars, aes(x = hp, y = mpg)) +
geom_point()
# frame 2
ggplot(mtcars, aes(x = hp, y = mpg)) +
geom_point(aes(color = factor(cyl)))
# frame 3
ggplot(mtcars, aes(x = hp, y = mpg)) +
geom_point(aes(color = factor(cyl), size = wt))
# frame 4
ggplot(mtcars, aes(x = hp, y = mpg)) +
geom_point(aes(color = factor(cyl), size = wt)) +
labs(title = "MTCARS")
How might this be accomplished?
You can manually add a frame aesthetic to each layer, though it will include the legends for all of the frames immediately (Intentionally, I believe, to keep ratios/margins, etc. correct:
saveAnimate <-
ggplot(mtcars, aes(x = hp, y = mpg)) +
# frame 1
geom_point(aes(frame = 1)) +
# frame 2
geom_point(aes(color = factor(cyl)
, frame = 2)
) +
# frame 3
geom_point(aes(color = factor(cyl), size = wt
, frame = 3)) +
# frame 4
geom_point(aes(color = factor(cyl), size = wt
, frame = 4)) +
# I don't think I can add this one
labs(title = "MTCARS")
gg_animate(saveAnimate)
If you want to be able to add things yourself, and even see how legends, titles, etc. move things around, you may need to step back to a lower-level package, and construct the images yourself. Here, I am using the animation package which allows you to loop through a series of plots, with no limitations (they need not be related at all, so can certainly show things moving the plot area around. Note that I believe this requires ImageMagick to be installed on your computer.
p <- ggplot(mtcars, aes(x = hp, y = mpg))
toSave <- list(
p + geom_point()
, p + geom_point(aes(color = factor(cyl)))
, p + geom_point(aes(color = factor(cyl), size = wt))
, p + geom_point(aes(color = factor(cyl), size = wt)) +
labs(title = "MTCARS")
)
library(animation)
saveGIF(
{lapply(toSave, print)}
, "animationTest.gif"
)
The gganimate commands in the earlier answers are deprecated as of 2021 and won't accomplish OP's task.
Building on Mark's code, you can now simply create a static ggplot object with multiple layered geoms and then add the gganimate::transition_layers function to create an animation that transitions from layer to layer within the static plot. Tweening functions like enter_fade() and enter_grow() control how elements change into and out of frames.
library(tidyverse)
library(gganimate)
anim <- ggplot(mtcars, aes(x = hp, y = mpg)) +
# Title
labs(title = "MTCARS") +
# Frame 1
geom_point() +
# Frame 2
geom_point(aes(color = factor(cyl))) +
# Frame 3
geom_point(aes(color = factor(cyl), size = wt)) +
# gganimate functions
transition_layers() + enter_fade() + enter_grow()
# Render animation
animate(anim)
the animation package doesn't force you to specify frames in the data. See the example at the bottom of this page here, where an animation is wrapped in a big saveGIF() function. You can specify the duration of individual frames and everything.
The drawback to this is that, unlike the nice gganimate functions, the basic frame-by-frame animation wont hold the plot dimensions/legend constant. But if you can hack your way into displaying exactly what you want for each frame, the basic animation package will serve you well.
I am trying to overlay multiple trend lines using the geom_smooth() in R. I currently have this code.
ggplot(mtcars2, aes(x=Displacement, y = Variable, color = Variable))
+ geom_point(aes(x=mpg, y = hp, col = "Power"))
+ geom_point(aes(x=mpg, y = drat, col = "Drag Coef."))
(mtcars2 is the normalized form of mtcars)
Which give me this graph.
I am trying to use the geom_smooth(method='lm') to draw two trend lines for the the two variables. Any ideas?
(Bonus: I would also like to implement the 'shape=1' paramater to differentiate the varaibles if possible. The following method does not work)
geom_point(aes(x=mpg, y = hp, col = "Power", shape=2))
Update
I managed to do this.
ggplot(mtcars2, aes(x=Displacement, y = Variable, color = Variable))
+ geom_point(aes(x=disp, y = hp, col = "Power"))
+ geom_point(aes(x=disp, y = mpg, col = "MPG"))
+ geom_smooth(method= 'lm',aes(x=disp, y = hp, col = "Power"))
+ geom_smooth(method= 'lm',aes(x=disp, y = mpg, col = "MPG"))
It looks like this.
But this is an ugly piece of code. If anybody can make this code look prettier, it'd be great. Also, I have not yet been able to implement the 'shape=2' parameter.
It seems like you're making your life harder than it needs to be...you can pass in additional parameters into aes() such as group and shape.
I don't know if I got your normalization right, but this should give you enough to get going in the right direction:
library(ggplot2)
library(reshape2)
#Do some normalization
mtcars$disp_norm <- with(mtcars, (disp - min(disp)) / (max(disp) - min(disp)))
mtcars$hp_norm <- with(mtcars, (hp - min(hp)) / (max(hp) - min(hp)))
mtcars$drat_norm <- with(mtcars, (drat - min(drat)) / (max(drat) - min(drat)))
#Melt into long form
mtcars.m <- melt(mtcars, id.vars = "disp_norm", measure.vars = c("hp_norm", "drat_norm"))
#plot
ggplot(mtcars.m, aes(disp_norm, value, group = variable, colour = variable, shape = variable)) +
geom_point() +
geom_smooth(method = "lm")
Yielding: