ggplot jitter geom_errorbar? - r

My data looks something like this:
df1 <-
structure(
list(
y = c(-0.19, 0.3,-0.05, 0.15,-0.05, 0.15),
lb = c(-0.61,
0.1,-0.19,-0.06,-0.19,-0.06),
ub = c(0.22, 0.51, 0.09, 0.36,
0.09, 0.36),
x = structure(
c(1L, 2L, 1L, 2L, 1L, 2L),
.Label = c("X1",
"X2"),
class = "factor"
),
Group = c("A", "A", "B", "B", "C",
"C")
),
.Names = c("y", "lb", "ub", "x", "Group"),
row.names = c(NA,-6L),
class = "data.frame"
)
I want to use ggplot2 to plotthe points x,y colored by group with error bars lb, ub. Because x is discrete, I want to jitter so the points and bars don't overlap. Right now, I can jitter the points but not the lines. Additionally, I would like to have the order of the point to be A,B,C
ggplot(data = df1, aes(x, y, color = Group)) + geom_point(size = 4, position = "jitter") +
geom_errorbar(
aes(ymin = lb, ymax = ub),
width = 0.1,
linetype = "dotted"
) +
geom_hline(aes(yintercept = 0), linetype = "dashed") + theme_bw()

You can use position_dodge to achieve both the desired order and the error bars being drawn at the location of the points
ggplot(data = df1, aes(x, y, color = Group)) +
geom_point(size = 4, position=position_dodge(width=0.5)) +
geom_errorbar(
aes(ymin = lb, ymax = ub),
width = 0.1,
linetype = "dotted",
position=position_dodge(width=0.5)) +
geom_hline(aes(yintercept = 0), linetype = "dashed") +
theme_bw()

If you want jitter, I do like this:
ggplot(data = df1, aes(x, y, color = Group)) +
geom_pointrange(aes(ymin = lb, ymax = ub),
position=position_jitter(width=0.5),
linetype='dotted') +
theme_bw()

Related

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 plot a chart with dual Y, both are bar plot with ggplot2?

I would like to plot a chart with dual Y, both are bar plot with ggplot2, and both bar with its own error bar and label, the following code fails. The bars overlaped, and the labels can not be displayed.
Thanks a lot.
df<- structure(list(dose = structure(1:3, .Label = c("0.5", "1", "2"
), class = "factor"), mean1 = c(13.23, 22.7, 26.06), sd1 = c(0.1,
0.2, 0.3), label = c("a", "b", "c"), mean2 = c(7.98, 16.77, 26.14
), sd2 = c(0.01, 0.2, 0.3), label2 = c("a", "b", "c")), row.names = c(NA,
-3L), class = "data.frame")
ggplot(df,aes(x = dose, fill = dose))+
geom_bar(aes(y = mean1), position = 'dodge', stat="identity", width=.4) +
geom_bar(aes(y = mean2/5), position = 'dodge', stat="identity", width=.4)+
scale_y_continuous(sec.axis = sec_axis(~. *5, name = "mean2"))+
geom_errorbar(aes(ymin = mean1, ymax = mean1 + sd1), width=.07,
position=position_dodge(0.4)) +
geom_errorbar(aes(ymin = mean2, ymax = mean2 + sd2), width=.07,
position=position_dodge(0.4))
geom_text(aes(y =mean1 + sd1, label = label1),vjust = -0.5, position=position_dodge(0.4))
geom_text(aes(y =mean2 + sd2, label = label2,),vjust = -0.5, position=position_dodge(0.4))
Is this what you are looking for? You just need to restructure your data so that it can be dodged by group.
bind_rows(
df |>
select(dose, label, mean = mean1, sd = sd1) |>
mutate(group = 1),
df |>
select(dose, label, mean = mean2, sd = sd2) |>
mutate(group = 2,
mean = mean/5)
) |>
ggplot(aes(x = dose, fill = dose, group = group))+
geom_bar(aes(y = mean), position = 'dodge', stat="identity", width=.4)+
geom_errorbar(aes(ymin = mean, ymax = mean + sd), width=.07,
position=position_dodge(0.4)) +
geom_text(aes(y =mean + sd, label = label),vjust = -0.5, position=position_dodge(0.4))+
scale_y_continuous(sec.axis = sec_axis(~. *5, name = "mean2"))

