ggplot2 coord_polar preserve order when using fill - r

Specifying the fill argument for aes results in a reverse order of the pie chart, so the breaks/labels wont match with pie pieces anymore. Please see the example and resulting plots below.
df = data.frame(Var1 = letters[1:5], Var2 = c(6, 31, 34, 66, 77))
df$Var1 = factor(df$Var1, levels = df$Var1, ordered = T)
# just fine, but no colors
ggplot(df, aes(x = 1,
y = Var2)) +
geom_bar(width = 1, stat = "identity") +
coord_polar(theta = "y") +
scale_fill_manual(values = c("red","green","yellow","black","white"),
guide_legend(title = "My_Title")) +
scale_y_continuous(breaks = (cumsum(df$Var2) -
df$Var2 / 2),
labels = df$Var1)
# reverse order appears
ggplot(df, aes(x = 1,
y = Var2,
fill = Var1)) +
geom_bar(width = 1, stat = "identity") +
coord_polar(theta = "y") +
scale_fill_manual(values = c("red","green","yellow","black","white"),
guide_legend(title = "My_Title")) +
scale_y_continuous(breaks = (cumsum(df$Var2) -
df$Var2 / 2),
labels = df$Var1)

Stacking will occur in reversed factor order (per v2.2.0), and therefore we can use the following code to stack in original order:
ggplot(df, aes(x = 1,
y = Var2,
fill = forcats::fct_rev(Var1))) +
geom_bar(width = 1, stat = "identity", col = 1) +
coord_polar(theta = "y") +
scale_y_continuous(breaks = (cumsum(df$Var2) -
df$Var2 / 2),
labels = df$Var1)
Also, you may use geom_col instead of geom_bar(stat = "identity").

Another option to reverse the order of the stack would be to make use of position_stack(reverse=TRUE):
df = data.frame(Var1 = letters[1:5], Var2 = c(6, 31, 34, 66, 77))
df$Var1 = factor(df$Var1, levels = df$Var1, ordered = T)
library(ggplot2)
# reverse order appears
ggplot(df, aes(x = 1,
y = Var2,
fill = Var1)) +
geom_bar(width = 1,
stat = "identity",
position = position_stack(reverse = TRUE)) +
coord_polar(theta = "y") +
scale_fill_manual(values = c("red","green","yellow","black","white"),
guide_legend(title = "My_Title")) +
scale_y_continuous(breaks = (cumsum(df$Var2) - df$Var2 / 2), labels = df$Var1)

Related

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()

R: show values in geom_bar(position = 'fill')

I have the following fake data:
n <- 100
set.seed(1)
df <- data.frame(grp = sample(c("A", "B", "C"), size = n, replace = TRUE),
values = sample(1:10, n, replace = TRUE) )
df
My goal is to have a "filled" barplot as follow, but I don't know how to use geom_text() in order to add the values of the percentages for each segment of the bars.
ggplot(df, aes(x = values, fill = grp)) +
geom_bar(position = 'fill') +
geom_text(??)
Can anyone help me please?
Are you looking for something like this?
df2 <- as.data.frame(apply(table(df), 2, function(x) x/sum(x)))
df2$grp <- rownames(df2)
df2 <- reshape2::melt(df2)
ggplot(df2, aes(x = variable, y = value, fill = grp)) +
geom_col(position = "fill") +
geom_text(aes(label = ifelse(value == 0, "", scales::percent(value))),
position = position_fill(vjust = 0.5)) +
scale_y_continuous(labels = scales::percent, name = "Percent") +
labs(x = "Value")

Why does the value of y increase in geom_bar(stat = "identity") for a stacked bar chart with a factor grouping?

In the following example, I think the height of the bars should be 500 and 45. Why are they both over 1000?
library(tidyverse)
dat <- tibble(
x = c(1, 1, 2, 2, 2),
grp = factor(c(0, 1, 0, 1, 2), levels = 0:2),
y = c(200, 300, 25, 15, 5)
)
ggplot(dat, aes(x = x, y = y, fill = grp)) +
geom_bar(stat = "identity") +
scale_y_log10(labels = scales::comma)
If you use position = "dodge", the y-axis values appear to be correct.
ggplot(dat, aes(x = x, y = y, fill = grp)) +
geom_bar(stat = "identity", position = "dodge") +
scale_y_log10(labels = scales::comma)
Any ideas where ggplot2 is getting its y-axis values in the first plot?

