Adjusting distance between groups of bars in ggplot2 - r

This is my data:
> sum.ex
Timepoint mean n sd Time Group
A1 A1-All 1.985249 26 1.000180 A1 All
A1-pT2D A1-pT2D 1.913109 13 1.012633 A1 pT2D
A1-Control A1-Control 2.934105 13 2.472951 A1 Control
B1 B1-All 2.555601 25 1.939970 B1 All
B1-pT2D B1-pT2D 2.057389 13 1.023416 B1 pT2D
B1-Control B1-Control 2.145555 12 1.089522 B1 Control
This is my code:
png('ex')
ggplot(sum.ex, aes(x = Timepoint, y = mean)) +
  geom_bar(width = 0.5, position = position_dodge(width = 200), stat="identity", aes(fill = Group)) +
geom_errorbar(aes(ymin=mean-sd, ymax=mean+sd), size = 1, shape = 1, width = 0.2) +
scale_fill_manual(values = c("#333333", "#FF0000", "#0000FF")) +
xlab(NULL) +
ggtitle("PLIN1") + theme_bw() + theme(panel.grid.major = element_blank())
dev.off()
This is the output:
However, I want to have Black+Red+Blue really close, then a space and then Black+Red+Blue really close again.
Thank you!

I think this is easiest to achieve if you use x = Time and fill = Group. Something like:
dodge <- position_dodge(width = 0.5)
ggplot(df, aes(x = Time, y = mean, fill = Group)) +
geom_bar(width = 0.5, stat="identity", position = dodge) +
geom_errorbar(aes(ymin=mean-sd, ymax=mean+sd),
position = dodge, size = 1, shape = 1, width = 0.2) +
scale_fill_manual(values = c("#333333", "#FF0000", "#0000FF")) +
theme_bw() +
theme(panel.grid.major = element_blank())

Plot against Time only, then position_dodge has meaning for the bars (there are 3 observations per group). Use position_dodge with width close to the bar width. Add group=Group to make the errorbars behave like the bars (you need it since they don't have colour aesthetic to distinguish them). Use the same position_dodge width as before to align them properly.
ggplot(sum.ex, aes(x = Time, y = mean)) +
geom_bar(width = 0.5, position = position_dodge(width = 0.5), stat = "identity", aes(fill = Group)) +
geom_errorbar(aes(ymin=mean-sd, ymax=mean+sd, group=Group), position=position_dodge(width = 0.5), size = 1, shape = 1, width = 0.2) +
scale_fill_manual(values = c("#333333", "#FF0000", "#0000FF")) +
xlab(NULL) +
ggtitle("PLIN1") + theme_bw() + theme(panel.grid.major = element_blank())

Related

How do I remove certain values from my x-axis?

I'm coding a graph for a project i was wondering if i could get rid of the 2,3 ,and 4 that appear on the x-axis so the bars are only on 0, 1 and 5
this is my code:
strain_colours <- c("dark blue", "light blue")
ggplot(data = bar_sum, aes(x = conc, y = mean, fill = strain)) +
scale_fill_manual(values = strain_colours) +
geom_bar(stat = 'identity',
position = "dodge") +
geom_errorbar(data = bar_sum, aes(x = conc, ymin = mean - se, ymax = mean + se),
width = 0.25,
position = position_dodge(width = 0.9)) +
scale_x_continuous(expand = c(0,0),
name = "Caffeine concentration (mM)",
) +
scale_y_continuous(expand = c(0,0),
name = "Mean distance travelled (mm)") +
theme_classic()
i've also tried setting the x-scale to discrete, and setting the x value to a string of numbers but it doesn't like that

How to create an individual line plot in between box plot in r

I'm trying to create a plot like this image below where the individual data lines are in between the box plots. Image to create in R ggplot2
The closest I am getting is something like this:
Image using ggplot2 but it looks a bit cluttered with the lines/points behind.
data1 %>%
ggplot(aes(Time,Trait)) +
geom_line(aes(group=ID), position = "identity")+
geom_point(aes(group=ID), shape=21, colour="black", size=2, position = "identity")+
geom_boxplot(width=.5,position = position_dodge(width=0.9), fill="white") +
stat_summary(fun.data= mean_cl_boot, geom = "errorbar", width = 0.1, position = position_dodge(width = .9)) +
stat_summary(fun = mean, geom = "point", shape = 18, size=3, position = "identity")+
facet_wrap(~Cond) +
theme_classic()
Any tips would be greatly appreciated!
One option to achieve your desired result would be to make use of continuous x scale. Doing so makes it possible to shift the box plots to the left or to right and vice versa for the points and lines:
Making use of some random data to mimic your real data set.
data1$Time1 <- as.numeric(factor(data1$Time, levels = c("Pre", "Post")))
data1$Time_box <- data1$Time1 + .1 * ifelse(data1$Time == "Pre", -1, 1)
data1$Time_lp <- data1$Time1 + .1 * ifelse(data1$Time == "Pre", 1, -1)
library(ggplot2)
ggplot(data1, aes(x = Time_box, y = Trait)) +
geom_line(aes(x = Time_lp, group=ID), position = "identity")+
geom_point(aes(x = Time_lp, group=ID), shape=21, colour="black", size=2, position = "identity")+
geom_boxplot(aes(x = Time_box, group=Time1), width=.25, fill="white") +
stat_summary(fun.data = mean_cl_boot, geom = "errorbar", width = 0.1) +
stat_summary(fun = mean, geom = "point", shape = 18, size=3, position = "identity") +
scale_x_continuous(breaks = c(1, 2), labels = c("Pre", "Post")) +
facet_wrap(~Cond) +
theme_classic()
DATA
set.seed(42)
data1 <- data.frame(
ID = rep(1:10, 4),
Time = rep(c("Pre", "Post"), each = 10),
Trait = runif(40),
Cond = rep(c("MBSR", "SME"), each = 20)
)
EDIT If you want to two boxplots side by side it's basically the same. However in that case you have to map the interaction of Time1 and the variable mapped on fill on the group aesthetic in geom_boxplot (and probably the error bars as well):
library(ggplot2)
set.seed(42)
data1 <- data.frame(
ID = rep(1:10, 4),
Time = rep(c("Pre", "Post"), each = 10),
Fill = rep(c("Fill1", "Fill2"), each = 5),
Trait = runif(40),
Cond = rep(c("MBSR", "SME"), each = 20)
)
ggplot(data1, aes(x = Time_box, y = Trait)) +
geom_line(aes(x = Time_lp, group=ID, color = Fill), position = "identity")+
geom_point(aes(x = Time_lp, group=ID, fill = Fill), shape=21, colour="black", size=2, position = "identity")+
geom_boxplot(aes(x = Time_box, group=interaction(Time1, Fill) , fill = Fill), width=.25) +
stat_summary(fun.data = mean_cl_boot, geom = "errorbar", width = 0.1) +
stat_summary(fun = mean, geom = "point", shape = 18, size=3, position = "identity") +
scale_x_continuous(breaks = c(1, 2), labels = c("Pre", "Post")) +
facet_wrap(~Cond) +
theme_classic()

Breaking y-axis in ggplot2 with geom_bar

I'm having a hard time dealing with this plot.
The height of values in ANI>96 making it hard to read the red and blue percentage text.
I failed to break the y-axis by looking at answers from other posts in StackOverflow.
Any suggestions?
Thanks.
library(data.table)
library(ggplot2)
dt <- data.table("ANI"= sort(c(seq(79,99),seq(79,99))), "n_pairs" = c(5, 55, 13, 4366, 6692, 59568, 382873, 397996, 1104955, 282915,
759579, 261170, 312989, 48423, 120574, 187685, 353819, 79468, 218039, 66314, 41826, 57668, 112960, 81652, 28613,
64656, 21939, 113656, 170578, 238967, 610234, 231853, 1412303, 5567, 4607268, 5, 14631942, 0, 17054678, 0, 3503846, 0),
"same/diff" = rep(c("yes","no"), 21))
for (i in 1:nrow(dt)) {
if (i%%2==0) {
next
}
total <- dt$n_pairs[i] + dt$n_pairs[i+1]
dt$total[i] <- total
dt$percent[i] <- paste0(round(dt$n_pairs[i]/total *100,2), "%")
dt$total[i+1] <- total
dt$percent[i+1] <- paste0(round(dt$n_pairs[i+1]/total *100,2), "%")
}
ggplot(data=dt, aes(x=ANI, y=n_pairs, fill=`same/diff`)) +
geom_text(aes(label=percent), position=position_dodge(width=0.9), hjust=0.75, vjust=-0.25) +
geom_bar(stat="identity") + scale_x_continuous(breaks = dt$ANI) +
labs(x ="ANI", y = "Number of pairs", fill = "Share one common species taxonomy?") +
theme_classic() + theme(legend.position="bottom")
Here is the list of major changes I made:
I reduced the y axis by zooming into the chart with coord_cartesian (which is called by coord_flip).
coord_flip shouuld also improve the readability of the chart by switching x and y. I don't know if the switch is a desirable output for you.
Also now position_dodge, works as expected: two bars next to each other with the labels on top (on the left in this case).
I set geom_bar before geom_text so that the text is always in front of the bars in the chart.
I set scale_y_continuous to change the labels of the y axis (in the chart the x axis because of the switch) to improve the readability of the zeros.
ggplot(data=dt, aes(x = ANI, y = n_pairs, fill = `same/diff`)) +
geom_bar(stat = "identity", position = position_dodge2(width = 1), width = 0.8) +
geom_text(aes(label = percent), position = position_dodge2(width = 1), hjust = 0, size = 3) +
scale_x_continuous(breaks = dt$ANI) +
scale_y_continuous(labels = scales::comma) +
labs(x ="ANI", y = "Number of pairs", fill = "Share one common species taxonomy?") +
theme_classic() +
theme(legend.position = "bottom") +
coord_flip(ylim = c(0, 2e6))
EDIT
Like this columns and labels are stacked but labels never overlap.
ggplot(data=dt, aes(x = ANI, y = n_pairs, fill = `same/diff`)) +
geom_bar(stat = "identity", width = 0.8) +
geom_text(aes(label = percent,
hjust = ifelse(`same/diff` == "yes", 1, 0)),
position = "stack", size = 3) +
scale_x_continuous(breaks = dt$ANI) +
scale_y_continuous(labels = scales::comma) +
labs(x ="ANI", y = "Number of pairs", fill = "Share one common species taxonomy?") +
theme_classic() +
theme(legend.position = "bottom") +
coord_flip(ylim = c(0, 2e6))
Alternatively, you can avoid labels overlapping with check_overlap = TRUE, but sometimes one of the labels will not be shown.
ggplot(data=dt, aes(x = ANI, y = n_pairs, fill = `same/diff`)) +
geom_bar(stat = "identity", width = 0.8) +
geom_text(aes(label = percent), hjust = 1, position = "stack", size = 3, check_overlap = TRUE) +
scale_x_continuous(breaks = dt$ANI) +
scale_y_continuous(labels = scales::comma) +
labs(x ="ANI", y = "Number of pairs", fill = "Share one common species taxonomy?") +
theme_classic() +
theme(legend.position = "bottom") +
coord_flip(ylim = c(0, 2e6))

Labling bars in grouped barplot in ggplot

The main goal of this plot is to make a comparison between A and B in three groups, but I want to have one, two, and three besides them, as well. Using below code, I can make a grouped barplot which is almost what I want. But I need to have the names of each bar below it since the legend is so ugly.
How can I do it?
m.names <- c("A1","B1","one","A2","B2","two","A3","B3","three")
m.group <- c(1,1,1,2,2,2,3,3,3)
m.value <- c(5,10,1,20,15,2,10,20,3)
df <- data.frame(m.names, m.group, m.value)
df
ggplot(df, aes(x = m.group, y = m.value)) +
geom_bar(aes(fill = m.names), position = "dodge", stat = "identity") +
scale_fill_manual(values=c("gray75", "gray75","gray75", "gray40","gray40","gray40", "blue", "red", "green" ))
Adding geom_text and making sure it's dodged in the same way as the bars:
# width = 0.9 should be the default for dodged bars but set
# it explicitly to be sure
dodger = position_dodge(width = 0.9)
ggplot(df, aes(x = m.group, y = m.value)) +
geom_bar(aes(fill = m.names), position = dodger, stat = "identity") +
scale_fill_manual(values=c("gray75", "gray75","gray75", "gray40","gray40","gray40", "blue", "red", "green" ),
guide = "none") +
geom_text(aes(x = m.group, group = m.names, label = m.names, y = 0),
position = dodger,
vjust = 1, colour = "black")
Faceting by group may work for this case as well:
fill.values = c("gray75", "gray75","gray75",
"gray40","gray40","gray40",
"blue", "red", "green")
names(fill.values) = levels(df$m.names)
> fill.values
A1 A2 A3 B1 B2 B3 one three two
"gray75" "gray75" "gray75" "gray40" "gray40" "gray40" "blue" "red" "green"
ggplot(df,
aes(x = m.names, y = m.value, fill = m.names)) +
geom_col() +
scale_fill_manual(values = fill.values, guide = F) +
facet_wrap(~m.group, scales = "free_x") +
theme_bw()
Seems like you might want this:
require(ggplot2)
ggplot(df, aes(x = m.names, y = m.value)) +
geom_bar(aes(fill = m.names), stat = "identity") +
scale_fill_manual(values=c("gray75", "gray75","gray75", "gray40",
"gray40","gray40", "blue", "red", "green" )) +
facet_grid(~m.group, scales = "free_x", space = "free_x") +
theme(strip.text.x = element_blank(),
panel.spacing = unit(0, "lines"))
Output:
The trick is to plot x by m.names here instead of m.groups. Then later we can facet the bars by m.group to keep them presented the way you want.
We could use geom_label
dodger = position_dodge(width = 0.9)
ggplot(df, aes(x = m.group, y = m.value)) +
geom_bar(aes(fill = m.names), position = dodger, stat = "identity") +
scale_fill_manual(values=c("gray75", "gray75","gray75",
"gray40","gray40","gray40", "blue", "red", "green" ),
guide = "none") +
theme(axis.text.x=element_blank(),
axis.ticks.x=element_blank()) +
geom_label(aes(x = m.group, group = m.names, label = m.names, y = 0),
position = dodger,
vjust = 1, colour = "black")

R - Name of each bar in ggplot2

I would like to have the name of each bar under each bar (in my case the names are "Round" and they happen to be 1, 2, ... 12)
Here is my current code:
ggplot(data=draft1, aes(x = Round, y = mean.age)) +
geom_bar(stat = "identity", fill = "steelblue", color = "black", width = 0.7) +
ylab("Average age of retirement") + ylim(c(0,40)) +
ggtitle("Average age of retirement by rounds of all players") +
geom_text(aes(label = mean.age), position=position_dodge(width=0.9), vjust = -0.5)
Here is the current output:
set your Round to be a factor
ggplot(data=draft1, aes(x = factor(Round), y = mean.age)) +
Or use scale_x_continuous()
ggplot(data=draft1, aes(x = Round, y = mean.age)) +
... +
scale_x_continuous(breaks=(seq(1:12)))
Just add a discrete scale to x:
library(ggplot2)
draft1 = data.frame(Round = seq(1, 12), mean.age = sample(29:32))
ggplot(data=draft1, aes(x = Round, y = mean.age)) +
geom_bar(stat = "identity", fill = "steelblue", color = "black", width = 0.7) +
ylab("Average age of retirement") + ylim(c(0,40)) +
ggtitle("Average age of retirement by rounds of all players") +
geom_text(aes(label = mean.age), position=position_dodge(width=0.9), vjust = -0.5) +
scale_x_discrete()

Resources