Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add axis text in this negative and positive bars differently using ggplot2?

Tags:

r

ggplot2

I've drawed bar graph with negative and positive bars which is familiar to the research. However, my code seems extremely inconvenient and verbose usinggraphics::plot() and graphics::text() as showed below. Try as I may, I could find the solution using element_text to fulfill in ggplot2. Please help or try to give some ideas how to achieve this in ggplot2.Thanks in advance. enter image description here

# my data
df <- data.frame(genus=c("Prevotella","Streptococcus","YRC22","Phascolarctobacterium","SMB53","Epulopiscium",
                         "CF231","Anaerovibrio","Paludibacter","Parabacteroides","Desulfovibrio","Sutterella",
                         "Roseburia","Others__0_5_","Akkermansia","Bifidobacterium","Campylobacter","Fibrobacter",
                         "Coprobacillus","Bulleidia","f_02d06","Dorea","Blautia","Enterococcus","Eubacterium",
                         "p_75_a5","Clostridium","Coprococcus","Oscillospira","Escherichia","Lactobacillus"),
                 class=c(rep("groupA",18),rep("groupB",13)),
                 value=c(4.497311,4.082377,3.578472,3.567310,3.410453,3.390026,
                         3.363542,3.354532,3.335634,3.284165,3.280838,3.218053,
                         3.071454,3.026663,3.021749,3.004152,2.917656,2.811455,
                        -2.997631,-3.074314,-3.117659,-3.151276,-3.170631,-3.194323,
                        -3.225207,-3.274281,-3.299712,-3.299875,-3.689051,-3.692055,
                        -4.733154)
     )

# bar graph 
tiff(file="lefse.tiff",width=2000,height=2000,res=400)
par(mar=c(5,2,1,1))
barplot(df[,3],horiz=T,xlim=c(-6,6),xlab="LDA score (log 10)",
        col=c(rep("forestgreen",length(which(df[,2]=="groupA"))),
              rep("goldenrod",length(which(df[,2]=="groupB")))))
axis(1,at=seq(-6,6,by=1))
# add text
text(0.85,36.7,label=df[,1][31],cex=0.6);text(0.75,35.4,label=df[,1][30],cex=0.6)
text(0.75,34.1,label=df[,1][29],cex=0.6);text(0.85,33.0,label=df[,1][28],cex=0.6)
text(0.75,31.8,label=df[,1][27],cex=0.6);text(0.6,30.6,label=df[,1][26],cex=0.6)
text(0.8,29.5,label=df[,1][25],cex=0.6);text(0.85,28.3,label=df[,1][24],cex=0.6)
text(0.45,27.1,label=df[,1][23],cex=0.6);text(0.4,25.9,label=df[,1][22],cex=0.6)
text(0.55,24.7,label=df[,1][21],cex=0.6);text(0.55,23.5,label=df[,1][20],cex=0.6)
text(0.85,22.3,label=df[,1][19],cex=0.6);text(-0.75,21.1,label=df[,1][18],cex=0.6)
text(-1,19.9,label=df[,1][17],cex=0.6);text(-1,18.8,label=df[,1][16],cex=0.6)
text(-0.85,17.6,label=df[,1][15],cex=0.6);text(-0.85,16.3,label=df[,1][14],cex=0.6)
text(-0.7,15.1,label=df[,1][13],cex=0.6);text(-0.65,13.9,label=df[,1][12],cex=0.6)
text(-0.85,12.7,label=df[,1][11],cex=0.6);text(-1.05,11.5,label=df[,1][10],cex=0.6)
text(-0.85,10.3,label=df[,1][9],cex=0.6);text(-0.85,9.1,label=df[,1][8],cex=0.6)
text(-0.47,7.9,label=df[,1][7],cex=0.6);text(-0.85,6.7,label=df[,1][6],cex=0.6)
text(-0.49,5.5,label=df[,1][5],cex=0.6);text(-1.44,4.3,label=df[,1][4],cex=0.6)
text(-0.49,3.1,label=df[,1][3],cex=0.6);text(-0.93,1.9,label=df[,1][2],cex=0.6)
text(-0.69,0.7,label=df[,1][1],cex=0.6)
# add lines
segments(0,-1,0,40,lty=3,col="grey")
segments(2,-1,2,40,lty=3,col="grey")
segments(4,-1,4,40,lty=3,col="grey")
segments(6,-1,6,40,lty=3,col="grey")
segments(4,-1,4,40,lty=3,col="grey")
segments(-2,-1,-2,40,lty=3,col="grey")
segments(-4,-1,-4,40,lty=3,col="grey")
segments(-6,-1,-6,40,lty=3,col="grey")
legend("topleft",bty="n",cex=0.65,inset=c(0.01,-0.02),ncol=2,
       legend=c("groupA","groupB"),
       col=c("forestgreen", "goldenrod"),pch=c(15,15))
dev.off()
like image 740
Dr Duck Avatar asked Mar 07 '17 08:03

Dr Duck


3 Answers

Here's a solution using dplyr to create some extra columns for the label position and the justification, and then theming the plot to match reasonably closely what you originally had:

library("dplyr")
library("ggplot2")
df <- df %>%
  mutate(
    genus = factor(genus, levels = genus[order(value, decreasing = TRUE)]),
    label_y = ifelse(value < 0, 0.2, -0.2),
    label_hjust = ifelse(value < 0, 0, 1)
  )

my_plot <- ggplot(df, aes(x = genus, y = value, fill = class)) +
  geom_bar(stat = "identity", col = "black") +
  geom_text(aes(y = label_y, label = genus, hjust = label_hjust)) +
  coord_flip() +
  scale_fill_manual(values = c(groupA = "forestgreen", groupB = "goldenrod")) +
  theme_minimal() +
  theme(axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        axis.title.y = element_blank(),
        legend.position = "top",
        legend.justification = 0.05,
        legend.title = element_blank(),
        panel.grid.major.y = element_blank(),
        panel.grid.minor.y = element_blank(),
        panel.grid.major.x = element_line(colour = "grey80", linetype = "dashed"),
        panel.grid.minor.x = element_blank()) +
  scale_y_continuous(expression(log[10](italic("LDA score"))),
                     breaks = -6:6, limits = c(-6, 6))

print(my_plot)
ggsave("lefse.tiff", width = 5, height = 5, dpi = 400, my_plot)

enter image description here

like image 168
Nick Kennedy Avatar answered Nov 08 '22 10:11

Nick Kennedy


I would try this:

library(ggplot2)

# change the factor levels so it will be displayed in correct order
df$genus <- factor(df$genus, levels = as.character(df$genus))

ggplot(df, aes(x = genus, y = value)) +
    geom_bar(aes(fill = class), stat = 'identity') +  # color by class
    coord_flip() +  # horizontal bars
    geom_text(aes(y = 0, label = genus, hjust = as.numeric(value > 0))) +  # label text based on value
    theme(axis.text.y = element_blank())

enter image description here

In the above, hjust will change the direction of the text relative to its y position (flipped to x now), which is similar to pos parameter in base R plot. So you code could also be simplified with a vector for pos argument to text function.

like image 20
mt1022 Avatar answered Nov 08 '22 10:11

mt1022


Two options:

library(ggplot2)

# my data
df <- data.frame(genus=c("Prevotella","Streptococcus","YRC22","Phascolarctobacterium","SMB53","Epulopiscium",
                         "CF231","Anaerovibrio","Paludibacter","Parabacteroides","Desulfovibrio","Sutterella",
                         "Roseburia","Others__0_5_","Akkermansia","Bifidobacterium","Campylobacter","Fibrobacter",
                         "Coprobacillus","Bulleidia","f_02d06","Dorea","Blautia","Enterococcus","Eubacterium",
                         "p_75_a5","Clostridium","Coprococcus","Oscillospira","Escherichia","Lactobacillus"),
                 class=c(rep("groupA",18),rep("groupB",13)),
                 value=c(4.497311,4.082377,3.578472,3.567310,3.410453,3.390026,
                         3.363542,3.354532,3.335634,3.284165,3.280838,3.218053,
                         3.071454,3.026663,3.021749,3.004152,2.917656,2.811455,
                         -2.997631,-3.074314,-3.117659,-3.151276,-3.170631,-3.194323,
                         -3.225207,-3.274281,-3.299712,-3.299875,-3.689051,-3.692055,
                         -4.733154)
)

ggplot(df, aes(reorder(genus, -value), value, fill = class)) +
    geom_bar(stat = "identity") +
    coord_flip() +
    geom_text(aes(label = genus,
                  y = ifelse(value < 1, 1.5, -1.5)), size = 2.5) +
    theme(axis.title.y=element_blank(),
          axis.text.y=element_blank(),
          axis.ticks.y=element_blank())

enter image description here

Or this:

library(ggplot2)

# my data
df <- data.frame(genus=c("Prevotella","Streptococcus","YRC22","Phascolarctobacterium","SMB53","Epulopiscium",
                         "CF231","Anaerovibrio","Paludibacter","Parabacteroides","Desulfovibrio","Sutterella",
                         "Roseburia","Others__0_5_","Akkermansia","Bifidobacterium","Campylobacter","Fibrobacter",
                         "Coprobacillus","Bulleidia","f_02d06","Dorea","Blautia","Enterococcus","Eubacterium",
                         "p_75_a5","Clostridium","Coprococcus","Oscillospira","Escherichia","Lactobacillus"),
                 class=c(rep("groupA",18),rep("groupB",13)),
                 value=c(4.497311,4.082377,3.578472,3.567310,3.410453,3.390026,
                         3.363542,3.354532,3.335634,3.284165,3.280838,3.218053,
                         3.071454,3.026663,3.021749,3.004152,2.917656,2.811455,
                         -2.997631,-3.074314,-3.117659,-3.151276,-3.170631,-3.194323,
                         -3.225207,-3.274281,-3.299712,-3.299875,-3.689051,-3.692055,
                         -4.733154)
)

ggplot(df, aes(reorder(genus, -value), value, fill = class)) +
    geom_bar(stat = "identity") +
    coord_flip() +
    xlab("genus")

enter image description here

like image 1
conrad-mac Avatar answered Nov 08 '22 10:11

conrad-mac