R - ggplot2 trace lines between "stacked" points - r

I am having problems to figure how I can trace lines (and ultimately arrows) between two points on top of each others. So my basic plot looks like this :
dt %>%
ggplot(aes(x = V2, y = V3, colour = V1) ) + geom_point(size = 3) + geom_point() +
scale_colour_manual(values = c('gray44', 'black')) +
theme_minimal(base_size = 16) + geom_text(aes(x = V2, y = V3+1.05, label = V1))
So, I tried to create "groups" in order to trace a line but it doesn't work,
what I want is that the points that are on top of each others get connected:
dt = dt %>% group_by(V1) %>% mutate(grp = 1:n())
dt %>%
ggplot(aes(x = V2, y = V3, colour = V1) ) + geom_point(size = 3) + geom_point() +
scale_colour_manual(values = c('gray44', 'black')) +
theme_minimal(base_size = 16) + geom_text(aes(x = V2, y = V3+1.05, label = V1)) +
geom_path(data = dt, aes(V2, V3, group = grp))
Ultimately, I would be very interested to trace an arrow going from 1985 to 1990, but I can't figure it
I tried to add something like :
geom_segment(aes(x = V3[V1 == 1985], y = V3[V1 == 1985], xend = V3[V1 == 2000], yend = V3[V1 == 2000]), arrow = arrow(length = unit(0.5, "cm")))
but it doesn't work.
Any idea ?
dt = structure(list(V1 = structure(c(1L, 2L, 1L, 2L, 1L, 2L), .Label = c("1985",
"1990"), class = "factor"), V2 = structure(c(1L, 2L, 3L, 1L,
2L, 3L), .Label = c("A", "B", "C"), class = "factor"), V3 = c(60,
40, 60, 80, 20, 40)), .Names = c("V1", "V2", "V3"), row.names = c(NA,
-6L), class = "data.frame")

Related

How can I center geom_label_repel labels so that they are in the middle of each bar?

