Creating error bars in one direction, a special case - r

Long time lurker here.
I am plotting the predicted values from a previously run, nlme model using the output by ggpredict. I have built a line plot and want to create error bars on the points. Though, reviewers want the error bars to only be going one direction (i.e., for the group who is higher = positive error bars, while the group who is negative gets negative error bars). I've successfully done this with this code:
Q1 <- ggpredict(MODEL, c("day", "group"),
#ci.lvl = NA,
type = "re")
q2 <- Q1 %>%
mutate(is.int = group == "Intervention",
conf.high = ifelse(is.int, std.error, conf.high),
conf.low = ifelse(is.int, 0, conf.low)) %>%
select(-is.int) %>%
mutate(is.cntr = group == "Control",
conf.high = ifelse(is.cntr, 0, conf.high),
conf.low = ifelse(is.cntr, std.error, conf.low)) %>%
select(-is.cntr)
ggplot(data = q2,
aes(x, predicted, group = group)) +
geom_point(aes(shape = group), size = 6) +
scale_shape_manual(values=c(19, 1)) +
geom_line(size = 2,
aes(linetype = group),
color = "black") +
scale_linetype_manual(values = c("solid", "dashed")) +
geom_linerange(size = 1,
aes(ymin = predicted - conf.low,
ymax = predicted + conf.high),
color = "black",
alpha = .8) +
labs(x = "Time",
y = "",
linetype = "",
shape = "")
scale_y_continuous(limits =c(1500, 2000)) +
geom_bracket(
xmin = "PRE", xmax = c("MID1", "MID2", "MID3", "POST"),
y.position = c(1850,1900,1950,2000), tip.length = 0.05,
label = c("*", "**", "***", "#"), size = 1)
and it works well.
however
The reviewers would like "caps" on the end of the error bars that i've reated with geom_linerange(). Obviously, geom_errorbar() is almost purpose built to have the "caps". But, when I use it, it creates lines across my data. See pic attached for example.
Thoughts??
Edit, Reproducibile data:
dput(q2)
structure(list(x = structure(c(1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L,
5L, 5L), .Label = c("PRE", "MID1", "MID2", "MID3", "POST"), class = "factor"),
predicted = c(1666.97185871754, 1660.27445165342, 1743.2831065274,
1678.48945165342, 1788.50605542978, 1637.40907049806, 1807.55826371403,
1639.78265640012, 1865.8766220711, 1652.91070173056), std.error = c(88.8033117577884,
91.257045996107, 92.9973963841595, 95.3834973421298, 95.0283457128716,
97.3739053806999, 95.6466346849776, 97.9142418717957, 93.3512943191676,
95.5735155125126), conf.low = c(0, 91.257045996107, 0, 95.3834973421298,
0, 97.3739053806999, 0, 97.9142418717957, 0, 95.5735155125126
), conf.high = c(88.8033117577884, 0, 92.9973963841595, 0,
95.0283457128716, 0, 95.6466346849776, 0, 93.3512943191676,
0), group = structure(c(1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L,
2L), .Label = c("Intervention", "Control"), class = "factor")), class = "data.frame", row.names = c(NA,
-10L))

My suggestion is to highjack the arrow argument of geom_segment() to serve as caps, since you've already precomputed the confidence intervals. You can control with an ifelse whether to take the lower or higher confidence level. Example with dummy data below:
library(ggplot2)
# Make dummy data
df <- data.frame(
x = c(1:10, 1:10),
y = c(1:10, seq(0.5, 5, by = 0.5)),
type = rep(LETTERS[1:2], each = 10)
)
# Dummy confidence intervals
df$conf.hi <- df$y * 1.1
df$conf.lo <- df$y * 0.9
ggplot(df, aes(x, y, colour = type)) +
geom_line() +
geom_point() +
geom_segment(aes(xend = x,
yend = ifelse(type == "A", conf.hi, conf.lo)),
arrow = arrow(angle = 90))
Created on 2020-04-03 by the reprex package (v0.3.0)
EDIT: Example for added data
Probably, the reason that it didn't turn out as the example was because the conf.high/conf.low variables were not added to the prediction.
I used the std.error instead of the conf.* variables, as I noticed these are similar values.
I got a decent plot using the following.
ggplot(q2, aes(x, predicted, colour = group)) +
geom_line(aes(group = group)) +
geom_point() +
geom_segment(aes(xend = x,
yend = predicted + ifelse(group == "Intervention", std.error, -std.error)),
arrow = arrow(angle = 90))

