Trouble with overlapping labels (geom_text) - r

Trouble with overlapping geom_text labels on pie chart
library(scales)
blank_theme <- theme_minimal()+
theme(
axis.title.x = element_blank(),
axis.title.y = element_blank(),
panel.border = element_blank(),
panel.grid=element_blank(),
axis.ticks = element_blank(),
plot.title=element_text(size=14, face="bold")
)
df6 <- data.frame(group = c("Seedling","Ground", "Fern", "Moss"),value = c(2.125,80.125, 11.376,6.375))
# Create a basic bar
pie6 = ggplot(df6, aes(x="", y=value, fill=group)) + geom_bar(stat="identity", width=1) + blank_theme + theme(axis.text.x=element_blank())
# Convert to pie (polar coordinates) and add labels
pie6 = pie6 + coord_polar("y", start=0) + geom_text(aes( label = paste0((value), "%")),position = position_stack(vjust = 0.5))
# Remove labels and add title
pie6 = pie6 + labs(x = NULL, y = NULL, fill = NULL, title = "Understory Composition, Site 2")
# Tidy up the theme
pie6 = pie6 + theme_classic() + theme(axis.line = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
plot.title = element_text(hjust = 0.5, color = "black"))
pie6
This is my current output. How can i change the labels such that they do not overlap? i have tried various hjust and vjust, positions and position_stack but to no avail
Any help appreciated. thank you.

A manual approach to this problem could be to manipulate the orientation of the text by setting the angle parameter in the geom_text function. This allows you to set the orientation of all text fragments at once by assigning a singel value to angle. You may also set the angle for the individual text items as illustrated below.
ggplot(df6, aes(x = "", y = value, fill = group)) +
geom_bar(stat = "identity", width = 1) +
coord_polar("y", start = 0) +
blank_theme +
theme(axis.text.x = element_blank()) +
geom_text(aes(label = paste0((value), "%")),
position = position_stack(vjust = 0.5),
angle = c(-90, -90, 0, -90)) ####### here
The code below adjust the angle depending on the pie it describes.
ggplot(df6, aes(x = "", y = value, fill = group)) +
geom_bar(stat = "identity", width = 1) +
coord_polar("y", start = 0) +
blank_theme +
theme(axis.text.x = element_blank()) +
geom_text(aes(label = paste0((value), "%")),
position = position_stack(vjust = 0.5),
angle = c(-97, -110, 0, -70)) ####### here
Another way to work around the problem you state, is to play with the start parameter of the coord_polar function:
ggplot(df6, aes(x = "", y = value, fill = group)) +
geom_bar(stat = "identity", width = 1) +
coord_polar("y", start = 180) + ####### here
blank_theme +
theme(axis.text.x = element_blank()) +
geom_text(aes(label = paste0((value), "%")) ,
position = position_stack(vjust = 0.5))

Have you tried using the package ggrepel? If so I recommend. It automatically stops labels overlapping and finds a fit for each other them.
#Install ggrepel package
install.packages("ggrepel", dependencies=TRUE)
df6 <- data.frame(group = c("Seedling","Ground", "Fern", "Moss"),value = c(2.125,80.125, 11.376,6.375))
# Create a basic bar
pie6 = ggplot(df6, aes(x="", y=value, fill=group)) + geom_bar(stat="identity",
width=1) + blank_theme + theme(axis.text.x=element_blank())
# Convert to pie (polar coordinates) and add labels using ggrepel
pie6 = pie6 + coord_polar("y", start=0) + ggrepel::geom_text_repel(aes( label =
paste0((value), "%")),position = position_stack(vjust = 0.5))
# Remove labels and add title
pie6 = pie6 + labs(x = NULL, y = NULL, fill = NULL, title = "Understory Composition, Site 2")
# Tidy up the theme
pie6 = pie6 + theme_classic() + theme(axis.line = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
plot.title = element_text(hjust = 0.5, color = "black"))
pie6

Related

How to make faceted pie charts for a dataframe of percentages in R?

