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;








0















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)









share|improve this question




























    0















    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)









    share|improve this question
























      0












      0








      0








      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)









      share|improve this question














      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






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 15 '18 at 10:01









      LouiseLouise

      33




      33






















          2 Answers
          2






          active

          oldest

          votes


















          0














          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)





          share|improve this answer
































            0














            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





            share|improve this answer























              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
              );



              );













              draft saved

              draft discarded


















              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









              0














              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)





              share|improve this answer





























                0














                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)





                share|improve this answer



























                  0












                  0








                  0







                  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)





                  share|improve this answer















                  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)






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Nov 17 '18 at 5:12

























                  answered Nov 17 '18 at 5:02









                  Robert HijmansRobert Hijmans

                  14.1k12530




                  14.1k12530























                      0














                      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





                      share|improve this answer



























                        0














                        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





                        share|improve this answer

























                          0












                          0








                          0







                          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





                          share|improve this answer













                          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






                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Nov 15 '18 at 10:31









                          nikoniko

                          3,3091421




                          3,3091421



























                              draft saved

                              draft discarded
















































                              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.




                              draft saved


                              draft discarded














                              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





















































                              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







                              Popular posts from this blog

                              Use pre created SQLite database for Android project in kotlin

                              Darth Vader #20

                              Ondo