主要问题
在尝试使用 ggplot2 制作直方图时,我无法理解为什么日期、标签和中断的处理不像我在 R 中所期望的那样工作。
我在找:
我的约会频率的直方图
在匹配栏下方居中的刻度线
%Yb 格式的日期标签
适当的限制;最小化网格空间边缘和最外层条之间的空白空间
我有 uploaded my data to 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
这是我尝试过的:
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))
产生 this graph。不过,我想要 %Y-%b
格式,所以我四处寻找并尝试了以下基于 this 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.
这给了我this graph
正确的 x 轴标签格式
频率分布已改变形状(binwidth 问题?)
刻度线未在条形下方居中显示
xlims 也发生了变化
我完成了 scale_x_date
部分的 ggplot2 documentation 中的示例,当我将它与相同的 x 轴数据一起使用时,geom_line()
似乎正确地中断、标记和居中刻度。我不明白为什么直方图不同。
根据 edgester 和 gauden 的回答进行更新
我最初认为gauden的回答帮助我解决了我的问题,但现在仔细观察后感到困惑。请注意代码后两个答案的结果图之间的差异。
假设两者:
library(ggplot2)
library(scales)
dates <- read.csv("http://pastebin.com/raw.php?i=sDzXKFxJ", sep=",", header=T)
根据@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))
这是我根据高登回答的尝试:
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))
基于 edgester 方法的绘图:
https://i.stack.imgur.com/SQB95.png
基于高登方法的绘图:
https://i.stack.imgur.com/qvXN5.png
请注意以下事项:
2009 年 12 月和 2010 年 3 月 gauden 图中的差距; table(dates$Date) 显示数据中有 2009-12-01 的 19 个实例和 2010-03-01 的 26 个实例
edgester 的情节从 2008 年 4 月开始,到 2012 年 5 月结束。根据 2008 年 4 月 1 日数据中的最小值和 2012 年 5 月 1 日的最大值,这是正确的。由于某种原因,高登的情节从 2008 年 3 月开始,但不知何故仍设法在 2012 年 5 月结束。在计算垃圾箱并阅读月份标签之后,对于我的生活,我无法弄清楚哪个情节有额外的或缺少直方图的垃圾箱!
对这里的差异有什么想法吗? edgester 的创建单独计数的方法
相关参考
顺便说一句,这里还有其他位置,其中包含有关日期和 ggplot2 的信息,供路人寻求帮助:
从 learnr.wordpress 开始,这是一个流行的 R 博客。它说我需要将我的数据转换为 POSIXct 格式,我现在认为这是错误的并且浪费了我的时间。
另一个学习者帖子在 ggplot2 中重新创建了一个时间序列,但并不真正适用于我的情况。
r-bloggers 对此有一个帖子,但它似乎已经过时了。简单的 format= 选项对我不起作用。
这个 SO 问题正在使用中断和标签。我尝试将我的 Date 向量视为连续的,但认为它效果不佳。看起来它一遍又一遍地覆盖相同的标签文本,所以这些字母看起来有点奇怪。分布是正确的,但有一些奇怪的休息。我基于接受的答案的尝试是这样的(结果here)。
lubridate
包。
更新
版本 2:使用 Date 类
我更新了示例以演示对齐标签并在图上设置限制。我还证明了 as.Date
在一致使用时确实有效(实际上它可能比我之前的示例更适合您的数据)。
目标情节 v2
https://i.stack.imgur.com/exn5E.png
守则 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
版本 1:使用 POSIXct
我尝试了一个解决方案,该解决方案在 ggplot2
中完成所有操作,在没有聚合的情况下进行绘制,并在 2009 年初和 2011 年底之间设置 x 轴上的限制。
目标情节 v1
https://i.stack.imgur.com/ia0Hd.png
代码 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
当然,它可以通过使用轴上的标签选项来完成,但这是为了在绘图包中使用一个干净的简短例程来完成绘图。
我知道这是一个老问题,但对于任何在 2021 年(或之后)提出的人来说,使用 geom_histogram()
的 breaks=
参数并创建一个小快捷函数来制作所需的序列,这可以更容易地完成。
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))
https://i.stack.imgur.com/uWCVC.png
with()
包围整个内容,例如 with(dates,...)
,将 ...
替换为上面的 ggplot
命令并删除 dates$
我认为关键是您需要在 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)
%Y-%b
和 %Y-%m-%d
值,应该可以使用?
df$Count
向量或您所做的其他一些事情来获得可用的结果。现在我只想知道如何根据日期范围设置限制。我也不需要lubridate
。
标题“基于 Gauden 方法的绘图”下的错误图是由于 binwidth 参数: ... + Geom_histogram (binwidth = 30, color = "white") + ... 如果我们将 30 的值更改为值小于 20,例如 10,您将获得所有频率。
在统计数据中,数值比显示更重要,平淡的图形对非常漂亮的图片但有错误。
ggplot2
正在做它正在做的事情,而不是关于如何充分减少 binwidth 以免看到它。有些事情似乎让我们这些试图创建按月分类的情节感到困惑,我认为这无助于解决这个问题。
geom_histogram(binwidth = 10)
运行代码?仅凭这种变化的结果肯定是不正确的。如果您上传一个代码块,这样我就可以理解您的意思,这将是首选。
c(as.Date(), as.Date())
设置限制不起作用但 as.POSIXct 起作用?谢谢!scale_x_date
(或日期时间)时,我得到一个缺失的 binwidth 注释,并且我的刻度/标签不与条对齐。怎么可能做到这一点?min(dates$num)
的中断上所做的移位/偏移。仍然不确定为什么这是必要的,但它确实有效。顺便说一句,我会用我的解决方案更新我的问题,但是 dates$num 的东西和 ..count.. 不是必需的。即便如此,您的回答是理解这一点的关键。谢谢!