如何使用 ggplot2 添加区域地图的图例以及描述相关标签的图例?

2024-02-19

SpatialPoly 数据:空间数据 https://www.dropbox.com/s/4x7kkragmnl6tkk/Morocco_adm1.zip

产量数据:产量数据 https://www.dropbox.com/s/rzlfuqxwzkqwgbg/Morocco_Yield.csv

Code:

    ## Loading packages
    library(rgdal)
    library(plyr)
    library(maps)
    library(maptools)
    library(mapdata)
    library(ggplot2)
    library(RColorBrewer)
    library(foreign)  
    library(sp)

    ## Loading shapefiles and .csv files
    #Morocco <- readOGR(dsn=".", layer="Morocco_adm0")
    MoroccoReg <- readOGR(dsn=".", layer="Morocco_adm1")
    MoroccoYield <- read.csv(file = "F:/Purdue University/RA_Position/PhD_ResearchandDissert/PhD_Draft/Country-CGE/RMaps_Morocco/Morocco_Yield.csv", header=TRUE, sep=",", na.string="NA", dec=".", strip.white=TRUE)

    ## Reorder the data in the shapefile based on the category variable "ID_1" and change to dataframe
    MoroccoReg <- MoroccoReg[order(MoroccoReg$ID_1), ]
    MoroccoReg.df <- fortify(MoroccoReg)

    ## Add the yield impacts column to shapefile from the .csv file by "ID_1"
    ## Note that in the .csv file, I just added the column "ID_1" to match it with the shapefile
    MoroccoReg.df <- cbind(MoroccoReg.df,MoroccoYield,by = 'ID_1')

    ## Check the structure and contents of shapefile
    attributes(MoroccoReg.df)

    ## Define new theme for map
    ## I have found this function on the website
    theme_map <- function (base_size = 12, base_family = "") {
    theme_gray(base_size = base_size, base_family = base_family) %+replace% 
    theme(
    axis.line=element_blank(),
    axis.text.x=element_blank(),
    axis.text.y=element_blank(),
    axis.ticks=element_blank(),
    axis.ticks.length=unit(0.3, "lines"),
    axis.ticks.margin=unit(0.5, "lines"),
    axis.title.x=element_blank(),
    axis.title.y=element_blank(),
    legend.background=element_rect(fill="white", colour=NA),
    legend.key=element_rect(colour="white"),
    legend.key.size=unit(1.5, "lines"),
    legend.position="right",
    legend.text=element_text(size=rel(1.2)),
    legend.title=element_text(size=rel(1.4), face="bold", hjust=0),
    panel.background=element_blank(),
    panel.border=element_blank(),
    panel.grid.major=element_blank(),
    panel.grid.minor=element_blank(),
    panel.margin=unit(0, "lines"),
    plot.background=element_blank(),
    plot.margin=unit(c(1, 1, 0.5, 0.5), "lines"),
    plot.title=element_text(size=rel(1.8), face="bold", hjust=0.5),
    strip.background=element_rect(fill="grey90", colour="grey50"),
    strip.text.x=element_text(size=rel(0.8)),
    strip.text.y=element_text(size=rel(0.8), angle=-90) 
    )   
    }

    ## Plotting 

    MoroccoRegMap1 <- ggplot(data = MoroccoReg.df, aes(long, lat, group = group)) 
    MoroccoRegMap1 <- MoroccoRegMap1 + geom_polygon(aes(fill = A2Med_noCO2))
    MoroccoRegMap1 <- MoroccoRegMap1 + geom_path(colour = 'gray', linestyle = 2)
    #MoroccoRegMap <- MoroccoRegMap + scale_fill_gradient(low = "#CC0000",high = "#006600")
    MoroccoRegMap1 <- MoroccoRegMap1 + scale_fill_gradient2(name = "%Change in yield",low = "#CC0000",mid = "#FFFFFF",high = "#006600")
    MoroccoRegMap1 <- MoroccoRegMap1 + labs(title="SRES_A2, noCO2 Effect")
    MoroccoRegMap1 <- MoroccoRegMap1 + coord_equal() + theme_map()
    MoroccoRegMap1

