这是一篇很务正业的可视化推送~(上篇)
自带学习R语言以来,从来没用把这些技能用在自己的专业方向上,说好的学以致用呢~
最近看到的一篇微信公众号推文,内容是关于山东省各县(细化到137个县级行政区)2016年的GDP规模、公共预算收入规模及其增速指标,数据质量还不错,是山东省发改委公布的。
http://mp.weixin.qq.com/s/Sk4fIh3-ykcNK8uP0gZryw
感觉自己终于离专业方向近了一些(本人学财政的),数据就在眼前,这次机会一定要抓住了。
数据虽然质量不错,但是苦于手头没有最新的山东省县级地图素材(之前练习用的SHP素材都是很古老的素材,使用市级范围没啥问题,但是县级行政单位变更太快了,根本没法用)。所以这篇文章写作过程特别艰难~
我用了半个上午爬取并整理数据,却用了两天时间寻找地图素材、最终找到了山东省17个地级市的json素材(还不会合并json数据),找到了个在线json转shp的平台,用17个json文件拼接成一个 完整的山东省地图,然后导出shp数据,这才搞定了县级地图工作。(想想也是太执着了~)
本篇文章主要主要还是演示地图可视化为主,其中包含基础的数据抓取、数据清洗、数据聚合、变量结构和ggplot图层语法,最终得到7福高质量的数据地图。
以下是本文需要用到的包:
library(XML)
library(RCurl)
library(stringr)
library(dplyr)
library(plyr)
library(ggplot2)
library(maptools)
library(Cairo)
library(RColorBrewer)
library(xlsx)
library(rjson)
library(rgdal)
library(data.table)
library(tidyr)
library(grid)
library(showtext)
library(sqldf)
数据抓取过程:
url<-"http://mp.weixin.qq.com/s/Sk4fIh3-ykcNK8uP0gZryw"
Name<- getURL(url,.encoding="utf-8")%>%htmlParse(encoding="UTF-8")%>%getNodeSet("//strong/span")
title<-grep("按",laply(Name,xmlValue,trim=T),value=T);title
tbls<-readHTMLTable(url,header=TRUE,trim=TRUE)
names(tbls)<-title;names(tbls)
sapply(tbls,nrow)
[1] "按公共财政预算收入规模:" "按公共财政预算收入增长幅度:"
[3] "按GDP规模:" "按GDP增长幅度:"
[5] "按人均GDP:"
以下数据网页中五张表格的提取过程:
BudgetScale<-tbls$`按公共财政预算收入规模:`[-1];names(BudgetScale)<-c("Country","BudgetScale")
BudgetScale$Country<-as.character(BudgetScale$Country)
BudgetScale$BudgetScale<-as.numeric(as.character(BudgetScale$BudgetScale))
BudgetGrowth<-tbls$`按公共财政预算收入增长幅度:`[-1];names(BudgetGrowth)<-c("Country","BudgetGrowth")
BudgetGrowth$Country<-as.character(BudgetGrowth$Country)
BudgetGrowth$BudgetGrowth<-as.numeric(as.character(BudgetGrowth$BudgetGrowth))
GDPScale<-tbls$`按GDP规模:`[-1];names(GDPScale)<-c("Country","GDPScale")
GDPScale$Country<-as.character(GDPScale$Country)
GDPScale$GDPScale<-as.numeric(as.character(GDPScale$GDPScale))
GDPGrowth<-tbls$`按GDP增长幅度:`[-1];names(GDPGrowth)<-c("Country","GDPGrowth")
GDPGrowth$Country<-as.character(GDPGrowth$Country)
GDPGrowth$GDPGrowth<-as.numeric(as.character(GDPGrowth$GDPGrowth))
PerGDPGrowth<-tbls$`按人均GDP:`[-1];names(PerGDPGrowth)<-c("Country","PerGDPGrowth")
PerGDPGrowth$Country<-as.character(PerGDPGrowth$Country)
PerGDPGrowth$PerGDPGrowth<-as.numeric(as.character(PerGDPGrowth$PerGDPGrowth))
BudgetScale<-arrange(BudgetScale,Country)
BudgetGrowth<-arrange(BudgetGrowth,Country)
GDPScale<-arrange(GDPScale,Country)
GDPGrowth<-arrange(GDPGrowth,Country)
PerGDPGrowth<-arrange(PerGDPGrowth,Country)
本来137个县级行政区的名称应该是一致的,但是网页中公布的数据名称不一致,所以没法合并,需要自己集合最新的行政区划名称手动修改,费老大劲!
先将五张表格的数据写入一个工作薄中,然后手动修改:
write.xlsx(BudgetScale,"D:/R/File/shddata.xlsx",sheetName="BudgetScale",append=FALSE,row.names=FALSE)
write.xlsx(BudgetGrowth,"D:/R/File/shddata.xlsx",sheetName="BudgetGrowth",append=TRUE,row.names=FALSE)
write.xlsx(GDPScale,"D:/R/File/shddata.xlsx",sheetName="GDPScale",append=TRUE,row.names=FALSE)
write.xlsx(GDPGrowth,"D:/R/File/shddata.xlsx",sheetName="GDPGrowth",append=TRUE,row.names=FALSE)
write.xlsx(PerGDPGrowth,"D:/R/File/shddata.xlsx",sheetName="PerGDPGrowth",append=TRUE,row.names=FALSE)
因为以上五个表格所用到的行政区划名称不完全相同,需要手动各县级行政区划对应的隶属地级市名称才能进行列合并。
以下是我从网络上找到并整理的山东省17地级市,137县级(包含县级市)行政单位的代号,名称,经纬度信息。
setwd("D:/R/mapdata/Country/shandong")
shandong_city<-read.xlsx("City.xlsx",sheetName="City",header=T,encoding='UTF-8',stringsAsFactors=FALSE)
shandong_district<-read.xlsx("City.xlsx",sheetName="District",header=T,encoding='UTF-8',stringsAsFactors=FALSE)
shandong_district<-
unite(shandong_district,address,City,Name,sep="")
shandong_district<-transform(shandong_district,Adress=paste0("山东省",shandong_district$address))[,-1][,c(4,1,2,3)]
names(shandong_district)[1]<-"address"
通过以上shandong_district表中的城市、县级市名称字段合理规范以上五张表中的县级行政单位名称,总最终合并至表6——shandongdata注意五张表在同一个工作薄中。
---------------------------------------------------------------------------------------------------------------
解析经纬度地址:这里调用百度地图的API解析县级市的经纬度地址:
(大家最好自己去注册百度地图开发者,然后申请免费秘钥)
baidu_lng <- c()
baidu_lat <- c()
ak<-"X8zlxPUdSe2weshrZ1WqnWxb43cfBI2N"
address<-shandong_district$address
for(location in address){
url<-paste("http://api.map.baidu.com/geocoder/v2/?ak=",ak,"&callback=renderOption&output=json&address=",location,sep="")
url_string <- URLencode(url)
json<- readLines(url_string, warn=F)
geo <- fromJSON(substr(json,regexpr("\\(",json)+1,nchar(json)-1))
lng<-geo$result$location$lng
lat<-geo$result$location$lat
baidu_lng<-c(baidu_lng,lng)
baidu_lat<-c(baidu_lat,lat)
}
result<-data.frame(address=address,longitude=baidu_lng,latitude=baidu_lat,stringsAsFactors=FALSE)
将县级市数据与经纬度数据合并:
shandong_district_data<-merge(shandong_district,result,by="address")[,-c(3,4)]
names(shandong_district_data)[3:4]<-c("lon","lat")
shandong_district_data$address<-as.character(shandong_district_data$address)
shandong_zhibiao_data<-read.xlsx("shddata.xlsx",sheetName="Shandongdata",header=T,encoding='UTF-8',stringsAsFactors=FALSE)
names(shandong_zhibiao_data)[2]<-"address"
shandong_district_data<-merge(shandong_district_data,shandong_zhibiao_data,by="address")
以上得到了山东省所有县级行政单位的点坐标信息。
--------------------------------------------------------------------------------------------------------------
读图背景素材导入:
素材一:山东省县级地图素材:
mymap<-readOGR(".","map",encoding = "UTF-8",verbose=FALSE)
myShape <- fortify(mymap)
x <- mymap@data
names(x)[3]<-"Code"
xs <- data.frame(x,ID=seq(0:139)-1)[,c(3,8)]
shandong_district_map_data<-merge(myShape,xs,by.x="id",by.y="ID",type="full")[,-c(5,6)]
很遗憾,我们从以上素材中所提取的城市名称数据,可能涉及到编码的问题,中文全部成为了乱码,这样我们前期整理的山东省GDP及公共财政相关数据的中名称便无法与该地图进行匹配,好在行政区代码还在,这样我们就可以从之前找到行政区划代码和名称信息进行匹配。
将县级行政区地图与县级市进行匹配,获得信息完整的县级地图数据。
shandong_district_map_data<-merge(shandong_district_map_data,shandong_district_data[,-c(3,4)],by="Code",all.x=TRUE)
shandong_district_map_data<-shandong_district_map_data[order(shandong_district_map_data$order),]
素材2:山东省市级地图素材:
CHN_adm2 <- readOGR("D:/R/rstudy/CHN_adm/CHN_adm2.shp")
CHN_adm2_1 <- fortify(CHN_adm2)
CHN_adm2_1$id<-as.numeric(CHN_adm2_1$id)
shx <- CHN_adm2@data
shxs <- data.frame(shx,id=seq(0:344)-1)
china_map_data <- join(CHN_adm2_1,shxs,type="full")
shandong_city_map_data<-subset(china_map_data,NAME_1==c("Shandong"))[,c(1,2,7,14)]
mydata<-read.csv("D:/R/rstudy/State/huanbohai.csv",header=T)[,-3]
#匹配市级行政单位信息:
shandong_city_map_data <-join(shandong_city_map_data,mydata,by="NAME_2",type="left")
--------------------------------------------------------------------------------------------------------
接下来整合指标信息与地图作图数据:
山东省市级地图作图数据:
因为我们之前获取的指标数据是按照县级行政区划整理的,这里需要使用聚合函数,整理成市级的。因为增长比率数据汇总聚合后意义不大,即便是平均值也不是很有意义,所以这里只用市级的公共预算支出和GDP数据。
shandongdata<-data.table(shandong_zhibiao_data)
shandongnewdata<-shandongdata[,.(SUM_BudgetScale=sum(BudgetScale),SUM_GDPScale=sum(GDPScale)),by=City]
shandong_city_map_data<-merge(shandong_city_map_data,shandongnewdata,by.x="city",by.y="City")
shandong_fill_map_data<-shandongnewdata
shandong_fill_map_data$city<-paste0(shandong_fill_map_data$City,"市")
shandong_fill_map_data<-shandong_fill_map_data[,c(1,4,2,3)]
shandong_fill_map_data<-merge(shandong_fill_map_data[,-1],shandong_city,by.x="city",by.y="City")
shandong_fill_map_data<-shandong_fill_map_data[,c(1,4,5,6,2,3)]
---------------------------------------------------------------------------------------------------------------
现在所有的数据已经整理完毕,我们一共得到了四张有用的数据集:
市级地图数据——shandong_city_map_data(含城市指标)
县级地图数据——shandong_district_map_data(含17个地级市指标及经纬度)
市级指标数据——shandong_fill_map_data(含城市经纬度及两个指标:GDP规模和公众预算规模)
县级指标数据——shandong_district_data(含137个行政县指标及经纬度和五个指标数据,GDP规模、GDP增速,人均GDP增速,预算规模、预算增速)。
因为地级市数据限制,只有两个指标(GDP规模和预算规模),所以,最多只能制作两张地图。
县级行政区数据比较齐全,这里计划的呈现的维度是GDP规模与GDP增速,GDP规模与人均GDP增速,GDP增速与人均GDP增速。预算规模和预算增速。合计一共四张图。
----------------------------------------------------------------------------------------------------
今天我才知道,微信推文有字数限制,20000字以内,我靠我竟然一篇 推送写了两万多字,晕倒~—~
篇幅所限,下半部分转第二篇:
欢迎关注魔方学院QQ群