Related

R: ggplot2 - add y-axis break [duplicate]

This question already has answers here:
How can I make a discontinuous axis in R with ggplot2?
(3 answers)
Force the origin to start at 0
(4 answers)
Closed last year.
I am still working on finalizing a reproducible figure for publication. Reviewers would like to see the below plot's y-axis start at 0 and include line break "//". The y-axis will need to not only be pretty large (think, 1500 units) but also zoomed in pretty tightly (think, 300 units). This makes the reviewer want us to add a line break to denote that our axis starts at 0, but continues on.
Example of what I can create:
Example of what I want (note the y axis; this was done manually in powerpoint in a similar figure):
My code:
ggplot(data = quad2,
aes(x, predicted, group = group)) +
geom_point(aes(shape = group), size = 6) +
scale_shape_manual(values=c(19, 1)) +
geom_line(size = 2,
aes(linetype = group),
color = "black") +
scale_linetype_manual(values = c("solid", "dashed")) +
geom_linerange(size = 1,
aes(ymin = predicted - conf.low,
ymax = predicted + conf.high),
color = "black",
alpha = .8) +
geom_segment(aes(xend = x,
yend = ifelse(group == "Control", conf.high, conf.low)),
arrow = arrow(angle = 90), color = "red")+
labs(x = "Time",
y = expression(bold("QUAD Volume (cm"^"3"*")")),
linetype = "",
shape = "") + #Legend title
scale_y_continuous(limits =c(1500, 2000))
Reproducible data:
dput(quad2)
structure(list(x = structure(c(1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L,
5L, 5L), .Label = c("PRE", "MID1", "MID2", "MID3", "POST"), class = "factor"),
predicted = c(1666.97185871754, 1660.27445165342, 1743.2831065274,
1678.48945165342, 1788.50605542978, 1637.40907049806, 1807.55826371403,
1639.78265640012, 1865.8766220711, 1652.91070173056), std.error = c(88.8033117577884,
91.257045996107, 92.9973963841595, 95.3834973421298, 95.0283457128716,
97.3739053806999, 95.6466346849776, 97.9142418717957, 93.3512943191676,
95.5735155125126), conf.low = c(0, 91.257045996107, 0, 95.3834973421298,
0, 97.3739053806999, 0, 97.9142418717957, 0, 95.5735155125126
), conf.high = c(88.8033117577884, 0, 92.9973963841595, 0,
95.0283457128716, 0, 95.6466346849776, 0, 93.3512943191676,
0), group = structure(c(1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L,
2L), .Label = c("Intervention", "Control"), class = "factor")), class = "data.frame", row.names = c(NA,
-10L))
Plotting discontinuous axis is made difficult for a reason, that reason being that you should avoid doing it whenever possible. While I disagree with your reviewers, you can get down and dirty with the underlying grid graphics if you truly want a y-axis break.
First make your plot. The only thing I added was y-axis formatting and an axis line theme. We'll just label the bottom tick with "0".
plt <- ggplot(data = quad2,
aes(x, predicted, group = group)) +
geom_point(aes(shape = group), size = 6) +
scale_shape_manual(values=c(19, 1)) +
geom_line(size = 2,
aes(linetype = group),
color = "black") +
scale_linetype_manual(values = c("solid", "dashed")) +
geom_linerange(size = 1,
aes(ymin = predicted - conf.low,
ymax = predicted + conf.high),
color = "black",
alpha = .8) +
geom_segment(aes(xend = x,
yend = ifelse(group == "Control", conf.high, conf.low)),
arrow = arrow(angle = 90), color = "red")+
labs(x = "Time",
y = expression(bold("QUAD Volume (cm"^"3"*")")),
linetype = "",
shape = "") + #Legend title
scale_y_continuous(limits =c(1400, 2000),
breaks = seq(1400, 2000, by = 200),
labels = c(0, seq(1600, 2000, by = 200)),
expand = c(0,0,0.05,0)) +
theme(axis.line = element_line())
Then, we'll make this into a gtable and grab the y-axis line:
gt <- ggplotGrob(plt)
is_yaxis <- which(gt$layout$name == "axis-l")
yaxis <- gt$grobs[[is_yaxis]]
# You should grab the polyline child
yline <- yaxis$children[[1]]
Now we can edit the line as we see fit:
yline$x <- unit(rep(1, 4), "npc")
yline$y <- unit(c(0, 0.1, 1, 0.15), "npc")
yline$id <- c(1, 1, 2, 2)
yline$arrow <- arrow(angle = 90)
Place it back into the gtable object and plot it:
yaxis$children[[1]] <- yline
gt$grobs[[is_yaxis]] <- yaxis
# grid plotting syntax
grid.newpage(); grid.draw(gt)
You can make stylistic choices at the line editing step as you see fit.
To my knowledge ggplot2 doesn't support axis breaks. There is a solution here with facet_grid.

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")

