adjusting position of text above an error bar in ggplot - r

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)

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

Positioning labels and color coding in sunburst - R

This is what is the output.I have a data set which contains unit, weight of each unit and compliance score for each unit in year 2016.
I was not able to add the table but here is the screenshot for the data in csv
I have named the columns in the data as unit, weight and year(which is compliance score) .
I want to create a sunburst chart where the first ring will be the unit divided based on weight and the second ring will be the same but will have labels compliance score.
The colour for each ring will be different.
I was able to do some code with the help from an online blog and the output I have gotten is similar to what I want but I am facing difficulty in positioning of the labels and also the colour coding for each ring
#using ggplot
library(ggplot2) # Visualisation
library(dplyr) # data wrangling
library(scales) # formatting
#read file
weight.eg = read.csv("Dummy Data.csv", header = FALSE, sep =
";",encoding = "UTF-8")
#change column names
colnames(weight.eg) <- c ("unit","weight","year")
#as weight column is factor change into integer
weight.eg$weight = as.numeric(levels(weight.eg$weight))
[as.integer(weight.eg$weight)]
weight.eg$year = as.numeric(levels(weight.eg$year))
[as.integer(weight.eg$year)]
#Nas are introduced, remove
weight.eg <- na.omit(weight.eg)
#Sum of the total weight
sum_total_weight = sum(weight.eg$weight)
#First layer
firstLevel = weight.eg %>% summarize(total_weight=sum(weight))
sunburst_0 = ggplot(firstLevel) # Just a foundation
#this will generate a bar chart
sunburst_1 =
sunburst_0 +
geom_bar(data=firstLevel, aes(x=1, y=total_weight),
fill='darkgrey', stat='identity') +
geom_text(aes(x=1, y=sum_total_weight/2, label=paste("Total
Weight", comma(total_weight))), color='black')
#View
sunburst_1
#this argument is used to rotate the plot around the y-axis which
the total weight
sunburst_1 + coord_polar(theta = "y")
sunburst_2=
sunburst_1 +
geom_bar(data=weight.eg,
aes(x=2, y=weight.eg$weight, fill=weight.eg$weight),
color='white', position='stack', stat='identity', size=0.6)
+
geom_text(data=weight.eg, aes(label=paste(weight.eg$unit,
weight.eg$weight), x=2, y=weight.eg$weight), position='stack')
sunburst_2 + coord_polar(theta = "y")
sunburst_3 =
sunburst_2 +
geom_bar(data=weight.eg,
aes(x=3, y=weight.eg$weight,fill=weight.eg$weight),
color='white', position='stack', stat='identity',
size=0.6)+
geom_text(data = weight.eg,
aes(label=paste(weight.eg$year),x=3,y=weight.eg$weight),position =
'stack')
sunburst_3 + coord_polar(theta = "y")
sunburst_3 + scale_y_continuous(labels=comma) +
scale_fill_continuous(low='white', high='darkred') +
coord_polar('y') + theme_minimal()
Output for dput(weight.eg)
structure(list(unit = structure(2:7, .Label = c("", "A", "B",
"C", "D", "E", "F", "Unit"), class = "factor"), weight = c(30,
25, 10, 17, 5, 13), year = c(70, 80, 50, 30, 60, 40)), .Names =
c("unit",
"weight", "year"), row.names = 2:7, class = "data.frame", na.action
= structure(c(1L,
8L), .Names = c("1", "8"), class = "omit"))
output for dput(firstLevel)
structure(list(total_weight = 100), .Names = "total_weight", row.names
= c(NA,
-1L), na.action = structure(c(1L, 8L), .Names = c("1", "8"), class =
"omit"), class = "data.frame")
So I think I might have some sort of solution for you. I wasn't sure what you wanted to color-code on the outer ring; from your code it seems you wanted it to be the weight again, but it was not obvious to me. For different colour scales per ring, you could use the ggnewscale package:
library(ggnewscale)
For the centering of the labels you could write a function:
cs_fun <- function(x){(cumsum(x) + c(0, cumsum(head(x , -1))))/ 2}
Now the plotting code could look something like this:
ggplot(weight.eg) +
# Note: geom_col is equivalent to geom_bar(stat = "identity")
geom_col(data = firstLevel,
aes(x = 1, y = total_weight)) +
geom_text(data = firstLevel,
aes(x = 1, y = total_weight / 2,
label = paste("Total Weight:", total_weight)),
colour = "black") +
geom_col(aes(x = 2,
y = weight, fill = weight),
colour = "white", size = 0.6) +
scale_fill_gradient(name = "Weight",
low = "white", high = "darkred") +
# Open up new fill scale for next ring
new_scale_fill() +
geom_text(aes(x = 2, y = cs_fun(weight),
label = paste(unit, weight))) +
geom_col(aes(x = 3, y = weight, fill = weight),
size = 0.6, colour = "white") +
scale_fill_gradient(name = "Another Weight?",
low = "forestgreen", high = "white") +
geom_text(aes(label = paste0(year), x = 3,
y = cs_fun(weight))) +
coord_polar(theta = "y")
Which looks like this:

ggplot jitter geom_errorbar?

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

Resources