两个栅格数据叠加展示:10*10的二元色彩图

本文介绍了如何使用R语言中的各种包,如tidyverse、raster、sf等,处理全球人口和熵数据,通过10*10的二元色彩图展示数据特征,并结合图例,以清晰地表示数据的分布和复杂度。
摘要由CSDN通过智能技术生成

复现文章【https://doi.org/10.1038/s41586-022-04788-w】的10*10二元色彩图  :

参考代码来自:用R绘制炫酷的二元色彩+山体阴影浮雕地图。这篇的代码处理的是矢量数据,并且做的是3*3的二元色彩图。进行了改进,以实现对两个栅格数据进行10*10的二元色彩展示。

代码如下:

一、读取栅格数据并转换为数据框

以全球的人口数据pop和一个全球的熵数据entr为例,读取数据后做预处理并分别转换为data.frame格式:

#加载包
library(rstudioapi) #
library(tidyverse) # ggplot2, dplyr, tidyr, readr, purrr, tibble
library(magrittr) # pipes# 包提供了一种称为"管道"(pipe)的操作,使代码更简洁和可读性更高。
library(lintr) # code linting  是一个用于代码静态分析和代码质量检查的包。
library(sf) # spatial data handling
library(raster) # raster handling (needed for relief)
library(viridis) # viridis color scale是一个用于生成美观的颜色映射的包。
library(cowplot) # stack ggplots  是一个用于组合和排列ggplot2图形的包
library(rmarkdown)

#读取两个栅格数据
popd2015<-rast("...文件路径.../popd2015.tif")
Entropy<-rast("...文件路径.../Entropy.tif")
#读取矢量边界数据用来裁剪两个栅格(这里直接加载世界地图矢量)
world.map <- ne_countries(returnclass = "sf") |>filter(continent != "Antarctica")
globalCountry <- vect(world.map) 

#预处理
popd2015_m <- trim(mask(popd2015, globalCountry))   #做mask
Entropy_m <- trim(mask(Entropy, globalCountry))

popd2015_r <- resample(popd2015_m, Entropy_m, method="bilinear")   #重采样
Entropy_m <- trim(mask(Entropy_m, popd2015_r))     #掩膜
Entropy_e <- extend(Entropy_m, popd2015_r)       #统一范围

二、合并为一个带坐标信息的数据框

#转换为带有坐标信息xy的data.frame格式
popd2015_df <- as.data.frame(popd2015_r, xy=TRUE)  
Entropy_df <- as.data.frame(Entropy_e, xy=TRUE)

#对数据进行归一化处理,统一度量方便展示:
# 定义归一化函数
normalize <- function(x) {
  return((x - min(x, na.rm = TRUE)) / (max(x, na.rm = TRUE) - min(x, na.rm = TRUE)))
}
#分别进行归一化处理-----
head(popd2015_df)   #查看数据列的名字为popd2015_30
popd2015_df$popd2015_30_normalized <- normalize(popd2015_df$popd2015_30)
head(Entropy_df)   #查看数据列的名字为sum
Entropy_df$sum_normalized <- normalize(Entropy_df$sum)

#按照xy的对应关系进行left_join
popentr_df <- left_join(popd2015_df, Entropy_df, by = c("x", "y"))
popentr_df <- na.omit(popentr_df)  #去掉na值
head(popentr_df)    #查看列名
names(popentr_df)<-c("x","y","pop","pop_n","entr","entr_n")   #重命名列名,这里xy是经纬度,pop_n和entr_n是归一化后的数据

三、设置分位数和10*10颜色变量

原理是给每一个像元按照分位数分组10*10,每一组分配一种颜色变量,因此,需要逐个设置每个位置的颜色代码。如果需要改变颜色,则需要改10*10个颜色代码。(颜色代码是把参考图给颜色识别网站,逐个取色识别的,然后复制粘贴了100次,这里直接把颜色代码给出来啦。)

同理需要4*4,5*5的,修改对应的length.out和颜色tibble就可以了

#设置10个分位数
quantiles_pop <- popentr_df %>%
  pull(pop_n) %>%
  quantile(probs = seq(0, 1, length.out = 11))

quantiles_entr <- popentr_df %>%
  pull(entr_n) %>%
  quantile(probs = seq(0, 1, length.out = 11))

#注意如果你的分位数中有重复的值,后面代码会报错可能需要处理
#举例子:给重复的加一个很小的值
quantiles_entr #检查分位数,看分位数的大小,根据分位数的大小拟定adjustment 
adjustment <- 0.0001   #以0.0001为例,如果数据更小,需要换成更小的数值
for(i in 2:length(quantiles_entr)) {
  if(quantiles_entr[i] == quantiles_entr[i-1]) {
    quantiles_entr[i] <- quantiles_entr[i] + adjustment
  }
  if(i>3 && quantiles_entr[i] == quantiles_entr[i-2]) {
    quantiles_entr[i] <- quantiles_entr[i-1] + adjustment  #防止连续三个分位数重复
  }
}
quantiles_entr#调整好后,检查分位数是否是递增的,如果不是,考虑改换adjustment或者改进循环的代码


#设置10*10颜色变量
bivariate_color_scale <- tibble(
  "1 - 10" ="#00FFFF","2 - 10" = "#11E6FD", "3 - 10" ="#23CDFB","4 - 10" = "#35B4FA","5 - 10" ="#479BF8","6 - 10"= "#5883F6","7 - 10" ="#6A6AF5","8 - 10" ="#7C51F3","9 - 10" ="#8E38F1","10 - 10" ="#A020F0",
  "1 - 9" = "#1BFDFB", "2 - 9" = "#2AE4F7", "3 - 9" = "#3ACCF4", "4 - 9" = "#4AB4F0","5 - 9" = "#5A9CED","6 - 9" = "#6A83E9","7 - 9" = "#7A6BE6","8 - 9" = "#8A53E2","9 - 9" = "#9A3BDF","10 - 9" = "#AA23DC",
  "1 - 8" = "#36FCF7", "2 - 8" = "#44E4F1", "3 - 8" = "#52CCEC", "4 - 8" = "#60B5E7","5 - 8" = "#6E9DE2","6 - 8" = "#7C85DC","7 - 8" = "#8A6ED7","8 - 8" = "#9856D2","9 - 8" = "#A63ECD","10 - 8" = "#B527C8",
  "1 - 7" = "#51FBF3", "2 - 7" = "#5DE3EC", "3 - 7" = "#69CCE5", "4 - 7" = "#75B5DE","5 - 7" = "#819ED7","6 - 7" = "#8E86D0","7 - 7" = "#9A6FC9","8 - 7" = "#A658C2","9 - 7" = "#B241BB","10 - 7" = "#BF2AB5",
  "1 - 6" = "#6CFAEF", "2 - 6" = "#76E3E6", "3 - 6" = "#80CCDD", "4 - 6" = "#8BB6D5","5 - 6" = "#959FCC","6 - 6" = "#A088C3","7 - 6" = "#AA72BB","8 - 6" = "#B55BB2","9 - 6" = "#BF44A9","10 - 6" = "#CA2EA1",
  "1 - 5" = "#88F9EB", "2 - 5" = "#90E2E0", "3 - 5" = "#98CCD6", "4 - 5" = "#A1B6CB","5 - 5" = "#A9A0C1","6 - 5" = "#B289B7","7 - 5" = "#BA73AD","8 - 5" = "#C35DA2","9 - 5" = "#CB4798","10 - 5" = "#D4318E",
  "1 - 4" = "#A3F8E7", "2 - 4" = "#A9E2DA", "3 - 4" = "#B0CCCE", "4 - 4" = "#B7B7C2","5 - 4" = "#BDA1B6","6 - 4" = "#C48BAA","7 - 4" = "#CB769E","8 - 4" = "#D16092","9 - 4" = "#D84A86","10 - 4" = "#DF357A",
  "1 - 3" = "#BEF7E3", "2 - 3" = "#C2E1D5", "3 - 3" = "#C7CCC7", "4 - 3" = "#CCB7B9","5 - 3" = "#D1A2AB","6 - 3" = "#D58C9E","7 - 3" = "#DA7790","8 - 3" = "#DF6282","9 - 3" = "#E44D74","10 - 3" = "#E93867",
  "1 - 2" = "#D9F6DF", "2 - 2" = "#DBE1CF", "3 - 2" = "#DFCCBF", "4 - 2" = "#E2B8B0","5 - 2" = "#E5A3A0","6 - 2" = "#E88E91","7 - 2" = "#EB7981","8 - 2" = "#EE6572","9 - 2" = "#F15062","10 - 2" = "#F43C53",
  "1 - 1" = "#F5F5DC", "2 - 1" = "#F6E0CA", "3 - 1" = "#F7CCB9", "4 - 1" = "#F8B8A8","5 - 1" = "#F9A496","6 - 1" = "#FA9085","7 - 1" = "#FB7C74","8 - 1" = "#FC6862","9 - 1" = "#FD5451","10 - 1" = "#FF4040",
  
) %>%
  gather("group", "fill")

四、“逐像元”分配颜色

使用cut函数将pop和entr的值分配到相应的分位数桶中(需要保证分位数唯一)

popentr_df1 <- popentr_df %>%
  mutate(
    pop_quantiles = cut(pop_n, breaks = quantiles_pop, include.lowest = TRUE, labels = FALSE),
    entr_quantiles = cut(entr_n, breaks = quantiles_entr, include.lowest = TRUE, labels = FALSE)
  ) %>%
  # 将分位数转换为数字,并创建一个新的组合列
  mutate(
    group = paste(as.numeric(pop_quantiles), "-", as.numeric(entr_quantiles))
    #group = paste(as.numeric(entr_quantiles), "-", as.numeric(pop_quantiles))
  ) %>%
  # 假设您已经有了一个颜色表bivariate_color_scale,其中包含group和对应的颜色值
  left_join(bivariate_color_scale, by = "group") # 将颜色值与主数据框合并

五、绘制地图和图例

#我这里用到了全球矢量边界
library(rnaturalearth)
coast <- ne_coastline(scale = "small", returnclass = "sf") %>% vect()
crs <- '+proj=longlat +datum=WGS84'

#绘制地图
map<-ggplot(popentr_df1) +
  geom_tile(aes(x = x, y = y,fill = fill)) +
  scale_fill_identity() +
  geom_spatvector(data=coast,fill=NA)+coord_sf(crs = crs,xlim=c(-160,165),ylim=c(-56,90))+
  #geom_sf(data = canton_geo, fill = NA, color = "white", size = 0.5) +    # 为行政区划绘制边界
  labs(x = NULL, y = NULL,) +
  #theme_minimal()+
  theme_bw()+
  theme(
    legend.position="none"
    )
print(map)


# bivariate_color_scale是颜色表,并且包含group和对应的颜色值
# 分离group列为pop和entr两个独立的列,并转换为整数类型
bivariate_color_scale <- bivariate_color_scale %>%
  separate(group, into = c("pop", "entr"), sep = " - ", convert = TRUE) %>%
  mutate(
    pop = as.integer(pop),
    entr = as.integer(entr)
  )

#绘制图例
legend <- ggplot(data = bivariate_color_scale) +
  geom_tile(mapping = aes(x = pop, y = entr, fill = fill)) +
  scale_fill_identity() +
  labs(x = "Higher population density ⟶️",
       y = "Higher entropy ⟶️") +
  theme_void() +  # 使用theme_void()来移除多余的元素
  theme(
    axis.title.x = element_text(size = 16, angle = 0),  # 旋转X轴标题
    axis.title.y = element_text(size = 16, angle = 90),   # 旋转Y轴标题
    plot.margin = margin(t = 10, r = 10, b = 30, l = 10)  # 调整图表边距
  ) +
  coord_fixed()  # 保持坐标比例固定
print(legend)

到这里就完成了,但地图和图例是分别绘制的,额外拼在一起就是这样的效果啦:

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值