如何掌握ggplot中的x轴中断?
How to master x-axis breaks in ggplot?
最近我经常使用 ggplot2。我喜欢该工具的灵活性和语法。
然而,在使用代表每周时间序列的 x 轴刻度时,我遇到了麻烦。
最大的问题是按顺序获得我想要的休息时间。基本上我需要每 8 周显示一次(KW = 日历周的德语)。
您将在下面找到数据和代码。在我的 RStudio 中,只有在 2021 年开始之前,休息才会按正确的顺序进行。之后就是一团糟。休息之间的 space 也不均匀。请帮助我,我已经尝试了网上的所有解决方案好几天了...
iso_week <- c(paste("2020", "KW", 11:53, sep = "_"),
paste("2021", "KW", 1:23, sep = "_"))
count_Test <- c(129291, 374534 , 377599 , 417646 , 386241, 339983 , 363659 , 327799, 385638 , 431682 ,356489 ,408078,
342328 , 327980, 384834 , 472823 , 512969 , 513572, 544219, 556634 , 589201 , 719476 , 871191 ,1034449,
1133623 ,1052942 ,1148465, 1147879 ,1220279 ,1129127 ,1218988, 1284349, 1445463 ,1663992 ,1634729 ,1467454,
1400145, 1381117, 1395790, 1516038, 1672033, 1090372 , 845729, 1231405, 1187564, 1113690, 1151633, 1101499,
1060602, 1103231, 1171798, 1153270 ,1280050 ,1367247 , 1416888, 1178378, 1169510 ,1312602 ,1427668, 1360960,
1255724, 1100259 ,1218879, 944376, 874665 ,822977)
count_Test2 <- c(24899 , 34853 , 28920 , 25168 , 18262 , 11915 , 8546, 6156 , 4969, 4084 , 3156 , 2642 , 2358, 2755,
4370 , 2875 , 2543 , 2656 , 3625 , 4717 , 5579, 7159, 9073 , 8734 , 8292 , 9165 , 11154 ,12533,
14486 , 21373 , 35631 , 61856, 105667, 122036, 120862 ,124172, 121464, 116050, 145687, 171481, 167404, 127912,
120452, 115805, 97104 , 85557 ,69442 ,56902, 49898 , 54642, 55667, 63029 ,82489, 104623, 118021, 111505,
129105, 139658 ,136057 ,109776 , 85240 , 59051 , 39067, 25476 , 17094 , 10168)
testData <- as.data.frame(cbind(iso_week, count_Test, count_Test2))
testData <- as.data.frame(apply(testData[2:3], 2, as.numeric))
testData <- as.data.frame(cbind(testData, iso_week))
meltdf <- testData %>%
dplyr::select(count_Test, count_Test2, iso_week)
meltdf <- melt(meltdf,id="iso_week")
# stacked bars
k = ggplot(data = meltdf,
aes(x = iso_week, y = value, fill = variable)) +
geom_bar(stat = 'identity') +
scale_x_discrete(breaks = meltdf$iso_week[c(T,F,F,F,F,F,F,F,F)]) +
theme_bw()+ theme(panel.border = element_blank() )
k
为了在几周内获得正确的顺序
- 在年和周中拆分您的 iso 周,例如使用
tidyr::separate
- 按年周排列
- 利用
forcats::fct_inorder
以正确的顺序设置iso_week
的级别
之后,您可以执行类似 seq_along(levels(meltdf$iso_week)) %% 8 == 1
的操作,从数据的第一周开始每隔八周设置一个休息时间。
library(dplyr)
library(tidyr)
library(forcats)
library(ggplot2)
meltdf <- testData %>%
dplyr::select(count_Test, count_Test2, iso_week)
meltdf <- reshape2::melt(meltdf, id = "iso_week") %>%
tidyr::separate(iso_week, into = c("year", "week"), sep = "_KW_", remove = FALSE) %>%
arrange(as.numeric(year), as.numeric(week)) %>%
mutate(iso_week = fct_inorder(iso_week))
breaks <- levels(meltdf$iso_week)[seq_along(levels(meltdf$iso_week)) %% 8 == 1]
# stacked bars
k = ggplot(data = meltdf,
aes(x = iso_week, y = value, fill = variable)) +
geom_bar(stat = 'identity') +
scale_x_discrete(breaks = breaks) +
theme_bw()+ theme(panel.border = element_blank() )
k
问题是您的 iso_week 是 character
类型,并且 ggplot 尝试根据字母顺序对 x 轴进行排序。这可以做到:
...
meltdf <- testData %>%
dplyr::select(count_Test, count_Test2, iso_week)
#meltdf <- melt(meltdf,id="iso_week")
meltdf <- meltdf %>%
mutate(iso_week = factor(iso_week, levels = iso_week, ordered = TRUE)) %>%
pivot_longer(cols = c(count_Test, count_Test2), names_to = "variable")
...
有一个带有参数 date_breaks
和 date_labels
的图层 scale_x_date
可以自动处理轴标签定位和格式化。
library(dplyr)
library(tidyr)
library(ggplot2)
ol <- Sys.getlocale("LC_TIME")
Sys.setlocale("LC_TIME", "de_DE.UTF-8")
testData %>%
mutate(iso_week = paste(iso_week, "1"),
iso_week = as.Date(iso_week, format = "%Y_KW_%U %u")) %>%
pivot_longer(-iso_week) %>%
ggplot(aes(x = iso_week, y = value, fill = name)) +
geom_bar(stat = 'identity') +
scale_x_date(date_breaks = "2 weeks", date_labels = "%Y-%U") +
theme_bw() +
theme(panel.border = element_blank(),
axis.text.x = element_text(angle = 60, vjust = 1, hjust = 1))
重置我的语言环境。
Sys.setlocale(ol)
最近我经常使用 ggplot2。我喜欢该工具的灵活性和语法。 然而,在使用代表每周时间序列的 x 轴刻度时,我遇到了麻烦。 最大的问题是按顺序获得我想要的休息时间。基本上我需要每 8 周显示一次(KW = 日历周的德语)。 您将在下面找到数据和代码。在我的 RStudio 中,只有在 2021 年开始之前,休息才会按正确的顺序进行。之后就是一团糟。休息之间的 space 也不均匀。请帮助我,我已经尝试了网上的所有解决方案好几天了...
iso_week <- c(paste("2020", "KW", 11:53, sep = "_"),
paste("2021", "KW", 1:23, sep = "_"))
count_Test <- c(129291, 374534 , 377599 , 417646 , 386241, 339983 , 363659 , 327799, 385638 , 431682 ,356489 ,408078,
342328 , 327980, 384834 , 472823 , 512969 , 513572, 544219, 556634 , 589201 , 719476 , 871191 ,1034449,
1133623 ,1052942 ,1148465, 1147879 ,1220279 ,1129127 ,1218988, 1284349, 1445463 ,1663992 ,1634729 ,1467454,
1400145, 1381117, 1395790, 1516038, 1672033, 1090372 , 845729, 1231405, 1187564, 1113690, 1151633, 1101499,
1060602, 1103231, 1171798, 1153270 ,1280050 ,1367247 , 1416888, 1178378, 1169510 ,1312602 ,1427668, 1360960,
1255724, 1100259 ,1218879, 944376, 874665 ,822977)
count_Test2 <- c(24899 , 34853 , 28920 , 25168 , 18262 , 11915 , 8546, 6156 , 4969, 4084 , 3156 , 2642 , 2358, 2755,
4370 , 2875 , 2543 , 2656 , 3625 , 4717 , 5579, 7159, 9073 , 8734 , 8292 , 9165 , 11154 ,12533,
14486 , 21373 , 35631 , 61856, 105667, 122036, 120862 ,124172, 121464, 116050, 145687, 171481, 167404, 127912,
120452, 115805, 97104 , 85557 ,69442 ,56902, 49898 , 54642, 55667, 63029 ,82489, 104623, 118021, 111505,
129105, 139658 ,136057 ,109776 , 85240 , 59051 , 39067, 25476 , 17094 , 10168)
testData <- as.data.frame(cbind(iso_week, count_Test, count_Test2))
testData <- as.data.frame(apply(testData[2:3], 2, as.numeric))
testData <- as.data.frame(cbind(testData, iso_week))
meltdf <- testData %>%
dplyr::select(count_Test, count_Test2, iso_week)
meltdf <- melt(meltdf,id="iso_week")
# stacked bars
k = ggplot(data = meltdf,
aes(x = iso_week, y = value, fill = variable)) +
geom_bar(stat = 'identity') +
scale_x_discrete(breaks = meltdf$iso_week[c(T,F,F,F,F,F,F,F,F)]) +
theme_bw()+ theme(panel.border = element_blank() )
k
为了在几周内获得正确的顺序
- 在年和周中拆分您的 iso 周,例如使用
tidyr::separate
- 按年周排列
- 利用
forcats::fct_inorder
以正确的顺序设置iso_week
的级别
之后,您可以执行类似 seq_along(levels(meltdf$iso_week)) %% 8 == 1
的操作,从数据的第一周开始每隔八周设置一个休息时间。
library(dplyr)
library(tidyr)
library(forcats)
library(ggplot2)
meltdf <- testData %>%
dplyr::select(count_Test, count_Test2, iso_week)
meltdf <- reshape2::melt(meltdf, id = "iso_week") %>%
tidyr::separate(iso_week, into = c("year", "week"), sep = "_KW_", remove = FALSE) %>%
arrange(as.numeric(year), as.numeric(week)) %>%
mutate(iso_week = fct_inorder(iso_week))
breaks <- levels(meltdf$iso_week)[seq_along(levels(meltdf$iso_week)) %% 8 == 1]
# stacked bars
k = ggplot(data = meltdf,
aes(x = iso_week, y = value, fill = variable)) +
geom_bar(stat = 'identity') +
scale_x_discrete(breaks = breaks) +
theme_bw()+ theme(panel.border = element_blank() )
k
问题是您的 iso_week 是 character
类型,并且 ggplot 尝试根据字母顺序对 x 轴进行排序。这可以做到:
...
meltdf <- testData %>%
dplyr::select(count_Test, count_Test2, iso_week)
#meltdf <- melt(meltdf,id="iso_week")
meltdf <- meltdf %>%
mutate(iso_week = factor(iso_week, levels = iso_week, ordered = TRUE)) %>%
pivot_longer(cols = c(count_Test, count_Test2), names_to = "variable")
...
有一个带有参数 date_breaks
和 date_labels
的图层 scale_x_date
可以自动处理轴标签定位和格式化。
library(dplyr)
library(tidyr)
library(ggplot2)
ol <- Sys.getlocale("LC_TIME")
Sys.setlocale("LC_TIME", "de_DE.UTF-8")
testData %>%
mutate(iso_week = paste(iso_week, "1"),
iso_week = as.Date(iso_week, format = "%Y_KW_%U %u")) %>%
pivot_longer(-iso_week) %>%
ggplot(aes(x = iso_week, y = value, fill = name)) +
geom_bar(stat = 'identity') +
scale_x_date(date_breaks = "2 weeks", date_labels = "%Y-%U") +
theme_bw() +
theme(panel.border = element_blank(),
axis.text.x = element_text(angle = 60, vjust = 1, hjust = 1))
重置我的语言环境。
Sys.setlocale(ol)