I'm using geom_label_repel to place percentages in a faceted horizontal bar chart, which mostly works great, except that I can't seem to find a way to shift the labels to the middle (or as close as possible) of each bar. Instead, they are justified right, which visually is a bit confusing as some bars are close to one another.
I've tried using h_just and v_just, but these just center the text within its box rather than the box within the plot. If I drop position_identity() in favour of nudge_x the bars all drop out, so that doesn't get me there. Assuming there is some simple way to do this, but I'm not seeing it!
Here's the function I've made to do the plot:
plot_single_result_with_facets <- function(x) {
x %>%
# we need to get the data including facet info in long format, so we use pivot_longer()
pivot_longer(!response, names_to = "bin_name", values_to = "b") %>%
# add counts for plot below
count(response, bin_name, b) %>%
# remove nas
filter(!is.na(response)) %>%
# add grouping by bins
group_by(bin_name,b) %>%
# calculate percentages
mutate(perc=paste0(round(n*100/sum(n),0),"%")) %>%
# run ggplot
ggplot(aes(x = n, y = "", fill = response, label = perc)) +
# reversing order here using forcats::fct_rev() note - needs to be changed under geom_label_repel as well
geom_col(position=position_fill(), aes(fill=forcats::fct_rev(response))) +
coord_cartesian(clip = "off") +
geom_vline(xintercept = x_limits, linetype = 3) +
geom_label_repel(
# important to make sure grouping of data matches grouping of labels so they aren't backwards
# reversing order here using forcats::fct_rev() note - needs to be changed above as well
aes(group = forcats::fct_rev(response), label = perc),
# justify text using center = 0.5, left = 0 and right = 1
hjust = 0.5,
vjust = 0.5,
direction = "y",
force = 1.5,
fill = "white",
# font size in the text labels
size = 1.5,
# allow labels to overlap
max.overlaps = Inf,
# make sure that bars are included
position = position_fill(),
# hide points
segment.size = 0.2,
point.size = NA,
# reduce padding around each text label
box.padding = 0.001
) +
scale_fill_brewer(palette="YlOrBr", direction = -1) +
scale_x_continuous(labels = scales::percent_format(), expand = c(0.05, 0.05)) +
facet_grid(vars(b), vars(bin_name), labeller=as_labeller(facet_names)) +
labs(title = title, caption = caption, x = "", y = "") +
guides(fill = guide_legend(title = NULL)) +
theme_classic()
}
And the code that uses it:
caption <- NULL
df <- select(data, Q51_bin, Q52_bin, Q57_bin, Q53_bin, Q4)
df <- as_factor(df)
names(df) <- c("Q51_bin", "Q52_bin", "Q57_bin", "Q53_bin", "response")
facet_names <- c(`Q51_bin` = "Nature Relatedness", `Q52_bin` = "Spirituality", `Q57_bin` = "Religiosity", `Q53_bin` = "Politics L/R", `low`="low", `medium`="medium", `high`="high")
facet_labeller <- function(variable,value){return(facet_names[value])}
x_limits <- c(.50, NA)
facet_grid(~fct_relevel(df,'Nature Relatedness','Spirituality','Religiosity','Politics L/R'))
plot_single_result_with_facets(df)
ggsave("figures/q5_faceted.png", width = 20, height = 10, units = "cm")
Here's the plot as it currently stands:
And a bit of data to make it reproducible:
df <- structure(list(Q51_bin = structure(c(2L, 2L, 2L, 2L), levels = c("low", "medium", "high"), class = "factor"), Q52_bin = structure(c(3L, 2L, 2L, 2L), levels = c("low", "medium", "high"), class = "factor"), Q57_bin = structure(c(2L, 2L, 2L, 2L), levels = c("low", "medium", "high"), class = "factor"), Q53_bin = structure(c(2L, 3L, 2L, 2L), levels = c("low", "medium", "high"), class = "factor"), Q4 = structure(c(2, 3, 3, 5), label = "How much have you thought about climate change before today?", format.spss = "F40.0", display_width = 5L, labels = c(`Not at all` = 1, `A little` = 2, Some = 3, `A lot` = 4, `A great deal` = 5, `Don't know` = 99), class = c("haven_labelled", "vctrs_vctr", "double"))), class = c("rowwise_df", "tbl_df", "tbl", "data.frame"), row.names = c(NA, -4L), groups = structure(list(.rows = structure(list(1L, 2L, 3L, 4L), ptype = integer(0), class = c("vctrs_list_of", "vctrs_vctr", "list"))), row.names = c(NA, -4L), class = c("tbl_df", "tbl", "data.frame")))
You need to put vjust = 0.5 inside position_fill:
x %>%
pivot_longer(!response, names_to = "bin_name", values_to = "b") %>%
count(response, bin_name, b) %>%
filter(!is.na(response)) %>%
group_by(bin_name,b) %>%
mutate(perc=paste0(round(n*100/sum(n),0),"%")) %>%
ggplot(aes(x = n, y = "", fill = response, label = perc)) +
geom_col(position=position_fill(), aes(fill=forcats::fct_rev(response))) +
coord_cartesian(clip = "off") +
geom_vline(xintercept = x_limits, linetype = 3) +
geom_label_repel(
aes(group = forcats::fct_rev(response), label = perc),
hjust = 0.5,
vjust = 0.5,
direction = "y",
force = 1.5,
fill = "white",
size = 1.5,
max.overlaps = Inf,
position = position_fill(vjust = 0.5),
segment.size = 0.2,
point.size = NA,
box.padding = 0.001
) +
scale_fill_brewer(palette="YlOrBr", direction = -1) +
scale_x_continuous(labels = scales::percent_format(), expand = c(0.05, 0.05)) +
facet_grid(vars(b), vars(bin_name), labeller=as_labeller(facet_names)) +
labs(title = 'title', caption = caption, x = "", y = "") +
guides(fill = guide_legend(title = NULL)) +
theme_classic()

Adding p value on top of grouped bar plot

This is my data which I'm trying to plot
dput(results)
structure(list(ontology = c("CC", "BP", "MF", "CC", "BP", "MF",
"CC", "BP", "MF"), breadth = structure(c(3L, 3L, 3L, 2L, 2L,
2L, 1L, 1L, 1L), .Label = c("10", "30", "100"), class = "factor"),
enrichment = c(4.09685904270847, 8.04193317540539, 5.5801230522415,
4.52127958016442, 8.9221766387218, 5.68189764335457, 4.25046722366786,
9.49038239297713, 6.75423163834793), p = c(0, 0, 0, 0, 0,
0, 2.09057402562873e-221, 0, 0)), class = "data.frame", row.names = c(NA,
-9L))
My code
results = read.delim("data/GO/LC-GO-enrichment_new.txt") %>%
mutate(breadth = factor(breadth))
p = ggplot(results, aes(x = breadth, y = enrichment, fill = ontology,
color = ontology)) +
geom_col(position = 'dodge', width = 0.8) +
labs(x = "Breadth", y = "Odds ratio") +
scale_fill_manual(values = ryb8[c(1, 5, 8)], name = "Ontology") +
scale_color_manual(values = darken(ryb8[c(1, 5, 8)], 1.3),
name = "Ontology") +
scale_y_log10(expand = c(0.01, 0)) +
sci_theme
p
I get something like this
is there a way the pvalue can be added similar to this
or its done post making the figure manually .
Any help or suggestion would be really helpfu;
You could simply add the p values as a text layer. Note though, that in your data, each bar has a p value, so it's not clear where the groupwise p values are coming from.
library(ggplot2)
ggplot(results, aes(x = breadth, y = enrichment, fill = ontology)) +
geom_col(position = 'dodge', width = 0.8,
aes(color = after_scale(colorspace::darken(fill, 1.3)))) +
geom_text(aes(label = paste("p", scales::pvalue(p)), group = ontology),
vjust = -1, position = position_dodge(width = 0.8)) +
labs(x = "Breadth", y = "Odds ratio", fill = "Ontology") +
scale_fill_manual(values = c("#d63228", "#dff2f8", "#4575b5")) +
scale_y_log10(expand = c(0.05, 0)) +
theme_classic(base_size = 16) +
theme(legend.position = "top")

how to combine 2 images with fixed area in ggplot2 in R

Here is my raw data.
v <-
structure(list(Estimate = c(0.233244696051868, 5.48753303603373,
1.95671969454631, 3.16568487759413, 4.79631204302344, 2.10818637730716,
0.329940200056173, 0.055145498993132, 0.222410032790494), `Std. Error` = c(1.10523192028695,
2.75434167314693, 2.52507525836928, 0.964768253150336, 1.73374160980673,
0.852388938087655, 0.736511882227423, 0.326506324068342, 1.26750100880987
), ID = structure(c(1L, 3L, 2L, 4L, 8L, 5L, 6L, 7L, 9L), .Label = c("CD",
"MFS2", "MFS", "Crop.Nb", "CD:SNC", "MFS:SNC", "CD:MFS", "SNC",
"SNC2"), class = "factor"), group = structure(c(1L, 1L, 1L, 1L,
3L, 2L, 2L, 2L, 3L), .Label = c("crop", "inter", "semi"), class = "factor"),
ES = c(-0.233244696051868, -5.48753303603373, 1.95671969454631,
3.16568487759413, 4.79631204302344, 2.10818637730716, 0.329940200056173,
0.055145498993132, 0.222410032790494)), class = "data.frame", row.names = c(NA,
-9L))
I want to plot 2 images as below:
p1 <- v %>% ggplot(aes(x = factor(ID), y = ES, color = factor(group))) +
geom_hline(yintercept = 0) +
geom_errorbar(aes(ymin = ES - `Std. Error`,ymax = ES + `Std. Error`),
width = 0, lwd = 1.5
)+
coord_flip()+
geom_text(aes(label = ID), nudge_y = .6,nudge_x = .2)+
geom_point(size = 4)+
scale_color_discrete()+
theme(axis.text.y = element_blank()) +
xlab('') + guides(color = FALSE)
(p2 <- arrange(v,desc(group)) %>% ggplot(aes(x = '1', y =Estimate, fill = group )) +
#geom_bar(position = 'fill', stat = 'identity') +
geom_col(position = position_fill(reverse = TRUE)) +
scale_y_continuous(labels = scales::percent, name = "Variance explained")+
theme(legend.position = 'none', axis.title.x = element_blank(), axis.text.x = element_blank()) )
Now I want to combine p2 and p1: I get:
cowplot::plot_grid(p2,p1,nrow = 1, rel_widths = c(0.2,1))
But what I want to achieve the effect as below:
Panel A : I wish the distance between p1 and p2 is less narrow; And red area only has red bars; Green area only has green bars; I wish you can help me to achieve the draft of panel B as below:
To ensure proper alignment, it might be neater to have both parts in the same plot. Also, I don't quite see the need to flip your coordinates here, so I went with a simpler version:
v %>%
# calculate y-axis positions within [0%, 100%] range
arrange(group) %>%
mutate(y = seq(0.5, by = 1, length.out = n())) %>%
mutate(y = y / ceiling(max(y))) %>%
ggplot(aes(y = y, x = ES, label = ID, color = group,
xmin = ES - `Std. Error`, xmax = ES + `Std. Error`)) +
geom_vline(xintercept = 0) +
geom_pointrange(lwd = 1.5, fatten = 2) + # instead of flipped errorbar with 0 width + point
geom_text(nudge_y = 0.05) +
geom_bar(aes(x = -10, fill = group), # change this to shift the bar closer / further away
position = position_fill(reverse = TRUE),
inherit.aes = FALSE) +
scale_y_continuous(name = "Variance explained", labels = scales::percent) +
# actually not necessary to have this line for default palette, but in case
# you want to change that, the `aesthetics = c("colour", "fill")` line saves you from
# having to specify the same palette twice in both colour & fill scales.
scale_color_discrete(aesthetics = c("colour", "fill")) +
theme_minimal() + # or whatever theme you need
theme(legend.position = "none")

