counting the depressions(group of negative numbers) over time from a raster brick, R

StackOverflow https://stackoverflow.com//questions/9616471

  •  09-12-2019
  •  | 
  •  

Question

I am trying to count the number of group of depressions (negative values) from a climate data set and have least idea on how to go about it. Let me explain the scenario. I have a raster brick with 468 layers and and each layer has 7458 cells.

> cntneg
class       : RasterBrick 
dimensions  : 66, 113, 7458, 468  (nrow, ncol, ncell, nlayers)
resolution  : 0.108, 0.108  (x, y)
extent      : 77.946, 90.15, 24.946, 32.074  (xmin, xmax, ymin, ymax)
coord. ref. : NA 
values      : in memory
min values  : -359.51 -341.21 -315.45 -148.10 -187.39  -52.87  -66.72  -52.17 -286.81 -306.74 ... 
max values  :  -7.589   0.000   0.000   0.000   0.000   0.000   0.000   0.000   0.000   0.000 ... 

Now for example lets take the 5000th pixel

> cntneg[5000]

Which will give me 468 values of that pixel over time.

[1]  -90.795107  -89.990016  -94.840754    0.000000  -15.085517    0.000000
  [7]    0.000000    0.000000    0.000000  -12.469657 -114.757702 -115.372023
 [13] -107.194478  -92.916680 -115.105817 -113.205776 -115.003430  -62.175070
 [19]    0.000000    0.000000    0.000000  -72.358073 -105.006508 -115.372023
 [25]  -48.836959 -102.314928 -113.271826 -115.372023  -79.530055    0.000000
 [31]    0.000000    0.000000    0.000000  -15.048987 -115.208204 -115.372023
 [37] -115.003430 -108.757617 -113.122594 -115.372023 -111.699048  -17.618498
 [43]    0.000000    0.000000

Now here I need to do two tasks

1) count number of times the rainfall went below the average - those with negative values. And zeros are with positive RF values (which i converted to zero using reclass) for the ease of calculation. In the above example I want to pick the group of negative numbers and count. ie, (-90.795107 -89.990016 -94.840754), (-15.085517), ( -12.469657 -114.757702 -115.372023, -107.194478 -92.916680 -115.105817 -113.205776 -115.003430 -62.175070), (-72.358073 -105.006508 -115.372023, -48.836959 -102.314928 -113.271826 -115.372023 -79.530055) etc. The resulted layer pixel value should be the count of these groups, which in this case is 5. Like wise need to do for all the pixels along time dimension.

2) For each group I want to pick the minimum values and resulted pixel will have the sum of those minimum values. If a group has one value, keep the same.

I am stuck to start with this process. I am assuming I need to convert the brick into dataframe and do this.

Can any one help me in giving a lead on how to go about it?

Really appreciate any help.

Sorry if the explanation is confusing.

Regards SP

Was it helpful?

Solution

There is a nice function called rle that finds contiguous elements of a vector satisfying a condition. The function call res<-rle(vector<0) gives back res$lengths and res$values, containing the length and the value of the blocks in your vector, respectively.

So we can do it like this

    sample.data <- rnorm(20)
    b <- (1:length(rle(sample.data<0)$lengths))
    c <- rle(sample.data<0)$lengths
    aggregate(sample.data,by = list(unlist(mapply(rep,b,c))),min)

(Sorry for the list(unlist()), apparently I don't know how to flatten a list in R)

The mapply command creates a list of identifiers for each block, numbered from 1 to total number of blocks. The rep command ensures that each identifier is repeated as long as its respective block. Then we aggregate our sample data, applying the min function on all entries with the same identifier. The resulting data.frame has alternating positive and negative entries. The negative entries are the desired minima of the negative blocks.

The result (in my case):

    sample.data
    [1]  0.781352094  0.005568218  1.230054543 -0.825140291  0.861346012
    [6] -0.829708513 -0.452102503 -0.559146728 -1.017299175 -0.979450702
    [11] -1.492603312 -0.466351610  1.189238669 -0.674493774 -0.120572288
    [16] -0.336176940  0.348560999  0.420171989  1.459037512  0.056945430
    aggregate(sample.data,by = list(unlist(mapply(rep,b,c))),min)

    Group.1            x
    1       1  0.005568218
    2       2 -0.825140291
    3       3  0.861346012
    4       4 -1.492603312
    5       5  1.189238669
    6       6 -0.674493774
    7       7  0.056945430

We can print out only the minima like this

     agg.df <- aggregate(sample.data,by = list(unlist(mapply(rep,b,c))),min)
     agg.df[,2][rle(sample.data<0)$value]

     [1] -0.8251403 -1.4926033 -0.6744938
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top