ggmap:使用ggplot2进行空间可视化绘图(中篇)

作者:戴维 · 卡尔&哈德利·威克姆
翻译:李博
原文地址:ggmap: Spatial Visualization with ggplot2
PS:由于原文较长,故翻译分为三次进行。

==================================

06.ggmap 函数

只要get_map抓取了有意思的地图,ggmap就可以绘制了。get_map抓取的结果是一个特殊类别的栅格(raster)对象(一个十六进制字符串的颜色矩阵)

paris <- get_map(location = "paris")
str(paris)
qmap(baylor, zoom = 14, maptype = 53428, api_key = api_key,
source = "cloudmade")
qmap("houston", zoom = 10, maptype = 58916, api_key = api_key,
source = "cloudmade")

chr [1:1280, 1:1280] "#C6DAB6" "#C2D6B3" "#C2D6B3" ...
- attr(*, "class")= chr [1:2] "ggmap" "raster"
- attr(*, "bb")=’data.frame’: 1 obs. of 4 variables:
..$ ll.lat: num 48.6
..$ ll.lon: num 1.91
..$ ur.lat: num 49.1
..$ ur.lon: num 2.79
图6

图6:两千万用户制作的CloudMade地图样式。左图与图3和图5相当,右图包含图4中的水域。(图1—图5,参考上篇)

以下为个人加入内容(代码):

##下面的地址链接表明了图片的位置
> paris <- get_map(location = "paris")
Map from URL : http://maps.googleapis.com/maps/api/staticmap?center=paris&zoom=10&size=640x640&scale=2&maptype=terrain&language=en-EN&sensor=false
Information from URL : http://maps.googleapis.com/maps/api/geocode/json?address=paris&sensor=false
> str(paris)#这里需要掌握str()函数的用法,即用于紧凑的显示任意R对象结构
 chr [1:1280, 1:1280] "#CBE5A2" "#CBE5A2" "#C8E3A1" "#C8E3A1" "#C8E09D" "#C3DD9D" ...
 - attr(*, "class")= chr [1:2] "ggmap" "raster"
 - attr(*, "bb")='data.frame':  1 obs. of  4 variables:
  ..$ ll.lat: num 48.6
  ..$ ll.lon: num 1.91
  ..$ ur.lat: num 49.1
  ..$ ur.lon: num 2.79
 - attr(*, "source")= chr "google"
 - attr(*, "maptype")= chr "terrain"
 - attr(*, "zoom")= num 10
> 

ggmap的目的是把地图从栅格对象中输出到屏幕,并通过创建一个ggplot对象来实现这一目的。图像打印时,在图形设备中绘制所需的地图。如图7所示。

图7

而ggmap需要一个ggmap对象,它接受一小部分参数——范围,底图(base_layer),距离(maprange),图例,填充和亮度。
若无这些附加参数,则ggmap有效返回以下ggplot对象。

ggplot(aes(x = lon, y = lat), data = fourCorners) +
geom_blank() + coord_map("mercator") +
annotation_raster(ggmap, xmin, xmax, ymin, ymax)

其中fourCorners是,将expand.grid应用于ggmap对象的bb属性中,并指定的经纬度范围产生的数据集。因此,由ggmap创建的ggplot2对象的默认底图(即原始画框)是,ggplot(aes(x = lon,y = lat),data = fourCorners),默认的x、y轴是根据地图的纬度范围计算而来。

范围参数指定地图覆盖了多少图形范围。它接受三个字符串:图7所示的“normal(标准)”,图10和图12所示的“panel(面板)”和每个图中所示的“device(图案)”。

“normal”通过ggplot2提供默认坐标来定位地图,因此可以看到它后面的面板。 “panel”则将绘图面板的极限设置为scale_ [x,y] _continuous(expand = c(0,0)))的地图的经纬度范围。而“device”则通过使用新的theme_nothing命令,将这一功能用到了极致。

base_layer是一个将默认基本层替换为用户要求的命令。因此,在上述代码中,用户可以将ggplot(aes(x = lon,y = lat),data = fourCorners)更改为不同的命令。由于ggplot2函数中facet_wrap和facet_grid处于基础层,因此这对于 faceting plots(局部小块绘图)非常重要。

同时,由于更改基本层会改变基本尺度并因此改变绘图的范围,所以当基本层改变时,只有部分地图可见。将maprange参数设置为TRUE(默认为FALSE),并通过ggmap对象本身的bb属性确定x和y轴(经度和纬度),而不是base_layer参数。

ggmap(paris, extent = "normal")
图7

