看着有节,摸着无节--打一生活用品
不知不觉,夏日已慢慢临近。姑娘们飞扬的裙角,小贩叫卖的西瓜,蚊蝇嗡嗡的声音,以及翻过的一页日历,都提醒着你--夏天快来了。夏季有着不同的定义,根据中国人的日历,我们所俗称的夏季从“立夏”开始,到“立秋”结束。在气候学上,若连续五天平均温度超过22度,则算作夏季的开始,若五天平均温度低于22度则算作入秋。而天文学上的夏季一般是指6、7、8三个月。
我们想知道:哪一种夏季的定义更合乎我们的感觉?还是用数据可视化来说话吧。这项任务基本上有两个步骤,一是获取某城市的2011年日平均温度数据,二是根据数据绘制日历热图(Calendar Heatmap)。
本文所采用的数据源是Wunderground提供的API。该API所提供的数据极为丰富,除了历史温度数据外,还有湿度、风向等大量信息可以利用,所以它被数据源手册所推荐。为了使用这个API我们先申请一个免费帐户,然后利用R语言中的RJSONIO包来解析所得到的天气数据。使用这个API要注意的是,其免费帐户每分钟限制10次调用,超出会中断连接。不知道别人怎么弄的,本人的笨办法是在程序中增加了暂停。这样就获得了365个日平均温度。
日历热图是一种有趣的工具,它可以在日历表中显示时间序列数据的变化。在2009年的The Data Expo中,获奖团队就是利用了SAS来生成日历热图。多才多艺的R语言当然也可以做到。在《R Graphs Cookbook》这本书中就提到了绘制日历热图的方法,第一种方法是Paul Bleicher所写的一个函数,它是基于grid,lattice,chron这三个扩展包来编写的。第二种方法是使用openair扩展包中的calendarPlot函数。生成的图形就象下面这个样子。
上图中数日子是竖着来数的,横轴表示每月的第几周,纵轴表示星期几。灰色部分表示当天平均温度在22度以下,有色彩的区块表示在22度以上。颜色越偏黄则表示温度越高。在2011年,立夏的时间是5月6日,立秋是8月8日,但可以观察到立秋之后仍有很多时间温度在22度以上。这就是我们所俗称的“秋老虎”。如果按照气候学的定义来看,四月末就出现了连续五天的高温,所以夏天应该在四月末就开始了,一直延续到十月初结束。而天文学上的夏季则是六、七、八三个月,这三个月基本上全是22度以上。看起来天文学的夏季是比较符合我们人体的感觉的。其它的要么偏短,要么偏长。
写到这里,想起了梁静茹的一首歌:
宁静的夏天
天空中繁星点点
心里头有些思念
思念着你的脸
我可以假装看不见
也可以偷偷的想念
直到让我摸到你那温暖的脸
(最后要说的是,本人不是气象专家,本文也没有考虑到湿度对体感温度的影响等其它因素。主要还是向各位介绍R语言中日历热图的绘制。)
R代码在此:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 加载所需扩展包 | |
library(RCurl) | |
library(RJSONIO) | |
require(quantmod) | |
library(ggplot2) | |
# 提取武汉市2011年一年的历史数据 | |
date <- seq.Date(from=as.Date('2011-01-01'), | |
to=as.Date('2011-12-31'), by='1 day') | |
date.range <- as.character(format(date,"%Y%m%d")) | |
n <- length(date.range) | |
temp <- humi <- rep(0,n) | |
for (i in 1:n) { | |
# 你要用自己申请的API key来代替程序中的yourkey | |
url <- 'http://api.wunderground.com/api/yourkey/' | |
finalurl <- paste(url,'history_',date.range[i], | |
'/q/wuhan.json',sep='') | |
web <- getURL(finalurl) | |
raw <-fromJSON(web) | |
temp[i] <- raw$history$dailysummary[[1]]$meantempm | |
humi[i] <- raw$history$dailysummary[[1]]$humidity | |
# 在循环内增加一个7秒的暂停,避免连接断开。 | |
Sys.sleep(7) | |
} | |
# 将获得的数据整合为数据框,并将温度和湿度转为数值格式 | |
dataset <- data.frame(temp,humi,date,stringsAsFactors=F) | |
dataset$temp <- as.numeric(dataset$temp) | |
dataset$humi <- as.numeric(dataset$humi) | |
# 用openair包绘制日历热图 | |
install.packages('openair') | |
library(openair) | |
calendarPlot(dataset,pollutant='temp',year=2011) | |
# 用ggplot2包绘制日历热图 | |
# 复制一个新的数据框 | |
dat <- dataset | |
# 先取得月份,再转为因子格式 | |
dat$month<-as.numeric(as.POSIXlt(dat$date)$mon+1) | |
dat$monthf<-factor(dat$month,levels=as.character(1:12), | |
labels=c("Jan","Feb","Mar","Apr","May","Jun","Jul", | |
"Aug","Sep","Oct","Nov","Dec"),ordered=TRUE) | |
# 得到每周的星期,也转为因子格式 | |
dat$weekday = as.POSIXlt(dat$date)$wday | |
dat$weekdayf<-factor(dat$weekday,levels=rev(0:6), | |
labels=rev(c("Sun","Mon","Tue","Wed","Thu","Fri","Sat")),ordered=TRUE) | |
# 先得到全年的周序号,然后得到每个月的周序号 | |
dat$week <- as.numeric(format(dat$date,"%W")) | |
dat<-ddply(dat,.(monthf),transform,monthweek=1+week-min(week)) | |
# 绘图 | |
P <- ggplot(dat, aes(monthweek, weekdayf, fill = temp)) + | |
geom_tile(colour='white') + | |
facet_wrap(~monthf ,nrow=3) + | |
scale_fill_gradient(space="Lab",limits=c(22, max(dat$value)), | |
low="red", high="yellow") + | |
opts(title = "武汉市2011年气温日历热图") + | |
xlab("Week of Month") + ylab("") | |
P |
感谢博主,刚学R,只会用各种统计...发现replicate你的博客应该很有趣!:) 谢谢分享
回复删除握手
删除这个日历热图是不是也可以把气温和适度换成别的数据?比如风速等等?只要是数据就可以还是必须是温度?
回复删除只要是数据就可以
删除用OPENAIR那个包做出来的是中文月份?
回复删除是的
删除Error in calendarPlot(dataset, pollutant = "so2", year = 2011) :
回复删除No data to plot - check year chosen
In addition: Warning message:
In match(x, table, nomatch = 0L) : NAs introduced by coercion
博主我执行openair的calendarPlot之后显示上面的信息,什么原因啊?我的数据一共两列,第一列是全年时间:yyyy-mm-dd,第二列是数据(numeric格式),包括了NA。是不是那个时间的格式有问题?
估计是缺失值的问题
删除有意思!
回复删除require(quantmod)
回复删除为什么用这个包呢?貌似是一个金融分析包吧?
貌似写错了,应该是加载plyr包,否则后面的ddply函数没法运行。
删除openair中Calendar函數所繪製圖形下面一堆星星星星可以轉換成一、二、三、四?還是得去下載歐美區的R來用?
回复删除