Reproduce a plot using ggplot - r

I am trying to reproduce a plot using ggplot.
The code I got from the textbook:
skeptic<-c(1,1.171,1.4,1.8,2.2,2.6,3,3.4,3.8,3.934,4.2,
4.6,5,5.4,5.8,6.2,6.6,7,7.4,7.8,8.2,8.6,9)
effect<-c(-.361,-.327,-.281,-.200,-.120,-.039,.041,.122,.202,.229,.282,
.363,.443,.524,.604,.685,.765,.846,.926,1.007,1.087,1.168,1.248)
llci<-c(-.702,-.654,-.589,-.481,-.376,-.276,-.184,-.099,-.024,0,.044,.105,
.161,.212,.261,.307,.351,.394,.436,.477,.518,.558,.597)
ulci<-c(-.021,0,.028,.080,.136,.197,.266,.343,.428,.458,.521,.621,.726,.836,
.948,1.063,1.180,1.298,1.417,1.537,1.657,1.778,1.899)
plot(x=skeptic,y=effect,type="l",pch=19,ylim=c(-1,1.5),xlim=c(1,6),lwd=3,
ylab="Conditional effect of disaster frame",
xlab="Climate Change Skepticism (W)")
points(skeptic,llci,lwd=2,lty=2,type="l")
points(skeptic,ulci,lwd=2,lty=2,type="l")
abline(h=0, untf=FALSE,lty=3,lwd=1)
abline(v=1.171,untf=FALSE,lty=3,lwd=1)
abline(v=3.934,untf=FALSE,lty=3,lwd=1)
text(1.171,-1,"1.171",cex=0.8)
text(3.934,-1,"3.934",cex=0.8)
The exemplary plot is
I have tried ggplot but I am struggling with the vertical and horizontal dashed line. Could anybody reproduce the plot using ggplot? And I have a follow-up question. How can I mark the area of x < 3.934 and x > 1.171? Thank you!

Here is a way to reproduce the posted graph.
library(ggplot2)
library(magrittr)
library(tidyr)
df1 <- data.frame(skeptic, effect, llci, ulci)
vlines <- data.frame(x = c(0, 1.171, 3.934))
vertices <- data.frame(xmin = 1.171, xmax = 3.934,
ymin = -Inf, ymax = Inf)
brks <- names(df1)[-1]
df1 %>%
pivot_longer(-skeptic, names_to = "line") %>%
ggplot(aes(skeptic, value)) +
geom_rect(data = vertices,
mapping = aes(xmin = xmin, xmax = xmax,
ymin = ymin, ymax = ymax),
fill = "blue", alpha = 0.2,
inherit.aes = FALSE) +
geom_line(aes(size = line, linetype = line)) +
geom_hline(yintercept = 0, linetype = "dotted") +
geom_vline(data = vlines,
mapping = aes(xintercept = x),
linetype = "dotted") +
geom_text(data = subset(vlines, x != 0),
mapping = aes(x = x, label = x),
y = -0.75,
hjust = 0, vjust = 1) +
scale_size_manual(breaks = brks, values = c(1, 0.5, 0.5)) +
scale_linetype_manual(breaks = brks, values = c("solid", "dashed", "dashed")) +
theme_bw() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank())

Constructing on your specific question (horizontal and vertical lines and area) as you said you got already the remaining parts right.
Use geom_hline for horizontal line and geom_vline for vertical one. linetype="dashed" will render dashed lines. As you didn't tell how you want the area rendered, here is my guess, a vertical grayed area extending horizontally from abcissa of your vertical lines and vertically from min effect to max effect (Inf values) drawn using a geom_rect.
ggplot(data.frame(skeptic,effect))+
geom_line(aes(skeptic,effect))+
geom_rect(aes(xmin=1.171,xmax=3.934,ymin=-Inf,ymax=Inf),fill="lightgray")+
geom_hline(yintercept=0,linetype="dashed") +
geom_vline(xintercept=c(1.171,3.934),linetype="dashed")

Related

R: Reduce axis to geom_density_ridges distance after flipping plot with coord_flip in ggplot2

