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

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

Related

Is there a way for adding labels with number of observations per value in violin plot in ggplot?

Image you want to create a violin plot and have data like this:
set.seed(123)
Bodytype <- sample(LETTERS[1:3], 500, replace = T)
Weight <- rnorm(500,40,1)
df <- data.frame(Bodytype, Weight)
ggplot(data = df,
aes(x = Bodytype, y = Weight, fill = Bodytype)) +
geom_violin(scale = "count", trim = F, adjust = 0.75) +
scale_y_continuous(breaks = seq(34, 46, 1)) +
theme_gray()
Now I would like to add text label or something for each bodytype at each kg level to see how many observations in each bodytype category that weigh 36 kg, 37kg, etc. Is there are way for achieving this, or am I better off using another plot?
This can be done in many ways, here is one:
library(dplyr)
library(ggplot2)
summ <- df %>%
group_by(Bodytype) %>%
summarize(n = n(), Weight = mean(Weight))
ggplot(data = df, aes(x = Bodytype, y = Weight, fill = Bodytype)) +
geom_violin(scale = "count", trim = F, adjust = 0.75) +
scale_y_continuous(breaks = seq(34, 46, 1)) +
theme_gray() +
geom_text(aes(label = n), data = summ)
Okay, so you want multiple weight counts:
weightcounts <- df %>%
mutate(Weight = as.integer(round(Weight, 0))) %>%
group_by(Bodytype, Weight) %>%
count()
ggplot(data = df, aes(x = Bodytype, y = Weight, fill = Bodytype)) +
geom_violin(scale = "count", trim = F, adjust = 0.75) +
scale_y_continuous(breaks = seq(34, 46, 1)) +
theme_gray() +
geom_text(aes(label = n), data = weightcounts)
Either way, the premise is that you can generate a summary frame with the associated labels you need, and then add geom_text (or geom_label) with the new dataset as an argument.
Another way computing labels outside in base R:
set.seed(123)
Bodytype <- sample(LETTERS[1:3], 500, replace = T)
Weight <- rnorm(500,40,1)
df <- data.frame(Bodytype, Weight)
#Labels
df$i <- 1
labs <- aggregate(i~Bodytype,df,sum)
labs$Weight<-NA
#Plot
ggplot(data = df,
aes(x = Bodytype, y = Weight, fill = Bodytype)) +
geom_violin(scale = "count", trim = F, adjust = 0.75) +
geom_text(data=labs,aes(x=Bodytype,y=45,label=i))
scale_y_continuous(breaks = seq(34, 46, 1)) +
theme_gray()
Output:

Col plot: fill 100 - value

I have a df, which gives the plot
library(ggplot2)
df <- data.frame(group = c("Thriller", "Horror", "Action"), number = c(60, 50, 90))
ggplot(df, aes(group, number)) +
geom_col()
But I want this
I tried tings with fill, but it does not give me the result. Does someone have any suggestions? Thanks in advance!
Are you looking for something like this?
ggplot(data.frame(group = rep(df$group, 2),
number = c(df$number, 100 - df$number),
class = rep(c("B", "A"), each = nrow(df))),
aes(group, number, fill = class)) +
geom_col() +
geom_text(aes(label = paste(number, "%")),
position = position_stack(vjust = 0.5)) +
scale_fill_manual(values = c("dodgerblue", "gray30"), guide = "none")

Combined geom_bar and geom_point legend in ggplotly

