R: Annual composite raster based on the median: How to get the index of the original layer for each pixel?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
I have a list of rasterstacks which are timeseries (300+ layers) for different bands. The timeseries are irregular, and therefore I want to create annual composites based on median ndvi. Thus from the available images for one year, the pixel with the (close to) median ndvi is chosen. For the other bands I want to create annual composites based on this ndvi composite. I try to make a mask in which each pixel has the value of the index of the image used for the median ndvi composite. I will apply this on the other bands, so I have 'the same' annual composite for each band per year.
Unfortunately, I am stuck on making the mask. I created some dummy data and somehow it returns two indexrasters (one with values 1-3, the other 2-4), while I expected one (with values 1-4).
Also my function cannot handle NA values and adding na.rm to the calc function does not solve this.
I am wondering what I need to adjust to get one output layer with values from 1-4, and how to let the 'which'-function deal with NAs.
#dummy data:
r <- raster(nrow=5, ncol=5)
set.seed(20181114)
s <- stack(lapply(1:5, function(i) setValues(r, runif(25, max=50))))
names(s) <- c("X2001", "X2002a", "X2002b", "X2002c", "X2002d")
#s$X2002a[2] <- NA
AnnualMask <- function(ts, year)
year <- as.character(year)
ts_year <- subset(ts, (grep(year, names(ts))))
indexraster <- calc(ts_year, function(x)
medianval <- median(x, na.rm = TRUE)
which(abs(x - medianval) == min(abs(x - medianval)))
)
return(indexraster)
mask2002 <- AnnualMask(s, 2002)
plot(mask2002)
r mask raster na median
add a comment |
I have a list of rasterstacks which are timeseries (300+ layers) for different bands. The timeseries are irregular, and therefore I want to create annual composites based on median ndvi. Thus from the available images for one year, the pixel with the (close to) median ndvi is chosen. For the other bands I want to create annual composites based on this ndvi composite. I try to make a mask in which each pixel has the value of the index of the image used for the median ndvi composite. I will apply this on the other bands, so I have 'the same' annual composite for each band per year.
Unfortunately, I am stuck on making the mask. I created some dummy data and somehow it returns two indexrasters (one with values 1-3, the other 2-4), while I expected one (with values 1-4).
Also my function cannot handle NA values and adding na.rm to the calc function does not solve this.
I am wondering what I need to adjust to get one output layer with values from 1-4, and how to let the 'which'-function deal with NAs.
#dummy data:
r <- raster(nrow=5, ncol=5)
set.seed(20181114)
s <- stack(lapply(1:5, function(i) setValues(r, runif(25, max=50))))
names(s) <- c("X2001", "X2002a", "X2002b", "X2002c", "X2002d")
#s$X2002a[2] <- NA
AnnualMask <- function(ts, year)
year <- as.character(year)
ts_year <- subset(ts, (grep(year, names(ts))))
indexraster <- calc(ts_year, function(x)
medianval <- median(x, na.rm = TRUE)
which(abs(x - medianval) == min(abs(x - medianval)))
)
return(indexraster)
mask2002 <- AnnualMask(s, 2002)
plot(mask2002)
r mask raster na median
add a comment |
I have a list of rasterstacks which are timeseries (300+ layers) for different bands. The timeseries are irregular, and therefore I want to create annual composites based on median ndvi. Thus from the available images for one year, the pixel with the (close to) median ndvi is chosen. For the other bands I want to create annual composites based on this ndvi composite. I try to make a mask in which each pixel has the value of the index of the image used for the median ndvi composite. I will apply this on the other bands, so I have 'the same' annual composite for each band per year.
Unfortunately, I am stuck on making the mask. I created some dummy data and somehow it returns two indexrasters (one with values 1-3, the other 2-4), while I expected one (with values 1-4).
Also my function cannot handle NA values and adding na.rm to the calc function does not solve this.
I am wondering what I need to adjust to get one output layer with values from 1-4, and how to let the 'which'-function deal with NAs.
#dummy data:
r <- raster(nrow=5, ncol=5)
set.seed(20181114)
s <- stack(lapply(1:5, function(i) setValues(r, runif(25, max=50))))
names(s) <- c("X2001", "X2002a", "X2002b", "X2002c", "X2002d")
#s$X2002a[2] <- NA
AnnualMask <- function(ts, year)
year <- as.character(year)
ts_year <- subset(ts, (grep(year, names(ts))))
indexraster <- calc(ts_year, function(x)
medianval <- median(x, na.rm = TRUE)
which(abs(x - medianval) == min(abs(x - medianval)))
)
return(indexraster)
mask2002 <- AnnualMask(s, 2002)
plot(mask2002)
r mask raster na median
I have a list of rasterstacks which are timeseries (300+ layers) for different bands. The timeseries are irregular, and therefore I want to create annual composites based on median ndvi. Thus from the available images for one year, the pixel with the (close to) median ndvi is chosen. For the other bands I want to create annual composites based on this ndvi composite. I try to make a mask in which each pixel has the value of the index of the image used for the median ndvi composite. I will apply this on the other bands, so I have 'the same' annual composite for each band per year.
Unfortunately, I am stuck on making the mask. I created some dummy data and somehow it returns two indexrasters (one with values 1-3, the other 2-4), while I expected one (with values 1-4).
Also my function cannot handle NA values and adding na.rm to the calc function does not solve this.
I am wondering what I need to adjust to get one output layer with values from 1-4, and how to let the 'which'-function deal with NAs.
#dummy data:
r <- raster(nrow=5, ncol=5)
set.seed(20181114)
s <- stack(lapply(1:5, function(i) setValues(r, runif(25, max=50))))
names(s) <- c("X2001", "X2002a", "X2002b", "X2002c", "X2002d")
#s$X2002a[2] <- NA
AnnualMask <- function(ts, year)
year <- as.character(year)
ts_year <- subset(ts, (grep(year, names(ts))))
indexraster <- calc(ts_year, function(x)
medianval <- median(x, na.rm = TRUE)
which(abs(x - medianval) == min(abs(x - medianval)))
)
return(indexraster)
mask2002 <- AnnualMask(s, 2002)
plot(mask2002)
r mask raster na median
r mask raster na median
asked Nov 15 '18 at 10:01
LouiseLouise
33
33
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
Thanks for providing good example data:
library(raster)
r <- raster(nrow=5, ncol=5)
set.seed(20181114)
s <- stack(lapply(1:5, function(i) setValues(r, runif(25, max=50))))
names(s) <- c("X2001", "X2002a", "X2002b", "X2002c", "X2002d")
s[[2]][1:3] <- NA
Here are two functions that do the same. #1 is perhaps simpler but probably less efficient.
annualIndex1 <- function(ts, year)
year <- as.character(year)
ts_year <- subset(ts, (grep(year, names(ts))))
medianval <- calc(ts_year, median, na.rm = TRUE)
dif <- abs(ts_year - medianval)
which.min(dif)
x1 <- annualIndex1(s, 2002)
This one uses calc
to combine multiple steps
annualIndex2 <- function(ts, year)
year <- as.character(year)
ts_year <- subset(ts, (grep(year, names(ts))))
fun <- function(x)
y <- median(x, na.rm=TRUE)
which.min(abs(x - y))
calc(ts_year, fun)
x2 <- annualIndex2(s, 2002)
The results are the same (and there are no NAs)
all(values(x1) == values(x2))
#[1] TRUE
However, if you make a cell NA in all layers
s[5] <- NA
function 2 fails. It could be adjusted like this
annualIndex2b <- function(ts, year)
year <- as.character(year)
ts_year <- subset(ts, (grep(year, names(ts))))
fun <- function(x)
if (all(is.na(x))) return( NA )
y <- median(x, na.rm=TRUE)
which.min(abs(x - y))
calc(ts_year, fun)
x2b <- annualIndex2b(s, 2002)
You use the term "mask", but really you are creating an index, can you can use the appropriate cells with strackSelect
like this:
ts_year <- subset(ts, (grep(year, names(ts))))
v <- stackSelect(ts_year, x2)
add a comment |
I am not sure yet about the part with the values ranging in 1-4, however here is something concerning the which
part and dealing with NA
:
# here is some dummy data
x <- c(3,4,5,NA,1,-2-45,2,54)
# now here is the which part as found in your function
medianval <- median(x, na.rm = TRUE)
which(abs(x - medianval) == min(abs(x - medianval)))
# returning in this case
integer(0)
# now let's add na.rm = T in the min function
medianval <- median(x, na.rm = TRUE)
which(abs(x - medianval) == min(abs(x - medianval), na.rm = T))
# returning
[1] 1
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53316829%2fr-annual-composite-raster-based-on-the-median-how-to-get-the-index-of-the-orig%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for providing good example data:
library(raster)
r <- raster(nrow=5, ncol=5)
set.seed(20181114)
s <- stack(lapply(1:5, function(i) setValues(r, runif(25, max=50))))
names(s) <- c("X2001", "X2002a", "X2002b", "X2002c", "X2002d")
s[[2]][1:3] <- NA
Here are two functions that do the same. #1 is perhaps simpler but probably less efficient.
annualIndex1 <- function(ts, year)
year <- as.character(year)
ts_year <- subset(ts, (grep(year, names(ts))))
medianval <- calc(ts_year, median, na.rm = TRUE)
dif <- abs(ts_year - medianval)
which.min(dif)
x1 <- annualIndex1(s, 2002)
This one uses calc
to combine multiple steps
annualIndex2 <- function(ts, year)
year <- as.character(year)
ts_year <- subset(ts, (grep(year, names(ts))))
fun <- function(x)
y <- median(x, na.rm=TRUE)
which.min(abs(x - y))
calc(ts_year, fun)
x2 <- annualIndex2(s, 2002)
The results are the same (and there are no NAs)
all(values(x1) == values(x2))
#[1] TRUE
However, if you make a cell NA in all layers
s[5] <- NA
function 2 fails. It could be adjusted like this
annualIndex2b <- function(ts, year)
year <- as.character(year)
ts_year <- subset(ts, (grep(year, names(ts))))
fun <- function(x)
if (all(is.na(x))) return( NA )
y <- median(x, na.rm=TRUE)
which.min(abs(x - y))
calc(ts_year, fun)
x2b <- annualIndex2b(s, 2002)
You use the term "mask", but really you are creating an index, can you can use the appropriate cells with strackSelect
like this:
ts_year <- subset(ts, (grep(year, names(ts))))
v <- stackSelect(ts_year, x2)
add a comment |
Thanks for providing good example data:
library(raster)
r <- raster(nrow=5, ncol=5)
set.seed(20181114)
s <- stack(lapply(1:5, function(i) setValues(r, runif(25, max=50))))
names(s) <- c("X2001", "X2002a", "X2002b", "X2002c", "X2002d")
s[[2]][1:3] <- NA
Here are two functions that do the same. #1 is perhaps simpler but probably less efficient.
annualIndex1 <- function(ts, year)
year <- as.character(year)
ts_year <- subset(ts, (grep(year, names(ts))))
medianval <- calc(ts_year, median, na.rm = TRUE)
dif <- abs(ts_year - medianval)
which.min(dif)
x1 <- annualIndex1(s, 2002)
This one uses calc
to combine multiple steps
annualIndex2 <- function(ts, year)
year <- as.character(year)
ts_year <- subset(ts, (grep(year, names(ts))))
fun <- function(x)
y <- median(x, na.rm=TRUE)
which.min(abs(x - y))
calc(ts_year, fun)
x2 <- annualIndex2(s, 2002)
The results are the same (and there are no NAs)
all(values(x1) == values(x2))
#[1] TRUE
However, if you make a cell NA in all layers
s[5] <- NA
function 2 fails. It could be adjusted like this
annualIndex2b <- function(ts, year)
year <- as.character(year)
ts_year <- subset(ts, (grep(year, names(ts))))
fun <- function(x)
if (all(is.na(x))) return( NA )
y <- median(x, na.rm=TRUE)
which.min(abs(x - y))
calc(ts_year, fun)
x2b <- annualIndex2b(s, 2002)
You use the term "mask", but really you are creating an index, can you can use the appropriate cells with strackSelect
like this:
ts_year <- subset(ts, (grep(year, names(ts))))
v <- stackSelect(ts_year, x2)
add a comment |
Thanks for providing good example data:
library(raster)
r <- raster(nrow=5, ncol=5)
set.seed(20181114)
s <- stack(lapply(1:5, function(i) setValues(r, runif(25, max=50))))
names(s) <- c("X2001", "X2002a", "X2002b", "X2002c", "X2002d")
s[[2]][1:3] <- NA
Here are two functions that do the same. #1 is perhaps simpler but probably less efficient.
annualIndex1 <- function(ts, year)
year <- as.character(year)
ts_year <- subset(ts, (grep(year, names(ts))))
medianval <- calc(ts_year, median, na.rm = TRUE)
dif <- abs(ts_year - medianval)
which.min(dif)
x1 <- annualIndex1(s, 2002)
This one uses calc
to combine multiple steps
annualIndex2 <- function(ts, year)
year <- as.character(year)
ts_year <- subset(ts, (grep(year, names(ts))))
fun <- function(x)
y <- median(x, na.rm=TRUE)
which.min(abs(x - y))
calc(ts_year, fun)
x2 <- annualIndex2(s, 2002)
The results are the same (and there are no NAs)
all(values(x1) == values(x2))
#[1] TRUE
However, if you make a cell NA in all layers
s[5] <- NA
function 2 fails. It could be adjusted like this
annualIndex2b <- function(ts, year)
year <- as.character(year)
ts_year <- subset(ts, (grep(year, names(ts))))
fun <- function(x)
if (all(is.na(x))) return( NA )
y <- median(x, na.rm=TRUE)
which.min(abs(x - y))
calc(ts_year, fun)
x2b <- annualIndex2b(s, 2002)
You use the term "mask", but really you are creating an index, can you can use the appropriate cells with strackSelect
like this:
ts_year <- subset(ts, (grep(year, names(ts))))
v <- stackSelect(ts_year, x2)
Thanks for providing good example data:
library(raster)
r <- raster(nrow=5, ncol=5)
set.seed(20181114)
s <- stack(lapply(1:5, function(i) setValues(r, runif(25, max=50))))
names(s) <- c("X2001", "X2002a", "X2002b", "X2002c", "X2002d")
s[[2]][1:3] <- NA
Here are two functions that do the same. #1 is perhaps simpler but probably less efficient.
annualIndex1 <- function(ts, year)
year <- as.character(year)
ts_year <- subset(ts, (grep(year, names(ts))))
medianval <- calc(ts_year, median, na.rm = TRUE)
dif <- abs(ts_year - medianval)
which.min(dif)
x1 <- annualIndex1(s, 2002)
This one uses calc
to combine multiple steps
annualIndex2 <- function(ts, year)
year <- as.character(year)
ts_year <- subset(ts, (grep(year, names(ts))))
fun <- function(x)
y <- median(x, na.rm=TRUE)
which.min(abs(x - y))
calc(ts_year, fun)
x2 <- annualIndex2(s, 2002)
The results are the same (and there are no NAs)
all(values(x1) == values(x2))
#[1] TRUE
However, if you make a cell NA in all layers
s[5] <- NA
function 2 fails. It could be adjusted like this
annualIndex2b <- function(ts, year)
year <- as.character(year)
ts_year <- subset(ts, (grep(year, names(ts))))
fun <- function(x)
if (all(is.na(x))) return( NA )
y <- median(x, na.rm=TRUE)
which.min(abs(x - y))
calc(ts_year, fun)
x2b <- annualIndex2b(s, 2002)
You use the term "mask", but really you are creating an index, can you can use the appropriate cells with strackSelect
like this:
ts_year <- subset(ts, (grep(year, names(ts))))
v <- stackSelect(ts_year, x2)
edited Nov 17 '18 at 5:12
answered Nov 17 '18 at 5:02
Robert HijmansRobert Hijmans
14.1k12530
14.1k12530
add a comment |
add a comment |
I am not sure yet about the part with the values ranging in 1-4, however here is something concerning the which
part and dealing with NA
:
# here is some dummy data
x <- c(3,4,5,NA,1,-2-45,2,54)
# now here is the which part as found in your function
medianval <- median(x, na.rm = TRUE)
which(abs(x - medianval) == min(abs(x - medianval)))
# returning in this case
integer(0)
# now let's add na.rm = T in the min function
medianval <- median(x, na.rm = TRUE)
which(abs(x - medianval) == min(abs(x - medianval), na.rm = T))
# returning
[1] 1
add a comment |
I am not sure yet about the part with the values ranging in 1-4, however here is something concerning the which
part and dealing with NA
:
# here is some dummy data
x <- c(3,4,5,NA,1,-2-45,2,54)
# now here is the which part as found in your function
medianval <- median(x, na.rm = TRUE)
which(abs(x - medianval) == min(abs(x - medianval)))
# returning in this case
integer(0)
# now let's add na.rm = T in the min function
medianval <- median(x, na.rm = TRUE)
which(abs(x - medianval) == min(abs(x - medianval), na.rm = T))
# returning
[1] 1
add a comment |
I am not sure yet about the part with the values ranging in 1-4, however here is something concerning the which
part and dealing with NA
:
# here is some dummy data
x <- c(3,4,5,NA,1,-2-45,2,54)
# now here is the which part as found in your function
medianval <- median(x, na.rm = TRUE)
which(abs(x - medianval) == min(abs(x - medianval)))
# returning in this case
integer(0)
# now let's add na.rm = T in the min function
medianval <- median(x, na.rm = TRUE)
which(abs(x - medianval) == min(abs(x - medianval), na.rm = T))
# returning
[1] 1
I am not sure yet about the part with the values ranging in 1-4, however here is something concerning the which
part and dealing with NA
:
# here is some dummy data
x <- c(3,4,5,NA,1,-2-45,2,54)
# now here is the which part as found in your function
medianval <- median(x, na.rm = TRUE)
which(abs(x - medianval) == min(abs(x - medianval)))
# returning in this case
integer(0)
# now let's add na.rm = T in the min function
medianval <- median(x, na.rm = TRUE)
which(abs(x - medianval) == min(abs(x - medianval), na.rm = T))
# returning
[1] 1
answered Nov 15 '18 at 10:31
nikoniko
3,3091421
3,3091421
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53316829%2fr-annual-composite-raster-based-on-the-median-how-to-get-the-index-of-the-orig%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown