简体   繁体   English

堆叠栅格并计算每个像素的最大值,然后在 R 中的 rest 个图层中保留该值

[英]Stack rasters and calculate each pixel's max value then keep that value for rest of the layers in R

I have 181 daily ndvi rasters stacked.我每天堆叠 181 个 ndvi 光栅。 I want to find peak for each pixel and then assign peak value to the rest. Original Data Curve:我想为每个像素找到峰值,然后将峰值分配给 rest。原始数据曲线:

在此处输入图像描述

This is what I want:这就是我要的:

在此处输入图像描述

This result is for single pixel.此结果适用于单个像素。 I've done it in excel but want to create a code in R for ease.我已经在 excel 中完成了,但为了方便起见,我想在 R 中创建一个代码。 Now every pixel reaches peak at different date (so different Layer in stack).现在每个像素在不同的日期达到峰值(因此堆栈中的不同层)。

This is what i tried这是我试过的

fn <- list.files(pn, '*.tif$', full.names = TRUE)
rn <- lapply(fn, raster)
bn <- brick(rn)

for (j in 1:ncell(bn)) {
  x <- bn[j]
  y <- which.max(x)
  x[y:length(x)] <- x[y]
}

Now this code works if I use it without loop.现在,如果我在没有循环的情况下使用它,这段代码就可以工作了。 Error is probably because some cells have NA's.错误可能是因为某些单元格有 NA。 Each layer has 24 cells and only 14 have data.每层有 24 个单元,只有 14 个有数据。 Rest are masked. Rest 被屏蔽了。

For processing raster data, I would recommend using the terra package. It is an update to the raster package that is faster and in most cases easier to use (you can install it with install.packages('terra') ).对于处理栅格数据,我建议使用terra package。它是对raster package 的更新,速度更快,在大多数情况下更易于使用(您可以使用install.packages('terra')安装)。 terra has a set of apply functions that allow you to apply functions over each stack of pixels. terra有一组apply函数,允许您在每个像素堆栈上应用函数。 In the example below, I create a 2x2 pixel raster with some dummy data, and use the terra::app function to carry out the process you outline in your question:在下面的示例中,我创建了一个带有一些虚拟数据的 2x2 像素栅格,并使用terra::app function 执行您在问题中概述的过程:

# Create random data for 181 rasters.
x = seq(-0, 10, length.out=181)

# `dnorm` can be used to simulate a bell curve, like the NDVI data. 
vals = rep(dnorm(x, 5, 1), 4)

# I couldn't get the raster to reshape correctly so I am just taking the first
# 50 values so the data are a nice bell curve. 
arr <- array(vals, dim = c(2, 2, 50)) 

# Replace this with your data. From your code, you can just use:
# bn <- terra::rast(fn)
r <- terra::rast(arr)

# Define a custom function that operates on one stack of pixels at a time.
fill_max <- function(timeseries) {
  
  # Find the index with the max value
  idx = which.max(timeseries)
  
  # Set all values past the max to the max value
  timeseries[idx:length(timeseries)] <- timeseries[idx]
  
  return(timeseries)
}

# Apply the function to the raster.
out <- terra::app(r, fun=fill_max)

# Check that process worked. Take the timeseries of the first pixel. 
vals <- terra::values(out)[1,]
# Plot the timeseries. 
plot(1:length(vals), vals)

Created on 2023-01-18 with reprex v2.0.2创建于 2023-01-18,使用reprex v2.0.2

If you wanted the curve to never go down, you could use terra::cummax如果您希望曲线永远不会下降 go,您可以使用terra::cummax

Example data示例数据

library(terra)
r <- rast(ncol=10, nrow=10, nlyr=30)
set.seed(1)
values(r) <- runif(size(r))

Solution解决方案

x <- cummax(r)

Illustrated for four cells图示为四个电池

par(mfrow=c(2,2), mar=rep(2,4))
for (i in c(2,3,8,9)) {
  plot(unlist(r[i]))
  lines(unlist(x[i]), col="blue", lwd=2)
}

在此处输入图像描述

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

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