I am trying to get a combined bar + point chart with a legend for both bars different Indicators) and points (a change in the Indicator). I tried to follow along with ggplot2 legend for plot combining geom_bar and geom_point and introduced a shape into my geom_point (without doing that I could not get a legend for points).
library(ggplot2)
library(dplyr)
library(ggthemes)
library(plotly)
set.seed(369)
obs <- 6
values1 <- c(round(100 + rnorm(obs) * 10, 2))
values2 <- c(round(100 + rnorm(obs) * 10, 2))
df <- data.frame(Year = rep(2014:2019, 2*2),
value = c(rep(values1, 2), rep(values2, 2)),
Indicator = rep(c("Indicator1", "Indicator2"), each = obs * 2),
Type = rep(c("Bar", "Point"), each = obs))
p <- ggplot(df, aes(value))
bars <- df %>%
filter(Type == "Bar")
points <- df %>%
filter(Type == "Point")
pl <- p +
geom_bar(data = bars,
aes(fill = Indicator, group = Indicator, x = Year, y = value), stat = "identity", position = "dodge") +
geom_point(data = points, aes(x = Year, y = value, group = Indicator, fill = Indicator, shape = "Change"), position = position_dodge(width = 0.9)) +
theme_tufte()
p
ggplotly(pl, tooltip = c("value"))
ggplotly has the output I want, however the legend has a strange grouping. Is there a way to fix the legend in the chart below?
there's probably a better way, but how's this:
library(tidyverse)
obs <- 6
values1 <- c(round(100 + rnorm(obs) * 10, 2))
values2 <- c(round(100 + rnorm(obs) * 10, 2))
df <- data.frame(Year = rep(2014:2019, 2*2),
value = c(rep(values1, 2), rep(values2, 2)),
Indicator = rep(c("Indicator1", "Indicator2"), each = obs * 2),
Type = rep(c("Bar", "Point"), each = obs))
bars <- df %>% filter(Type == "Bar")
points <- df %>% filter(Type == "Point") %>% mutate(Year =
ifelse(Indicator == "Indicator1", Year - 0.25, Year + 0.25))
p <- ggplot(bars, aes(fill = Indicator, group = Indicator, x = Year, y = value)) +
geom_bar(stat = "identity", position = "dodge", width = 1)
p <- p + geom_point(data = points, mapping = aes(fill = Indicator, x =
Year, y = value), shape = 21) + labs(x = "value") + labs(y = "value")
p
I don't know ggplotly() , but building separate geom_bar() and geom_point() plots, and then using get_legend() to remove each legend, and then building them back with plot_grid with the full plot seems a decent option.
library(tidyverse)
obs <- 6
values1 <- c(round(100 + rnorm(obs) * 10, 2))
values2 <- c(round(100 + rnorm(obs) * 10, 2))
df <- data.frame(Year = rep(2014:2019, 2*2),
value = c(rep(values1, 2), rep(values2, 2)),
Indicator = rep(c("Indicator1", "Indicator2"), each = obs * 2),
Type = rep(c("Bar", "Point"), each = obs))
bars <- df %>% filter(Type == "Bar")
points <- df %>% filter(Type == "Point") %>% mutate(Year =
ifelse(Indicator == "Indicator1", Year - 0.25, Year + 0.25),
IndicatorChange = Indicator)
p1 <- ggplot(points, mapping = aes(fill = IndicatorChange, x = Year, y = value )) + labs(x = "value") + labs(y = "value") +
geom_point(shape = 21)
p1_leg <- get_legend(p1)
p2 <- ggplot(bars, aes(fill = Indicator, group = Indicator, x = Year, y = value)) +
geom_bar(stat = "identity", position = "dodge")
p2_leg <- get_legend(p2)
p_leg <- plot_grid(p1_leg, p2_leg, ncol = 1, nrow = 5) #toggle nrow to get right spacing between legends
p3 <-ggplot(bars, aes(fill = Indicator, group = Indicator, x = Year, y = value)) + geom_bar(stat = "identity", position = "dodge", width = 1)
p3 <- p3 + geom_point(data = points, mapping = aes(fill = Indicator, x = Year, y = value), shape = 21) +
labs(x = "value") + labs(y = "value")
p3 <- p3 + theme(legend.position="none")
p3
p <- plot_grid(p3, p_leg, ncol =2, nrow =2) #more toggling possible
p
I don't know whether this is what you want(although the font size of the legend should be modified):
library(ggplot2)
library(dplyr)
library(ggthemes)
library(plotly)
set.seed(369)
obs <- 6
values1 <- c(round(100 + rnorm(obs) * 10, 2))
values2 <- c(round(100 + rnorm(obs) * 10, 2))
df <- data.frame(Year = rep(2014:2019, 2*2),
value = c(rep(values1, 2), rep(values2, 2)),
Indicator = rep(c("Indicator1", "Indicator2"), each = obs * 2),
Type = rep(c("Bar", "Point"), each = obs))
p <- ggplot(df, aes(value))
bars <- df %>%
filter(Type == "Bar")
points <- df %>%
filter(Type == "Point")
points$Type1=paste(points$Indicator,"change",sep=",")
pl <- p +
geom_bar(data = bars,
aes(fill = Indicator, group = Indicator, x = Year, y = value), stat = "identity", position = "dodge") +
geom_point(data = points,
aes(x = Year, y = value, group = Indicator, fill = Indicator, shape = "Change"),
position = position_dodge(width = 0.9)) +
theme_tufte()+
theme(legend.position="bottom")
pl <- p +
geom_bar(data = bars,
aes(fill = Indicator, group = Indicator,x = Year, y = value), stat = "identity", position = "dodge") +
geom_point(data = points,
aes(x = Year, y = value,shape = Type1),
position = position_dodge(width = 0.9)) +
theme_tufte()+
theme(legend.position="bottom",
legend.title=element_blank())
p

Labels in geom_bar having only x variable and fill factor

I have created a DF based on the following code.
sex <- c("m","f","m","m","m","m","m","f","f","f")
age <- c(">10",">20",">30",">10",">20",">30",">10",">20",">30",">10")
df1 <- data.frame(sex,age)
ggplot (df1, aes(sex, fill = factor(age))) + geom_bar()
I want to individually label the counts of combination of age and sex
sex="f" and age = ">10" = 1, sex="f" and age = ">20" = 2, sex="f" and
age = ">30" = 1, sex="m" and age = ">10" = 3, sex="m" and age = ">20"
= 1, sex="m" and age = ">30" = 2
I think you want something like this:
ggplot(df1, aes(sex, fill = factor(age))) + geom_bar() +
geom_text(stat = "count", aes(y = ..count.., label = ..count..), position = "stack", vjust = 3)
Not sure if I understood your question correctly, but do you mean something like this:
df2 <- as.data.frame(table(df1))
df2$sex_age <- paste(df2$sex, df2$age, sep = "_")
ggplot(df2, aes(x = sex_age, y = Freq)) + geom_bar(stat = "identity")

Combining position_dodge and position_fill in ggplot2

What I would like to do is use both the position = "fill" and the position = "dodge" arguments of geom_bar() at the same time somehow. Using some sample data
set.seed(1234)
df <- data.frame(
Id = rep(1:10, each = 12),
Month = rep(1:12, times = 10),
Value = sample(1:2, 10 * 12, replace = TRUE)
)
I'm able to create the following graph
df.plot <- ggplot(df, aes(x = as.factor(Month), fill = as.factor(Value))) +
geom_bar(position = "fill") +
scale_x_discrete(breaks = 1:12) +
scale_y_continuous(labels = percent) +
labs(x = "Month", y = "Value")
I like the scaling and labeling of this graph but I want to be able to unstack it. However when I do the following
df.plot2 <- ggplot(df, aes(x = as.factor(Month), fill = as.factor(Value))) +
geom_bar(position = "dodge", aes(y = (..count..)/sum(..count..))) +
scale_x_discrete(breaks = 1:12) +
scale_y_continuous(labels = percent) +
labs(x = "Month", y = "Value")
The bars are in the position and scaling that I want but the y-axis labels represent the percentage of each bar relative to the total count, not the count within each month.
All in all I want the visuals of the second graph with the labeling of the first graph. Is there a relatively easy way to automate this?
Expanding on my comment:
library(ggplot2)
library(dplyr)
library(tidyr)
library(scales)
df1 <- df %>%
group_by(Month) %>%
summarise(Value1 = sum(Value == 1) / n(),
Value2 = sum(Value == 2) / n()) %>%
gather(key = Group,value = Val,Value1:Value2)
df.plot2 <- ggplot(df1, aes(x = as.factor(Month),
y = Val,
fill = as.factor(Group))) +
geom_bar(position = "dodge",stat = "identity") +
scale_y_continuous(labels = percent_format()) +
scale_x_discrete(breaks = 1:12) +
labs(x = "Month", y = "Value")

Resources