How to set alpha parameter for background in gganimate - r

I try to set alpha parameter 0.1 for background in my animation:
library(tidyverse)
library(gganimate)
mtcars_ <- rename(mtcars, mpg_ = mpg, disp_ = disp)
mtcars_$mpg = min(mtcars$mpg)
gg <- ggplot(mtcars, aes(x = mpg, y = disp)) + geom_density_2d_filled(data = mtcars_, aes(x = mpg_, y = disp_), alpha = 0.1) + geom_line() + theme(legend.position = "none")
gg
anim <- gg + transition_reveal(mpg) + shadow_wake(1)
anim
but alpha is 1 in final movie. How to fix it?
I need movie with this image

One way to do this would be to replicate the data you need for each frame. geom_density should see everything in every frame, but geom_line should only "see" the values up to the currently displayed value. We could accomplish that using tidyr::uncount to make copies of our data, and then creating a variable for geom_line that is NA when the value is too high for the current frame.
library(tidyverse)
library(gganimate)
distinct_mpg <- mtcars %>% distinct(mpg) %>% arrange(mpg) %>% pull(mpg)
mtcars_frames <- mtcars %>%
uncount(length(distinct_mpg), .id = "frame") %>%
mutate(mpg_reveal = distinct_mpg[frame],
mpg_shown = if_else(mpg <= mpg_reveal, mpg, NA_real_))
animate(
ggplot(mtcars_frames, aes(y = disp)) +
geom_density_2d_filled(aes(x = mpg), alpha = 0.1) +
geom_line(aes(x = mpg_shown, group = frame)) +
transition_states(frame) +
scale_fill_viridis_d(guide = NULL),
fps = 20
)

You might just want either to remove the shadow_wake() or set its wake_length closer to 0. The visual results will be similar, but the computation time will be higher for the shadow_wake() option.
gg1 <- ggplot(mtcars, aes(x = mpg, y = disp)) +
geom_density_2d_filled(data = mtcars_, aes(x = mpg_, y = disp_), alpha = 0.2) + geom_line() +
theme(legend.position = "none",
panel.background = element_blank())
gg1 + transition_reveal(mpg)
shadow_wake() removed
Or set shadow_wake to a lower setting.
gg2 <-
ggplot(data = mtcars, aes(x = mpg, y = disp)) +
geom_density_2d_filled(data = mtcars_ , aes(x = mpg_, y = disp_), alpha = 0.2) +
geom_line() +
theme(legend.position = "none",
panel.background = element_blank())
gg2 + transition_reveal(mpg) + shadow_wake(wake_length = 0.05)
shadow_wake() lowered

Related

How to add labels to multiple ggplot graphs (A, B, C)

I am trying to add the labels A, B, and C to the top left hand corner of each of these graphs. I have tried cowplot::draw_plot_label(), but nothing seems to work. Can anyone help?
These A, B and C labels are not the main title of each plot.
# Packages
library(ggplot2)
library(gridExtra)
library(cowplot)
# 1st plot
p1 <- ggplot(data = new_data %>%
filter(Species =="Sharksucker_Remora")) +
scale_colour_manual(values=c(Sharksucker_Remora="black"), labels = c("Sharksucker Remora")) +
geom_line(mapping = aes(x = Date, y = Proportion, group = Species, colour = Species)) +
xlab("") +
ylab("Proportion") +
theme(legend.position="top") +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)) + labs(colour = ~italic(M.alfredi)~"Hitchhiker Species:") +
theme(legend.key=element_blank())
# 2nd plot
p2 <- ggplot(data = new_data %>%
filter(Species !="Sharksucker_Remora")) +
geom_line(mapping = aes(x = Date, y = Proportion, group = Species, colour = Species)) +
scale_colour_manual(values=c(Golden_Trevally="goldenrod2", Red_Snapper="firebrick2", Juvenile_Remora="darkolivegreen3"), labels = c("Juvenile Remora", "Golden Trevally", "Red Snapper")) +
xlab("") + ylab("Proportion") + labs(colour = "") + theme(legend.position="top") + theme(legend.key=element_blank()) +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))
# 3rd plot
p3 <- ggplot(data = new_data_counts) +
geom_bar(mapping = aes(x = Date, y = Count), stat =
'identity') +
xlab("Date (2015-2019)") + ylab("Total"~italic
(M.alfredi)~"Sightings") +
draw_plot_label(label =c("C") + theme(axis.text.x =
element_text(angle = 90, vjust = 0.5, hjust = 1))
# The grid
grid.arrange(p1,p2,p3)
I suggest you use labs(..., tag = ...) and theme(plot.tag = element_text()).
The code show how you can format the main title (here centered with hjust = 0.5) and the tag inside the theme() function. See the reproducible example, below:
# Packages
library(ggplot2)
library(gridExtra)
# library(cowplot) # not necessary here
# Plots
p1 <- ggplot() +
labs(title = "plot 1", tag = "A") +
theme(plot.title = element_text(hjust = 0.5),
plot.tag = element_text())
p2 <- ggplot() +
labs(title = "plot 2", tag = "B") +
theme(plot.title = element_text(hjust = 0.5),
plot.tag = element_text())
grid.arrange(p1, p2)
If you want the tag (A, B, C) to be inside the plotting area, this post suggest to use plot.tag.position = c(x, y). See for example:
p3 <- ggplot() +
labs(title = "plot 3", tag = "C") +
theme(plot.title = element_text(hjust = 0.5),
plot.tag = element_text(),
plot.tag.position = c(0.1, 0.8))
p3
Have you tried the package egg?
https://cran.r-project.org/web/packages/egg/vignettes/Overview.html
library(tidyverse)
library(magrittr)
data <- list()
for(i in 1:6) data[[i]] <- rnorm(100,0,1)
data %<>% bind_cols() %>% setNames(paste0("var",1:6))
p1 <- ggplot(data,aes(x = var1, y = var2)) + geom_point()
p2 <- ggplot(data,aes(x = var3, y = var4)) + geom_point()
p3 <- ggplot(data,aes(x = var5, y = var6)) + geom_point()
egg::ggarrange(p1,p2,p3,ncol = 1,
labels = c("A","B","C"))
Another option is using the patchwork package with plot_annotation which has the tag_levels argument which gives the possibility to add tags like letters or numbers. First a reproducible example with letters:
library(patchwork)
library(ggplot2)
p1 <- ggplot(mtcars) +
geom_point(aes(hp, disp)) +
ggtitle('Plot 1')
p2 <- ggplot(mtcars) +
geom_boxplot(aes(gear, mpg, group = gear)) +
ggtitle('Plot 2')
p1 + p2 & plot_annotation(tag_levels = 'A')
Created on 2022-08-21 with reprex v2.0.2
Another option with numbers where you change the tag_levels to "1" like this:
p1 + p2 & plot_annotation(tag_levels = '1')
Created on 2022-08-21 with reprex v2.0.2
As you can see, the tags have letters or numbers. Check the links above for more information and options.

How do I nudge geom text labels to the right with a chart with ggplotly?

I'd like to set the text on each of the columns in ggplot and they're bunching up altogether
this is my code
set.seed(1)
gg <-
iris[sample(300, 50), ] %>%
ggplot(aes(Species, Sepal.Length, label = Sepal.Length, fill = as.factor(Sepal.Width > 3))) +
geom_col(position = "dodge2") +
geom_text(position=position_dodge(width = .7),
vjust=-0.25)
ggplotly(gg)
Maybe I would suggest using same position style in geom_col() and geom_text():
library(plotly)
library(ggplot2)
set.seed(1)
#Plot
gg <-
iris[sample(300, 50), ] %>%
ggplot(aes(Species, Sepal.Length, label = Sepal.Length, fill = as.factor(Sepal.Width > 3))) +
geom_col(position = position_dodge2(0.9)) +
geom_text(position=position_dodge2(width = .9),
vjust=-0.5)
#Transform
ggplotly(gg)
Output:
With shared data, try this, you have to format the date to have dodged labels:
library(dplyr)
library(ggplot2)
library(plotly)
#Code
gg <- df %>%
mutate(first_month=factor(format(first_month,'%b-%m'),
levels = unique(format(first_month,'%b-%m')),
ordered = T)) %>%
ggplot(aes(x=first_month, y=customers,
label = customers, fill = plan_id,group=plan_id)) +
geom_bar(stat='identity',position = 'dodge')+
geom_text(aes(group=plan_id),position = position_dodge(0.9),vjust = -0.5)
#Plot 2
ggplotly(gg)
Output:

Adding boxplot below density plot

I'm new to ggplot and I'm trying to create this graph:
But actually, I'm just stuck here:
This is my code :
ggplot(diamonds) +
aes(x = carat, group = cut) +
geom_line(stat = "density", size = 1) +
theme_grey() +
facet_wrap(~cut, nrow = 5, strip.position = "right") +
geom_boxplot(aes())
Does someone know what I can do next?
Edit: As of ggplot2 3.3.0, this can be done in ggplot2 without any extension package.
Under the package's news, under new features:
All geoms and stats that had a direction (i.e. where the x and y axes
had different interpretation), can now freely choose their direction,
instead of relying on coord_flip(). The direction is deduced from
the aesthetic mapping, but can also be specified directly with the new
orientation argument (#thomasp85, #3506).
The following will now work directly (replacing all references to geom_boxploth / stat_boxploth in the original answer with geom_boxplot / stat_boxplot:
library(ggplot2)
ggplot(diamonds, aes(x = carat, y = -0.5)) +
# horizontal boxplots & density plots
geom_boxplot(aes(fill = cut)) +
geom_density(aes(x = carat), inherit.aes = FALSE) +
# vertical lines at Q1 / Q2 / Q3
stat_boxplot(geom = "vline", aes(xintercept = ..xlower..)) +
stat_boxplot(geom = "vline", aes(xintercept = ..xmiddle..)) +
stat_boxplot(geom = "vline", aes(xintercept = ..xupper..)) +
facet_grid(cut ~ .) +
scale_fill_discrete()
Original answer
This can be done easily with a horizontal boxplot geom_boxploth() / stat_boxploth(), found in the ggstance package:
library(ggstance)
ggplot(diamonds, aes(x = carat, y = -0.5)) +
# horizontal box plot
geom_boxploth(aes(fill = cut)) +
# normal density plot
geom_density(aes(x = carat), inherit.aes = FALSE) +
# vertical lines at Q1 / Q2 / Q3
stat_boxploth(geom = "vline", aes(xintercept = ..xlower..)) +
stat_boxploth(geom = "vline", aes(xintercept = ..xmiddle..)) +
stat_boxploth(geom = "vline", aes(xintercept = ..xupper..)) +
facet_grid(cut ~ .) +
# reproduce original chart's color scale (o/w ordered factors will result
# in viridis scale by default, using the current version of ggplot2)
scale_fill_discrete()
If you are limited to the ggplot2 package for one reason or another, it can still be done, but it would be less straightforward, since geom_boxplot() and geom_density() go in different directions.
Alternative 1: calculate the box plot's coordinates, & flip them manually before passing the results to ggplot(). Add a density layer in the normal way:
library(dplyr)
library(tidyr)
p.box <- ggplot(diamonds, aes(x = cut, y = carat)) + geom_boxplot()
p.box.data <- layer_data(p.box) %>%
select(x, ymin, lower, middle, upper, ymax, outliers) %>%
mutate(cut = factor(x, labels = levels(diamonds$cut), ordered = TRUE)) %>%
select(-x)
ggplot(p.box.data) +
# manually plot flipped boxplot
geom_segment(aes(x = ymin, xend = ymax, y = -0.5, yend = -0.5)) +
geom_rect(aes(xmin = lower, xmax = upper, ymin = -0.75, ymax = -0.25, fill = cut),
color = "black") +
geom_point(data = . %>% unnest(outliers),
aes(x = outliers, y = -0.5)) +
# vertical lines at Q1 / Q2 / Q3
geom_vline(data = . %>% select(cut, lower, middle, upper) %>% gather(key, value, -cut),
aes(xintercept = value)) +
# density plot
geom_density(data = diamonds, aes(x = carat)) +
facet_grid(cut ~ .) +
labs(x = "carat") +
scale_fill_discrete()
Alternative 2: calculate the density plot's coordinates, & flip them manually before passing the results to ggplot(). Add a box plot layer in the normal way. Flip the whole chart:
p.density <- ggplot(diamonds, aes(x = carat, group = cut)) + geom_density()
p.density.data <- layer_data(p.density) %>%
select(x, y, group) %>%
mutate(cut = factor(group, labels = levels(diamonds$cut), ordered = TRUE)) %>%
select(-group)
p.density.data <- p.density.data %>%
rbind(p.density.data %>%
group_by(cut) %>%
filter(x == min(x)) %>%
mutate(y = 0) %>%
ungroup())
ggplot(diamonds, aes(x = -0.5, y = carat)) +
# manually flipped density plot
geom_polygon(data = p.density.data, aes(x = y, y = x),
fill = NA, color = "black") +
# box plot
geom_boxplot(aes(fill = cut, group = cut)) +
# vertical lines at Q1 / Q2 / Q3
stat_boxplot(geom = "hline", aes(yintercept = ..lower..)) +
stat_boxplot(geom = "hline", aes(yintercept = ..middle..)) +
stat_boxplot(geom = "hline", aes(yintercept = ..upper..)) +
facet_grid(cut ~ .) +
scale_fill_discrete() +
coord_flip()
Maybe this will help. Although need little upgrade :)
library(tidyverse)
library(magrittr)
library(wrapr)
subplots <-
diamonds$cut %>%
unique() %>%
tibble(Cut = .) %>%
mutate(rn = row_number() - 1) %$%
map2(
.x = Cut,
.y = rn,
~annotation_custom(ggplotGrob(
diamonds %>%
filter(cut == .x) %.>%
ggplot(data = .) +
aes(x = carat, fill = cut) +
annotation_custom(ggplotGrob(
ggplot(data = .) +
geom_boxplot(
aes(x = -1, y = carat),
fill = .y + 1
) +
coord_flip() +
theme_void() +
theme(plot.margin = margin(t = 20))
)) +
geom_line(stat = 'density', size = 1) +
theme_void() +
theme(plot.margin = margin(t = .y * 100 + 10, b = (4 - .y) * 100 + 40))
))
)
ggplot() + subplots

ggplot2 add sum to chart

Using mtcars as an example, I've produced some violin plots. I wanted to add two things to this chart:
for each group, list n
for each group, sum a third variable (e.g. wt)
I can do (1) with the geom_text code below although (n) is actually plotted on the x axis rather than off to the side.
But I can't work out how to do (2).
Any help much appreciated!
library(ggplot2)
library(gridExtra)
library(ggthemes)
result <- mtcars
ggplot(result, aes(x = gear, y = drat, , group=gear)) +
theme_tufte(base_size = 15) + theme(line=element_blank()) +
geom_violin(fill = "white") +
geom_boxplot(fill = "black", alpha = 0.3, width = 0.1) +
ylab("drat") +
xlab("gear") +
coord_flip()+
geom_text(stat = "count", aes(label = ..count.., y = ..count..))
You can add both of these annotations by creating them in your dataframe temporarily prior to graphing. Using the dplyr package, you can create two new columns, one with the count for each group, and one with the sum of wt for each group. This can then be piped directly into your ggplot using %>% (alternatively, you could save the new dataset and insert it into ggplot the way you have it). Then with some minor edits to your geom_text call and adding a second one, we can create the plot you want. The code looks like this:
library(ggplot2)
library(gridExtra)
library(ggthemes)
library(magrittr)
library(dplyr)
result <- mtcars
result %>%
group_by(gear) %>%
mutate(count = n(), sum_wt = sum(wt)) %>%
ggplot(aes(x = gear, y = drat, , group=gear)) +
theme_tufte(base_size = 15) + theme(line=element_blank()) +
geom_violin(fill = "white") +
geom_boxplot(fill = "black", alpha = 0.3, width = 0.1) +
ylab("drat") +
xlab("gear") +
coord_flip()+
geom_text(aes(label = paste0("n = ", count),
x = (gear + 0.25),
y = 4.75)) +
geom_text(aes(label = paste0("sum wt = ", sum_wt),
x = (gear - 0.25),
y = 4.75))
The new graph looks like this:
Alternatively, if you create a summary data frame named result_sum, then you can manually add that into the geom_text calls.
result <- mtcars %>%
mutate(gear = factor(as.character(gear)))
result_sum <- result %>%
group_by(gear) %>%
summarise(count = n(), sum_wt = sum(wt))
ggplot(result, aes(x = gear, y = drat, , group=gear)) +
theme_tufte(base_size = 15) +
theme(line=element_blank()) +
geom_violin(fill = "white") +
geom_boxplot(fill = "black", alpha = 0.3, width = 0.1) +
ylab("drat") +
xlab("gear") +
coord_flip()+
geom_text(data = result_sum, aes(label = paste0("n = ", count),
x = (as.numeric(gear) + 0.25),
y = 4.75)) +
geom_text(data = result_sum, aes(label = paste0("sum wt = ", sum_wt),
x = (as.numeric(gear) - 0.25),
y = 4.75))
This gives you this:
The benefit to this second method is that the text isn't bold like in the first graph. The bold effect occurs in the first graph due to the text being printed over itself for all observations in the dataframe.
Thanks to those who helped.... I used this in the end which plots the calculated values, one set of classes being text based so using vjust to position the vertical offset.
thanks again!
library(ggplot2)
library(gridExtra)
library(ggthemes)
results <- mtcars
results$gear <- as.factor(as.character(results$gear)) #Turn 'gear' to text to simulate classes, then factorise
result_sum <- results %>%
group_by(gear) %>%
summarise(count = n(), sum_wt = sum(wt))
ggplot(results, aes(x = gear, y = drat, group=gear)) +
theme_tufte(base_size = 15) + theme(line=element_blank()) +
geom_violin(fill = "white") +
geom_boxplot(fill = "black", alpha = 0.3, width = 0.1) +
ylab("drat") +
xlab("gear") +
coord_flip()+
geom_text(data = result_sum, aes(label = paste0("n = ", count), x = (gear), vjust= 0, y = 5.25)) +
geom_text(data = result_sum, aes(label = paste0("sum wt = ", round(sum_wt,0)), x = (gear), vjust= -2, y = 5.25))

Line height spacing for text in ggplot

I am trying to reduce the space between my long axis labels. In base R graphics I would use lheight, but is seems to have no effect in ggplot. Is there a ggplot equivalent?
Toy example to show the problem:
library("tidyverse")
df0 <- mtcars %>%
rownames_to_column("car") %>%
mutate(car = str_wrap(car, width = 10))
ggplot(data = df0, aes(x = car, y = mpg)) +
geom_bar(stat = "identity") +
coord_flip()
# has no effect
par(lheight = 0.5)
ggplot(data = df0, aes(x = car, y = mpg)) +
geom_bar(stat = "identity") +
coord_flip()
You may be looking for a combination of options. The closest to lheight is likely setting lineheight in element_text. I also made the font smaller, just to show options.
ggplot(data = df0, aes(x = car, y = mpg)) +
geom_bar(stat = "identity") +
coord_flip() +
theme(axis.text.y = element_text(lineheight = 0.5,
size = 6))
I had a same problem and I found a solution in reducing my list with: slice(1:40)
library("tidyverse")
df0 <- mtcars %>%
rownames_to_column("car") %>%
mutate(car = str_wrap(car, width = 10)) %>% slice(1:40)
ggplot(data = df0, aes(x = car, y = mpg)) +
geom_bar(stat = "identity") +
coord_flip()
# has no effect
par(lheight = 0.6)
ggplot(data = df0, aes(x = car, y = mpg)) +
geom_bar(stat = "identity") +
coord_flip()
ggplot(data = df0, aes(x = car, y = mpg)) +
geom_bar(stat = "identity") +
coord_flip() +
theme(axis.text.y = element_text(lineheight = 0.6, size = 5))
Another option is using guide_axis with n.dodge in scale_y_discrete to automatically dodge the labels like this:
library("tidyverse")
df0 <- mtcars %>%
rownames_to_column("car") %>%
mutate(car = str_wrap(car, width = 10))
ggplot(data = df0, aes(x = car, y = mpg)) +
geom_bar(stat = "identity") +
coord_flip() +
scale_y_discrete(guide = guide_axis(n.dodge = 2)) +
theme(axis.text.y = element_text(size = 5))
Created on 2022-10-20 with reprex v2.0.2

Resources