How can I add the following feature to my existing ggplot2 graph?

I have the following R codes running in RStudio.
library(ggplot2)
library(tidyverse)
DF <- structure(list(Type = structure(c(1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L), .Label = c("Current", "SPLY"), class = "factor"),
variable = structure(c(1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L),
.Label = c("Wk 06 Jan 2020-12 Jan 2020", "Wk 13 Jan 2020-19 Jan 2020", "Wk 20 Jan 2020-26 Jan 2020", "Wk 27 Jan 2020-02 Feb 2020"), class = "factor"),
value = c(6212, 12195,5508, 10574,15060, 9763,5341, 9478)),
row.names = c(NA, -8L), .Names = c("Type", "variable", "value"), class = "data.frame")
diff_df = DF %>%
group_by(variable) %>%
spread(Type, value) %>%
mutate(diff = Current - SPLY,
max_y = max(Current, SPLY),
sim_higher = Current > SPLY)
ggplot(DF, aes(variable, value)) +
geom_bar(aes(y = max_y), data = diff_df, stat = "identity", fill = "grey80", width = 0.4) +
geom_bar(aes(fill = Type), position = "dodge", stat="identity", width=.5) +
geom_text(aes(label=value, group=Type), position=position_dodge(width=0.5), vjust=3.0) +
geom_text(aes(label = diff, y = max_y), vjust=-0.5, data = diff_df %>% filter(sim_higher),
hjust = 0.0, colour = scales::muted("red")) +
geom_text(aes(label = diff, y = max_y), vjust=-0.5, data = diff_df %>% filter(!sim_higher),
hjust = 1.0, colour = scales::muted("red")) +
theme_bw(base_size = 18) +
ylab('Room Nights') + xlab('Week')
The above codes produces the following graph:
I would like to add the % change next to the bars in the chart.
Expected output:
How can I achieve this?
The easiest way to do this is to create a separate little data frame for the circles. You can plot these as large green points, then plot white text labels over them:
circle_df <- data.frame(variable = 1:4 + 0.4, value = rep( 1000, 4),
labels = scales::percent(1- DF$value[DF$Type == "SPLY"]/
DF$value[DF$Type == "Current"]))
ggplot(DF, aes(variable, value)) +
geom_col(aes(y = max_y), data = diff_df, fill = "grey80", width =0.4) +
geom_col(aes(fill = Type), position = "dodge", width = 0.5) +
geom_text(aes(label=value, group=Type), position = position_dodge(width = 0.5),
vjust=3.0) +
geom_text(aes(label = diff, y = max_y), vjust=-0.5,
data = diff_df %>% filter(sim_higher),
hjust = 0.0, colour = scales::muted("red")) +
geom_text(aes(label = diff, y = max_y), vjust=-0.5,
data = diff_df %>% filter(!sim_higher),
hjust = 1.0, colour = scales::muted("red")) +
geom_point(data = circle_df, size = 20, colour = "forestgreen") +
geom_text(data = circle_df, aes(label = labels), colour = "white") +
theme_bw(base_size = 18) +
ylab('Room Nights') + xlab('Week')

