查看原文
其他

一篇小短文助你打开数据可视化的任督二脉!

2017-06-01 杜雨 数据小魔方

本文主要讨论ggplot2是如何通过颜色信号来对多边形进行填充的底层理念,这也是想要进阶R语言数据可视化过程中必须搞明白的关键环节。


ggplot2所有图层对象中,geom_ploygon()几何图层对象最为复杂,也最为特殊:


复杂在哪儿呢?


这种几何对象所定义的多边形(特别是在地理信息数据里面),领土边界是基于行政区划、行政区划再细分为单个多边形(也就是group),单个多边形又是一组经纬度坐标点构成(按照order排序)。


所以说geom_ploygon()所要显式声明的参数至少需要四个:


  • data(地理信息数据框)

  • long(经度简写)

  • lat(维度简写)

  • group(多边形分组变量)


即该图层至少需要这四个参数才能保证可以输出一张具有完成地理信息边界的地图出来。


注意了,我这里所说的完整的地理信息边界,并不带表行政边界,地理信息边界仅仅描述地球上实际存在的地理单位轮廓,所以这张图仅仅是地理轮廓的描述,而无法看到国界线。


那么国界线是通过什么定义的呢?


国家线通常需要在group的基础上,施加id(该id将同属一个国家的不同group归类为一个编号),当然我们也可以将id匹配上国家(行政区划)的实际名称(通常获取的数据地图素材都会同时匹配上id和行政区划名称,甚至还有很多附加信息:ios编码、简写、拼音、英文名称等等)。


那么问题来了,为啥之前所说的order没有在geom_polygon()参数中进行显式声明呢?


边界点不声明顺序,软件如何知道该按照什么样的顺序来进行打印呢?


这个问题是个好问题,一语中的,确实,order变量十分重要,但是通常获取的地理信息文件中,order变量是已经按照group分组变量排序过的,即通常所用到的地理信息数据框中,所有的边界点经纬度信息,是先按group分组,组内按照order排序,这样保证最后绘制出的地理信息边界点不会出现错乱,不同多边形有连接线等这种我们不想看到的情形。


当这种group和order顺序定义之后,软件首先将所有的经纬度坐标点按照group顺序打印,即先打印group顺序排在第一的多边形,group内部按照order的顺序,依次打印左边点,单个group但因完毕之后,这组点就被定义为一组,组标识即为group的名称(可以为数值、浮点或者文本,主要能够区分开组别就可以)。


当所有的组内经纬度点都按照此规则打印一遍之后,我们就可以看到整个地理信息边界的轮廓。


此时地理信息轮廓定义完成,那么接下来需要进行颜色映射,颜色映射规则很简单,不同的国家(或者行政区划)对应一个ID或者区划名称,每一个区划名称(或者国家,这里统称为id)则对应若干个group(之所有是若干个,是因为这里的对应关系可能是一一对应,也可能是一对多的关系,因为之前在讲述如何从json素材提取地理信息数据框已经讲述过原理,有些国家或者行政区仅有一个轮廓,而有些国家或者地区有多个地理上相互分离的领土,比如爱尔兰、英国、中国的海南岛、台湾省、以及东南沿海诸多海岛等)。


而每一个id(国家或者地区)会对应一个数值型(或者因子型变量),当你在给ID赋值指标变量的时候,就已经完成了group到颜色之间的对应映射关系。


我们只需要一个fill\colour美学映射属性指定给一个指标变量(数值型或者因子型),指定之后,软件会在打印每一个地理多边形同事,给这个多边形指定填充色(或者轮廓色)。因为可能存在一个id对应多个多边形(group)的情况,所以这些同属一个id的多边形都会被填充(或者轮廓色)同一个数量级的填充色(或者轮廓色)。


所以到这里,我们再回头看以上内容:


一副完整的,带有行政区划与指标变量映射关系的geom_polygon()的图层完整的语法需要指定以下一个参数:


gggplot(data=mydata)+

geom_polygon(aes(x=long,y=lat,group=group,fill/colour=zhibiao))


以上是最为典型的数据地图做法,fill/colour的颜色映射结果会根据zhibiao变量的性质进行映射形式调整,即如果zhibiao是连续型变量,那么最终就会按照连续渐变色进行填充,图例也是练习渐变的图例,指标是分类或者因子型,则会按照离散渐变进行填充。(至于这两种颜色映射方法的具体规则和原理,以后会讲到)。


没有考虑order并不代表,order不重要,事实上,order是非常重要的一个变量,只是它已经被提前考虑过了(因为太重要了),所以我们需要再考虑它,但是倘若数据顺序因为某种原因而被打乱了,那么我们需要自己重新排序。


通常只需追加一句代码:


dplyr::arrange(mymapdata,group,order)


即先按照group分组,组内按照order排序,这样既可保证最终的数据是符合几何图层映射规则,能被正确映射出来的。


接下来我用几个图形来展示以上所说的所有的原理:


library(maps)  

library("ggplot2")

library("ggthemes")

library("ggthemes")

library("RColorBrewer")


world_map<-map_data("world")

head(world_map)


ggplot(world_map)+

geom_polygon(aes(x=long,y=lat))



以上我未指定分组变量,所以自然映射结果出现这种情况,即软件将所有点全部连在一起。


ggplot(data=world_map)+

geom_polygon(aes(x=long,y=lat,group=group),colour="white")



指定分组之后,勾勒出了地理信息轮廓,事实上此时你并不知道国家的分界线(你只是基于常识,记得那个国家在那个位置,但是精确的领土分界是无法得知的,相信我~)


world_map[world_map$region=="Taiwan",]$region<-"China"

ggplot(data=world_map)+

geom_polygon(aes(x=long,y=lat,group=group,fill=region),color="grey95")+

theme_map() %+replace% theme(legend.position ="none")



此时通过region映射之后的地图,呈现的才是相对精确的行政区划边界信息。

(这里说明以下,所用地图仅用于案例演示使用,限于经济能力,无法获得高精度地图,如果出现边界线纠纷问题,不代表官方观点)。


当然,你可以将颜色映射在行政区划的轮廓线上。(但是只这样往往是不可取的,因为轮廓线颜色色彩占比太少,不利于肉眼识别,区分度不高)


ggplot(data=world_map)+

geom_polygon(aes(x=long,y=lat,group=group,color=region),fill="grey95")+

theme_map() %+replace% theme(legend.position ="none")



以上使用的region(即地区ID)映射,因为此份地图有将近200+个国家行政区,免不了颜色重复,而且通常我们并不必要将每一个国家和地区都指定一个单独的颜色。


更有意义的做法是,根据不同国家或者地区的某个指标进行连续渐变填充或者离散颜色填充。


region<-unique(world_map$region)

zhibiao<-runif(251,0,500)

mydata<-data.frame(region,zhibiao)

mydata$factor<-cut(mydata$zhibiao,breaks=c(0,100,200,300,400,500),labels=c("0~100","100~200","200~300","300~400","400~500"),order=TRUE,include.lowest = FALSE)

mynewmapdata<-merge(world_map,mydata)%>%dplyr::arrange(group,order)


连续渐变:

ggplot(data=mynewmapdata)+

geom_polygon(aes(x=long,y=lat,group=group,fill=zhibiao),colour="grey95")+

scale_fill_gradient(low="white",high="steelblue") +

theme_map() %+replace% theme(legend.position ="none")



离散填充:

ggplot(data=mynewmapdata)+

geom_polygon(aes(x=long,y=lat,group=group,fill=factor),colour="grey95")+

scale_fill_brewer(palette="Greens",guide=FALSE)+

theme_map() %+replace% theme(legend.position ="none")



欢迎关注魔方学院QQ群



您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存