【问题标题】:How to master x-axis breaks in ggplot?如何掌握ggplot中的x轴中断?
【发布时间】:2021-09-05 23:25:01
【问题描述】:

最近我在 ggplot2 上做了很多工作。我喜欢这个工具的灵活性和语法。 然而,当使用代表每周时间序列的 x 轴刻度时,我遇到了麻烦。 最大的问题是按顺序获得我想要的休息时间。基本上我需要每 8 周显示一次(KW = 日历周的德语)。 您将在下面找到数据和代码。在我的 RStudio 中,直到 2021 年开始,休息时间才会正确。之后就一团糟了。休息之间的空间也不均匀。请帮帮我,我已经尝试了网上的所有解决方案好几天了......

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

【问题讨论】:

    标签: r ggplot2 time-series x-axis


    【解决方案1】:

    为了获得正确的顺序,您可以

    1. 使用例如拆分您的 iso 周年和周tidyr::separate
    2. 按年和周排列
    3. 利用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
    

    【讨论】:

    • 非常感谢这段代码!我将它集成到我的原始脚本中,因为我非常喜欢你定义休息顺序的方式
    【解决方案2】:

    问题是您的 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")
    ...
    

    【讨论】:

    • 感谢您的回答! ggplot 的这种默认排序行为让我很头疼。但这是有道理的,因为数据基础是一个融化的框架,所以我猜 ggplot 必须创建一个排序顺序
    【解决方案3】:

    有一个层scale_x_date 带有参数date_breaksdate_labels 可以自动处理轴标签的定位和格式化。

    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)
    

    【讨论】:

    • 非常感谢!在我看来,这似乎是最“ggplot”的方式,实际上是我正在寻找的转换类型。顺便说一句,您知道为什么图表网格线的显示会有所不同吗?我在某些情节中遇到了这个问题,并认为这是一个软件错误。在上面的图表中,我可以看到条形图的 4 个部分,其中有 3 个条在光学上表现为一个,因为缺少白色网格线。这让我在另一个项目中很头疼
    • @LGe 我相信这种效果是由于试图在小型设备中进行绘图。如果绘图区域变宽,那么条形之间没有白线就会消失。
    • 我明白了,这很有道理!
    猜你喜欢
    • 1970-01-01
    • 2015-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-29
    • 1970-01-01
    • 1970-01-01
    • 2011-05-27
    相关资源
    最近更新 更多