ggplot2:年月刻度和geom_bar

8

我希望能够理解为什么本应该很简单的事情实际上却并不简单。

[我从另一篇涉及此问题的帖子中借用了一部分代码,但最终得到的解决方案并不令我满意]

library(ggplot2)
library(xts)
library(dplyr)
library(scales)

csvData <- "dt,status
2015-12-03,1
2015-12-05,1
2015-12-05,0
2015-11-24,1
2015-10-17,0
2015-12-18,0
2016-06-30,0
2016-05-21,1
2016-03-31,0
2015-12-31,0"

tmp <- read.csv(textConnection(csvData))
tmp$dt <- as.Date(tmp$dt)
tmp$yearmon <- as.yearmon(tmp$dt)
tmp$status <- as.factor(tmp$status)

### Not good. Why?
ggplot(tmp, aes(x = yearmon, fill = status)) + 
  geom_bar() + 
  scale_x_yearmon()

### Almost good but long-winded and ticks not great
chartData <- tmp %>%
  group_by(yearmon, status) %>%
  summarise(count = n()) %>%
  as.data.frame()
ggplot(chartData, aes(x = yearmon, y = count, fill = status)) + 
  geom_col() + 
  scale_x_yearmon()

第一个图表完全错误;第二个几乎完美(X轴刻度不太好,但我可以接受)。难道geom_bar()不应该执行我在第二个图表中手动执行的计数工作吗? 第一张图表 poor plot 第二张图表 better plot 我的问题是:为什么第一个图表如此糟糕?有一个警告,意味着要建议一些东西(“position_stack需要非重叠的x间隔”),但我真的无法理解它。谢谢。 我的个人答案 这就是我学到的东西(非常感谢你们所有人!):
即使有一个scale_#_yearmonscale_#_date,不幸的是ggplot将这些对象类型视为连续数字。这使得geom_bar无法使用。 geom_histogram可能会奏效。但你失去了对相关美学部分的控制。 底线:您需要在绘图之前进行分组/求和。 不确定(如果您计划使用ggplot2)xtslubridate是否真正对我尝试实现的目标有用。我怀疑对于任何连续的情况 - 日期方面 - 它们将是完美的。 总之,我最终得到了这个完全满足我的要求的东西(请注意,没有必要使用xtslubridate):
library(ggplot2)
library(dplyr)
library(scales)

csvData <- "dt,status
2015-12-03,1
2015-12-05,1
2015-12-05,0
2015-11-24,1
2015-10-17,0
2015-12-18,0
2016-06-30,0
2016-05-21,1
2016-03-31,0
2015-12-31,0"

tmp <- read.csv(textConnection(csvData))
tmp$dt <- as.Date(tmp$dt)
tmp$yearmon <- as.Date(format(tmp$dt, "%Y-%m-01"))
tmp$status <- as.factor(tmp$status)

### GOOD
chartData <- tmp %>%
  group_by(yearmon, status) %>%
  summarise(count = n()) %>%
  as.data.frame()

ggplot(chartData, aes(x = yearmon, y = count, fill = status)) + 
  geom_col() + 
  scale_x_date(labels = date_format("%h-%y"),
               breaks = seq(from = min(chartData$yearmon), 
                            to = max(chartData$yearmon), by = "month"))

最终输出 final plot 请注意,这是HTML代码。

我没有看到第一个和第二个图之间的任何区别。你能发布你的图像并指出第一个图的问题吗? - Adam Quek
完成请求。这可能是平台/软件包版本的某种问题吗?我使用的是WIN10;R版本3.4.0(2017-04-21);ggplot2 2.2.1。 - Matteo Castagna
我会使用以下代码代替:ggplot(tmp, aes(x = floor_date(dt, "month"), fill = status)) + geom_bar() + scale_x_date(labels = date_format("%Y-%b")),这样可以得到更好的x轴。 - Edgar Santos
floor_date() 是来自 lubridate 包对吧?不管怎样:我使用它可以得到和上面“FIRST CHART”一样的结果。 - Matteo Castagna
使用ggplot2 3.3.0版本无法正常工作。 - Oliver
2个回答

2
您可以使用aes(x=factor(yearmon), ...)作为一种快捷修复方法。

1
第一个图表出现问题的原因基本上是因为ggplot2不能准确理解yearmon。正如您在这里看到的,它只是一个带有标签的内部num
> as.numeric(tmp$yearmon)
[1] 2015.917 2015.917 2015.917 2015.833 2015.750 2015.917 2016.417 2016.333 2016.167 2015.917

因此,如果您在没有先前聚合的情况下绘制图表,则条形图会分散。您需要使用 geom_histogram() 分配适当的 binwidth,如下所示:

ggplot(tmp, aes(x = yearmon, fill = status)) + 
  geom_histogram(binwidth = 1/12) + 
  scale_x_yearmon()

1/12 相当于每年的 12 个月。

对于聚合后的图形,正如 @ed_sans 建议的那样,我也更喜欢使用 lubridate,因为我更了解如何更改刻度和修改轴标签。

chartData <- tmp %>%
  mutate(ym = floor_date(dt,"month")) %>%
  group_by(ym, status) %>%
  summarise(count = n()) %>%
  as.data.frame()

ggplot(chartData, aes(x = ym, y = count, fill = status)) + 
  geom_col() + 
  scale_x_date(labels = date_format("%Y-%m"),
               breaks = as.Date("2015-09-01") + 
                 months(seq(0, 10, by = 2)))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接