ggplot2: Display values in stacked bar charts (Values are hidden behind bars) - r

I am having troubles to display the y-values in stacked bar charts as they appear but are displayed behind the bars and hence not visible.
My goal is to display the values within the stacked bars so they are visible. Any help would be highly apprciated. Thank you very much!
The values that should be displayed in the respective stack of every bars are the following:
RAIH <- c(11,13,10,5,7,10,8,4,11,11,4,3,7,9,3,2,11,15,10,6,11,13,14,7,8,16,10,7,6,8,6,4,11,8,5,3,10,12,3,1,11,10,5,2,10,11,4,2,17,12,7,6,9,10,5,3,18,17,7,7,14,11,6,2)
I used following code to display the values, which is also included in the main code.
geom_text(aes(label = RAIH), size = 3,
position = position_stack(vjust = 0.5))
The rest of my code for creating the graph is:
library(ggplot2)
library(patchwork)
library(dplyr)
library(plotrix)
library(plyr)
ploughed1 <- Data_GG %>%
dplyr::select(Tillage, RAI_N, Mulch, compost, Ferment, Horizont, mean, se) %>%
filter(Tillage == "Ploughed", Mulch=="No Mulch") %>%
group_by(Tillage)
ploughed2 <- Data_GG %>%
dplyr::select(Tillage, RAI_N, Mulch, compost, Ferment, Horizont, mean, se) %>%
filter(Tillage == "Ploughed", Mulch=="Mulch") %>%
group_by(Tillage)
reduced1 <- Data_GG %>%
dplyr::select(Tillage, RAI_N, Mulch, compost, Ferment, Horizont, mean, se) %>%
filter(Tillage == "Reduced", Mulch=="No Mulch") %>%
group_by(Tillage)
reduced2 <- Data_GG %>%
dplyr::select(Tillage, RAI_N, Mulch, compost, Ferment, Horizont, mean, se) %>%
filter(Tillage == "Reduced", Mulch=="Mulch") %>%
group_by(Tillage)
plot_fun <- function(x, title) {
ggplot(arrange(x, Horizont), aes(Ferment, RAI_N, label = RAIH,
fill = factor(Horizont, levels = c("4", "3", "2", "1")))) +
geom_bar(stat = "identity", position = "dodge") +
geom_text(aes(label = RAIH), size = 3,
position = position_stack(vjust = 0.5))+
scale_fill_manual(name ="Soil layer (cm)",
values = c("#FF9933", "#CC6600", "#663300", "#000000"),
labels = c("22,5 - 30", "15 - 22,5", "7,5 - 15", "0 - 7,5")) +
guides(fill = guide_legend(reverse = TRUE)) +
ylim(0, 100) +
theme_bw() +
facet_wrap(~compost) +
theme(
strip.text = element_text(size = 6),
panel.spacing = unit(0.2, "lines"),
plot.margin = margin(1,1,1,1)
) +
geom_col(position = position_stack(reverse = TRUE)) +
labs(x = "Ferment", y = "RAI", fill = "Horizon", title = title)
}
remove_y <- theme(
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.title.y = element_blank())
remove_x <- theme(
axis.title.x = element_blank())
p <- list(
plot_fun(ploughed1, "P-"),
plot_fun(ploughed2, "P+") + remove_y + remove_x,
plot_fun(reduced1, "RT-") + remove_y + remove_x,
plot_fun(reduced2, "RT+") + remove_y + remove_x
)
wrap_plots(p, nrow = 1) + plot_layout(guides = "collect")
Output plot

Related

ggplot: labes are doubled in bar chart

I'm trying to do a horizontal, stacked bar chart. I want to label each part of the bar with the corresponding number (count). Those labels appear twice and I don't now why. How can I make "92" etc. appear only once?
Code:
library(ggplot2)
library(dplyr)
library(plyr)
data2 <- data.frame(System=rep(c('participants opinion'), each=5),
attitude=rep(c('totally agree','agree somewhat','unsure','disagree somewhat','totally disagree'), times=2),
count=c(92, 83, 22, 17, 6))
data2$attitude = factor(data2$attitude, levels = c('unsure','totally disagree','disagree somewhat','agree somewhat','totally agree'))
data2 = arrange(data2, System, desc(attitude))
data2 = ddply(data2, .(System), transform, pos = (cumsum(count) - 0.5 * count))
cbPalette <- c("#999999", "#2A7AD4", "#5C96D7", "#D3A253", "#D48F1D")
ggplot(data2, aes(x = factor(System), y = count, fill = attitude)) +
geom_bar(stat = "identity", width = .3) +
geom_text(aes(y = pos, label = count), size = 4) +
coord_flip() +
theme(panel.background = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.title.y = element_blank()) +
scale_fill_manual(values=cbPalette)
your data2 object has 2 rows for every count, if you remove one row of each by:
label_data <- data2 |>
split(~count) |>
purrr::map_dfr(~.x |> head(1))
and putting it into:
geom_text(data = label_data, aes(y = pos, label = count), size = 4)
you can avoid that

Table below x axis in ggplot

Hello everyone I was trying to add some text below the x axis in ggplot2 and I was able to do so using geom_textand with help of coord_cartesian but I couldn't make it reproducible as this need to run in a loop. I thought that adding the values I want with the row names (First, Second) in a table would fix it, does anybody have experience in that. below is the workaround I did. Thank you very much in advance.
## Data
Grade <- 1 : 20
Case <- rep(paste('case' , 1:5,sep = ''),4)
Number <- paste('n', 1:20 , sep = '')
Class <- c(rep('Class1',5) , rep('Class2',5) , rep('Class3',5) , rep('Class4',5))
se <- 0.2
df <- data.frame(Grade,Case ,Number, Class , se)
## plot
ggplot(df, aes(x= factor(Case , levels = c('case1','case2' , 'case3' , 'case4','case5')) , y=Grade ,
fill= Grade)) +
geom_bar(position="dodge", stat="identity",
colour="black",
size=.4) +
geom_errorbar(aes(ymin=Grade +se, ymax=Grade +se),
size=.3,
width=.2,
position=position_dodge(.9))+
geom_linerange(aes(ymin = Grade , ymax = Grade +se),position=position_dodge(.9))+
geom_text(aes(label=Number , y = Grade + se + 1),data=df, position=position_dodge(0.9), size= 4) +
ggtitle('Place a table below x axis')+
facet_grid(~Class) +
xlab('') +
ylab('Case Num') +
theme_gray()+
theme(plot.margin = unit(c(1,1,1,6), "lines"),
axis.text.x = element_text(size = 15)) +
scale_x_discrete(labels = paste(1:5 , '\n' , 10:15, sep = '')) +
geom_text(data = df[df$Class == 'Class1',],x = -1 , y = -3,
label= 'First\nSecond' , size = 4)+
coord_cartesian(clip = "off" , xlim = c(1, 5) )
EDIT:
Sorry for the confusion,although the solution suggested by #stefan is pretty much convenient but the main purpose is to have something like this:
considering that the proposed table will contain external characters, not taken from the data frame at all (if possible!).
As an alternative approach to tackle this problem I simply set up the table as a second ggplot which I glue together with the major ggplot using patchwork.
## Data
Grade <- 1 : 20
Case <- rep(paste('case' , 1:5,sep = ''),4)
Number <- paste('n', 1:20 , sep = '')
Class <- c(rep('Class1',5) , rep('Class2',5) , rep('Class3',5) , rep('Class4',5))
se <- 0.2
df <- data.frame(Grade,Case ,Number, Class , se)
library(patchwork)
library(ggplot2)
library(tidyr)
library(dplyr)
## plot
p1 <- ggplot(df, aes(x= factor(Case , levels = c('case1','case2' , 'case3' , 'case4','case5')) , y=Grade ,
fill= Grade)) +
geom_bar(position="dodge", stat="identity",
colour="black",
size=.4) +
geom_errorbar(aes(ymin=Grade +se, ymax=Grade +se),
size=.3,
width=.2,
position=position_dodge(.9))+
geom_linerange(aes(ymin = Grade , ymax = Grade +se),position=position_dodge(.9))+
geom_text(aes(label=Number , y = Grade + se + 1),data=df, position=position_dodge(0.9), size= 4) +
ggtitle('Place a table below x axis')+
facet_grid(~Class) +
xlab(NULL) +
ylab('Case Num') +
theme_gray()+
theme(axis.text.x = element_blank())
p2 <- df %>%
mutate(First = as.integer(stringr::str_extract(Case, "\\d")),
Second = First + 9,
Third = Second + 9) %>%
pivot_longer(c(First, Second, Third), names_to = "layer", values_to = "label") %>%
ggplot(aes(x = Case)) +
geom_text(aes(y = factor(layer, c("Third", "Second", "First")), label = label)) +
labs(y = "", x = NULL) +
theme_minimal() +
theme(axis.line = element_blank(), axis.ticks = element_blank(), axis.text.x = element_blank(),
panel.grid = element_blank(), strip.text = element_blank()) +
facet_grid(~Class)
p1 / p2 + plot_layout(heights = c(8, 1))
Created on 2020-05-23 by the reprex package (v0.3.0)
EDIT: Tweak to get a more table like output by adding a geom_tile and removing the spacing between facets as well as setting expansion of x-axis to zero:
p2 <- df %>%
select(Case, Class) %>%
mutate(First = letters[1:nrow(.)],
Second = LETTERS[1:nrow(.)],
Third = as.character(1:nrow(.))) %>%
pivot_longer(c(First, Second, Third), names_to = "layer", values_to = "label") %>%
ggplot(aes(x = Case, y = factor(layer, c("Third", "Second", "First")))) +
# Add Table Style
geom_tile(fill = "blue", alpha = .4, color = "black") +
geom_text(aes(label = label)) +
# Remove expansion of axsis
scale_x_discrete(expand = expansion(mult = c(0, 0))) +
labs(y = "", x = NULL) +
theme_minimal() +
theme(axis.line = element_blank(), axis.ticks = element_blank(), axis.text.x = element_blank(),
panel.grid = element_blank(), strip.text = element_blank(), panel.spacing.x = unit(0, "mm")) +
facet_grid(~Class)
p1 / p2 + plot_layout(heights = c(8, 1))
Created on 2020-05-24 by the reprex package (v0.3.0)
If I understand your requirement correctly, (as in my comment above), this may help you. You just need to name your graph and add the labels in loop and render outside the loop.
...
theme(plot.margin = unit(c(1,1,1,6), "lines"),
axis.text.x = element_text(size = 15)) +
scale_x_discrete(labels = paste(1:5 , '\n' , 10:15, sep = '')) +
coord_cartesian(clip = "off" , xlim = c(1, 5) )
label = NULL
ordinal <- c('first','second','third','fourth','fifth','sixth','seventh','eighth','ninth','tenth')
for (i in 1:5) {
label <- paste(label, '\n', ordinal[i])
}
g1 <- g1 + geom_text(data = df[df$Class == 'Class1',],x = -1 , y = -3,
label= label , size = 4)
g1
This is what I get as a result:

heatmap in ggplot, different color for each group

I am trying to produce a heatmap in ggplot. I want each group to have different color gradient, but don't know how to do that. My current code looks like this:
## dummy data -----------------------------------------------------------------------------
data <- data.frame(
group = sample(c("Direct Patient Care", "Indirect Patient Care", "Education", "Rounds", "Handoff", "Misce"), 30, replace = T),
pct = rnorm(30, mean = 50, sd = 8)
)
## generate group id
data <- data %>%
group_by(group) %>%
mutate(id = row_number())
data$grpid <- with(data, ifelse(group == "Direct Patient Care", 1, ifelse(group == "Indirect Patient Care", 2,
ifelse(group == "Education", 3,
ifelse(group == "Rounds", 4,
ifelse(group == "Handoff", 5,6 ))))))
## draw graph ------------------------------------------------------------------------------
library(ggplot2)
p <- ggplot(data, aes(x=id, y=group, fill = pct)) +
theme(panel.background = element_rect(fill = "white", colour = "grey50"), aspect.ratio = 0.4) +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank()
)+
# guides(fill = guide_legend("Time, %")) +
geom_tile() +
scale_x_continuous (name = " ", breaks = seq(1, 8, by = 1)) +
scale_y_discrete(name = " ") +
theme(axis.text.x = element_text(angle = 0,hjust = 1,vjust = 1), plot.title = element_text(hjust = 0.5) ) +
ggtitle("Heatmap of time spent doing activities across 194 shifts")
p + scale_fill_gradient2(low = "white", high = "red", limits = c(0, 80), breaks = c(0, 10, 20, 30, 40, 50, 60, 70), guide = guide_legend("Time, %")) ## change the color theme ##
And the resulting figure looks like this:
How can I change the color theme for each group, like red for 'Rounds', blue for 'Misce', green for 'Handoff' etc...
Many thanks!
You can do this by creating your own rescaled value in your data and then slightly "hacking" the alpha aesthetic combined with the fill aesthetic:
library(tidyverse)
data %>%
group_by(group) %>%
mutate(rescale = scales::rescale(pct)) %>%
ggplot(., aes(x = factor(id), y = group)) +
geom_tile(aes(alpha = rescale, fill = group), color = "white") +
scale_alpha(range = c(0.1, 1))
First we create a new column called rescale which rescales the pct from 0 to 1 then you force the scale_alpha(range = c(0, 1)) [note, in this case I used c(0.1, 1) so that you can still "see" the zero points.
Finally, you probably want to remove the guides:
data %>%
group_by(group) %>%
mutate(rescale = scales::rescale(pct)) %>%
ggplot(., aes(x = factor(id), y = group)) +
geom_tile(aes(alpha = rescale, fill = group), color = "white") +
scale_alpha(range = c(0.1, 1)) +
theme(legend.position = "none")
N.B. by using aes(x = factor(id)... you can get around manually setting your x-axis since in this case it appears you want to treat it as a factor not a numeric scale.
Finally, if you really want to get fancy, you could double-encode the axis.text.y colors to that of the levels of your factor (i.e., data$group) variable:
data %>%
group_by(group) %>%
mutate(rescale = scales::rescale(pct)) %>%
ggplot(., aes(x = factor(id), y = group)) +
geom_tile(aes(alpha = rescale, fill = group), color = "white") +
scale_alpha(range = c(0.1, 1)) +
theme(legend.position = "none",
axis.text.y = element_text(color = scales::hue_pal()(length(levels(data$group)))),
axis.ticks = element_blank()) +
labs(x = "", y = "")

R: Aligning/Sizing for plot_grid in cowplot?

I'm having trouble with the sizing and aligning of one my plots using the plot_grid function in the cowplot package. The bottom left plot always seems to be a tad bit smaller then the others. I did some researching and couldn't seem to find anything that works. I'm new to R, so any help would be greatly appreciated! Thanks!
Attached is my code as well as what the plot is looking like and what I want it to look like
'#Data frame with huc results for each parameter
parameter_results <- readRDS("param_results_2014.RDS") %>% select(1:84)
#list of parameter names
parameters <- sort(readRDS("parameters.RDS"))
blank_theme <- theme_minimal()+ theme(
axis.title.x = element_blank(),
plot.margin = unit(c(0,0,0,0), "pt"),
axis.title.y = element_blank(),
panel.border = element_blank(),
legend.position=c(.5,.02),
legend.direction="horizontal",
legend.key=element_rect(colour="black",size=0.5,linetype="solid"),
panel.grid=element_blank(),
axis.ticks = element_blank(),
plot.title= element_text(size=8, vjust=-4.0, face="bold")
)
#Function for creating poroportions table for parameters
parameter_summary <-function(parameter) {
parameter_df <- parameter_results %>%
select(results = parameter) %>% #keep only column for the parameter you want to plot
filter(results != "Not Applicable") %>% #filters out 'not applicable' results
count(results) %>% #
mutate(prop = prop.table(n), perc = paste0(round(prop * 100),"%"))
return(parameter_df)
}
parameter_pie_chart <- function(parameter,title="",nudgex=5,nudgey=-10) {
# parameter: the parameter you want to create a pie chart for, example: 'DO'
# title: plot title, default is the name of the parameter
parameter_df <- parameter_summary(parameter)
#data frame of proportions less than 10%. necessary because for these values, labels are implemented with an arrow
small_perc <- parameter_df %>% filter(prop < .10)
#dataframe of proportions greater than 10%
signif_perc <- parameter_df %>% filter(prop >= .10)
pie_chart <- ggplot(parameter_df, aes(x = "", y = n, fill = fct_inorder(results))) +
geom_bar(stat = "identity", width = 1,colour='black') +
coord_polar(theta = "y") +
blank_theme +
theme(axis.text.x=element_blank()) +
theme(legend.title=element_blank()) +
#ggtitle(title)+
theme(plot.title = element_text(hjust = 0.5)) +
geom_text(data = signif_perc, aes(label = perc),
position = position_stack(vjust = .5), size = 5, show.legend = F) +
scale_fill_manual(values = c("Attaining" = "#99FF99","Insufficient Information" = "#FFFF99", "Non Attaining" = "#FF9999", "Not Applicable" = "orange"),labels=c("Attaining ",
"Insufficient Information ",
"Non Attaining "))
if (sum(parameter_df$prop < .10) > 0) {
pie_chart <- pie_chart + geom_text_repel(data = small_perc, aes(label = perc), size= 5, show.legend = F, nudge_x = nudgex,nudge_y = nudgey)
}
pie_chart
}
#Indivdual pie charts to create combined pie charts
pie_do <- parameter_pie_chart('DO')
pie_TP<-parameter_pie_chart('Total Phosphorus')
pie_temp<-parameter_pie_chart('Temperature')
pie_pH<-parameter_pie_chart('pH')
pie_arcs<-parameter_pie_chart('Arsenic-HH')
pie_TDS<-parameter_pie_chart('Total Dissolved Solids')
pie_causebio<-parameter_pie_chart('Biological (Cause Unknown)')
pie_human_lead<-parameter_pie_chart('Lead-HH - DWS')
pie_mercury<-parameter_pie_chart('Mercury-HH')
pie_nitrate<-parameter_pie_chart('Nitrate')
pie_aluminum <- parameter_pie_chart("Aluminum")
pie_temp_trout<-parameter_pie_chart('Temperature Trout')
pie_do_trout<-parameter_pie_chart('DO Trout')
pie_fish_merc<-parameter_pie_chart('Fish-Mercury')
pie_fish_ddt<-parameter_pie_chart('Fish-DDx')
pie_fish_dioxin<-parameter_pie_chart('Fish-Dioxin')
pie_fish_chlordane<-parameter_pie_chart('Fish-Chlordane')
pie_fish_pcb<-parameter_pie_chart('Fish-PCB')
pie_human_arsenic<-parameter_pie_chart('Arsenic-HH')
pie_TDS<-parameter_pie_chart('Total Dissolved Solids')
pie_arsenic_dws<-parameter_pie_chart('Arsenic HH - DWS')
pie_trout_do<-parameter_pie_chart('DO Trout')
pie_unknown_trout<-parameter_pie_chart('Biological Trout (Cause Unknown)')
pie_ecoli<-parameter_pie_chart('e.Coli')
pie_enterococcus<-parameter_pie_chart('Enterococcus')
pie_beach_enterococcus<-parameter_pie_chart('Beach Closing (Enterococcus)')
##Figure 2.10
combined_plot1 <- plot_grid(pie_human_arsenic + theme(legend.position="none"),
pie_TDS + theme(legend.position = "none"),
pie_human_lead + theme(legend.position = "none"),
pie_mercury + theme(legend.position = "none"),
pie_nitrate + theme(legend.position = "bottom"),
nrow = 2,ncol=3,align="hv",labels=c("Arsenic,human health","TDS","Lead,human health","Mercury,human health","Nitrate"),label_fontface="bold",label_size=10,hjust=-0.3,vjust=9)+
draw_label("Figure 2.10:Assessment Results for Key Parameters Associated with Water Supply Use,\nPercent(%) of 826 AUs",fontface="bold",hjust=0.5,vjust=-14.5)
ggsave(filename="Figure2.10-Water Supply Use.pdf",path="V:/lum/WM&S/BEAR (Bureau of Environmental Analysis and Restoration)/Envpln/Hourly Employees/KevinZolea/Rwork/2014IR/PieCharts",width=11.5,height=11)
`
Plot that I have:
Plot I Want:

How to add axis text in this negative and positive bars differently using 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.
# 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()
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)
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())
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.
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())
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")

Resources