了解日期并使用R中的ggplot2绘制直方图

Hen*_*ndy 62 datetime r histogram ggplot2

主要问题

我在理解为什么日期,标签和中断的处理没有像我在R中尝试使用ggplot2进行直方图时所预期的那样有问题.

我在找:

  • 我日期频率的直方图
  • 刻度标记位于匹配条的中心
  • %Y-b格式的日期标签
  • 适当的限制; 最小化网格空间边缘和最外边条之间的空白空间

我已将数据上传到pastebin以使其可重现.我创建了几个列,因为我不确定这样做的最佳方法:

> dates <- read.csv("http://pastebin.com/raw.php?i=sDzXKFxJ", sep=",", header=T)
> head(dates)
       YM       Date Year Month
1 2008-Apr 2008-04-01 2008     4
2 2009-Apr 2009-04-01 2009     4
3 2009-Apr 2009-04-01 2009     4
4 2009-Apr 2009-04-01 2009     4
5 2009-Apr 2009-04-01 2009     4
6 2009-Apr 2009-04-01 2009     4
Run Code Online (Sandbox Code Playgroud)

这是我试过的:

library(ggplot2)
library(scales)
dates$converted <- as.Date(dates$Date, format="%Y-%m-%d")

ggplot(dates, aes(x=converted)) + geom_histogram()
+      opts(axis.text.x = theme_text(angle=90))
Run Code Online (Sandbox Code Playgroud)

这会产生这个图表.我想要%Y-%b格式化,所以我在周围搜索并尝试以下内容,基于此SO:

ggplot(dates, aes(x=converted)) + geom_histogram()
+    scale_x_date(labels=date_format("%Y-%b"),
+    breaks = "1 month")
+    opts(axis.text.x = theme_text(angle=90))

stat_bin: binwidth defaulted to range/30. Use 'binwidth = x' to adjust this.
Run Code Online (Sandbox Code Playgroud)

这给了我这张图

  • 更正x轴标签格式
  • 频率分布改变了形状(binwidth问题?)
  • 刻度标记不会显示在条形下方
  • xlims也发生了变化

我在该部分的ggplot2文档中完成了该示例,当我将其与相同的x轴数据一起使用时,它似乎正确地打破,标记和居中.我不明白为什么直方图不同.scale_x_dategeom_line()


根据edgeter和gauden的答案进行更新

我最初认为gauden的回答帮助我解决了我的问题,但现在我更加困惑地看了一眼.请注意代码后两个答案的结果图之间的差异.

假设两者:

library(ggplot2)
library(scales)
dates <- read.csv("http://pastebin.com/raw.php?i=sDzXKFxJ", sep=",", header=T)
Run Code Online (Sandbox Code Playgroud)

基于@ edgester的答案,我能够做到以下几点:

freqs <- aggregate(dates$Date, by=list(dates$Date), FUN=length)
freqs$names <- as.Date(freqs$Group.1, format="%Y-%m-%d")

ggplot(freqs, aes(x=names, y=x)) + geom_bar(stat="identity") +
       scale_x_date(breaks="1 month", labels=date_format("%Y-%b"),
                    limits=c(as.Date("2008-04-30"),as.Date("2012-04-01"))) +
       ylab("Frequency") + xlab("Year and Month") +
       theme_bw() + opts(axis.text.x = theme_text(angle=90))
Run Code Online (Sandbox Code Playgroud)

这是我基于高登答案的尝试:

dates$Date <- as.Date(dates$Date)
ggplot(dates, aes(x=Date)) + geom_histogram(binwidth=30, colour="white") +
       scale_x_date(labels = date_format("%Y-%b"),
                    breaks = seq(min(dates$Date)-5, max(dates$Date)+5, 30),
                    limits = c(as.Date("2008-05-01"), as.Date("2012-04-01"))) +
       ylab("Frequency") + xlab("Year and Month") +
       theme_bw() + opts(axis.text.x = theme_text(angle=90))
Run Code Online (Sandbox Code Playgroud)

基于edgeter方法的绘图:

edgester积

基于gauden方法的情节:

高登积

请注意以下事项:

  • 高登2009年12月和2010年3月的情节差距; table(dates$Date)显示,有19个实例2009-12-01和26个实例的2010-03-01数据
  • edgeter的情节从2008年4月开始,到2012年5月结束.根据2008-04-01数据中的最小值和2012-05-01的最大日期,这是正确的.出于某种原因,高登的情节始于2008年至3月,并且仍然以某种方式设法在2012年至5月结束.在计算垃圾箱并沿着月份标签阅读之后,对于我的生活,我无法弄清楚哪个地块有额外的或缺少直方图的垃圾箱!

有关这些差异的任何想法吗?edgeter创建单独计数的方法


相关参考文献

顺便说一句,这里有其他位置有关于日期的信息和ggplot2供路人寻求帮助:

  • Learnr.wordpress 开始,这是一个受欢迎的R博客.它表示我需要将我的数据转换为POSIXct格式,我现在认为这种格式是错误的,浪费了我的时间.
  • 另一个学习者帖子在ggplot2中重新创建了一个时间序列,但并不适用于我的情况.
  • r-bloggers有关于此的帖子,但它似乎过时了.简单的format=选择对我不起作用.
  • 这个问题正在玩休息和标签.我试着把我的Date矢量视为连续的,并且不认为它的效果如此之好.看起来它一遍又一遍地覆盖相同的标签文字,所以字母看起来很奇怪.分布是正确的,但有一些奇怪的休息.我基于接受的答案的尝试是这样的(结果在这里).

gau*_*den 33

UPDATE

版本2:使用Date类

我更新了示例以演示在绘图上对齐标签和设置限制.我还证明了as.Date在使用时确实有效(实际上它可能比我之前的例子更适合你的数据).

目标图v2

基于日期的直方图

守则v2

这是(有点过分)评论代码:

library("ggplot2")
library("scales")

dates <- read.csv("http://pastebin.com/raw.php?i=sDzXKFxJ", sep=",", header=T)
dates$Date <- as.Date(dates$Date)

# convert the Date to its numeric equivalent
# Note that Dates are stored as number of days internally,
# hence it is easy to convert back and forth mentally
dates$num <- as.numeric(dates$Date)

bin <- 60 # used for aggregating the data and aligning the labels

p <- ggplot(dates, aes(num, ..count..))
p <- p + geom_histogram(binwidth = bin, colour="white")

# The numeric data is treated as a date,
# breaks are set to an interval equal to the binwidth,
# and a set of labels is generated and adjusted in order to align with bars
p <- p + scale_x_date(breaks = seq(min(dates$num)-20, # change -20 term to taste
                                   max(dates$num), 
                                   bin),
                      labels = date_format("%Y-%b"),
                      limits = c(as.Date("2009-01-01"), 
                                 as.Date("2011-12-01")))

# from here, format at ease
p <- p + theme_bw() + xlab(NULL) + opts(axis.text.x  = theme_text(angle=45,
                                                                  hjust = 1,
                                                                  vjust = 1))
p
Run Code Online (Sandbox Code Playgroud)

版本1:使用POSIXct

我尝试了一个可以完成所有工作的解决方案,在ggplot2没有聚合的情况下进行绘制,并在2009年初和2011年底之间设置x轴的限制.

目标图v1

在ggplot2中设置限制的绘图

守则v1

library("ggplot2")
library("scales")

dates <- read.csv("http://pastebin.com/raw.php?i=sDzXKFxJ", sep=",", header=T)
dates$Date <- as.POSIXct(dates$Date)

p <- ggplot(dates, aes(Date, ..count..)) + 
    geom_histogram() +
    theme_bw() + xlab(NULL) +
    scale_x_datetime(breaks = date_breaks("3 months"),
                     labels = date_format("%Y-%b"),
                     limits = c(as.POSIXct("2009-01-01"), 
                                as.POSIXct("2011-12-01")) )

p
Run Code Online (Sandbox Code Playgroud)

当然,它可以在轴上使用标签选项,但这是在绘图包中使用干净的短程序完成绘图.


edg*_*ter 5

我认为关键是你需要在ggplot之外进行频率计算.将aggregate()与geom_bar(stat ="identity")一起使用以获得没有重新排序因子的直方图.这是一些示例代码:

require(ggplot2)

# scales goes with ggplot and adds the needed scale* functions
require(scales)

# need the month() function for the extra plot
require(lubridate)

# original data
#df<-read.csv("http://pastebin.com/download.php?i=sDzXKFxJ", header=TRUE)

# simulated data
years=sample(seq(2008,2012),681,replace=TRUE,prob=c(0.0176211453744493,0.302496328928047,0.323054331864905,0.237885462555066,0.118942731277533))
months=sample(seq(1,12),681,replace=TRUE)
my.dates=as.Date(paste(years,months,01,sep="-"))
df=data.frame(YM=strftime(my.dates, format="%Y-%b"),Date=my.dates,Year=years,Month=months)
# end simulated data creation

# sort the list just to make it pretty. It makes no difference in the final results
df=df[do.call(order, df[c("Date")]), ]

# add a dummy column for clarity in processing
df$Count=1

# compute the frequencies ourselves
freqs=aggregate(Count ~ Year + Month, data=df, FUN=length)

# rebuild the Date column so that ggplot works
freqs$Date=as.Date(paste(freqs$Year,freqs$Month,"01",sep="-"))

# I set the breaks for 2 months to reduce clutter
g<-ggplot(data=freqs,aes(x=Date,y=Count))+ geom_bar(stat="identity") + scale_x_date(labels=date_format("%Y-%b"),breaks="2 months") + theme_bw() + opts(axis.text.x = theme_text(angle=90))
print(g)

# don't overwrite the previous graph
dev.new()

# just for grins, here is a faceted view by year
# Add the Month.name factor to have things work. month() keeps the factor levels in order
freqs$Month.name=month(freqs$Date,label=TRUE, abbr=TRUE)
g2<-ggplot(data=freqs,aes(x=Month.name,y=Count))+ geom_bar(stat="identity") + facet_grid(Year~.) + theme_bw()
print(g2)
Run Code Online (Sandbox Code Playgroud)


Mic*_*man 5

我知道这是一个老问题,但对于在 2021 年(或之后)提出这个问题的任何人,使用breaks=for 参数geom_histogram()并创建一个小快捷函数来制作所需的序列可以更容易地做到这一点。

dates <- read.csv("http://pastebin.com/raw.php?i=sDzXKFxJ", sep=",", header=T)

dates$Date <- lubridate::ymd(dates$Date)

by_month <- function(x,n=1){
  seq(min(x,na.rm=T),max(x,na.rm=T),by=paste0(n," months"))
}

ggplot(dates,aes(Date)) +
  geom_histogram(breaks = by_month(dates$Date)) +
  scale_x_date(labels = scales::date_format("%Y-%b"),
               breaks = by_month(dates$Date,2)) + 
  theme(axis.text.x = element_text(angle=90))
Run Code Online (Sandbox Code Playgroud)

直方图