r - ggplot2 - Add differences to grouped bar charts

I am plotting the following data on ggplot:
library(ggplot2)
DF <- structure(list(Type = structure(c(1L, 2L, 1L, 2L, 1L, 2L, 1L,
2L), .Label = c("Observed", "Simulated"), class = "factor"),
variable = structure(c(1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L), .Label = c("EM to V6",
"V6 to R0", "R0 to R4", "R4 to R9"), class = "factor"), value = c(28,
30, 29, 35, 32, 34, 26, 29)), row.names = c(NA, -8L), .Names = c("Type",
"variable", "value"), class = "data.frame")
ggplot(DF, aes(variable, value)) +
geom_bar(aes(fill = Type), position = "dodge", stat="identity", width=.5) +
geom_text(aes(label=value, group=Type), position=position_dodge(width=0.5), vjust=-0.5) +
theme_bw(base_size = 18) +
ylab('Duration (days)') + xlab('Growth stages')
I was wondering if there is any graphical way to add the differences between each group of bars to the chart?
This is the data frame with the differences to be added:
DF2 <- data.frame(variable=c("EM to V6", "V6 to R0", "R0 to R4", "R4 to R9"), value=c(2,6,2,3)
The final chart would look somewhat like this (notice the coloured bars):
source: https://www.excelcampus.com/charts/variance-clustered-column-bar-chart/
Is that possible to do using ggplot?
As rawr suggested, you can add a layer of bars behind the current ones with a slightly smaller width:
library(tidyverse)
diff_df = DF %>%
group_by(variable) %>%
spread(Type, value) %>%
mutate(diff = Simulated - Observed)
ggplot(DF, aes(variable, value)) +
geom_bar(aes(y = Simulated), data = diff_df, stat = "identity", fill = "grey80", width = 0.4) +
geom_bar(aes(fill = Type), position = "dodge", stat="identity", width=.5) +
geom_text(aes(label=value, group=Type), position=position_dodge(width=0.5), vjust=-0.5) +
geom_text(aes(label = diff, y = Simulated), vjust=-0.5, data = diff_df, hjust = 2, colour = scales::muted("red")) +
theme_bw(base_size = 18) +
ylab('Duration (days)') + xlab('Growth stages')
Updated code to deal with Observed sometimes being higher than Simulated:
library(tidyverse)
diff_df = DF %>%
group_by(variable) %>%
spread(Type, value) %>%
mutate(diff = Simulated - Observed,
max_y = max(Simulated, Observed),
sim_higher = Simulated > Observed)
ggplot(DF, aes(variable, value)) +
geom_bar(aes(y = max_y), data = diff_df, stat = "identity", fill = "grey80", width = 0.4) +
geom_bar(aes(fill = Type), position = "dodge", stat="identity", width=.5) +
geom_text(aes(label=value, group=Type), position=position_dodge(width=0.5), vjust=-0.5) +
geom_text(aes(label = diff, y = max_y), vjust=-0.5, data = diff_df %>% filter(sim_higher),
hjust = 2, colour = scales::muted("red")) +
geom_text(aes(label = diff, y = max_y), vjust=-0.5, data = diff_df %>% filter(!sim_higher),
hjust = -1, colour = scales::muted("red")) +
theme_bw(base_size = 18) +
ylab('Duration (days)') + xlab('Growth stages')

Resources