First we prepare some toy data that sufficiently resembles the one I am working with.
rawdata <- data.frame(Score = rnorm(1000, seq(1, 0, length.out = 10), sd = 1),
Group = rep(LETTERS[1:3], 10000))
stdev <- c(10.78,10.51,9.42)
Now we plot the estimated densities via geom_density_ridges. I also add a grey highlight around zero via geom_rect. I also flip the chart with coord_flip.
p <- ggplot(rawdata, aes(x = Score, y = Group)) +
scale_y_discrete() +
geom_rect(inherit.aes = FALSE, mapping = aes(ymin = 0, ymax = Inf, xmin = -0.1 * min(stdev), xmax = 0.1 * max(stdev)),
fill = "grey", alpha = 0.5) +
geom_density_ridges(aes(fill = Group), scale = 0.5, size = 1, alpha=0.5) +
scale_color_manual(values = col) +
scale_fill_manual(values = col) +
labs(title="Toy Graph", y="Group", x="Value") +
coord_flip(xlim = c(-8, 8), ylim = NULL, expand = TRUE, clip = "on")
p
And this is the solution I get, which is close to what I was expecting, despite the detail of this enormous gap between the y axis an the start of the first factor in the x axis A. I tried using expand=c(0,0) inside scale_y_discrete() following some suggestions from other posts, but it does not make the gap smaller at all. If possible I would still like to have a certain gap, although minimal. I've been also trying to flip the densities in the y axis so the gap is filled by first factor density plot but I have been unsuccessful as it does not seem as trivial as one could expect.
Sorry, I know this might be technically two different questions, "How to reduce the gap from the y axis to the first density plot?" and "How to flip the densities from y axis to reduce the gap?" But I would really be happy with the first one as I understand the second question seems to be apparently less straightforward.
Thanks in advance! Any help is appreciated.
Flipping the densities also effectively reduces the space, so this might be all you need to do. You can achieve it with a negative scale parameter:
ggplot(rawdata, aes(x = Score, y = Group)) +
scale_y_discrete() +
geom_rect(inherit.aes = FALSE,
mapping = aes(ymin = 0, ymax = Inf,
xmin = -0.1 * min(stdev),
xmax = 0.1 * max(stdev)),
fill = "grey", alpha = 0.5) +
geom_density_ridges(aes(fill = Group), scale = -0.5, size = 1, alpha = 0.5) +
scale_color_manual(values = col) +
scale_fill_manual(values = col) +
labs(title = "Toy Graph", y = "Group", x = "Value") +
coord_flip(xlim = c(-8, 8), ylim = NULL, expand = TRUE, clip = "on")
If you want to keep the densities pointing the same way but just reduce space on the left side, simply set hard limits in your coord_flip, with no expansion:
ggplot(rawdata, aes(x = Score, y = Group)) +
geom_rect(inherit.aes = FALSE,
mapping = aes(ymin = 0, ymax = Inf,
xmin = -0.1 * min(stdev),
xmax = 0.1 * max(stdev)),
fill = "grey", alpha = 0.5) +
geom_density_ridges(aes(fill = Group), scale = 0.5, size = 1, alpha = 0.5) +
scale_color_manual(values = col) +
scale_fill_manual(values = col) +
scale_y_discrete() +
labs(title = "Toy Graph", y = "Group", x = "Value") +
coord_flip(xlim = c(-8, 8), ylim = c(0.8, 4), expand = FALSE)

How to get overlapped rectangular bars in ggplot?

I am trying to create 3 layers of rectangles each with different color on top of each other to get something like below image:
Data:
library(tidyverse)
df_vaccination <- data.frame(type = c('Population', 'First.Dose.Administered', 'Second.Dose.Administered'),
count = c(1366400000, 952457943, 734608556))
Code tried:
df_vaccination %>%
ggplot()+
geom_rect(aes(xmin = 0, ymin = 0, xmax = count, ymax = 0,
size = 10, lineend = 'round',
alpha = 0.5, fill = type)) +
scale_fill_manual(values = c("#d8b365", "orange", "#5ab4ac")) +
theme_clean() +
scale_x_continuous(labels = unit_format(scale = 1e-7, unit = "Cr")) +
guides(color = guide_legend(order = 1),
size = FALSE,
alpha = FALSE)
Result I am getting is blank plot when I am using geom_rect() & scale_fill_manual(). I am not sure why am I getting blank rectangle:
Convert type column to ordered factor so that largest number plots first, then use geom_col with x = 1. This will make the bars to plot on top of each other, lastly flip the coordinates:
df_vaccination$type <- factor(df_vaccination$type, levels = df_vaccination$type)
ggplot(df_vaccination, aes(x = 1, y = count, fill = type))+
geom_col() +
scale_fill_manual(values = c("#d8b365", "orange", "#5ab4ac")) +
coord_flip() +
theme_void()

