R ggplot2与shapefile和csv数据合并以填充多边形

时间:2013-11-05 14:23:29

标签: r merge ggplot2

我们每天都会制作地图,显示我们地区30个不同区域的温度计算水平,每个区域根据水平填充不同的颜色。这张地图看起来像

enter image description here

现在我想将地图生成切换为R.我已经下载了省级和市级边界(您可以找到boundaries for whole Spain或此处subset for my region)并设法使用ggplot2在Hadley的{{{ 3}}

我还可以生成一个包含两列的ascii文件:identifier(CODINE)和每日级别。您可以下载example

这是我的第一个尝试使用R和ggplot2绘制shapefile的脚本,因此可能存在错误并且肯定可以改进,建议欢迎。以下代码(基于Hadley之前提到的)对我有用:

> require("rgdal")
> require("maptools")
> require("ggplot2")
> require("plyr")

# Reading municipal boundaries

esp = readOGR(dsn=".", layer="lineas_limite_municipales_etrs89")

muni=subset(esp, esp$PROV1 == "46" | esp$PROV1 == "12" | esp$PROV1 == "3")
muni@data$id = rownames(muni@data)
muni.points = fortify(muni, region="id")
muni.df = join(muni.points, muni@data, by="id")

# Reading province boundaries

prov = readOGR(dsn=".", layer="poligonos_provincia_etrs89")

pr=subset(prov, prov$CODINE == "46" | prov$CODINE == "12" | prov$CODINE == "03" )
pr@data$id = rownames(pr@data)
pr.points = fortify(pr, region="id")
pr.df = join(pr.points, pr@data, by="id")

ggplot(muni.df) + aes(long,lat,group=group) + geom_path(color="blue") +
+ coord_equal()+ geom_path(data=pr.df, + 
aes(x=long, y=lat, group=group),color="red", size=0.5) 

此代码绘制了一个包含所有边界enter image description here

的漂亮地图

对于按级别填充多边形,我尝试按照here

中的建议阅读然后合并
  

level = read.csv(“levels.dat”,header = T,sep =“”)
  munlevel =合并(muni.df,水平,通过= “CODINE”)

但是它会出错

  

错误en fix.by(by.x,x):'by'必须指定唯一有效的列

我不熟悉shapefile,也许我需要了解更多关于shp数据属性的信息,以便找到合并两个数据集的正确选择。我如何合并数据,以便我可以绘制线条(市政边界),然后用水平填充它?

1 个答案:

答案 0 :(得分:17)

[注意:这个问题在一个月前被问到,所以OP可能找到了解决问题的不同方法。我在this related question工作时偶然发现了它。这个答案包括在内,希望它能使其他人受益。]

这似乎是OP要求的......

...并使用以下代码生成:

require("rgdal")
require("maptools")
require("ggplot2")
require("plyr")

# read temperature data
setwd("<location if your data file>")
temp.data        <- read.csv(file = "levels.dat", header=TRUE, sep=" ", na.string="NA", dec=".", strip.white=TRUE)
temp.data$CODINE <- str_pad(temp.data$CODINE, width = 5, side = 'left', pad = '0')

# read municipality polygons
setwd("<location of your shapefile")
esp     <- readOGR(dsn=".", layer="poligonos_municipio_etrs89")
muni    <- subset(esp, esp$PROVINCIA == "46" | esp$PROVINCIA == "12" | esp$PROVINCIA == "3")
# fortify and merge: muni.df is used in ggplot
muni@data$id <- rownames(muni@data)
muni.df <- fortify(muni)
muni.df <- join(muni.df, muni@data, by="id")
muni.df <- merge(muni.df, temp.data, by.x="CODIGOINE", by.y="CODINE", all.x=T, a..ly=F)
# create the map layers
ggp <- ggplot(data=muni.df, aes(x=long, y=lat, group=group)) 
ggp <- ggp + geom_polygon(aes(fill=LEVEL))         # draw polygons
ggp <- ggp + geom_path(color="grey", linestyle=2)  # draw boundaries
ggp <- ggp + coord_equal() 
ggp <- ggp + scale_fill_gradient(low = "#ffffcc", high = "#ff4444", 
                                 space = "Lab", na.value = "grey50",
                                 guide = "colourbar")
ggp <- ggp + labs(title="Temperature Levels: Comunitat Valenciana")
# render the map
print(ggp)

<强>解释

导入到readOGR(...)的R的Shapefile类型为SpacialDataFrame,并且有两个主要部分: ploygon 部分,其中包含每个多边形上所有点的坐标,以及 data 部分,其中包含有关每个多边形的信息(因此,每个多边形一行)。可以使用muni@polygonsmuni@data来引用这些。效用函数fortify(...)将多边形部分转换为为ggplot绘图而组织的数据框。所以基本的工作流程是:

[1] Import temperature data file (temp.data)
[2] Import polygon shapefile of municipalities (muni)
[3] Convert muni polygons to a data frame for plotting (muni.df <- fortify(...))
[4] Join columns from muni@data to muni.df
[5] Join columns from temp.data to muni.df
[6] Make the plot

必须在公共字段上完成连接,这是大多数问题的来源。原始shapefile中的每个多边形都有唯一的ID属性。在shapefile上运行fortify(...)会创建一个基于此的列id。但数据部分中没有ID列。相反,多边形ID存储为行名称。首先,我们必须向id添加muni@data列,如下所示:

muni@data$id <- rownames(muni@data)

现在我们在id中有一个muni@data字段,在id中有一个相应的muni.df字段,因此我们可以进行加入:

muni.df <- join(muni.df, muni@data, by="id")

要创建地图,我们需要根据温度水平设置填充颜色。为此,我们需要加入LEVELtemp.data的{​​{1}}列。在muni.df中有一个字段temp.data,用于标识市政当局。现在,CODINE中还有一个相应的字段CODIGOINE。但是有一个问题:muni.dfCODIGOINE,前导零,而char(5)是整数,这意味着缺少前导零(从Excel导入,也许?)。所以加入这两个字段就不会产生匹配。我们必须先将CODINE转换为带有前导零的CODINE

char(5)

现在,我们可以根据相应字段将temp.data$CODINE <- str_pad(temp.data$CODINE, width = 5, side = 'left', pad = '0') 加入temp.dat

muni.df

我们使用muni.df <- merge(muni.df, temp.data, by.x="CODIGOINE", by.y="CODINE", all.x=T, a..ly=F) 代替merge(...),因为联接字段具有不同的名称,join(...)要求它们具有相同的名称。 (请注意,join(...)速度更快,如果可能,应该使用它。所以,最后,我们有一个数据框,其中包含用于绘制多边形的所有信息以及可用于为每个多边形建立填充颜色的温度join(...)

关于OP原始代码的一些注释:

  1. OP的第一张地图(顶部的绿色地图)标识了“我们地区的30个不同区域......”。我找不到识别这些区域的shapefile。市政府文件确定了543个城市,我认为没有办法将这些区域划分为30个区域。此外,温度级别文件有542行,每个市镇一个(或多或少)。

  2. OP正在为市政府导入线形文件以绘制边界。您不需要,因为LEVEL将绘制(并填充)多边形,geom_polygon(...)将绘制边界。