Results:

问题:

在产量数据中,我有一列描述与“ID_1”列中的每个条目相对应的标签。我想要实现的是两件事:

1)绘制地图,并在地图上添加“ID_1”变量条目作为标签,从而识别每个区域;

2) 除了捕获数据中的值的图例之外,生成第二个图例,其中包含“ID_1”中的条目及其数据帧中“标签”列中的相应描述。

我希望我清楚地提出了我的问题。

thanks.


首先,让我为花了这么长时间才回来表示歉意 - 我错过了您在所有其他评论中的评论。这就是你的想法吗?

这是使用以下代码生成的。在进行解释之前,您应该意识到创建图例是最不重要的问题。请注意两张地图中的颜色有何不同。您上面的代码没有将二氧化碳变化分配到正确的区域。例如,根据MoroccoYields.csv,最大的变化(改进?)是-0.205 in Region 4,但在你的地图上最大的(最深红色的)位于摩洛哥的东北端,实际上是l'Oriental (Region 6)。代码后面有解释。

## Loading packages
library(rgdal)
library(plyr)
library(maps)
library(maptools)
library(mapdata)
library(ggplot2)
library(RColorBrewer)
library(foreign)  
library(sp)

# get.centroids: function to extract polygon ID and centroid from shapefile
get.centroids = function(x){
  poly = MoroccoReg@polygons[[x]]
  ID   = poly@ID
  centroid = as.numeric(poly@labpt)
  return(c(id=ID, long=centroid[1], lat=centroid[2]))
}
#setwd("Directory where shapefile and Yields are stored")
## Loading shapefiles and .csv files
MoroccoReg        <- readOGR(dsn=".", layer="Morocco_adm1")
MoroccoYield      <- read.csv(file = "Morocco_Yield.csv", header=TRUE, sep=",", na.string="NA", dec=".", strip.white=TRUE)
MoroccoYield$ID_1 <- substr(MoroccoYield$ID_1,3,10)

## Reorder the data in the shapefile based on the category variable "ID_1" and change to dataframe
MoroccoReg    <- MoroccoReg[order(MoroccoReg$ID_1), ]
MoroccoYield  <- cbind(id=rownames(MoroccoReg@data),MoroccoYield)
#  build table of labels for annotation (legend).
labs          <- do.call(rbind,lapply(1:14,get.centroids))
labs          <- merge(labs,MoroccoYield[,c("id","ID_1","Label")],by="id")
labs[,2:3]    <- sapply(labs[,2:3],function(x){as.numeric(as.character(x))})
labs$sort <- as.numeric(as.character(labs$ID_1))
labs          <- labs[order(labs$sort),]

MoroccoReg.df <- fortify(MoroccoReg)
## This does NOT work...
## Add the yield impacts column to shapefile from the .csv file by "ID_1"
## Note that in the .csv file, I just added the column "ID_1" to match it with the shapefile
#MoroccoReg.df <- cbind(MoroccoReg.df,MoroccoYield,by = 'ID_1')
## Do it this way...
MoroccoReg.df <- merge(MoroccoReg.df,MoroccoYield, by="id")

## Check the structure and contents of shapefile
attributes(MoroccoReg.df)
## Plotting 

MoroccoRegMap1 <- ggplot(data = MoroccoReg.df, aes(long, lat, group=id)) 
MoroccoRegMap1 <- MoroccoRegMap1 + geom_polygon(aes(fill = A2Med_noCO2))
MoroccoRegMap1 <- MoroccoRegMap1 + geom_path(colour = 'gray', linestyle = 2)
MoroccoRegMap1 <- MoroccoRegMap1 + scale_fill_gradient2(name = "%Change in yield",low = "#CC0000",mid = "#FFFFFF",high = "#006600")
MoroccoRegMap1 <- MoroccoRegMap1 + labs(title="SRES_A2, noCO2 Effect")
MoroccoRegMap1 <- MoroccoRegMap1 + coord_equal() #+ theme_map()
MoroccoRegMap1 <- MoroccoRegMap1 + geom_text(data=labs, aes(x=long, y=lat, label=ID_1), size=4)
MoroccoRegMap1 <- MoroccoRegMap1 + annotate("text", x=max(labs$long)-5, y=min(labs$lat)+3-0.5*(1:14),
                                            label=paste(labs$ID_1,": ",labs$Label,sep=""),
                                            size=3, hjust=0)
MoroccoRegMap1

解释:

首先,将产量数据与地图区域合并:您使用

MoroccoReg.df <- cbind(MoroccoReg.df,MoroccoYield,by = 'ID_1')

这不是如何cbind(...) works. cbind(...)只是按列组合它的参数。它不是合并函数。所以你有一个数据框,MoroccoReg.df,有 107,800 行(地图上的每个线端点一行),并且您将其与MoroccoYield,有 14 行(每个区域 1 行)。所以cbind(...)将这 14 行复制 7700 次以填充所需的 107,800 行。表达方式by="ID_1"仅添加另一列名为“by" with "ID_1"重复107,800次。运行上面的语句并输入head(MoroccoReg.df)并查找最后一列。

那么如何进行合并呢?里面有很多函数R这应该会让这变得容易,但我无法让它们中的任何一个工作。这是有效的:

shapefile 中的每个多边形都有一个 ID。 shapefile 数据部分中还有一个“ID_1”字段,但这些是不同且不相关的。 [顺便说一句:ID_1shapefile 数据部分中的字段,以及ID_1你的领域csv文件也不同:后者有"TR"前置到区域编号;所以这也必须得到处理]。 使用以下命令重新排序 shapefile:

MoroccoReg    <- MoroccoReg[order(MoroccoReg$ID_1), ]

将更改多边形的顺序,但不会更改其 ID。事实证明,多边形 ID 与 shapefile 数据部分中的行名称匹配,因此我在前面添加了它(使用cbind(...)!)到你的MoroccoYeild数据框。

MoroccoYield  <- cbind(id=rownames(MoroccoReg@data),MoroccoYield)

So now MoroccoYield has an id映射到多边形 ID 的字段,以及ID_1字段,标识区域。现在我们可以fortify(...) and merge(...). merge(...)确实需要一个by=争论。

MoroccoReg.df <- fortify(MoroccoReg)
MoroccoReg.df <- merge(MoroccoReg.df,MoroccoYield, by="id")

这会附加您的所有MoroccoYield列到适当的行MoroccoReg.df.

创建传奇:

显而易见的问题是如何放置标签?理想情况下,我们会将区域编号放在MoroccoYield$ID_1在每个区域的质心,然后创建一个图例来标识区域,基于MoroccoYield$Label.

那么哪里可以找到质心呢?它们存储在 shapefile 的多边形部分的一个不起眼的位置。长话短说,我创建了一个实用函数get.centroid(...)从多边形中提取质心。然后我将该函数应用于所有多边形,以生成具有相应多边形 ID 的质心表。然后我将其与标签合并MoroccoYield。这创建了一个数据框labs其中有以下列:

id:    polygon ID
long:  centroid longitude
lat:   centroid latitude
ID_1:  region ID
label: region name
sort:  a sortable (numeric) version of ID_1

然后,将以下代码添加到您的 ggplot...

...
MoroccoRegMap1 <- MoroccoRegMap1 + geom_text(data=labs, aes(x=long, y=lat, label=label.id), size=4)
MoroccoRegMap1 <- MoroccoRegMap1 + annotate("text", x=max(labs$long)-5, y=min(labs$lat)+3-0.5*(1:14),
                                            label=paste(labs$label.id,": ",labs$Label,sep=""),
                                            size=3, hjust=0)

...创建地图。我找不到干净的方法来使用正式的“ggplot legend”来做到这一点,所以我不得不使用annotate(...)。定位注释是一种黑客行为,但它似乎有效。

Edit:作为对 @smailov83 的评论的回应,如果您将创建 ggplot 的代码更改为此...

MoroccoRegMap1 <- ggplot(data = MoroccoReg.df, aes(long, lat, group=group)) 
MoroccoRegMap1 <- MoroccoRegMap1 + geom_polygon(aes(fill = A2Med_noCO2))
MoroccoRegMap1 <- MoroccoRegMap1 + geom_path(colour = 'gray', linestyle = 2)
MoroccoRegMap1 <- MoroccoRegMap1 + scale_fill_gradient2(name = "%Change in yield",low = "#CC0000",mid = "#FFFFFF",high = "#006600")
MoroccoRegMap1 <- MoroccoRegMap1 + labs(title="SRES_A2, noCO2 Effect")
MoroccoRegMap1 <- MoroccoRegMap1 + coord_equal() #+ theme_map()
MoroccoRegMap1 <- MoroccoRegMap1 + geom_text(data=labs, aes(x=long, y=lat, label=ID_1, group=ID_1), size=4)
MoroccoRegMap1 <- MoroccoRegMap1 + annotate("text", x=max(labs$long)-5, y=min(labs$lat)+3-0.5*(1:14),
                                            label=paste(labs$ID_1,": ",labs$Label,sep=""),
                                            size=3, hjust=0)

...你得到这个:

我相信这可以解决问题。地图中额外线条的原因是ggplot必须按列分组MoroccoReg.df$group (so, aes(..., group=group) not aes(...,group=id))。然而,当你这样做时,ggplot尝试分组依据"group"在所有层中。在geom_text(...),我们使用一个新的本地数据集 -labs数据框 - 没有group柱子。为了解决这个问题,我们必须明确设置group到其他东西geom_text(...)。底线:这似乎有效。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 ggplot2 添加区域地图的图例以及描述相关标签的图例? 的相关文章

  • 在ggplot中设置y轴中断

    我在代码中设置中断时遇到困难 我尝试添加breaks seq 0 100 by 20 但似乎无法让它正常工作 本质上我希望 Y 轴从 0 到 100 每 20 个刻度一次 YearlyCI lt read table header T te
  • 为什么这个 R ggplot2 代码会显示一个空白的显示设备?

    虽然 SO 通常不用于帮助解决错误 但这个显示了特别简单且特别烦人的行为 如果你是一个ggplot2用户 您可以在 10 秒或更短的时间内重现它 正如这个 GitHub 问题 ggplot gtable 创建空白显示 https githu
  • 增加雷达图中长轴标签的空间

    我想创建一个雷达图ggirahExtra ggRadar 问题是我的标签很长并且被剪掉了 我想我可以通过添加在标签和绘图之间创建更多空间margin margin 0 0 2 0 cm to element text in axis tex
  • Python:在字典中查找具有唯一值的键?

    我收到一个字典作为输入 并且想要返回一个键列表 其中字典值在该字典的范围内是唯一的 我将用一个例子来澄清 假设我的输入是字典 a 构造如下 a dict a cat 1 a fish 1 a dog 2 lt unique a bat 3
  • 要在子集中显示的非数字条目的维恩图

    我有以下数据框 SET1 SET2 SET3 par1 par2 par1 par2 par3 par2 par3 par4 par5 我想制作一个维恩图 其中所有这些 parX 元素都显示在各自的子集中 即作为标签 而不仅仅是重叠元素的数
  • 如何在 R 中的 dygraph 标题中使用 UTF-8 字符

    使用 Rstudio Windows8 当我使用 dygraph 函数绘制时间序列时 在尝试在主标题中使用 UTF 8 字符时遇到问题 library dygraphs dygraph AirPassengers main T tulo 这
  • 如何动态地将 sliderInput 添加到闪亮的应用程序中?

    使用闪亮 我上传一个 csv 文件 并根据列名称 我需要向 ui 添加滑块 sidebarPanel fileInput file1 Upload CSV File to Create a Model accept c text csv t
  • R 改变构面的顺序

    我正在尝试将方面的顺序从 BA SLG 更改为 SLG BA 我发现了与此类似的问题 但我认为我的解决方案可能不起作用 因为我已经在Excel中汇总了数据 因此 我的数据框可能会有所不同 无论如何 我尝试实现这个但无济于事 df2 lt f
  • Typescript Map 在使用其函数时抛出错误(mapobject.keys() 不是函数)

    我是 typescript 中的新蜜蜂 在我的 angular4 项目中 我收到一个 json 形式的地图对象 所以我声明了一个如下所示的类
  • Python模块可以访问英语词典,包括单词的定义[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个 python 模块 它可以帮助我从英语词典中获取单词的定义 当然有enchant 这可以帮助我检查该单词是否存在于英语中
  • 无法编译包“maps”

    当我安装 maps 包时 安装中出现警告 ld warning ignoring file Library Developer CommandLineTools SDKs MacOSX10 14 sdk usr lib libSystem
  • 如何将参数从 Excel/VBA 传递到 Rstudio 中的脚本

    我正在尝试使用 Rstudio 从 VBA 打开 R 脚本 同时将参数传递给 R 脚本 然后我可以使用 commandArgs 访问该脚本 该问题与此处描述的问题非常相似 WScript Shell 用于运行路径中包含空格且来自 VBA 的
  • 无法将“gather”输出的列名称更改为默认名称以外的任何名称

    我正在尝试使用gather in the tidyr包 但我无法更改默认名称的输出列名称 例如 df data frame time 1 100 a 1 100 b 101 200 df long df gt gather foo bar
  • 更改 R 中 ggplot geom_polygon 的颜色方案

    我正在使用地图库和 ggplot 的 geom polygon 创建地图 我只是想将默认的蓝色 红色 紫色配色方案更改为其他颜色 我对 ggplot 非常陌生 所以如果我没有使用正确的数据类型 请原谅 我使用的数据如下所示 gt head
  • 条件和分组 mutate dplyr

    假设我有以下每个抽屉库存增加的数据 gt socks year drawer nbr sock total 1990 1 2 1991 1 2 1990 2 3 1991 2 4 1990 3 2 1991 3 1 我想要一个二进制变量来标
  • R:改变堆积条形图的颜色

    library ggplot2 df2 lt data frame supp rep c VC OJ each 3 dose rep c D0 5 D1 D2 2 len c 6 8 15 33 4 2 10 29 5 head df2 g
  • 使用data.table进行聚合

    经过 SO 用户的多次建议后 我终于尝试将我的代码转换为使用data table library data table DT lt data table plate paste0 plate rep 1 2 each 5 id rep c
  • 如何使用plotmath更新ggplot图例标签

    我正在尝试更新ggplot要使用的图例标签plotmath但是 当我这样做时 它将之前组合的图例分成两部分 通过一个例子可能更容易理解 test data and the default plot gives the correct col
  • 如何在R中实现countifs函数(excel)

    我有一个包含 100000 行数据的数据集 我尝试做一些countifExcel 中的操作 但速度慢得惊人 所以我想知道R中是否可以完成这种操作 基本上 我想根据多个条件进行计数 例如 我可以指望职业和性别 row sex occupati
  • 检查字典键是否有空值

    我有以下字典 dict1 city name yass region zipcode phone address tehsil planet mars 我正在尝试创建一个基于 dict1 的新字典 但是 它不会包含带有空字符串的键 它不会包

随机推荐