Annotate plot with text left to y axis title

Hello everyone and happy new year !!! I would need help in order to improve a ggplot figure.
df1 <- structure(list(x = structure(c(1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L,
1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L), .Label = c("a", "b", "c", "d"
), class = "factor"), y = c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 3L,
3L, 3L, 3L, 4L, 4L, 4L, 4L), z = c(-0.130312994048691, 0.714073455094197,
-0.156691533710652, 0.39894708481517, 0.644656691110372, -1.18694632145378,
-0.257204564112021, 1.34927378214664, -1.03584454605617, 0.148408762003154,
0.501192202628166, 0.511688097742773, -0.947953281835912, 0.0861048893885463,
1.55144239199118, 0.20220333664676)), class = "data.frame", row.names = c(NA,
-16L))
library(ggplot2)
df1$facet <- ifelse(df1$x %in% c("c", "d"), "cd", df1$x)
p1 <- ggplot(df1, aes(x = x, y = y))
p1 <- p1 + geom_tile(aes(fill = z), colour = "grey20")
p1 <- p1 + scale_fill_gradient2(
low = "darkgreen",
mid = "white",
high = "darkred",
breaks = c(min(df1$z), max(df1$z)),
labels = c("Low", "High")
)
p1 + facet_grid(.~facet, space = "free", scales = "free_x") +
theme(strip.text.x = element_blank())
With this code (inspired from here) I get this figure:
But I wondered if someone had an idea in order to :
To add sub Y axis element (here noted as Element 1-3) where Element1 (first box); Element2 (2 and 3 box) and Element3 (4 box)
the result should be something like:
This is not easy! As usual with plot annotation, there are basically three main options.
annotate outside the plot area with clipping turned off.
create plots and paste them together
mess with the grobs.
In my plots, I've decided to replace your scale_fill call with something simpler.
Here option 1:
library(tidyverse)
df1$facet <- fct_collapse(df1$x, cd = c("c", "d")) # slightly changed
# Create data frames for segments and labels
yseg <- c(.5, 1.5, 3.5, 4.5)
df_txt <- data.frame(x = -0.75, y = c(1, 2.5, 4),
label = paste0("element", 1:3), facet = "a")
df_seg <- data.frame(x = 0.5, xend = -1.5, y = yseg, facet = "a")
ggplot(df1, aes(x = x, y = y)) +
geom_tile(aes(fill = z), colour = "grey20") +
scale_fill_distiller(palette = "RdBu") +
scale_x_discrete(expand = c(0, 0)) + # kind of necessary
facet_grid(.~facet, scales = "free_x", space = "free") +
geom_segment(data = df_seg,
aes(x = x, xend = xend, y = yseg,yend = yseg), lty = "dashed",
color = "black") +
geom_text(data = df_txt, aes(x = x, y = y, label = label), hjust = 0.5) +
coord_cartesian(xlim = c(0.5, NA), clip = "off") + # this is how you turn clipping off
theme(strip.text.x = element_blank(),
plot.margin = margin(l = 2, unit = "inch"))
Another option is to make 3 different plots - arguably less hacky. Well. I still think it's hacky.
library(patchwork)
# create three plots. You could obviously also create four plots.
p_right <-
ggplot(filter(df1, x != "a"), aes(x = x, y = y)) +
geom_tile(aes(fill = z), colour = "grey20") +
scale_x_discrete(expand = c(0, 0)) +
scale_fill_distiller(palette = "RdBu", limits = c(-1, 1.5)) + # You need to set the same scale limits
facet_grid(.~facet, scales = "free_x", space = "free") +
theme(axis.title.y = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
plot.margin = margin(),
panel.spacing = unit(0.5, "lines")
)
p_left <-
ggplot(filter(df1, x == "a"), aes(x = x, y = y)) +
geom_tile(aes(fill = z), colour = "grey20") +
scale_x_discrete(expand = c(0, 0)) +
scale_fill_distiller(palette = "RdBu", limits = c(-1, 1.5)) + # You need to set the same scale limits
facet_grid(.~facet, scales = "free_x", space = "free") +
theme(plot.margin = margin(r = 0.4, unit = "lines"),
axis.title.y = element_text(margin = margin()))
p_seg <-
ggplot() +
geom_segment(data = df_seg,
aes(x = x, xend = xend, y = yseg,yend = yseg), lty = "dashed",
color = "black") +
scale_x_discrete(expand = c(0, 0)) +
geom_text(data = df_txt, aes(x = x, y = y, label = label), hjust = 0.5) +
theme_void() # important short cut to get rid of "everything but... "
p_seg + p_left + p_right +
plot_layout(nrow = 1, guides = "collect",
widths = c(2, 1, 3)) &
# the theme call in patchwork sets theme options globally, for all plots.
theme(strip.text.x = element_blank(),
axis.title.x = element_blank())
There is now a gap between segments and plots, so not quite the expected result, but visually fairly close. Also it requires (too much?) trial and error with the right margins / relative plot widths to get everything to look nice... On the other hand, this option probably gives you the biggest flexibility and you don't need to worry too much of the effects of scale expansion. So I personally would prefer the option. Would probably create four separate plots for full control of the gaps.
The last option would be to mess with the grobs, which I admit I am not very good at, so I will leave it with those two options. Hope this helped.

