如何使用 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 添加区域地图的图例以及描述相关标签的图例? 的相关文章

  • kernlab 中 SVM 训练之外的核矩阵计算

    我正在开发一种新算法 该算法可以生成修改后的核矩阵以用于 SVM 训练 但遇到了一个奇怪的问题 出于测试目的 我比较了使用 kernelMatrix 接口和普通内核接口学习的 SVM 模型 例如 Model with kernelMatri
  • 尝试读取 CSV 文件时出现“无法识别的字符串转义”

    我正在尝试导入一个 csv文件 以便我可以观看此视频 R ggplot2 图形直方图 http www youtube com watch v 47kWynt3b6M 我安装了所有正确的软件包 包括ggplot以及相关的包 视频中的第一个说
  • twitterR 和 ROAuth R 软件包安装

    我在安装 CRAN 上的 twitteR 和 RAOuth 软件包时遇到一些问题 我尝试了几种不同的方法 在 Windows 下使用源代码 在 Ubuntu 下使用 RStudio 我尝试了以下命令 sudo apt get install
  • 在 R 中创建虚拟变量,排除某些情况为 NA

    我的数据看起来像这样 V1 V2 A 0 B 1 C 2 D 3 E 4 F 5 G 9 我想创建一个虚拟变量R where 0 1 1 2 3 4 and NA 0 5 9 应该很简单 有人可以帮忙吗 我们可以转换V2 into a fa
  • Purrr::map_df() 删除 NULL 行

    使用时purrr map df 我偶尔会传递一个数据框列表 其中一些项目是NULL 当我做 map df 返回行数少于原始列表的数据框 我想发生的事情是这样的map df calls dplyr bind rows 它忽略了NULL价值观
  • 使用 Shiny 发布平行坐标图表时出现“错误:路径[1]="”:没有这样的文件或目录”

    我有一个似乎很常见但我还没有找到解决方案的问题 当尝试使用 rCharts Parcoords 发布 Web 应用程序时 出现以下错误 错误 路径 1 没有这样的文件或目录 奇怪的是 该应用程序在我的笔记本电脑上运行得很好 下面是我正在使用
  • 旋转 Markdown 的表格 pdf 输出

    我想将 pdf 上的表格输出旋转 90 度 我正在使用 Markdown 生成报告并kable循环显示表格 如果可以的话我想继续使用kable因为还有很多其他依赖于它的东西我没有包含在这个 MWE 中 这是一个简单的例子 使用iris数据集
  • 改变字典的哈希函数

    按照此question https stackoverflow com questions 37100390 towards understanding dictionaries 我们知道两个不同的字典 dict 1 and dict 2例
  • 计算 R 中各列的唯一值

    我正在尝试创建一个新变量 其中包含来自两个不同列的字符串值的唯一计数 所以我有这样的东西 例如 A tibble 4 x 2 names partners
  • 在 Rcpp 中使用其他包中的 C 函数

    我试图从 C 函数中的 cubature 包调用 C 例程来执行多维积分 我试图重现的基本 R 示例是 library cubature integrand lt function x sin x adaptIntegrate integr
  • 所有 x 轴标签未以 45 度显示

    I m having the code as like below But I m not getting all the x axis labels and it is not displaying in 45 degree when I
  • 纵向比较 R 中的值...并进行扭转

    我有许多人在多达四个时间段进行的测试结果 这是一个示例 dat lt structure list Participant ID c A A A A B B B B C C C C phase structure c 1L 2L 3L 4L
  • 将不均匀的层次列表转换为数据框

    我认为还没有有人问过这个问题 但是有没有一种方法可以将具有多个级别和不均匀结构的列表的信息组合成 长 格式的数据帧 具体来说 library XML library plyr xml inning lt http gd2 mlb com c
  • R:如何获取该月的周数

    我是 R 新手 我想要该日期所属月份的周数 通过使用以下代码 gt CurrentDate lt Sys Date gt Week Number lt format CurrentDate format U gt Week Number 3
  • R 中用于调用 sed、rsync、ssh 等的 system() 的替代方案:函数是否存在,我应该编写自己的函数,还是我错过了重点?

    最近 我发现了base files命令 与其他命令一起使用 例如getwd write lines file show dir等等 似乎有许多 bash 函数的 R 等价物 我还在 R 中编写了一些函数来简化对ssh and rsync通过
  • 如何从 R 读取 PDF 元数据

    我们很好奇 有没有一种方法可以从 R 读取 PDF 元数据 例如下面显示的信息 通过搜索我对此无能为力 r pdf metadata在当前的问题库中 非常欢迎任何指点 我想不出纯 R 的方法来执行此操作 但您可能可以安装您最喜欢的 PDF
  • 以编程方式将字符串宽度值插入到 sprintf() 中

    我正在尝试以编程方式将字符串宽度值插入到sprintf 格式 期望的结果是 sprintf 20s hello 1 hello 但我想插入20在同一通话中即时进行 因此它可以是任何号码 我努力了 sprintf ds 20 hello 1
  • 闭包作为数据合并习惯的解决方案

    我正在尝试解决闭包问题 而且我think我发现了一个案例 他们可能会有所帮助 我有以下几部分需要处理 一组正则表达式 旨在清理状态名称 位于函数中 具有州名称 上述函数创建的标准化形式 和州 ID 代码的 data frame 用于链接两者
  • 为字典中的一个键附加多个值[重复]

    这个问题在这里已经有答案了 我是 python 新手 我有每年的年份和值列表 我想要做的是检查字典中是否已存在该年份 如果存在 则将该值附加到特定键的值列表中 例如 我有一个年份列表 并且每年都有一个值 2010 2 2009 4 1989
  • 在 ifelse() 语句内部和外部运行一行时的不同输出

    我正在尝试运行一个简单的命令 但不知道为什么在内部和外部运行它时输出不同ifelse 功能 函数条件评估为FALSE 所以输出应该完全相同 但是 单独运行时 输出为0 0 1 1 0 1 0 1 NA 根据需要 但是从ifelse 函数 输

随机推荐