使用带有空洞多边形的ggplot区域地图

16

我正在尝试绘制德国的分级地图,显示每个州的贫困率(受这个问题的启发)。

问题在于,一些州(例如柏林)完全被其他州(勃兰登堡)包围,我无法让ggplot识别勃兰登堡中的“空洞”。

此示例的数据在此处

library(rgdal)
library(ggplot2)
library(RColorBrewer)

map <- readOGR(dsn=".", layer="germany3")
pov <- read.csv("gerpoverty.csv")

mrg.df <- data.frame(id=rownames(map@data),ID_1=map@data$ID_1)
mrg.df <- merge(mrg.df,pov, by="ID_1")
map.df <- fortify(map)
map.df <- merge(map.df,mrg.df[,c("id","poverty")], by="id")
ggplot(map.df, aes(x=long, y=lat, group=group)) +
  geom_polygon(aes(fill=poverty))+
  geom_path(colour="grey50")+
  scale_fill_gradientn(colours=brewer.pal(5,"OrRd"))+
  labs(x="",y="")+ theme_bw()+
  coord_fixed()

请注意柏林和勃兰登堡(位于东北部)的颜色是相同的。它们不应该相同-柏林的贫困率要低得多。似乎ggplot先渲染了柏林的面,然后在没有洞的情况下渲染了勃兰登堡的面。

如果按照这里建议的更改geom_polygon(...)的调用,就可以解决柏林/勃兰登堡的问题,但现在三个最北部的州的呈现是错误的。

ggplot(map.df, aes(x=long, y=lat, group=group)) +
  geom_polygon(aes(group=poverty, fill=poverty))+
  geom_path(colour="grey50")+
  scale_fill_gradientn(colours=brewer.pal(5,"OrRd"))+
  labs(x="",y="")+ theme_bw()+
  coord_fixed()

我做错了什么??


你尝试使用map<-fortify(map)来处理你的地图了吗? http://docs.ggplot2.org/0.9.3.1/fortify.sp.html - Rentrop
请查看代码的第8行:map.df <- fortify(map)。或者你是指其他的内容? - jlhoward
这个问题的讨论和解决方法示例可以在 https://github.com/hadley/ggplot2/wiki/plotting-polygon-shapefiles 找到。 - Ista
@Ista - 谢谢你。你知道这个问题是否会被修复吗?其他软件包不会以这种方式失败(请参见下面的答案)。此外,如果只有一个“洞”(例如湖泊),应该如何使其透明(背景透过)我认为这种方法行不通。这个回答中有一个例子。 - jlhoward
@jlhoward - 我怀疑这个问题不会很快得到解决,你必须像我所示的那样绕过它。 - Ista
4个回答

16

这只是对@Ista答案的扩展,不需要知道哪些州(柏林、不来梅)需要最后呈现。

此方法利用了fortify(...)生成一个名为hole的列,该列标识一组坐标是否为洞。因此,它将在呈现没有洞的地区之前(例如,在其下方)呈现所有具有任何洞的区域(ID)。

非常感谢@Ista,没有他的答案,我想不出这个方法(相信我,我花了很多小时尝试...)

ggplot(map.df, aes(x=long, y=lat, group=group)) +
  geom_polygon(data=map.df[map.df$id %in% map.df[map.df$hole,]$id,],aes(fill=poverty))+
  geom_polygon(data=map.df[!map.df$id %in% map.df[map.df$hole,]$id,],aes(fill=poverty))+
  geom_path(colour="grey50")+
  scale_fill_gradientn(colours=brewer.pal(5,"OrRd"))+
  labs(x="",y="")+ theme_bw()+
  coord_fixed()


@jhoward - 我实际上尝试过并且在我的原始答案中失败了。我曾认为 'geom_polygon(data=map.df[!map.df$hole,],aes(fill=poverty))' 应该可以工作,但很失望它没有。很高兴在这里看到你的解决方案。 - Ista
@jhoward 非常感谢您提供的这个高明解决方案! - ikashnitsky

10

您可以按照ggplot2维基上的示例,在单独的图层中绘制岛屿多边形。我已经修改了您的合并步骤,以使此过程更加容易:

mrg.df <- data.frame(id=rownames(map@data),ID_1=map@data$ID_1)
mrg.df <- merge(mrg.df,pov, by="ID_1")
map.df <- fortify(map)
map.df <- merge(map.df,mrg.df, by="id")

ggplot(map.df, aes(x=long, y=lat, group=group)) +
    geom_polygon(aes(fill=poverty), color = "grey50", data =subset(map.df, !Id1 %in% c("Berlin", "Bremen")))+
    geom_polygon(aes(fill=poverty), color = "grey50", data =subset(map.df, Id1 %in%  c("Berlin", "Bremen")))+
    scale_fill_gradientn(colours=brewer.pal(5,"OrRd"))+
    labs(x="",y="")+ theme_bw()+
    coord_fixed()

德国地图

作为一种未经邀请的宣传行为,我鼓励您考虑类似的事情

library(ggmap)
qmap("germany", zoom = 6) +
    geom_polygon(aes(x=long, y=lat, group=group, fill=poverty),
                 color = "grey50", alpha = .7,
                 data =subset(map.df, !Id1 %in% c("Berlin", "Bremen")))+
    geom_polygon(aes(x=long, y=lat, group=group, fill=poverty),
                 color = "grey50", alpha= .7,
                 data =subset(map.df, Id1 %in%  c("Berlin", "Bremen")))+
    scale_fill_gradientn(colours=brewer.pal(5,"OrRd"))

提供背景和熟悉的参考点。


2

为@Ista和@jhoward的回答增加一点小改进(非常感谢您的帮助!)。

@jhoward的修改可以很容易地包装在一个小函数中,如下所示:

gghole <- function(fort){
        poly <- fort[fort$id %in% fort[fort$hole,]$id,]
        hole <- fort[!fort$id %in% fort[fort$hole,]$id,]
        out <- list(poly,hole)
        names(out) <- c('poly','hole')
        return(out)
} 
# input has to be a fortified data.frame

那么,我们就不需要每次都记得如何提取孔洞信息了。代码看起来像这样:

    ggplot(map.df, aes(x=long, y=lat, group=group)) +
            geom_polygon(data=gghole(map.df)[[1]],aes(fill=poverty),colour="grey50")+
            geom_polygon(data=gghole(map.df)[[2]],aes(fill=poverty),colour="grey50")+
    # (optionally). Call by name
    #         geom_polygon(data=gghole(map.df)$poly,aes(fill=poverty),colour="grey50")+
    #         geom_polygon(data=gghole(map.df)$hole,aes(fill=poverty),colour="grey50")+
            scale_fill_gradientn(colours=brewer.pal(5,"OrRd"))+
            labs(x="",y="")+ theme_bw()+
            coord_fixed()

1
一个更短的版本:ggpolyhole <- function(fort, poly = TRUE){ idx <- fort$id %in% fort[fort$hole, ]$id fort[idx - poly, ] } - Polor Beer

1

或者您可以使用rworldmap创建该地图。

library(rworldmap)
library(RColorBrewer)
library(rgdal)

map <- readOGR(dsn=".", layer="germany3")
pov <- read.csv("gerpoverty.csv")

#join data to the map
sPDF <- joinData2Map(pov,nameMap='map',nameJoinIDMap='VARNAME_1',nameJoinColumnData='Id1')

#default map
#mapPolys(sPDF,nameColumnToPlot='poverty')

colours=brewer.pal(5,"OrRd")
mapParams <- mapPolys( sPDF
                      ,nameColumnToPlot='poverty'
                      ,catMethod="pretty"
                      ,numCats=5
                      ,colourPalette=colours
                      ,addLegend=FALSE )


do.call( addMapLegend, c( mapParams
                          , legendLabels="all"
                          , legendWidth=0.5
                        ))

#to test state names
#text(pov$x,pov$y,labels=pov$Id1)

German poverty map created using rworldmap


谢谢,但这不是关于这张具体地图的问题。我正在尝试弄清楚这是否是 ggplot 的 bug,还是我做错了什么。 - jlhoward

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接