【问题标题】:Choropleth map in ggplot with polygons that have holesggplot中带有孔的多边形的Choropleth图
【发布时间】:2014-02-13 08:32:32
【问题描述】:

我正在尝试绘制德国的等值线地图,显示各州的贫困率(灵感来自 this question)。

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

这个例子的数据是here

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 正在渲染柏林多边形,然后在其上渲染勃兰登堡多边形,没有孔。

如果我按照here 的建议将调用更改为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()

我做错了什么??

【问题讨论】:

  • 您是否尝试使用 mapdocs.ggplot2.org/0.9.3.1/fortify.sp.html
  • 见代码第 8 行:map.df &lt;- fortify(map)。还是你的意思是别的?
  • github.com/hadley/ggplot2/wiki/plotting-polygon-shapefiles 有一个关于此问题的解决方法的讨论和示例
  • @Ista - 谢谢。你知道这个问题是否会得到解决吗?其他软件包不会以这种方式失败(请参阅下面的答案)。此外,如果“只是”一个应该呈现为透明的洞(例如湖)(背景显示通过),我认为这不会起作用。 This response 有一个例子。
  • @jlhoward - 我怀疑这会很快得到解决,你必须按照我的说明解决问题。

标签: r ggplot2 maps


【解决方案1】:

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

这种方法利用fortify(...) 生成一个列hole 来标识一组坐标是否为孔的事实。因此,这会在没有孔的区域之前(例如下方)呈现带有 any 孔的 所有 区域(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))' 应该可以工作,但对它没有用感到沮丧。很高兴在这里看到您的解决方案。
  • @jhoward 感谢这一出色的解决方案!
【解决方案2】:

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

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"))

提供上下文和熟悉的参考点。

【讨论】:

    【解决方案3】:

    只是为@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()
    

    【讨论】:

    • 一个更短的版本:ggpolyhole
    【解决方案4】:

    您也可以使用 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)
    

    【讨论】:

    • 谢谢,但这与这张特定的地图无关。我试图找出这是否是 ggplot 中的错误,或者我做错了什么。
    猜你喜欢
    • 2016-10-06
    • 2012-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多