Is there a method to set the theta-axis ticks for circular ring plot in ggplot2?

I want to show a tick mark for theta axis in the ggplot2 poar plot. However, both axis.ticks.y and axis.ticks.y in the theme() does not work for theta axis. Any help would be appreciated, thanks
library(ggplot2)
df <- data.frame(
start = c(0, 121, 241),
end = c(120, 240, 359),
group = letters[1:3]
)
# a example circular ring plot
base <- ggplot(df, aes(ymax = end, ymin = start,
xmin = 0.8, xmax = 1,
fill = group)) +
geom_rect() +
coord_polar(theta = "y") +
xlim(c(0, 1))
base
# the tick of y axis can be changed
base + theme(axis.ticks.y = element_blank(), axis.text.y = element_blank())
# set the tick of x axis not worked for the theta axis
base + theme(axis.ticks.x = element_line(color = "black", size = 2))
Thanks for #Vishal A., the answer from Controlling ticks and odd text in a pie chart generated from a factor variable in ggplot2 used the panel.grid.major.y. However, it will add the major grids rather than ticks like the following:
base + theme(panel.grid.major.y = element_line(colour = "black"))
Created on 2021-12-20 by the reprex package (v2.0.1)
I see two options. You can use the panel grids, but you need to hide them. The usefulness of this solution depends on your intended plot background. I've used white, but this can be customised, of course.
Second option is to fake the ticks with annotation, e.g., with the symbol "|".
Further smaller comments in the code below.
library(tidyverse)
df <- data.frame(
start = c(0, 121, 241),
end = c(120, 240, 359),
group = letters[1:3]
)
ggplot(df) +
## annotate with a rectangle, effectively covering your central hole
annotate(geom = "rect", xmin = 0, xmax = 1, ymin = min(df$start), ymax = max(df$end),
fill = "white") +
## move aes to the geom_layer
geom_rect(aes(ymax = end, ymin = start,
xmin = 0.8, xmax = 1,
fill = group)) +
coord_polar(theta = "y") +
xlim(c(0, 1)) +
theme(panel.grid.major.y = element_line(colour = "black"))
## Option 2 - fake the ticks
## the position along the theta axis is defined by y
## you need to change the angle of your fake ticks according to the angle.
df_annot <-
data.frame(y = seq(0,300,100), x = Inf, angle = 360-seq(0,300,100))
ggplot(df) +
## annotate with text, along your y
## by placing it beneath your geom_rect layer it will automatically be covered
geom_text(data = df_annot, aes(x, y, label = "|", angle = angle)) +
## move aes to the geom_layer
geom_rect(aes(ymax = end, ymin = start,
xmin = 0.8, xmax = 1,
fill = group)) +
coord_polar(theta = "y") +
xlim(c(0, 1))
Created on 2021-12-21 by the reprex package (v2.0.1)
You need to use panel.grid.minor.y instead of axis.ticks.y in order to change the ticks.
Your code will look like this:
base + theme(axis.ticks.y = element_blank(), axis.text.y = element_blank())
base + theme(panel.grid.minor.y = element_line(color = "black", size = 1))
The output will look like this:

trouble combining geom_rect and facet_grid in ggplot

I want to shade part of the background in each facet of a simple plot. If I omit faceting and run geom_rect + geom_point, the expected results appear as shown in the MRE below. If I omit the rectangle and run geom_point + facet_grid, the expected 4 panels have each point in the correct facet. But when I combine geom_rect + geom_point + and facet_grid, the points in the first category and only those get plotted in every facet. What is going on please???
library(ggplot2)
set.seed(42)
syn.dat <- data.frame(
category.1 = as.factor(rep(c("1A", "1B"), each = 8)),
category.2 = as.factor(rep(rep(c("2A", "2B"), times = 2), each = 4)),
x = rep(-1:2, each = 4) + runif(8, max = .4),
y = rep(-1:2, each = 4) + runif(8, max = .4))
ggplot() +
geom_rect(aes(xmin = -Inf, xmax = Inf, ymin = .5,
ymax = Inf), fill = "lightyellow") +
geom_point(data = syn.dat, aes(x = x, y = y)) +
facet_grid(cols = vars(category.1),
rows = vars(category.2))
I'm not totally sure about this, but it may be that you need to explicitly provide the data argument to ggplot itself, in order for facet_grid to correctly pick up all the values?
ggplot(syn.dat) +
geom_rect(aes(xmin = -Inf, xmax = Inf, ymin = 0.5, ymax = Inf), fill = "lightyellow") +
geom_point(aes(x = x, y = y)) +
facet_grid(rows = vars(category.2), vars(cols = category.1))