adjusting position of text above an error bar in ggplot

I have the following data frame:
df <- structure(list(Gender = c("M", "M", "M", "M", "F", "F", "F",
"F"), HGGroup = structure(c(1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L), .Label =
c("Low: \n F: <11.5, M: <12.5",
"Medium: \n F: > 11.5 & < 13, M: >12.5 & < 14.5", "High: \n F: >= 13, M >=
14.5", "No data"), class = "factor"), MeanBlood = c(0.240740740740741,
1.20689655172414, 0.38150289017341, 0.265957446808511, 0.272727272727273,
1.07821229050279, 0.257309941520468, 0.288776796973518), SEBlood =
c(0.0694516553311722, 0.154646785911315, 0.0687932999815165,
0.0383529942166715, 0.0406072582435844, 0.0971802933392401,
0.0327856332532931, 0.0289636037703526),
N = c(108L, 116L, 173L, 376L, 319L, 179L, 342L, 793L)), row.names = c(NA,
-8L), class = c("tbl_df", "tbl", "data.frame"))
I have the following command for plotting the means and confidence intervals for each group:
ggplot(df, aes(x = Gender, y = MeanBlood, colour = Gender)) +
geom_errorbar(aes(ymin = MeanBlood - SEBlood*qnorm(0.975), ymax = MeanBlood
+ SEBlood*qnorm(0.975)), width = 0.3, stat = "identity") +
geom_point(size = 3) + facet_grid(~HGGroup) + theme(legend.position =
"none") +
geom_text(aes(label = N, x = Gender), vjust = -5)
I am trying to get the text exactly on top of the error bar, but it needs to be in a different location for each group and currently comes out weird.
I think the problem originates from the fact that the confidence interval has a different length for each group, so that a constant justification would not work - it has to be relative to the lower quartile.
Any suggestions?
This seems to work, the y of your label, as you want it, is not the y set in the aes of ggplot, but is ymax:
ggplot(df, aes(x = Gender, y = MeanBlood, colour = Gender)) +
geom_errorbar(aes(ymin = MeanBlood - SEBlood*qnorm(0.975), ymax = MeanBlood
+ SEBlood*qnorm(0.975)), width = 0.3, stat = "identity") +
geom_point(size = 3) + facet_grid(~HGGroup) + theme(legend.position =
"none") +
geom_text(aes(y = MeanBlood + SEBlood*qnorm(0.975), label = N, x = Gender), vjust = -1)
If you move ymax to the ggplot call other layers will be able to access it so no need to redefine it:
ggplot(df, aes(x = Gender, y = MeanBlood, colour = Gender,
ymin = MeanBlood - SEBlood*qnorm(0.975), ymax = MeanBlood
+ SEBlood*qnorm(0.975))) +
geom_errorbar(aes(width = 0.3), stat = "identity") +
geom_point(size = 3) + facet_grid(~HGGroup) + theme(legend.position =
"none") +
geom_text(aes(y = stat(ymax), label = N, x = Gender), vjust = -1)

ggplot: remove lines at ribbon edges

I am using ggplot to plot time course data (fixation proportions over time to different objects on the screen) and want to use a ribbon to show the SE, but the ribbon itself has lines at the top and bottom edges, which makes reading the graph a bit harder. I haven't been able to figure out how to get rid of those edge lines. Here is my plot code:
ggplot(d, aes(Time, y, color = Object, fill = Object)) +
stat_summary(fun.y = "mean", geom = "line", size = 2) +
stat_summary(fun.data = "mean_se", geom = "ribbon", alpha = .3)
Any suggestions?
Here is a minimal working example. I've compressed my data to:
Time Object y lower upper
1 1000 C 0.12453389 0.04510504 0.2039627
2 1000 T 0.58826856 0.37615078 0.8003864
3 1000 U 0.09437160 0.03278069 0.1559625
4 1100 C 0.12140127 0.03943988 0.2033627
5 1100 T 0.64560823 0.44898727 0.8422292
6 1100 U 0.06725172 0.01584248 0.1186610
d <- structure(list(Time = c(1000L, 1000L, 1000L, 1100L, 1100L, 1100L), Object = structure(c(1L, 2L, 3L, 1L, 2L, 3L), .Label = c("C",
"T", "U"), class = "factor"), y = c(0.12453389, 0.58826856, 0.0943716,
0.12140127, 0.64560823, 0.06725172), lower = c(0.04510504, 0.37615078,
0.03278069, 0.03943988, 0.44898727, 0.01584248), upper = c(0.2039627,
0.8003864, 0.1559625, 0.2033627, 0.8422292, 0.118661)), .Names = c("Time",
"Object", "y", "lower", "upper"), class = "data.frame", row.names = c("1",
"2", "3", "4", "5", "6"))
and here is the new plot code:
ggplot(d, aes(Time, y, color = Object, fill = Object)) +
geom_line(size = 2) +
geom_ribbon(aes(ymin = lower, ymax = upper), alpha = .3)
You can remove the border using the colour argument:
ggplot(d, aes(Time, y, color = Object, fill = Object)) +
geom_line(size = 2) +
geom_ribbon(aes(ymin = lower, ymax = upper), alpha = .3, colour = NA)
geom_ribbon understands linetype aesthetic. If you want to map linetype to a variable include it in the aes() argument, otherwise, place linetype outside and just give it 0, like so:
ggplot(d, aes(Time, y, color = Object, fill = Object)) +
geom_line(size = 2) +
geom_ribbon(aes(ymin = lower, ymax = upper), linetype = 0, alpha = .3)
More info here: http://docs.ggplot2.org/current/geom_ribbon.html
ggplot2's geom_ribbon() now includes an outline.type argument that helps control how the ribbon outlines are displayed.
Outline Type
library(tidyverse)
huron <- tibble(year = 1875:1972, level = as.vector(LakeHuron))
huron %>%
ggplot(aes(year, level)) +
geom_ribbon(aes(ymin = level - 1, ymax = level + 1),
fill = "grey70", color = "red",
outline.type = "lower") +
geom_line(aes(y = level))
Created on 2020-05-28 by the reprex package (v0.3.0)
Linetype = 0
Alternatively, as suggested we can set linetype = 0 to remove all lines.
library(tidyverse)
huron <- tibble(year = 1875:1972, level = as.vector(LakeHuron))
huron %>%
ggplot(aes(year, level)) +
geom_ribbon(aes(ymin = level - 1, ymax = level + 1),
fill = "grey70", color = "red", linetype = 0) +
geom_line(aes(y = level))
Created on 2020-05-28 by the reprex package (v0.3.0)
Here you go
ggplot(d, aes(Time, y, fill=Object)) +
geom_line(size=2, aes(colour = Object)) +
geom_ribbon(aes(ymin=lower, ymax=upper), alpha=.3)

Resources