Aligning ggplot labels

I have a dataset where I would compare some new and old changes within some groups (Species). I have a plot which creates the desired output, but the labels are not as desired. I would like them to be between the old and new bars. This is a bit tricky when the labels are of different length.
Example
library(ggplot2)
iris$change <- sample(c('new', 'old'), 150, replace = TRUE)
iris$mean1 <- ifelse(iris$Sepal.Length < mean(iris$Sepal.Length), 'Below', 'Above')
breaks
breaks <- unique(paste(iris$Species[iris$change == 'new'], iris$change[iris$change == 'new']))
ggplot(iris, aes(x = paste(Species, change), y = Petal.Width, fill = mean1)) +
geom_bar(stat = 'identity', position = 'fill') +
scale_x_discrete(breaks = breaks, labels = c('Setosa', 'vers', 'Virginica')) +
theme(axis.text.x = element_text(hjust = -1.2)) +
geom_text(aes(label = ifelse(change == "new", 'new', '')), size = 3, y = 0.05) +
geom_text(aes(label = ifelse(change == "old", 'old', '')), size = 3, y = 0.05)
I believe you can get what you want using faceting:
library(ggplot2)
iris$change <- sample(c('new', 'old'), 150, replace = TRUE)
iris$mean1 <- ifelse(iris$Sepal.Length < mean(iris$Sepal.Length), 'Below', 'Above')
ggplot(iris, aes(x = change, y = Petal.Width, fill = mean1)) +
geom_bar(stat = 'identity', position = 'fill') +
facet_wrap(~Species, strip.position = "bottom")+
theme(strip.placement = "outside",
strip.background = element_rect(colour = "white", fill = "white"))+
xlab(NULL)

Change y limits in ggplot with facet_wrap to mix of log and regular scales

I have a dataset that has a wide range of values for one group. Using ggplot's facet_wrap, I would plot the y axis in a log scale for one group (the group that has the widest range of values) and regular axis for the other group.
Below is a reproducible example.
set.seed(123)
FiveLetters <- LETTERS[1:2]
df <- data.frame(MonthlyCount = sample(1:10, 36, replace=TRUE),
CustName = factor(sample(FiveLetters,size=36, replace=TRUE)),
ServiceDate = format(seq(ISOdate(2003,1,1), by='day', length=36),
format='%Y-%m-%d'), stringsAsFactors = F)
df$ServiceDate <- as.Date(df$ServiceDate)
# replace some counts to really high numbers for group A
df$MonthlyCount[df$CustName =="A" & df$MonthlyCount >= 9 ] <-300
df
library(ggplot2)
library(scales)
ggplot(data = df, aes(x = ServiceDate, y = MonthlyCount)) +
geom_point() +
facet_wrap(~ CustName, ncol = 1, scales = "free_y" ) +
scale_x_date("Date",
labels = date_format("%Y-%m-%d"),
breaks = date_breaks("1 week")) +
theme(axis.text.x = element_text(colour = "black",
size = 16,
angle = 90,
vjust = .5))
The resulting graph has two facets. The facet for group A has dots on the top and the bottom on the graph, which are difficult to compared, the facet for B is easier to read. I would like to plot facet for group A in log scale and leave the other "free".
this does the job
ggplot(data = df, aes(x = ServiceDate, y = MonthlyCount)) +
geom_point() +
facet_wrap(~ CustName, ncol = 1, scales = "free_y" ) +
scale_x_date("Date",
labels = date_format("%Y-%m-%d"),
breaks = date_breaks("1 week")) +
scale_y_continuous(trans=log_trans(), breaks=c(1,3,10,50,100,300),
labels = comma_format())+
theme(axis.text.x = element_text(colour = "black",
size = 16,
angle = 90,
vjust = .5))
You can make a transformed monthly count and use that as the y-axis.
## modify monthly count
df$mcount <- with(df, ifelse(CustName == "A", log(MonthlyCount), MonthlyCount))
ggplot(data = df, aes(x = ServiceDate, y = mcount)) +
geom_point() +
facet_wrap(~ CustName, ncol = 1, scales = "free_y" ) +
scale_x_date("Date",
labels = date_format("%Y-%m-%d"),
breaks = date_breaks("1 week")) +
theme(axis.text.x = element_text(colour = "black",
size = 16,
angle = 90,
vjust = .5))

Resources