Force y axis to start at 0, insert "break", AND have a large y axis using ggplot2 [duplicate]

This question already has answers here:
How can I make a discontinuous axis in R with ggplot2?
(3 answers)
Force the origin to start at 0
(4 answers)
Closed last year.
I am still working on finalizing a reproducible figure for publication. Reviewers would like to see the below plot's y-axis start at 0 and include line break "//". The y-axis will need to not only be pretty large (think, 1500 units) but also zoomed in pretty tightly (think, 300 units). This makes the reviewer want us to add a line break to denote that our axis starts at 0, but continues on.
Example of what I can create:
Example of what I want (note the y axis; this was done manually in powerpoint in a similar figure):
My code:
ggplot(data = quad2,
aes(x, predicted, group = group)) +
geom_point(aes(shape = group), size = 6) +
scale_shape_manual(values=c(19, 1)) +
geom_line(size = 2,
aes(linetype = group),
color = "black") +
scale_linetype_manual(values = c("solid", "dashed")) +
geom_linerange(size = 1,
aes(ymin = predicted - conf.low,
ymax = predicted + conf.high),
color = "black",
alpha = .8) +
geom_segment(aes(xend = x,
yend = ifelse(group == "Control", conf.high, conf.low)),
arrow = arrow(angle = 90), color = "red")+
labs(x = "Time",
y = expression(bold("QUAD Volume (cm"^"3"*")")),
linetype = "",
shape = "") + #Legend title
scale_y_continuous(limits =c(1500, 2000))
Reproducible data:
dput(quad2)
structure(list(x = structure(c(1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L,
5L, 5L), .Label = c("PRE", "MID1", "MID2", "MID3", "POST"), class = "factor"),
predicted = c(1666.97185871754, 1660.27445165342, 1743.2831065274,
1678.48945165342, 1788.50605542978, 1637.40907049806, 1807.55826371403,
1639.78265640012, 1865.8766220711, 1652.91070173056), std.error = c(88.8033117577884,
91.257045996107, 92.9973963841595, 95.3834973421298, 95.0283457128716,
97.3739053806999, 95.6466346849776, 97.9142418717957, 93.3512943191676,
95.5735155125126), conf.low = c(0, 91.257045996107, 0, 95.3834973421298,
0, 97.3739053806999, 0, 97.9142418717957, 0, 95.5735155125126
), conf.high = c(88.8033117577884, 0, 92.9973963841595, 0,
95.0283457128716, 0, 95.6466346849776, 0, 93.3512943191676,
0), group = structure(c(1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L,
2L), .Label = c("Intervention", "Control"), class = "factor")), class = "data.frame", row.names = c(NA,
-10L))
Plotting discontinuous axis is made difficult for a reason, that reason being that you should avoid doing it whenever possible. While I disagree with your reviewers, you can get down and dirty with the underlying grid graphics if you truly want a y-axis break.
First make your plot. The only thing I added was y-axis formatting and an axis line theme. We'll just label the bottom tick with "0".
plt <- ggplot(data = quad2,
aes(x, predicted, group = group)) +
geom_point(aes(shape = group), size = 6) +
scale_shape_manual(values=c(19, 1)) +
geom_line(size = 2,
aes(linetype = group),
color = "black") +
scale_linetype_manual(values = c("solid", "dashed")) +
geom_linerange(size = 1,
aes(ymin = predicted - conf.low,
ymax = predicted + conf.high),
color = "black",
alpha = .8) +
geom_segment(aes(xend = x,
yend = ifelse(group == "Control", conf.high, conf.low)),
arrow = arrow(angle = 90), color = "red")+
labs(x = "Time",
y = expression(bold("QUAD Volume (cm"^"3"*")")),
linetype = "",
shape = "") + #Legend title
scale_y_continuous(limits =c(1400, 2000),
breaks = seq(1400, 2000, by = 200),
labels = c(0, seq(1600, 2000, by = 200)),
expand = c(0,0,0.05,0)) +
theme(axis.line = element_line())
Then, we'll make this into a gtable and grab the y-axis line:
gt <- ggplotGrob(plt)
is_yaxis <- which(gt$layout$name == "axis-l")
yaxis <- gt$grobs[[is_yaxis]]
# You should grab the polyline child
yline <- yaxis$children[[1]]
Now we can edit the line as we see fit:
yline$x <- unit(rep(1, 4), "npc")
yline$y <- unit(c(0, 0.1, 1, 0.15), "npc")
yline$id <- c(1, 1, 2, 2)
yline$arrow <- arrow(angle = 90)
Place it back into the gtable object and plot it:
yaxis$children[[1]] <- yline
gt$grobs[[is_yaxis]] <- yaxis
# grid plotting syntax
grid.newpage(); grid.draw(gt)
You can make stylistic choices at the line editing step as you see fit.
To my knowledge ggplot2 doesn't support axis breaks. There is a solution here with facet_grid.

What to do when adding asterisks to bar graph shifts the bars in R?

I've created a bar graph in R and now I tried to add the significant differences to the bar graph.
I've tried using geom_signif from the ggsignif package and stat_compare_means from the ggpubr package (based on these suggestions/examples: Put stars on ggplot barplots and boxplots - to indicate the level of significance (p-value) or https://cran.r-project.org/web/packages/ggsignif/vignettes/intro.html)
I was only able to add the significance levels when using geom_signif and choose the parameters as in https://cran.r-project.org/web/packages/ggsignif/vignettes/intro.html.
This is an example of what I would like to get:
And this is what I get:
So when I want to add the asterisks, it shifts the bars from the bar graph. I don't know how to change it...
This is a part of what I wrote:
bargraph = ggplot(dataPlotROI, aes(x = ROI, y=mean, fill = Group))
bargraph +
geom_bar(position = position_dodge(.5), width = 0.5, stat = "identity") +
geom_errorbar(position = position_dodge(width = 0.5), width = .2,
aes(ymin = mean-SEM, ymax = mean+SEM)) +
geom_signif(y_position = c(4.5,10,10), xmin=c(0.85,0.85,4.3), xmax = c(5,4,7.45),
annotation=c("***"), tip_length = 0.03, inherit.aes = TRUE) +
facet_grid(.~ROI, space= "free_x", scales = "free_x", switch = "x")
This is the output from dput(dataPlotROI):
> Dput <- dput(dataPlotROI)
structure(list(Group = structure(c(1L, 1L, 1L, 2L, 2L, 2L), .Label = c("1",
"2"), class = "factor"), ROI = structure(c(1L, 2L, 3L, 1L, 2L,
3L), .Label = c("LOT", "MO", "ROT"), class = "factor"), mean = c(2.56175803333696,
7.50825658538044, 3.34290874605435, 2.41750375190217, 6.90310020776087,
3.03040666678261), SD = c(1.15192431061913, 4.30564383354597,
2.01581544982848, 1.11404900115086, 3.35276625079825, 1.23786817391241
), SEM = c(0.120096411333424, 0.448894400545147, 0.210163288684092,
0.11614763735292, 0.349550045127766, 0.129056678481624)), class = "data.frame", row.names = c(NA,
-6L))
> Dput
Group ROI mean SD SEM
1 1 LOT 2.561758 1.151924 0.1200964
2 1 MO 7.508257 4.305644 0.4488944
3 1 ROT 3.342909 2.015815 0.2101633
4 2 LOT 2.417504 1.114049 0.1161476
5 2 MO 6.903100 3.352766 0.3495500
6 2 ROT 3.030407 1.237868 0.1290567
Does anyone know what I am doing wrong and how I can fix it?
Thanks!
I don't think geom_signif is meant to span across the facets, but in your case, I don't see any real need for facets anyway. See if the following works for you:
ggplot(dataPlotROI,
aes(x = ROI, y = mean, fill = Group)) +
# geom_col is equivalent to geom_bar(stat = "identity")
geom_col(position = position_dodge(0.5), width = 0.5) +
geom_errorbar(position = position_dodge(0.5), width = 0.2,
aes(ymin = mean - SEM, ymax = mean + SEM)) +
# xmin / xmax positions should match the x-axis labels' positions
geom_signif(y_position = c(4.5, 10, 10),
xmin = c(1, 1, 2.05),
xmax = c(3, 1.95, 3),
annotation = "***",
tip_length = 0.03)

Resources