图7:在ggmap中设置extent =“normal”,说明ggmap中的地图和ggplot2绘制图形的相似性。

ggmap有关说明性的参数是图例和填充,它们只适用于extent =“device”。图例参数确定了在地图上绘制图例的位置。它的选项是“left”,“right”(默认),“bottom”,“top”,“topleft”,“bottomleft”,“topright”,“bottomright”和“none”。

前四个根据ggplot2的标准规格(没有任何轴)绘制图例;后四个绘制地图上的图例就像ArcGIS(一个可伸缩的,全面的GIS平台)一样;最后的“none”用于减去图例。填充控制主要是定义图例应该绘制在距离边角多远的地方。

亮度参数,是由Jean-Olivier Irisson提出的一个建议,用于调整图像色彩。默认值c(0,“black”)表示完全半透明的黑色层,即完全没有色彩。

通常情况下,第一个参数对应于alpha混合(0 =不可见(invisible),1 =不透明(opaque)),第二个参数是色调的颜色。如果只有一个数字被提供给ggmap(假定一个黑色色彩的亮度参数),色调本身是通过在地图的上添加一个geom_rect层来制作的。图2提供了一个例子,其中黑色色彩被添加到地图以增强点的可视性。

翻译2.jpg

由于ggmap返回一个ggplot对象,ggmap的输出本身可以作为ggplot2框架中的基础层。这是一个非常难得的重要的实现——它允许ggplot2的全部功能。我们现在通过在德克萨斯州休斯顿市中心的一个暴力犯罪案例研究来说明这些方法的有效性 。

==================================
</br>

07.ggmap实践

数据data

犯罪数据是由休斯顿警察局的网站,在2010年1月至 8月期间汇编的。使用plyr(韦翰,2011年)对这些数据进行了轻微的清理和汇总,同时使用了谷歌地图的地理编码;因此,完整的数据在ggmap中可用来作为犯罪数据集。

> str(crime)
’data.frame’: 86314 obs. of 17 variables:
$ time : POSIXt, format: "2010-01-01 0...
$ date : chr "1/1/2010" "1/1/2010" "1...
$ hour : int 0 0 0 0 0 0 0 0 0 0 ...
$ premise : chr "18A" "13R" "20R" "20R" ...
$ offense : chr "murder" "robbery" "aggr...
$ beat : chr "15E30" "13D10" "16E20" ...
$ block : chr "9600-9699" "4700-4799" ...
$ street : chr "marlive" "telephone" "w...
$ type : chr "ln" "rd" "ln" "st" ...
$ suffix : chr "-" "-" "-" "-" ...
$ number : int 1 1 1 1 1 1 1 1 1 1 ...
$ month : Factor w/ 12 levels "january"...
$ day : Factor w/ 7 levels "monday" ...
$ location: chr "apartment parking lot" ...
$ address : chr "9650 marlive ln" "4750 ...
$ lon : num -95.4 -95.3 -95.5 -95.4 ...
$ lat : num 29.7 29.7 29.6 29.8 29.7...

由于我们只对在市中心发生的暴力犯罪感兴趣,所以我们需要对数据进行一些设置限定。首先要确定一个地理位置的边界,使用gglocator,一个ggmap输出的类似于定位的函数ggplot2。 gglocator不仅用于ggmap绘图,而且可用于一般的ggplot2制图。

##原文如下
> # find a reasonable spatial extent(找到一个合理的空间范围)
> qmap(’houston’, zoom = 13)
> gglocator(2)
> lon lat
> 1 -95.39681 29.78400
> 2 -95.34188 29.73631
>
> # only violent crimes(仅限暴力犯罪)
> violent_crimes <- subset(crime,
+ offense != "auto theft" & offense != "theft" & offense != "burglary")
>
> # order violent crimes(攻击性暴力犯罪)
> violent_crimes$offense <- factor(violent_crimes$offense,
+ levels = c("robbery", "aggravated assault", "rape", "murder"))
>
> # restrict to downtown(市中心范围)
> violent_crimes <- subset(violent_crimes,
+ -95.39681 <= lon & lon <= -95.34188 &
+ 29.73631 <= lat & lat <= 29.78400)

分析只涉及严重伤害袭击,抢劫,强奸和谋杀的暴力犯罪数据。请注意,尽管为确保数据的质量做出了一些努力,但是数据还是被轻微清理,同时数据集可能仍然包含错误。

==================================
</br>

08.分析

第一步,我们能做的是看看个体犯罪发生的地方。通过模拟一些简单的ggplot2类型(主要是通过ggplot2具有导向功能的图例字体和键型),图8左侧包含生成显示空间气泡图的代码。

泡泡图的其中一个问题是图的重叠和点的大小,我们不能依靠感觉去确定犯罪的发生地。

处理这一问题的一个方法是将点分开,并剔除没有任何样本的点。(图8右图)向我们展示了犯罪行为的发生情况。

图8

图8:休斯顿市中心的暴力犯罪泡泡图(左)和同样的箱图(右)

theme_set(theme_bw(16))
HoustonMap <- qmap("houston", zoom = 14, color = "bw", legend = "topleft")
HoustonMap +
geom_point(aes(x = lon, y = lat, colour = offense, size = offense),
data = violent_crimes)
HoustonMap +
stat_bin2d(
aes(x = lon, y = lat, colour = offense, fill = offense),
size = .5, bins = 30, alpha = 1/2,
data = violent_crimes
)

这个箱图是我们第一次开始在ggplot2框架中看到地图的情况。虽然它实际上并不是一个非常好的绘图,但它在说明ggplot2框架与地图的上下文信息中有很大优势 ——根据犯罪变量将数据框架暴力行为划分为块的过程,将每个地点的点数汇总到一个数据集,绘图最后由ggplot2在幕后完成。

那么,一般暴力犯罪怎么办?如果我们忽略了犯罪的类型,我们可以通过使用轮廓图来了解暴力犯罪的空间分布。由于地图图像本身是基于ggplot2的annotation_raster,它没有绘制坐标,但我们可以访问添加的坐标,以形成一个填充的轮廓图。这在图9中看到(左图)。

图9

图9:暴力犯罪的轮廓图(左),加入一个小插图(右图右下角)。

houston <- get_map("houston", zoom = 14)
HoustonMap <- ggmap("houston", extent = "device", legend = "topleft")
HoustonMap +
stat_density2d(
aes(x = lon, y = lat, fill = ..level.., alpha = ..level..),
size = 2, bins = 4, data = violent_crimes,
geom = "polygon"
)
overlay <- stat_density2d(
aes(x = lon, y = lat, fill = ..level.., alpha = ..level..),
bins = 4, geom = "polygon",
data = violent_crimes
)
HoustonMap + overlay + inset(
grob = ggplotGrob(ggplot() + overlay + theme_inset()),
xmin = -95.35836, xmax = Inf, ymin = -Inf, ymax = 29.75062
)

这种类型叠加图是非常有效,然而,他们传达信息的能力可能受到阻碍,即叠加图与地图本身存在的视觉混淆。这在使用彩色地图时尤其常见。

为了解决这个问题,插图功能可以用于在白色背景上插入包含叠加层的地图插图,辅助轴线用于theme_inset函数实现的图例说明。这在图9(右图)中可以明显看到。

同时,该图像表明有三个主要的热点活动。这三个中的每一个对应于休斯敦人经常活动且特别危险的地点。

从东到西,热点是由(1)一个县监狱,每天释放囚犯两次,大量的囚犯在该区域活动,(2)在大量无家可归和贫困地区的商业公交车站, 3)一个卖淫窝点,处在城市繁华步行街地区。

除了单个图,ggmap或qmap的base_layer参数允许小面绘图(见图10)。

houston <- get_map(location = "houston", zoom = 14, color = "bw",
source = "osm")
HoustonMap <- ggmap(houston, base_layer = ggplot(aes(x = lon, y = lat),
data = violent_crimes))
HoustonMap +
stat_density2d(aes(x = lon, y = lat, fill = ..level.., alpha = ..level..),
bins = 5, geom = "polygon",
data = violent_crimes) +
scale_fill_gradient(low = "black", high = "red") +
facet_wrap(~ day)
图10

图10:按天形成小型轮廓图

这对于具有离散时间分量(日,月,季度,年等)的空间数据特别有用。

最后一个绘图显示ggplot2中轮廓线的问题之一 ——“剪切”或“撕裂”的轮廓。除了这个直观现象(这可能在后续的ggplot2版本中可能会被修正),我们可以看到,实际上大多数暴力犯罪发生在星期一,其次是星期五。星期五的小图很容易解释——在市中心的酒吧区有一个小圆点,在西南部较大地区,夜生活较为活跃。而星期一的小图不是很容易解释。

(未完待续)......

“本译文仅供个人研习、欣赏语言之用,谢绝任何转载及用于任何商业用途。本译文所涉法律后果均由本人承担。本人同意简书平台在接获有关著作权人的通知后,删除文章。”

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容