stacked bar *bringing labels to the graph * - r

I'm plotting a stacked bar graph and use geom_text to insert the value and name of each stack. The problem is some stacks are very small/narrow, so that the text of two stacks overlap each other and hence is not very readable. How can I modify the code to solve this issue.
Type<-c("ddddddddddd","ddddddddddd","bbbbbbbbbbbbb","ddddddddddd","eeeeeeeeeeeeee","bbbbbbbbbbbbb","ddddddddddd","bbbbbbbbbbbbb","ddddddddddd",
"eeeeeeeeeeeeee","mmmmmmmmmmmmmmmmmmm","bbbbbbbbbbbbb","ddddddddddd","bbbbbbbbbbbbb","eeeeeeeeeeeeee")
Category<-c("mmmmm","mmmmm","gggggggggggggggggg","ffffffffffff","ffffffffffff","ffffffffffff","sanddddddddd","sanddddddddd","yyyyyyyyyyy",
"yyyyyyyyyyy","yyyyyyyyyyy","sssssssssssssss","sssssssssssssss","sssssssssssssss","ttttttttttttt")
Frequency<-c(4,1,30,7,127,11,1,1,6,9,1,200,3,4,5)
Data <- data.frame(Type, Category, Frequency)
p <- ggplot(Data, aes(x = Type, y = Frequency)) +
geom_bar(aes(fill = Category), stat="identity", show.legend = FALSE) +
geom_text(aes(label = Frequency), size = 3) +
geom_text(aes(label = Category), size = 3)

Considering your data, a facetted plot might be a better approach:
# summarise your data
library(dplyr)
d1 <- Data %>%
mutate_each(funs(substr(.,1,2)),Type,Category) %>%
group_by(Type,Category) %>%
summarise(Freq = sum(Frequency)) %>%
mutate(lbl = paste(Category,Freq)) # create a label by pasting the 'Category' and the 'Freq' variables together
# plot
ggplot(d1, aes(x = Category, y = Freq, fill = Category)) +
geom_bar(stat="identity", width = 0.7, position = position_dodge(0.8)) +
geom_text(aes(label = lbl), angle = 90, size = 5, hjust = -0.1, position = position_dodge(0.8)) +
scale_y_continuous(limits = c(0,240)) +
guides(fill = FALSE) +
facet_grid(.~Type, scales = "free", space = "free") +
theme_bw(base_size = 14)
which gives:
In the above plot I shortened the labels on purpose. If you don't want to do that, you could consider this:
d2 <- Data %>%
group_by(Type,Category) %>%
summarise(Freq = sum(Frequency)) %>%
mutate(lbl = paste(Category,Freq))
ggplot(d2, aes(x = Category, y = Freq, fill = Category)) +
geom_bar(stat="identity", width = 0.7, position = position_dodge(0.8)) +
geom_text(aes(y = 5, label = lbl), alpha = 0.6, angle = 90, size = 5, hjust = 0, position = position_dodge(0.8)) +
scale_y_continuous(limits = c(0,240)) +
guides(fill = FALSE) +
facet_grid(.~Type, scales = "free", space = "free") +
theme_bw(base_size = 14) +
theme(axis.text.x = element_blank(),
axis.ticks.x = element_blank())
which gives:

Related

how to have the legend inside a grouped bar graph in R ggplot?

So my legend here is village which has (Chirodzo, God, Ruaca). How to remove the legend and display it inside the bars; for instance inside the bar for chirodzo, I want chirodzo written inside?
ggplot(data = interviews_plotting, aes(x = respondent_wall_type, fill = village)) +
geom_bar(position = "fill")
Source is here https://mq-software-carpentry.github.io/r-ggplot-extension/02-categorical-data/index.html
ggplot(data = interviews_plotting, aes(x = respondent_wall_type, fill = village)) +
geom_bar(position = "fill")
To label your bars with the fill category and getting rid of the legend you could use geom_text like so:
Using mtcars as example data:
library(ggplot2)
ggplot(data = mtcars, aes(x = am, fill = factor(cyl))) +
geom_bar(position = "fill") +
geom_text(aes(label = cyl), stat = "count", position = position_fill(vjust = 0.5)) +
guides(fill = "none")
From your comments, it sounds like you are looking for something like this:
library(ggplot2)
ggplot(interviews_plotting, aes(x = respondent_wall_type, fill = village)) +
geom_bar(position = position_dodge()) +
geom_text(stat = 'count',
aes(y = stat(count)/2, label = village, group = village),
position = position_dodge(width = 1), angle = 90) +
guides(fill = guide_none())
Or, if you want to get a bit more sophisticated with your label placement and theme choices:
library(ggplot2)
ggplot(interviews_plotting, aes(x = respondent_wall_type, fill = village)) +
geom_bar(position = position_dodge(width = 0.9), width = 0.8) +
geom_text(stat = 'count', size = 6,
aes(y = ifelse(stat(count) > 2, stat(count)/2, stat(count)),
label = village, group = village,
hjust = ifelse(stat(count) > 2, 0.5, -0.2)),
position = position_dodge(width = 0.9), angle = 90) +
labs(x = 'Wall type', y = 'Count') +
theme_minimal(base_size = 16) +
scale_fill_brewer(palette = 'Set2', guide = 'none')
Data used
interviews_plotting <- read.csv(paste0("https://raw.githubusercontent.com/",
"humburg/r-ggplot-project/master/",
"data_output/interviews_plotting.csv"))

Labeling pie charts using ggplot2

I have this code:
as_tibble(earlyCiliated[[]]) %>%
ggplot(aes(x="", y=Phase, fill=Phase)) + geom_col() +
coord_polar("y", start=0) +
geom_text(aes(label = paste0(Phase, "%")))
and my output looks like this:
What am I doing wrong that's causing the labels to all be on top of each other?
I can't completely recreate your plot because I do not have your data. That being said, you can try this:
install.packages("ggrepel")
library(ggrepel)
as_tibble(earlyCiliated[[]]) %>%
ggplot(aes(x="", y=Phase, fill=Phase)) + geom_col() +
coord_polar("y", start=0) +
geom_label_repel(data = earlyCiliated[[]],
aes(y = Phase, label = paste0(Phase, "%")),
size = 4.5, nudge_x = 1, show.legend = FALSE)
This is what it will look like (using other data because none was provided)
library(ggplot2)
library(ggrepel)
library(tidyverse)
df <- data.frame(value = c(15, 25, 32, 28),
group = paste0("G", 1:4))
# Get the positions
df2 <- df %>%
mutate(csum = rev(cumsum(rev(value))),
pos = value/2 + lead(csum, 1),
pos = if_else(is.na(pos), value/2, pos))
ggplot(df, aes(x = "" , y = value, fill = fct_inorder(group))) +
geom_col(width = 1, color = 1) +
coord_polar(theta = "y") +
scale_fill_brewer(palette = "Pastel1") +
geom_label_repel(data = df2,
aes(y = pos, label = paste0(value, "%")),
size = 4.5, nudge_x = 1, show.legend = FALSE) +
guides(fill = guide_legend(title = "Group")) +
theme_void()

ggplot: Order stacked barplots by variable proportion

I am creating a plot with 3 variables as below. Is there a way to arrange the plot in a descending order such that the bar with the highest proportion of variable "c" comes first in the plot. Using this example last bar should come in first then middle one and then the first bar in the last.
long<- data.frame(
Name = c("abc","abc","abc","gif","gif","gif","xyz","xyz","xyz"),
variable = c("a","b","c","a","b","c","c","b","a"),
value = c(4,6,NA,2,8,1,6,NA,NA))
long_totals <- long %>%
group_by(Name) %>%
summarise(Total = sum(value, na.rm = T))
p <- ggplot()+
geom_bar(data = long,
aes(x = Name,
y = value,
fill=variable),
stat="summary",
position = "fill") +
geom_text(data = long_totals,
aes(y = 100,
x = Name,
label = Total),
size = 7,
position = position_fill(vjust = 1.02)) +
scale_y_continuous(labels = scales::percent_format()) +
ylab("Total_num") +
ggtitle("Totalnum") +
theme(plot.title = element_text(size = 20, hjust = 0.5)) +
theme(axis.text.x = element_text(angle = 75, vjust = 0.95, hjust=1))
The following code does arrange the bars by count of "c" but not by proportion. How can I arrange by proportion?
p<-long %>%
mutate(variable = fct_relevel(variable,
c("c", "b", "a"))) %>%
arrange(variable) %>%
mutate(Name = fct_inorder(Name))
p %>%
ggplot() +
aes(x = Name,
y = value,
fill = variable) +
geom_bar(position = "fill",
stat = "summary") +
We could use fct_rev from forcats package, it is in tidyverse:
p <- ggplot()+
geom_bar(data = long,
aes(x = fct_rev(Name),
y = value,
fill=variable),
stat="summary",
position = "fill") +
geom_text(data = long_totals,
aes(y = 100,
x = Name,
label = Total),
size = 7,
position = position_fill(vjust = 1.02)) +
scale_y_continuous(labels = scales::percent_format()) +
ylab("Total_num") +
ggtitle("Totalnum") +
theme(plot.title = element_text(size = 20, hjust = 0.5)) +
theme(axis.text.x = element_text(angle = 75, vjust = 0.95, hjust=1))

Placing a color legend below a fill legend in ggplot

If I have the following plot, how would I place the color (error) legend item below the fill (yr) one?
library(dplyr)
library(ggplot2)
dat <- data.frame(yr = c(2017:2019) %>% as.factor,
val = 1:3)
dat %>%
ggplot(aes(x = yr, y = val, fill = yr)) +
geom_bar(stat = "identity") +
geom_errorbar(aes(ymin = 7, ymax = 7,
color = "Error")) +
theme(legend.position = "bottom")
There are two parts, you need to change the order with guides and then add legend.box = "vertical" to theme:
dat %>%
ggplot(aes(x = yr, y = val, fill = yr)) +
geom_bar(stat = "identity") +
geom_errorbar(aes(ymin = 7, ymax = 7,
color = "Error")) +
guides(fill = guide_legend(order = 1),
color = guide_legend(order = 2)) +
theme(legend.box="vertical", legend.position = "bottom")

X axis and right box in stacked bars

In a plot like this
library(ggplot2)
df <- data.frame(class = c("a","b","a","b"), date = c(2009,2009,2010,2010), volume=c(1,1,2,0))
df <- df %>% group_by(date) %>% mutate(volumep = 100 * volume/sum(volume))
ggplot(df, aes(x = date, y = volumep, fill = class, label = volumep)) +
geom_bar(stat = "identity") +
geom_text(size = 3, position = position_stack(vjust = 0.5)) + coord_flip()
How is it possible to increase the text in the boxes in the right (class) and how to make the x axis have 0, 25, 50 and 100 values?
To answer the question, just adjust the involved aesthetics, y and size.
ggplot(df, aes(x = date, y = 100*volume, fill = class, label = volume)) +
geom_bar(stat = "identity") +
geom_text(size = c(3, 3, 5, 5), position = position_stack(vjust = 0.5)) +
coord_flip() +
ylab("volume")
Another option is to mutate the values of volume first. In this case, there would be no need to manually set the y axis label.
After the question's edit, the code is now as follows.
library(ggplot2)
library(dplyr)
df %>%
group_by(date) %>%
mutate(volume = 100*volume/sum(volume)) %>%
ggplot(aes(x = date, y = volume, fill = class, label = volume)) +
geom_bar(stat = "identity") +
geom_text(size = c(3, 3, 5, 5), position = position_stack(vjust = 0.5)) +
coord_flip()
ggplot(df, aes(x = date, y = volumnep, fill = class, label = volumnep)) +
geom_bar(stat = "identity") +
geom_text(size = 3, position = position_stack(vjust = 0.5)) +
coord_flip() +
theme(legend.title=element_text(size=22),
legend.text=element_text(size=22)) +
scale_y_continuous(breaks=c(0,25, 50, 100))
Edit:
I'd suggest recasting date as a factor:
ggplot(df, aes(x = factor(date), y = volumnep, fill = class, label = volumnep)) +
geom_bar(stat = "identity") +
geom_text(size = 3, position = position_stack(vjust = 0.5)) +
coord_flip() +
theme(legend.title=element_text(size=22),
legend.text=element_text(size=22)) +
scale_y_continuous(breaks=c(0,25, 50, 100)) +
labs(y="date")

Resources