Raincloud plot - histogram?

I would like to create a raincloud plot. I have successfully done it. But I would like to know if instead of the density curve, I can put a histogram (it's better for my dataset).
This is my code if it can be usefull
ATSC <- ggplot(data = data, aes(y = atsc, x = numlecteur, fill = numlecteur)) +
geom_flat_violin(position = position_nudge(x = .2, y = 0), alpha = .5) +
geom_point(aes(y = atsc, color = numlecteur), position = position_jitter(width = .15), size = .5, alpha = 0.8) +
geom_point(data = sumld, aes(x = numlecteur, y = mean), position = position_nudge(x = 0.25), size = 2.5) +
geom_errorbar(data = sumld, aes(ymin = lower, ymax = upper, y = mean), position = position_nudge(x = 0.25), width = 0) +
guides(fill = FALSE) +
guides(color = FALSE) +
scale_color_brewer(palette = "Spectral") +
scale_y_continuous(breaks=c(0,2,4,6,8,10), labels=c("0","2","4","6","8","10"))+
scale_fill_brewer(palette = "Spectral") +
coord_flip() +
theme_bw() +
expand_limits(y=c(0, 10))+
xlab("Lecteur") + ylab("Age total sans check")+
raincloud_theme
I think we can maybe put the "geom_histogram()" but it doesn't work
Thank you in advance for your help !
(sources : https://peerj.com/preprints/27137v1.pdf
https://neuroconscience.wordpress.com/2018/03/15/introducing-raincloud-plots/)
This is actually not quite easy. There are a few challenges.
geom_histogram is "horizontal by nature", and the custom geom_flat_violin is vertical - as are boxplots. Therefore the final call to coord_flip in that tutorial. In order to combine both, I think best is switch x and y, forget about coord_flip, and use ggstance::geom_boxploth instead.
Creating separate histograms for each category is another challenge. My workaround to create facets and "merge them together".
The histograms are scaled way bigger than the width of the points/boxplots. My workaround scale via after_stat function.
How to nudge the histograms to the right position above Boxplot and points - I am converting the discrete scale to a continuous by mapping a constant numeric to the global y aesthetic, and then using the facet labels for discrete labels.
library(tidyverse)
my_data<-read.csv("https://data.bris.ac.uk/datasets/112g2vkxomjoo1l26vjmvnlexj/2016.08.14_AnxietyPaper_Data%20Sheet.csv")
my_datal <-
my_data %>%
pivot_longer(cols = c("AngerUH", "DisgustUH", "FearUH", "HappyUH"), names_to = "EmotionCondition", values_to = "Sensitivity")
# use y = -... to position boxplot and jitterplot below the histogram
ggplot(data = my_datal, aes(x = Sensitivity, y = -.5, fill = EmotionCondition)) +
# after_stat for scaling
geom_histogram(aes(y = after_stat(count/100)), binwidth = .05, alpha = .8) +
# from ggstance
ggstance::geom_boxploth( width = .1, outlier.shape = NA, alpha = 0.5) +
geom_point(aes(color = EmotionCondition), position = position_jitter(width = .15), size = .5, alpha = 0.8) +
# merged those calls to one
guides(fill = FALSE, color = FALSE) +
# scale_y_continuous(breaks = 1, labels = unique(my_datal$EmotionCondition))
scale_color_brewer(palette = "Spectral") +
scale_fill_brewer(palette = "Spectral") +
# facetting, because each histogram needs its own y
# strip position = left to fake discrete labels in continuous scale
facet_wrap(~EmotionCondition, nrow = 4, scales = "free_y" , strip.position = "left") +
# remove all continuous labels from the y axis
theme(axis.title.y = element_blank(), axis.text.y = element_blank(),
axis.ticks.y = element_blank())
Created on 2021-04-15 by the reprex package (v1.0.0)

Resources