在R中使用国家值作为颜色绘制地图?

15

我有以下简单的示例数据,我想在地图上绘制,并根据给定国家的值显示渐变颜色。

ddf = read.table(text="
country value
USA 10
UK 30
Sweden 50
Japan 70
China 90
Germany 100
France 80
Italy 60
Nepal 40
Nigeria 20
", header=T)

在谷歌搜索中,我找到了几个网站。但是我正在寻找小而清晰的代码,并且最好快速(相对来说,我发现ggplot方法比较慢)。世界地图的分辨率不需要很高。

我尝试了以下代码:

library(maptools)
data(wrld_simpl)
plot(wrld_simpl)

可以根据以下网址中的说明将特定国家着色: 使用[R]地图包在世界地图上为特定国家着色 使用以下命令:

plot(wrld_simpl, col = c(gray(.80), "red")[grepl("^U", wrld_simpl@data$NAME) + 1])

但是我该如何获得具有上述数据颜色渐变的地图呢?感谢您的帮助。

1
你要找的术语是等值线图 - Tyler Rinker
4
@TylerRinker 我想你是指等级分化图。 - rrs
4个回答

12

定义"慢"。 ggplot提供了一种最灵活的方式,在地图上呈现数据,代价是多花费几秒钟。

library(RColorBrewer)
library(maptools)
library(ggplot2)

data(wrld_simpl)

ddf = read.table(text="
                 country value
                 'United States' 10
                 'United Kingdom' 30
                 'Sweden' 50
                 'Japan' 70
                 'China' 90
                 'Germany' 100
                 'France' 80
                 'Italy' 60
                 'Nepal' 40
                 'Nigeria' 20", header=TRUE)

# Pascal had a #spiffy solution that is generally faster

plotPascal <- function() {

  pal <- colorRampPalette(brewer.pal(9, 'Reds'))(length(ddf$value))
  pal <- pal[with(ddf, findInterval(value, sort(unique(value))))]

  col <- rep(grey(0.8), length(wrld_simpl@data$NAME))
  col[match(ddf$country, wrld_simpl@data$NAME)] <- pal

  plot(wrld_simpl, col = col)

}

plotme <- function() {

  # align colors to countries

  ddf$brk <- cut(ddf$value, 
                 breaks=c(0, sort(ddf$value)), 
                 labels=as.character(ddf[order(ddf$value),]$country),
                 include.lowest=TRUE)

  # this lets us use the contry name vs 3-letter ISO
  wrld_simpl@data$id <- wrld_simpl@data$NAME

  wrld <- fortify(wrld_simpl, region="id")
  wrld <- subset(wrld, id != "Antarctica") # we don't rly need Antarctica

  gg <- ggplot()

  # setup base map
  gg <- gg + geom_map(data=wrld, map=wrld, aes(map_id=id, x=long, y=lat), fill="white", color="#7f7f7f", size=0.25)

  # add our colored regions
  gg <- gg + geom_map(data=ddf, map=wrld, aes(map_id=country, fill=brk),  color="white", size=0.25)

  # this sets the scale and, hence, the legend
  gg <- gg + scale_fill_manual(values=colorRampPalette(brewer.pal(9, 'Reds'))(length(ddf$value)), 
                               name="Country")

  # this gives us proper coords. mercator proj is default
  gg <- gg + coord_map()
  gg <- gg + labs(x="", y="")
  gg <- gg + theme(plot.background = element_rect(fill = "transparent", colour = NA),
                   panel.border = element_blank(),
                   panel.background = element_rect(fill = "transparent", colour = NA),
                   panel.grid = element_blank(),
                   axis.text = element_blank(),
                   axis.ticks = element_blank(),
                   legend.position = "right")
  gg

}

system.time(plotme())
##  user  system elapsed 
## 1.911   0.005   1.915 

system.time(plotthem())
##  user  system elapsed 
## 1.125   0.014   1.138 

ggplot代码生成以下地图:

enter image description here

时间会因每次运行而异,但我从未见过它们相差超过一分钟(在我的系统上平均为0.6m,但我不打算进行详尽的基准测试)。

更新

随着您的需求逐渐被揭示,您可以很容易地用连续比例尺替换离散比例尺。

pal <- colorRampPalette(brewer.pal(9, 'Reds'))(length(ddf$value))
palSz <- 10 # not sure what you really want/need for this range

gg <- gg + scale_fill_gradient2(low = pal[1],
                                mid = pal[palSz/2],
                                high = pal[palSz],
                                midpoint = (max(ddf$value) + min(ddf$value)) / 2,
                                name="value")

图片描述

听起来你应该坚持使用@Andy的rworldmap,因为它抽象了复杂性。


我们能否在图例中使用数字而不是国家名称? - rnso
1
我正在尝试自己完成,正如我在上面的评论中所表明的那样。感谢您花费的所有时间和精力。并非每个人都是程序员,我认为R不仅适用于程序员。我相信经过一段时间,ggplot将推出geom_map()函数,这将简化此过程。再次感谢。 - rnso
有没有解决以下问题的想法:Error: isTRUE(gpclibPermitStatus()) is not TRUE - Brian P
这段代码非常有用。但是,为了将离散图例更改为连续图例,在您的代码“gg <- gg + scale_fill_gradient2...”中,我应该在哪个“gg”中添加“scale_fill_gradient2”?当我将行“gg <- gg + scale_fill_manual...”替换为“gg <- gg + scale_fill_gradient2...”时,我收到了“Discrete value supplied to continuous scale”的错误提示。 - yliueagle
是否有更新版本的 wrld_simpl 可以将南苏丹、库拉索、博内尔和圣马丁识别为独立国家? - pfadenhw
显示剩余6条评论

12

如果您想要减少代码量并使用更粗糙的分辨率地图,您可以使用rworldmap。

library(rworldmap)

#create a map-shaped window
mapDevice('x11')
#join to a coarse resolution map
spdf <- joinCountryData2Map(ddf, joinCode="NAME", nameJoinColumn="country")

mapCountryData(spdf, nameColumnToPlot="value", catMethod="fixedWidth")

默认分类、颜色和图例可以更改,请参见此RJournal文献

使用国家代码而不是名称会更快。

rworldmap地图


这真的很好。代码简洁明了,执行速度快,绘图完整,包括标题和图例数字刻度。谢谢。 - rnso
在印度行政层面,例如州、城市或邮政编码级别,是否有类似的更细粒度的东西可用? - Sandeep
我不知道为什么会出现QuartzBitmap_Output - 无法打开文件'/var/folders/5z/gtbz8c5x10lc6fc67n3flmq00000gn/T//Rtmpy5dZU6/7b05e095ecc1462eabffd93a610e7bfe.png'的错误。 - Emmanuel Goldstein
我只有一些国家,我可以选择一个子集的国家而不是整个世界地图吗? - Marco

4

可能没有进行优化:

library(RColorBrewer)
library(maptools)
data(wrld_simpl)

ddf = read.table(text="
country value
'United States' 10
'United Kingdom' 30
'Sweden' 50
'Japan' 70
'China' 90
'Germany' 100
'France' 80
'Italy' 60
'Nepal' 40
'Nigeria' 20", header=TRUE)

Reds 是一种颜色调色板的名称。查看 ?brewer.pal 可以获取其他可用的调色板。

pal <- colorRampPalette(brewer.pal(9, 'Reds'))(length(ddf$value))
pal <- pal[with(ddf, findInterval(value, sort(unique(value))))]

col <- rep(grey(0.8), length(wrld_simpl@data$NAME))
col[match(ddf$country, wrld_simpl@data$NAME)] <- pal

plot(wrld_simpl, col = col)

enter image description here


1
谢谢。我们能否获得一个图例,显示颜色对应的值是什么? - rnso
2
@rnso 请查看legend函数。做一些功课。 - Tyler Rinker

1

我认为其他答案有点复杂,可能是因为这个问题相对较早被问答过?以下是使用ggplot2的简单方法。至于这是否“快”,我不确定基准是什么。

library(ggplot2)
library(dplyr)

ddf = read.table(text="
country value
USA 10
UK 30
Sweden 50
Japan 70
China 90
Germany 100
France 80
Italy 60
Nepal 40
Nigeria 20
", header=T)

world <- map_data("world")

world %>%
  merge(ddf, by.x = "region", by.y = "country", all.x = T) %>%
  arrange(group, order) %>%
  ggplot(aes(x = long, y = lat, group = group, fill = value)) + geom_polygon()

世界地图,按值着色

这样可以使用所有常见的ggplot2操作进行修改。例如,如果我们想快速美化它:

library(viridis)

world %>%
  merge(ddf, by.x = "region", by.y = "country", all.x = T) %>%
  arrange(group, order) %>%
  ggplot(aes(x = long, y = lat, group = group, fill = value)) +
  geom_polygon(color = "white", size = 0.2) +
  scale_fill_viridis("", na.value = "gray90") +
  theme_minimal() +
  theme(axis.text = element_blank(),
        axis.title = element_blank(),
        panel.grid = element_blank())

prettier map with viridis color scale, no axis titles, etc.


1
感谢您的好回答。我7年前提出了这个问题,当时ggplot2还不存在(我想)。 - rnso
@rnso 没问题,我刚刚因为同样的原因更新了我的一个旧问题或答案。很好看到这些常见的问题可以在环境变化时得到更新。 :) - Hendy

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