I have reached to create a melted dataframe containing as values the % of the energy sources (factor variable) for several Years, as additional factor or Date:
How could I make nice faceted pie charts for the different years with ggplot (or plotrix)?
So, far, I have reached to:
ggplot(melted_df, aes(x=Year, y=Share, fill=Source)) +
geom_bar(stat="identity", width=1)+
coord_polar("y", start=0) +
geom_text(aes(label = paste0(round(Share*100), "%")), position = position_stack(vjust = 0.5),size=3)+
labs(x = NULL, y = NULL, fill = NULL, title = "Energy Mix")+
theme_classic() + theme(axis.line = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
plot.title = element_text(hjust = 0.5, color = "#666666"))
which without the facet command gives this, which is not aesthetically pleasant:
while if I add the facet_wrap(~Year) command, it becomes worse...
After commentators suggestion, aes(x=1) in the ggplot() line solves the issue and makes normal circle parallel pies:
ggplot(melted_df, aes(x=1, y=Share, fill=Source)) +
geom_col(width=1,position="fill", color = "black")+
coord_polar("y", start=0) +
geom_text(aes(x = 1.7, label = paste0(round(Share*100), "%")), size=2,
position = position_stack(vjust = 0.5))+
labs(x = NULL, y = NULL, fill = NULL, title = "Energy Mix")+
theme_classic() + theme(axis.line = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
plot.title = element_text(hjust = 0.5, color = "#666666"))+
facet_wrap(~Year)

add labels to stacked bar chart with proportions using ggplot

I am trying to include labels to a stacked bar chart for proportions. I have been able to create the chart but I haven't been able to successfully add the labels. I've gotten labels but they are centered and overwriting one another....I know this has been asked, but I haven't found a solution that works.
The data is tidy in the sense that it is long
ggplot(data=dat) +
geom_bar(stat="identity",
mapping = aes(x=Vintage, y=OrigAmt, fill=fct_rev(Grade)),
position = "fill") +
ggtitle("Proportions by Grade") +
scale_fill_manual(values = c("grey", "gray40", "black")) +
guides(fill = guide_legend(reverse = TRUE, title="Grade")) +
scale_y_continuous(name="Proportion",label=percent_format()) +
theme_bw() +
theme(plot.title = element_text(hjust=0.5),
panel.border = element_blank(),
panel.grid = element_blank(),
axis.text.x = element_text(angle = 90))
Try adding this after geom_bar
geom_text(aes(y = cumsum(OrigAmt)-OrigAmt/2, label = Grade), show.legend = F)
Changing the y to a cumulative summation (cumsum) of the y variable minus half the y variable places the text in the middle of each section of each bar.
You can also add a color aesthetic and maybe turn Grade into a factor with defined color values
This appears to work.
ggplot(data = dat,
aes(y = freq, x = Vintage, fill = fct_rev(Grade))) +
geom_col() +
geom_text(aes(label = paste0(freq,"%")),
position = position_stack(vjust = 0.5), size = 2) +
scale_y_continuous(
labels = dollar_format(suffix = "%", prefix = "")) +
labs(title = "Distribution by Vintage",
subtitle = "xxx") +
labs(x = NULL, y = "Percentage") +
theme_bw() +
theme(legend.position = "bottom",
legend.direction = "horizontal",
legend.title = element_blank()) +
guides(fill = guide_legend(reverse = T)) +
scale_fill_manual(values = c("grey", "gray40", "brown")) +
theme(axis.text.x = element_text(angle = 90),
axis.text.x.bottom = element_text(vjust = 0.5))
However, I want to change the font colors and I can't see to be able to do that successfully.
For example, I want the label fonts to be BOLD and the font for A and B to be WHITE and the font for C to be BLACK. Thanks!

Is it possible to vertically adjust a label in a dodged bar chart?

I want to lower the height of the labels in my dodged bar chart so that they are not on the edge of the bar.
I tried using height= in position_dodge() however this gives the error 'unused argument' since height is not an argument in position_dodge(). This is my code:
newdata <- read.table(text = "2010 2018
healthcare 0.09940358 0.09256198
allsectors 0.14713699 0.15306588", sep = " ", header = TRUE)
library(reshape)
datnew <- melt(cbind(newdata, ind = rownames(newdata)), id.vars = c('ind'))
library(ggplot2)
library(scales)
library(dplyr)
ggplot(datnew, aes(x = variable, y = value, fill = ind)) +
geom_col(position = "dodge", colour = 'black') +
geom_text(size = 3.5, position = position_dodge(width=1), aes(label =
scales::percent(value))) +
scale_x_discrete(labels = c('2010', '2018')) +
scale_y_continuous(labels = percent_format()) +
scale_fill_manual(name = "sector" , values = c("brown3", "darkgrey")) +
xlab('Year') +
ylab('% of workforce') +
ggtitle('figure 4', subtitle = 'Workers under the age of 25')
theme_bw() +
theme(plot.title=element_text(lineheight = NULL, hjust=0.5, face="bold",
color="black", size=16), plot.subtitle = element_text(lineheight = NULL,
hjust=0.5, color = 'black', size=14), panel.border = element_blank(),
panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
axis.line = element_line(colour = "black")) + expand_limits(y = 0)
As explained, I want to lower the position of the labels in the bars.

ggplot pie chart choose axes ticks

I would like to know if it's possible to modify the ticks of x axis with a ggplot pie chart.
Here what I can do :
# Some colors
couleurs <- data.frame(
id=seq(1,17,1),
mix=c(c(rep(1,6),rep(2,7),rep(3,4))),
html=c("#A00020","#109618","#388EE4","#C484D1","#FFAA33","#CCCDD0","#004AC5","#F80094","#CB5023","#638995","#33CFCF","#95DC4E","#F7D633","#5C403C","#F72020","#00D96C","#FDE4C5")
)
couleurs$html <- factor(couleurs$html, levels = couleurs$html[order(couleurs$id, decreasing = FALSE)])
# Data
activite <- data.frame(label=c("B to B","B to C","B to B / B to C", "B to B"), cible=c(rep("Externe",3), "Interne"), nb=c(12,9,3,12))
activite$label <- factor(activite$label, levels = activite$label[order(activite$nb[activite$cible=="Externe"], decreasing = TRUE)])
library(plyr)
activite<-ddply(activite,.(cible),transform,pc=(nb/sum(nb))*100)
activite
# Pie chart
library(ggplot2)
ggplot(data = activite, aes(x = "", y = nb, fill = label )) +
geom_bar(stat = "identity", position = position_fill(), width = 1) +
coord_polar(theta= "y", start = 0, direction = -1) +
labs(fill="") +
scale_fill_manual(values=as.character(couleurs$html[1:nrow(activite)]), labels=paste(activite$label,"\t\t\t",sep="")) +
geom_text(aes(label = paste(pc,"%", sep=" ")), size=4, colour = "white", fontface = "bold", position = position_fill(vjust = 0.5)) +
theme(strip.text = element_text(size=20, face = "bold", ), strip.background = element_rect(fill="grey75")) +
theme(panel.background = element_rect(fill = "white")) +
theme(plot.background = element_rect(fill = "grey92")) +
theme(legend.position="bottom", legend.background = element_rect(fill="grey92")) +
theme(legend.key = element_blank()) +
theme(panel.grid.minor = element_blank(), panel.grid.major = element_line(colour = "grey75")) +
theme(axis.text.y = element_blank()) +
theme(axis.ticks.length = unit(0, "mm")) +
theme(axis.title.x = element_blank(),axis.title.y = element_blank()) +
theme(legend.box.spacing = unit(1, "mm")) +
facet_wrap(~ cible)
Here my result:
After several hours of serach, I didn't find a solution to create what I want. The exact same pie chart but with personalised ticks like that :
With these particular conditions :
- do not change the direction of the data in the pie chart, I want it like exactly this
- if possible (but if not possible, it's okay), I would like the ticks' labels not superposed with the axis.
If someone can help me, I would really appreciate.
Here's one solution:
ggplot(data = activite %>%
group_by(cible) %>%
arrange(desc(nb)) %>%
mutate(axis.label = cumsum(nb),
axis.position = cumsum(pc)/100) %>%
mutate(axis.label = ifelse(pc == min(pc),
paste(axis.label, "0", sep = "-"),
axis.label)),
aes(x = 1, y = nb, fill = label )) +
geom_segment(aes(x = 1, xend = 1.6, y = axis.position, yend = axis.position),
colour = "grey75") +
geom_vline(xintercept = 1.6, colour = "grey75") +
geom_bar(stat = "identity", position = position_fill(reverse = T), width = 1) +
coord_polar(theta= "y", start = 0, direction = 1) +
labs(fill="") +
scale_fill_manual(values=as.character(couleurs$html[1:nrow(activite)]), labels=paste(activite$label,"\t\t\t",sep="")) +
geom_text(aes(label = paste(pc,"%", sep=" ")), size=4, colour = "white",
fontface = "bold", position = position_fill(vjust = 0.5, reverse = T)) +
geom_text(aes(x = 1.7, label = axis.label), size = 3,
position = position_fill(reverse = T)) +
theme(strip.text = element_text(size=20, face = "bold", ), strip.background = element_rect(fill="grey75")) +
theme(panel.background = element_rect(fill = "white")) +
theme(plot.background = element_rect(fill = "grey92")) +
theme(legend.position="bottom", legend.background = element_rect(fill="grey92")) +
theme(legend.key = element_blank()) +
theme(panel.grid = element_blank()) +
theme(axis.text = element_blank()) +
theme(axis.ticks = element_blank()) +
theme(axis.title = element_blank()) +
theme(legend.box.spacing = unit(1, "mm")) +
facet_wrap(~ cible)
Explanation:
The sequence in your labels went clockwise, while the direction of the polar coordinates went counter-clockwise. That makes labelling rather troublesome. I switched the direction for polar coordinates, & added reverse = T inside the position adjustment calls for the geoms.
It's hard to assign different axis breaks to different facets of the same plot, so I didn't. Instead, I modified the data to include calculated axis labels / margin positions, added margins via geom_segment / geom_vline, & hid the axis text / ticks in theme().

ggplot2: How to move x-axis up, so it can be under arbitrarily picked bar on horizontal barplot?

I made horizontal barplot. I need to move x-axis up, so it is placed not under the last bar, but under some bar, picked based on other criterion.
I've tried some things, like gtable, but with no success. I would appreciate any help.
This is a picture that illustrats what I want to achieve:
Here is the code to produce sample horizontal barplot:
library("ggplot2")
library("RColorBrewer")
colours <- brewer.pal(11, "RdYlGn")[3:9]
no.names <- 4
name.percentage <- data.frame(name = paste0(LETTERS[1:no.names], letters[1:no.names], sample(LETTERS[1:no.names], size = no.names, replace = TRUE )), percentage = 0.85 + runif(no.names, 0, 0.15))
name.percentage <- rbind(
transform(name.percentage, type = 1, fill = cut(percentage, breaks = c(-Inf,(1:6 * 3 + 81)/100, Inf), right = T, labels = colours)),
transform(name.percentage, percentage = 1 - percentage, type = 2, fill = "#EEEEEE")
)
plot <- ggplot(data = name.percentage,
aes( x = name, y = percentage, fill = fill)) +
geom_bar(stat = "identity", position = "stack", width = 0.75) +
scale_fill_identity(guide = "none") +
labs(x = NULL, y = NULL) +
scale_y_continuous(expand = c(0,0)) +
scale_x_discrete(expand = c(0,0)) +
coord_flip() +
theme_classic() +
theme(axis.ticks.y = element_blank(),
axis.text.y = element_text(size = 11, colour = "black" ),
axis.text.x = element_text(size = 11, colour = "black" ),
axis.line = element_blank(),
plot.margin = grid::unit(c(5,5,5,5),"mm"),
aspect.ratio = ((no.names %% 30) / 30 ) * 1.70)
print(plot)
You could create two separate plots first, removing the axis ticks and labels in one of them entirely:
plot1 <- ggplot(data = subset(name.percentage, name=="AaC" | name=="BbA"),
aes( x = name, y = percentage, fill = fill)) +
geom_bar(stat = "identity", position = "stack", width = 0.75) +
scale_fill_identity(guide = "none") +
labs(x = NULL, y = NULL) +
scale_y_continuous(expand = c(0,0)) +
scale_x_discrete(expand = c(0,0)) +
coord_flip() +
theme_classic() +
theme(axis.ticks.y = element_blank(),
axis.text.y = element_text(size = 11, colour = "black" ),
axis.text.x = element_blank(),
axis.line=element_blank(),
axis.ticks=element_blank(),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
aspect.ratio = ((no.names %% 30) / 30 ) * 1.70)
plot2 <- ggplot(data = subset(name.percentage, name=="CcA" | name=="DdD"),
aes( x = name, y = percentage, fill = fill)) +
geom_bar(stat = "identity", position = "stack", width = 0.75) +
scale_fill_identity(guide = "none") +
labs(x = NULL, y = NULL) +
scale_y_continuous(expand = c(0,0)) +
scale_x_discrete(expand = c(0,0)) +
coord_flip() +
theme_classic() +
theme(axis.ticks.y = element_blank(),
axis.text.y = element_text(size = 11, colour = "black" ),
axis.text.x = element_text(size = 11, colour = "black" ),
axis.line = element_blank(),
aspect.ratio = ((no.names %% 30) / 30 ) * 1.70)
Then you can use plot_grid from package cowplot to arrange the two plots, with align="h" aligning both plots horizontally:
library(cowplot)
plot_grid(plot2, plot1, align="h", ncol=1)

Resources