如何逐条计算堆叠条形图中的百分比?
How to calculate percentages in a stacked barplot bar-wise?
问题
当前栏中的百分比是根据数据总量计算的。我希望每个堆栈都有一个完整的 100%。 (已解决)
此外,百分比应四舍五入为最接近的整数。 (已解决)
编辑:删除所有小于或等于 1 的百分比。(已解决)
Edit2:确保没有标签重叠。
我已经用谷歌搜索了一段时间了。似乎没有正确的方法来防止标签重叠。
我发现的可能解决方案:
- 反转剧情
- 添加 angle() 来旋转标签
- "Manually"计算每个位置
- 利用check_overlap = TRUE
当前状态
到目前为止我的代码
# Load libraries & packages =================================
library("ggplot2")
library("scales")
library("dplyr")
library("foreign")
library("tidyverse")
library("forcats")
# Data setup =================================
spss_file_path <- "D:\Programming\Testing\2017-03-15_data_import&ggplot2\Beispieldatensatz(fiktiv).sav"
exampledata <- read.spss(spss_file_path, use.value.labels = TRUE,
to.data.frame = TRUE, reencode = TRUE)
exampledata$V43 <- factor(exampledata$V43,
levels = c(1,2,3,4,5),
labels = c("1 Sehr zufrieden","2","3","4", "5 Sehr unzufrieden"))
exampledata$V43 <- factor(exampledata$V43, levels = rev(unique(levels(exampledata$V43))))
exampledata$A_REF <- factor(exampledata$A_REF, levels = rev(unique(levels(exampledata$A_REF))))
exampledata$V101 <- factor(exampledata$V101, levels = rev(unique(levels(exampledata$V101))))
labels <- exampledata %>%
filter(!is.na(V101), !is.na(V43)) %>%
count(A_REF) %>%
mutate(labels = paste(A_REF,"(n=", n, ")")) %>%
select(A_REF, labels)
plot_data <- exampledata %>%
filter(!is.na(V101), !is.na(V43)) %>%
left_join(labels, by = "A_REF")
plot_data <- plot_data %>%
group_by(labels) %>%
summarize(`5 Sehr unzufrieden` = sum(ifelse(V43 == "5 Sehr unzufrieden", 1, 0)) / n(),
`4` = sum(ifelse(V43 == "4", 1, 0)) / n(),
`3` = sum(ifelse(V43 == "3", 1, 0)) / n(),
`2` = sum(ifelse(V43 == "2", 1, 0)) / n(),
`1 Sehr zufrieden` = sum(ifelse(V43 == "1 Sehr zufrieden", 1, 0)) / n()) %>%
gather(key = Rating, value = prop, -labels)
plot_data$labels <- factor(plot_data$labels)
plot_data$Rating <- factor(plot_data$Rating) %>% fct_rev()
# Plot =================================
ggplot(plot_data, aes(x = labels, y = prop, fill = Rating)) +
geom_col() +
scale_y_continuous(labels = scales::percent, breaks = c(0, 0.2, 0.4, 0.6, 0.8, 1)) +
labs(y=NULL, x=NULL, fill=NULL) +
ggtitle(paste(attr(exampledata, "variable.labels")[77])) +
theme_classic() +
geom_text(aes(label = if_else(prop > 0.02, scales::percent(round(prop, 2)), NULL)), position = position_fill(vjust=0.5)) +
coord_flip()
数据
structure(list(exampledata.V101 = structure(c(2L, NA, 2L, 2L,
2L, 2L, 1L, 1L, 1L, 2L, 1L, 2L, 2L, NA, 2L, 2L, 2L, 1L, 2L, NA,
NA, NA, 1L, 1L, 2L, NA, 2L, 2L, 2L, NA, 2L, 2L, NA, NA, 1L, NA,
2L, 2L, 2L, 1L, 2L, 2L, 2L, 2L, NA, NA, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 1L, 1L, 2L, 2L, 2L, 2L, 1L, 2L, NA, 1L, NA, 1L, NA,
1L, 2L, NA, NA, 2L, NA, 1L, 2L, 2L, NA, 2L, NA, 2L, 2L, 1L, 2L,
1L, 2L, 1L, 1L, 2L, 1L, NA, 2L, 2L, 2L, 2L, NA, 2L, 1L, 2L, 2L
), .Label = c("Weiblich", "Männlich"), class = "factor"), exampledata.A_REF = structure(c(18L,
18L, 18L, 18L, 18L, 17L, 18L, 18L, 18L, 18L, 18L, 18L, 16L, 18L,
18L, 18L, 18L, 18L, 18L, 18L, 18L, 18L, 16L, 18L, 18L, 16L, 18L,
16L, 18L, 18L, 17L, 18L, 18L, 18L, 18L, 18L, 18L, 18L, 18L, 18L,
16L, 18L, 18L, 17L, 18L, 18L, 18L, 18L, 18L, 18L, 17L, 16L, 18L,
18L, 18L, 18L, 18L, 18L, 18L, 18L, 18L, 18L, 18L, 17L, 18L, 18L,
16L, 18L, 16L, 18L, 18L, 16L, 16L, 18L, 18L, 18L, 18L, 18L, 18L,
18L, 17L, 18L, 18L, 18L, 18L, 18L, 18L, 18L, 18L, 18L, 16L, 18L,
16L, 16L, 18L, 18L, 18L, 17L, 16L, 18L), .Label = c("Zertifikat eines Aufbau- oder Ergänzungsstudiums",
"LA Berufliche Schulen", "LA Sonderschule", "LA Gymnasium", "LA Haupt- und Realschule",
"LA Grundschule", "Künstlerischer/musischer Abschluss", "Kirchlicher Abschluss",
"Staatsexamen (ohne Lehramt)", "Diplom Fachhochschule, Diplom I an Gesamthochschulen",
"Diplom Universität, Diplom II an Gesamthochschulen", "Sonstiges",
"Promotion", "Staatsexamen", "Magister", "Diplom", "Master",
"Bachelor"), class = "factor"), exampledata.V43 = structure(c(3L,
5L, 4L, 4L, 4L, 4L, 4L, 5L, 5L, 4L, 3L, 3L, 2L, NA, 4L, 5L, 5L,
4L, 4L, 4L, 4L, NA, 2L, 4L, 3L, 5L, 4L, 4L, 4L, NA, 4L, 4L, NA,
NA, 3L, 5L, 2L, 4L, 5L, 4L, 4L, 5L, 5L, 4L, NA, NA, 4L, NA, 3L,
4L, 5L, 5L, 2L, 4L, 4L, 3L, 4L, 4L, 4L, 3L, 5L, 4L, 5L, NA, 4L,
NA, 4L, NA, 4L, 5L, 4L, NA, 5L, NA, 4L, 4L, 4L, NA, 4L, NA, 5L,
4L, 4L, 4L, 4L, 4L, 3L, 3L, 4L, 2L, 4L, 4L, 4L, 3L, 4L, NA, 4L,
5L, 5L, 4L), .Label = c("5 Sehr unzufrieden", "4", "3", "2",
"1 Sehr zufrieden"), class = "factor")), .Names = c("exampledata.V101",
"exampledata.A_REF", "exampledata.V43"), row.names = c(NA, 100L
), class = "data.frame")
通常最好在绘制图表之前将数据处理成汇总数据。我发现试图让 ggplot2
为您做摘要要么是有限的,要么很难以您想要的方式显示它。
library(tidyverse)
library(forcats)
因为最好在将数据绘制到 ggplot2
中之前先对其进行总结,因此以下代码会计算每组 label
在量表上选择特定答案的比例。在最后一步,我将数据从宽变为长,这样所有要绘制图表的比例都在同一个变量中(我称之为 prop
)。
plot_data <- plot_data %>% group_by(labels) %>%
summarize(`5 Sehr unzufrieden` = sum(ifelse(V43 == "5 Sehr unzufrieden", 1, 0)) / n(),
`4` = sum(ifelse(V43 == "4", 1, 0)) / n(),
`3` = sum(ifelse(V43 == "3", 1, 0)) / n(),
`2` = sum(ifelse(V43 == "2", 1, 0)) / n(),
`1 Sehr zufrieden` = sum(ifelse(V43 == "1 Sehr zufrieden", 1, 0)) / n()) %>%
gather(key = Rating, value = prop, -labels)
最好将分类变量设置为用于操纵的因素,例如,顺序和颜色,因此这就是以下内容。最初,我的代码中的刻度标签(我在上面的 gather
函数中称为 Rating
)的顺序与你的相反,所以我使用 fct_rev
来自 forcats
包将其反转回来。
plot_data$labels <- factor(plot_data$labels)
plot_data$Rating <- factor(plot_data$Rating) %>% fct_rev()
对于下面的图表,我只是做了一些更改。最值得注意的是我使用 geom_col
而不是 geom_bar
。在后台,geom_col
与 geom_bar(stat = "identity")
相同 - 只是输入速度更快。我们实际上是在告诉 ggplot2
按原样绘制数据图表,而不是将其视为原始数据。但是,我确实需要指定 y
美学来指示我想要绘制哪些数据,因此我指定在初始 ggplot
调用中使用 prop
变量。
# Plot =================================
ggplot(plot_data, aes(x = labels, y = prop, fill = Rating)) +
geom_col() +
scale_y_continuous(labels = scales::percent, breaks = c(0, 0.2, 0.4, 0.6, 0.8, 1)) +
labs(y=NULL, x=NULL, fill=NULL) +
ggtitle(paste(attr(exampledata, "variable.labels")[77])) +
theme_classic() +
geom_text(aes(label = if_else(prop > 0.01, scales::percent(round(prop, 2)), NULL)), position = position_fill(vjust=0.5)) +
coord_flip()
我唯一更改的另一行是上面的 geom_text
调用。我添加了一个 if_else
函数,以便它显示标签(如果它高于 1%)或不显示(1% 或更少)。此外,我四舍五入了百分比,这样您就不会使用 round
函数得到任何小数。请记住,您需要四舍五入到小数点后两位。
不确定这是否会让您到达您想去的地方,但这是一个基于我之前编写的一些代码的简单版本。没有包括所有 ggplot2 位,因为我同意@Phil 的总结应该在绘图之前完成。
devtools::install_github("ekstroem/MESS")
x <- c(35, 34.6, 12, 5, .1, .99, 1.2, 11.11) # Input percentages
round_percent(x)
这给出了
[1] 35 35 12 5 0 1 1 11
或者你可以
round_percent(x[x>1])
这给出了
[1] 36 35 12 5 1 11
您需要确保颜色与其余组匹配,所以还有一些工作要做。
问题
当前栏中的百分比是根据数据总量计算的。我希望每个堆栈都有一个完整的 100%。 (已解决)
此外,百分比应四舍五入为最接近的整数。 (已解决)
编辑:删除所有小于或等于 1 的百分比。(已解决)
Edit2:确保没有标签重叠。
我已经用谷歌搜索了一段时间了。似乎没有正确的方法来防止标签重叠。
我发现的可能解决方案:
- 反转剧情
- 添加 angle() 来旋转标签
- "Manually"计算每个位置
- 利用check_overlap = TRUE
当前状态
到目前为止我的代码
# Load libraries & packages =================================
library("ggplot2")
library("scales")
library("dplyr")
library("foreign")
library("tidyverse")
library("forcats")
# Data setup =================================
spss_file_path <- "D:\Programming\Testing\2017-03-15_data_import&ggplot2\Beispieldatensatz(fiktiv).sav"
exampledata <- read.spss(spss_file_path, use.value.labels = TRUE,
to.data.frame = TRUE, reencode = TRUE)
exampledata$V43 <- factor(exampledata$V43,
levels = c(1,2,3,4,5),
labels = c("1 Sehr zufrieden","2","3","4", "5 Sehr unzufrieden"))
exampledata$V43 <- factor(exampledata$V43, levels = rev(unique(levels(exampledata$V43))))
exampledata$A_REF <- factor(exampledata$A_REF, levels = rev(unique(levels(exampledata$A_REF))))
exampledata$V101 <- factor(exampledata$V101, levels = rev(unique(levels(exampledata$V101))))
labels <- exampledata %>%
filter(!is.na(V101), !is.na(V43)) %>%
count(A_REF) %>%
mutate(labels = paste(A_REF,"(n=", n, ")")) %>%
select(A_REF, labels)
plot_data <- exampledata %>%
filter(!is.na(V101), !is.na(V43)) %>%
left_join(labels, by = "A_REF")
plot_data <- plot_data %>%
group_by(labels) %>%
summarize(`5 Sehr unzufrieden` = sum(ifelse(V43 == "5 Sehr unzufrieden", 1, 0)) / n(),
`4` = sum(ifelse(V43 == "4", 1, 0)) / n(),
`3` = sum(ifelse(V43 == "3", 1, 0)) / n(),
`2` = sum(ifelse(V43 == "2", 1, 0)) / n(),
`1 Sehr zufrieden` = sum(ifelse(V43 == "1 Sehr zufrieden", 1, 0)) / n()) %>%
gather(key = Rating, value = prop, -labels)
plot_data$labels <- factor(plot_data$labels)
plot_data$Rating <- factor(plot_data$Rating) %>% fct_rev()
# Plot =================================
ggplot(plot_data, aes(x = labels, y = prop, fill = Rating)) +
geom_col() +
scale_y_continuous(labels = scales::percent, breaks = c(0, 0.2, 0.4, 0.6, 0.8, 1)) +
labs(y=NULL, x=NULL, fill=NULL) +
ggtitle(paste(attr(exampledata, "variable.labels")[77])) +
theme_classic() +
geom_text(aes(label = if_else(prop > 0.02, scales::percent(round(prop, 2)), NULL)), position = position_fill(vjust=0.5)) +
coord_flip()
数据
structure(list(exampledata.V101 = structure(c(2L, NA, 2L, 2L,
2L, 2L, 1L, 1L, 1L, 2L, 1L, 2L, 2L, NA, 2L, 2L, 2L, 1L, 2L, NA,
NA, NA, 1L, 1L, 2L, NA, 2L, 2L, 2L, NA, 2L, 2L, NA, NA, 1L, NA,
2L, 2L, 2L, 1L, 2L, 2L, 2L, 2L, NA, NA, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 1L, 1L, 2L, 2L, 2L, 2L, 1L, 2L, NA, 1L, NA, 1L, NA,
1L, 2L, NA, NA, 2L, NA, 1L, 2L, 2L, NA, 2L, NA, 2L, 2L, 1L, 2L,
1L, 2L, 1L, 1L, 2L, 1L, NA, 2L, 2L, 2L, 2L, NA, 2L, 1L, 2L, 2L
), .Label = c("Weiblich", "Männlich"), class = "factor"), exampledata.A_REF = structure(c(18L,
18L, 18L, 18L, 18L, 17L, 18L, 18L, 18L, 18L, 18L, 18L, 16L, 18L,
18L, 18L, 18L, 18L, 18L, 18L, 18L, 18L, 16L, 18L, 18L, 16L, 18L,
16L, 18L, 18L, 17L, 18L, 18L, 18L, 18L, 18L, 18L, 18L, 18L, 18L,
16L, 18L, 18L, 17L, 18L, 18L, 18L, 18L, 18L, 18L, 17L, 16L, 18L,
18L, 18L, 18L, 18L, 18L, 18L, 18L, 18L, 18L, 18L, 17L, 18L, 18L,
16L, 18L, 16L, 18L, 18L, 16L, 16L, 18L, 18L, 18L, 18L, 18L, 18L,
18L, 17L, 18L, 18L, 18L, 18L, 18L, 18L, 18L, 18L, 18L, 16L, 18L,
16L, 16L, 18L, 18L, 18L, 17L, 16L, 18L), .Label = c("Zertifikat eines Aufbau- oder Ergänzungsstudiums",
"LA Berufliche Schulen", "LA Sonderschule", "LA Gymnasium", "LA Haupt- und Realschule",
"LA Grundschule", "Künstlerischer/musischer Abschluss", "Kirchlicher Abschluss",
"Staatsexamen (ohne Lehramt)", "Diplom Fachhochschule, Diplom I an Gesamthochschulen",
"Diplom Universität, Diplom II an Gesamthochschulen", "Sonstiges",
"Promotion", "Staatsexamen", "Magister", "Diplom", "Master",
"Bachelor"), class = "factor"), exampledata.V43 = structure(c(3L,
5L, 4L, 4L, 4L, 4L, 4L, 5L, 5L, 4L, 3L, 3L, 2L, NA, 4L, 5L, 5L,
4L, 4L, 4L, 4L, NA, 2L, 4L, 3L, 5L, 4L, 4L, 4L, NA, 4L, 4L, NA,
NA, 3L, 5L, 2L, 4L, 5L, 4L, 4L, 5L, 5L, 4L, NA, NA, 4L, NA, 3L,
4L, 5L, 5L, 2L, 4L, 4L, 3L, 4L, 4L, 4L, 3L, 5L, 4L, 5L, NA, 4L,
NA, 4L, NA, 4L, 5L, 4L, NA, 5L, NA, 4L, 4L, 4L, NA, 4L, NA, 5L,
4L, 4L, 4L, 4L, 4L, 3L, 3L, 4L, 2L, 4L, 4L, 4L, 3L, 4L, NA, 4L,
5L, 5L, 4L), .Label = c("5 Sehr unzufrieden", "4", "3", "2",
"1 Sehr zufrieden"), class = "factor")), .Names = c("exampledata.V101",
"exampledata.A_REF", "exampledata.V43"), row.names = c(NA, 100L
), class = "data.frame")
通常最好在绘制图表之前将数据处理成汇总数据。我发现试图让 ggplot2
为您做摘要要么是有限的,要么很难以您想要的方式显示它。
library(tidyverse)
library(forcats)
因为最好在将数据绘制到 ggplot2
中之前先对其进行总结,因此以下代码会计算每组 label
在量表上选择特定答案的比例。在最后一步,我将数据从宽变为长,这样所有要绘制图表的比例都在同一个变量中(我称之为 prop
)。
plot_data <- plot_data %>% group_by(labels) %>%
summarize(`5 Sehr unzufrieden` = sum(ifelse(V43 == "5 Sehr unzufrieden", 1, 0)) / n(),
`4` = sum(ifelse(V43 == "4", 1, 0)) / n(),
`3` = sum(ifelse(V43 == "3", 1, 0)) / n(),
`2` = sum(ifelse(V43 == "2", 1, 0)) / n(),
`1 Sehr zufrieden` = sum(ifelse(V43 == "1 Sehr zufrieden", 1, 0)) / n()) %>%
gather(key = Rating, value = prop, -labels)
最好将分类变量设置为用于操纵的因素,例如,顺序和颜色,因此这就是以下内容。最初,我的代码中的刻度标签(我在上面的 gather
函数中称为 Rating
)的顺序与你的相反,所以我使用 fct_rev
来自 forcats
包将其反转回来。
plot_data$labels <- factor(plot_data$labels)
plot_data$Rating <- factor(plot_data$Rating) %>% fct_rev()
对于下面的图表,我只是做了一些更改。最值得注意的是我使用 geom_col
而不是 geom_bar
。在后台,geom_col
与 geom_bar(stat = "identity")
相同 - 只是输入速度更快。我们实际上是在告诉 ggplot2
按原样绘制数据图表,而不是将其视为原始数据。但是,我确实需要指定 y
美学来指示我想要绘制哪些数据,因此我指定在初始 ggplot
调用中使用 prop
变量。
# Plot =================================
ggplot(plot_data, aes(x = labels, y = prop, fill = Rating)) +
geom_col() +
scale_y_continuous(labels = scales::percent, breaks = c(0, 0.2, 0.4, 0.6, 0.8, 1)) +
labs(y=NULL, x=NULL, fill=NULL) +
ggtitle(paste(attr(exampledata, "variable.labels")[77])) +
theme_classic() +
geom_text(aes(label = if_else(prop > 0.01, scales::percent(round(prop, 2)), NULL)), position = position_fill(vjust=0.5)) +
coord_flip()
我唯一更改的另一行是上面的 geom_text
调用。我添加了一个 if_else
函数,以便它显示标签(如果它高于 1%)或不显示(1% 或更少)。此外,我四舍五入了百分比,这样您就不会使用 round
函数得到任何小数。请记住,您需要四舍五入到小数点后两位。
不确定这是否会让您到达您想去的地方,但这是一个基于我之前编写的一些代码的简单版本。没有包括所有 ggplot2 位,因为我同意@Phil 的总结应该在绘图之前完成。
devtools::install_github("ekstroem/MESS")
x <- c(35, 34.6, 12, 5, .1, .99, 1.2, 11.11) # Input percentages
round_percent(x)
这给出了
[1] 35 35 12 5 0 1 1 11
或者你可以
round_percent(x[x>1])
这给出了
[1] 36 35 12 5 1 11
您需要确保颜色与其余组匹配,所以还有一些工作要做。