I have a dataframe which I would like to create a bargraph with primary and secondary axes.
geom_bar(data=top_ten_S, aes(x=Combination, y=AvgTopline), stat="identity",fill="red") +
coord_flip() +
geom_text(
data=top_ten_S,
aes(
x=Combination, y=AvgTopline,
label=paste0("R",round(AvgTopline,0)),
hjust=ifelse(AvgTopline < max(top_ten_S$AvgTopline) / 1.5, -0.1, 1.1), # <- Here lies the magic
),
)
my df looks like
top_ten_S <- data.frame(Combination = c("a", "b", "c"),
Nrcustomers = c(20, 200, 1900),
AvgTopline = c(1000,3000,1500))
I am only able to plot one column with the above code - I would like to a secondary axes so that I could plot Combination against NrCustomers and AvgTopline in
Method 1
top_ten_S %>%
gather(key, value, -Combination) %>%
ggplot(aes(x = Combination, y = value, fill = key)) +
geom_bar(stat = "identity", position = "dodge") +
labs(fill = "")
Method 2
top_ten_S %>%
gather(key, value, -Combination) %>%
ggplot(aes(x = Combination, y = value, fill = key)) +
geom_bar(stat = "identity", position = "dodge", show.legend = FALSE) +
facet_grid(. ~ key)
Edit: Method 2
top_ten_S %>%
gather(key, value, -Combination) %>%
ggplot(aes(x = Combination, y = value, fill = key)) +
geom_bar(stat = "identity", position = "dodge", show.legend = FALSE) +
facet_grid(. ~ key, space = "free_y", scales = "free_y") +
theme(axis.text.x = element_text(angle = 60))
Related
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))
I can order my plot based on count but not by proportion. I want to bars on x-axis to be arranged by proportion of "c". Here is my code
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<-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") +
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())
Also, I am plotting total numbers using geom_text
Add the proportion c by group like this, when generating p:
... %>%
group_by(Name) %>%
mutate(prop_c = sum(value[variable=="c"], na.rm=T)/sum(value, na.rm=T))
Then plot, using reorder:
ggplot() +
geom_col(data= p,aes(x = reorder(Name,prop_c, decreasing=T),y = value,fill = variable),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())
The following bar chart can be produced without problems:
library(dplyr)
library(ggplot2)
library(forcats)
data <- tibble(Category = c("Baseball",
"Basketball",
"Basketball",
"Basketball",
"Football",
"Football",
"Hockey")) %>%
group_by(Category) %>%
summarise(n = n()) %>%
mutate(n = prop.table(n))
# displays correctly
ggplot(data, aes (x="", y = n, fill = Category)) +
geom_bar(width = 1, stat = "identity") +
geom_text(aes(label = paste(n, "%")),
position = position_stack(vjust = 0.5))
If, however, fill = Category is placed inside aes of geom_bar, then the labels of geom_text are displayed in reverse order.
# labels are displayed in reverse order
ggplot(data, aes (x="", y = n)) +
geom_bar(aes(fill = Category), width = 1, stat = "identity") +
geom_text(aes(label = paste(n, "%")),
position = position_stack(vjust = 0.5))
This behavior can be prevented, either by: using fct_rev
ggplot(data, aes (x="", y = n)) +
geom_bar(aes(fill = fct_rev(Category)), width = 1, stat = "identity") +
geom_text(aes(label = paste(n, "%")),
position = position_stack(vjust = 0.5))
Or by adding fill = Category in the aes of geom_text.
ggplot(data, aes (x="", y = n)) +
geom_bar(aes(fill = Category), width = 1, stat = "identity") +
geom_text(aes(fill = Category, label = paste(n, "%")),
position = position_stack(vjust = 0.5))
#> Warning: Ignoring unknown aesthetics: fill
Although this yields a warning saying:
Ignoring unknown aesthetics: fill
I do not understand:
why labels in geom_text are reversed when fill is placed in geom_bar(aes); and
why this behavior can be prevented when adding fill (which is an unknown aesthetic) to geom_text(aes).
I'm not entirely sure yet what exactly the issue is, but it is related to grouping. The reason that fill triggers this problem is that it sets up grouping, so when you don't provide the fill aesthetic in the main ggplot() call you don't get the groups right. One way to fix this is to provide explicit grouping in geom_text().
library(dplyr)
library(ggplot2)
library(forcats)
data <- tibble(Category = c("Baseball",
"Basketball",
"Basketball",
"Basketball",
"Football",
"Football",
"Hockey")) %>%
group_by(Category) %>%
summarise(n = n()) %>%
mutate(n = prop.table(n))
ggplot(data, aes (x="", y = n)) +
geom_bar(aes(fill = Category), width = 1, stat = "identity") +
geom_text(aes(label = paste(n, "%"), group = Category),
position = position_stack(vjust = 0.5))
Created on 2019-11-02 by the reprex package (v0.3.0)
I can't reproduce your issue:
library(dplyr)
library(ggplot2)
library(forcats)
library(cowplot)
data <- tibble(Category = c("Baseball",
"Basketball",
"Basketball",
"Basketball",
"Football",
"Football",
"Hockey")) %>%
group_by(Category) %>%
summarise(n = n()) %>%
mutate(n = prop.table(n))
# displays correctly
p_good = ggplot(data, aes (x="", y = n, fill = Category)) +
geom_bar(width = 1, stat = "identity") +
geom_text(aes(label = paste(n, "%")),
position = position_stack(vjust = 0.5))
# labels are displayed in reverse order
p_bad = ggplot(data, aes (x="", y = n)) +
geom_bar(aes(fill = Category), width = 1, stat = "identity") +
geom_text(aes(label = paste(n, "%")),
position = position_stack(vjust = 0.5))
p = plot_grid(p_good, p_bad)
show(p)
I think the issue might be with your R installation, rather then the code.
I have this bar chart:
group = c("A","A","B","B")
value = c(25,-75,-40,-76)
day = c(1,2,1,2)
dat = data.frame(group = group , value = value, day = day)
ggplot(data = dat, aes(x = group, y = value, fill = factor(day))) +
geom_bar(stat = "identity", position = "identity")+
geom_text(aes(label = round(value,0)), color = "black", position = "stack")
and I'd like the bars stacked and the values to show up. When I run the code above the -76 is not in the correct location (and neither is the 75 it seems).
Any idea how to get the numbers to appear in the correct location?
ggplot(data=dat, aes(x=group, y=value, fill=factor(day))) +
geom_bar(stat="identity", position="identity")+
geom_text(label =round(value,0),color = "black")+
scale_y_continuous(breaks=c(-80,-40,0))
Stacking a mix of negative and positive values is difficult for ggplot2. The easiest thing to do is to split the dataset into two, one for positives and one for negatives, and then add bar layers separately. A classic example is here.
You can do the same thing with the text, adding one text layer for the positive y values and one for the negatives.
dat1 = subset(dat, value >= 0)
dat2 = subset(dat, value < 0)
ggplot(mapping = aes(x = group, y = value, fill = factor(day))) +
geom_bar(data = dat1, stat = "identity", position = "stack")+
geom_bar(data = dat2, stat = "identity", position = "stack") +
geom_text(data = dat1, aes(label = round(value,0)), color = "black", position = "stack") +
geom_text(data = dat2, aes(label = round(value,0)), color = "black", position = "stack")
If using the currently development version of ggplot2 (2.1.0.9000), the stacking doesn't seem to be working correctly in geom_text for negative values. You can always calculate the text positions "by hand" if you need to.
library(dplyr)
dat2 = dat2 %>%
group_by(group) %>%
mutate(pos = cumsum(value))
ggplot(mapping = aes(x = group, y = value, fill = factor(day))) +
geom_bar(data = dat1, stat = "identity", position = "stack")+
geom_bar(data = dat2, stat = "identity", position = "stack") +
geom_text(data = dat1, aes(label = round(value,0)), color = "black") +
geom_text(data = dat2, aes(label = round(value,0), y = pos), color = "black")
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: