简体   繁体   English

R:如何从网格创建平均值的热图并用 ggplot 绘制它?

[英]R: how to create a heat map of averaged values from a grid and plot it with ggplot?

I have a data frame (see below) with over 50 000 values, each associated to a position (lat, lon).我有一个包含超过 50 000 个值的数据框(见下文),每个值都与一个位置(纬度、经度)相关联。 I would like to calculate the average value for each cell of a 5° latitude x 5° longitude grid in order to create a heat map.我想计算 5° 纬度 x 5° 经度网格的每个单元格的平均值,以创建热图。 The final goal is to plot this grid over a bathymetry map.最终目标是在测深图上绘制此网格。

I looked at similar questions like this one Average values of a point dataset to a grid dataset .我查看了类似这样的问题 one Average values of a point dataset to a grid dataset But I couldn't replicate these examples with my own data.但我无法用我自己的数据复制这些例子。 Saddly, I am stuck at the first step which is creating the grid.可悲的是,我被困在创建网格的第一步。

My data look like this:我的数据是这样的:

library(sp)
library(proj4)

coordinates(data) <- c("lon", "lat")        
proj4string(data) <- CRS("+init=epsg:4326") #defined CRS to WGS 84
df<- data.frame(data)

> head(df)
         lon      lat  value
1 -48.1673562 57.71791  822.9
2 -48.7430053 57.83568 1302.3
3 -48.5662663 57.82087 1508.0
4 -48.3252052 58.29815  224.0
5 -47.1716772 58.42417   38.0
6 -46.4098311 58.67651  431.2
7 -45.8071218 58.70022  365.6
8 -45.5558936 58.46975   50.0

Ideally, I would like to plot the grid on a map from the marmap package using ggplot2 (see below):理想情况下,我想使用 ggplot2 在来自 marmap 包的地图上绘制网格(见下文):

library(marmap)
library(ggplot2)

atlantic <- getNOAA.bathy(-80, 40, 0, 90, resolution = 25, keep = TRUE)

atl.df <- fortify(atlantic)

map <- ggplot(atl.df, aes(x=x, y=y)) +
  geom_raster(aes(fill=z), data=atl.df) +
  geom_contour(aes(z=z),
               breaks=0, #contour for continent
               colour="black", size=1) +
  scale_fill_gradientn(values = scales::rescale(c(-5000, 0, 1, 2400)),
                       colors = c("steelblue4", "#C7E0FF", "gray40", "white"))

It sounds like you want to cut your numerical variables (lat & lon) into even intervals and summarise the values within each interval.听起来您想将数值变量(纬度和经度)切成均匀的间隔并总结每个间隔内的值。 Does the following work for you?以下对您有用吗?

library(dplyr)

df2 <- df %>%
  mutate(lon.group = cut(lon, breaks = seq(floor(min(df$lon)), ceiling(max(df$lon)), by = 5),
                         labels = seq(floor(min(df$lon)) + 2.5, ceiling(max(df$lon)), by = 5)),
         lat.group = cut(lat, breaks = seq(floor(min(df$lat)), ceiling(max(df$lat)), by = 5),
                         labels = seq(floor(min(df$lat)) + 2.5, ceiling(max(df$lat)), by = 5))) %>%
  group_by(lon.group, lat.group) %>%
  summarise(value = mean(value), .groups = "drop") %>%
  mutate(across(where(is.factor), ~as.numeric(as.character(.x))))

Sample data:样本数据:

set.seed(444)

n <- 10000
df <- data.frame(lon = runif(n, min = -100, max = -50),
                 lat = runif(n, min = 30, max = 80),
                 value = runif(n, min = 0, max = 1000))

> summary(df)
      lon              lat            value          
 Min.   :-99.99   Min.   :30.00   Min.   :   0.1136  
 1st Qu.:-87.55   1st Qu.:42.45   1st Qu.: 247.2377  
 Median :-75.29   Median :55.11   Median : 501.4165  
 Mean   :-75.12   Mean   :55.01   Mean   : 499.5385  
 3rd Qu.:-62.69   3rd Qu.:67.63   3rd Qu.: 748.8834  
 Max.   :-50.01   Max.   :80.00   Max.   : 999.9600 

Comparison of before & after data:前后数据对比:

gridExtra::grid.arrange(
  ggplot(df, 
         aes(x = lon, y = lat, colour = value)) + 
    geom_point() + 
    ggtitle("Original points"),
  ggplot(df2, 
         aes(x = lon.group, y = lat.group, fill = value)) + 
    geom_raster() + 
    ggtitle("Summarised grid"),
  nrow = 1
)

在此处输入图片说明

As (almost!) always, there's a function for that.就像(几乎!)总是一样,有一个功能。 I believe marmap::griddify() is what you are looking for.我相信marmap::griddify()是您正在寻找的。 The help file states:帮助文件指出:

Transforms irregularly spaced xyz data into a raster object suitable to create a bathy object with regularly spaced longitudes and latitudes.将不规则间隔的 xyz 数据转换为适合创建具有规则间隔经度和纬度的深海对象的栅格对象。

Here's a script using your coordinates:这是使用您的坐标的脚本:

library(marmap)
library(ggplot2)

# Create fake data
set.seed(42)
n <- 10000
data_irregular <- data.frame(lon = runif(n, min = -80, max = 40),
                             lat = runif(n, min = 0, max = 90),
                             value = runif(n, min = 0, max = 1000))

# Fit data into a grid of 30 cells in longitude and 50 cells in latitude
data_grid <- as.bathy(griddify(data_irregular, nlon = 30, nlat = 50))
fortified_grid <- fortify(data_grid)

# Get bathymetric data to plot continent contours
atlantic <- getNOAA.bathy(-80, 40, 0, 90, resolution = 25)
atl_df <- fortify(atlantic)

# Plot with ggplot with gridded data as tiles
map <- ggplot(atl_df, aes(x = x, y = y)) +
  geom_raster(data = fortified_grid, aes(fill = z)) +
  geom_contour(data = atl_df, aes(z = z), 
               breaks = 0, # contour for continent
               colour = "black", size = 1) +
  scale_fill_gradientn(values = scales::rescale(c(-5000, 0, 1, 2400)),
                       colors = c("steelblue4", "#C7E0FF", "gray40", "white")) +
  labs(x = "Longitude", y = "Latitude", fill = "Value")


map +
  theme_bw()

And here is the result:结果如下:

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM