10

I'm using ArcGIS Desktop 10 with its Spatial Analyst extension.

How do I combine multiple rasters into one, always choosing randomly from the values of overlapping cells?

I have an image that may explain this better:

example

3 Answers 3

7

Pick was created for problems like this. Think of it as the "switch" (or "case") version of "con", which is the map algebra implementation of "if...else."

If there are 3 overlapping rasters, for instance, the (Python) syntax would look like

inPositionRaster = 1 + int(3 * CreateRandomRaster())
Pick(inPositionRaster, [inRas01, inRas02, inRas03])

Note that pick starts indexing at 1, not 0.


Edit

(see the comment thread)

To cope with NoData values, first you need to turn off ArcGIS's NoData handling. Do this by creating grids that have a special (but valid) value in place of NoData, such as 99999 (or whatever: but make sure to choose a value that is larger than any valid number that can appear: this will be handy later). This requires use of the IsNull request, as in

p01 = Con(IsNull(inRas01), 99999, inRas01)
p02 = Con(IsNull(inRas02), 99999, inRas01)
p03 = Con(IsNull(inRas03), 99999, inRas01)

For example, consider the case of these one-row grids (NoData is shown as "*"):

inRas01:  1  2 19  4  *  *  *  *
inRas02:  9  2  *  * 13 14  *  *
inRas03: 17  *  3  * 21  * 23  *

The result is to put a 99999 in place of each "*".

Next, imagine all these rasters as flat arrays of wooden blocks with NoData corresponding to missing blocks (holes). When you vertically stack these rasters, blocks will fall into any holes beneath them. We need that behavior to avoid picking NoData values: we don't want any vertical gaps in the stacks of blocks. The order of the blocks in each tower doesn't really matter. To this end, we can obtain each tower by ranking the data:

q01 = Rank(1, [p01, p02, p03])
q02 = Rank(2, [p01, p02, p03])
q03 = Rank(3, [p01, p02, p03])

In the example, we obtain

q01:      1     2     3     4    13    14    23 99999
q02:      9     2    19 99999    21 99999 99999 99999
q03:     17 99999 99999 99999 99999 99999 99999 99999

Note that the ranks are from lowest to highest, so that q01 contains the lowest values at each location, q02 contains the second-lowest, etc. The NoData codes don't start showing up until all the valid numbers are collected, because those codes are larger than any valid numbers.

In order to avoid picking these NoData codes during the random selection, you need to know how many blocks are stacked at each location: this tells us how many valid values occur. One way to handle this is to count the number of NoData codes and subtract that from the total number of selection grids:

n0 = 3 - EqualToFrequency(99999, [q01, q02, q03])

This yields

n0:       3 2 2 1 2 1 1 0

To handle the cases where n=0 (so there's nothing available to select), set them to NoData:

n = SetNull(n0 == 0, n0)

Now

n:        3 2 2 1 2 1 1 *

This will also guarantee that your (temporary) NoData codes disappear in the final calculation. Generate random values between 1 and n:

inPositionRaster = 1 + int(n * CreateRandomRaster())

For instance, this raster might look like

inPositionRaster: 3 2 1 1 2 1 1 *

All its values lie between 1 and the corresponding value in [n].

Select values exactly as before:

selection = Pick(inPositionRaster, [q01, q02, q03])

This would result in

selection:       17  2  3  4 21 14 23  *

To check that all is ok, try selecting all output cells that have the NoData code (99999 in this example): there shouldn't be any.

Although this running example uses only three grids to select from, I have written it in a way that generalizes easily to any number of grids. With lots of grids, writing a script (to loop over the repeated operations) will be invaluable.

6
  • Do you know how I could ignore the NoData values from the calculations (with Raster Calculator and Python)?
    – Sam
    Commented Feb 17, 2012 at 21:11
  • Sam, "Ignore" how, precisely? I believe the default behavior is to output NoData wherever one or more input rasters are NoData (but I'm not completely sure of that in the case of pick: if inPositionRaster and the selected raster both have valid values in a cell, then plausibly the result for that cell should be the value of the selected raster, regardless of what any of the other rasters may contain). What alternative behavior are you thinking of?
    – whuber
    Commented Feb 17, 2012 at 21:17
  • I need it to only select from the whole number values. Let's say I have three rasters. For a cell, their values are as follows: 4,5,NoData. I want the outraster to either have a 4 or 5 in that cell but never the NoData.
    – Sam
    Commented Feb 17, 2012 at 21:24
  • I'm having trouble getting this 1 + Int(n * CreateRandomRaster()) to work.
    – Sam
    Commented Feb 24, 2012 at 0:57
  • "Trouble" in what sense? Please be specific!
    – whuber
    Commented Feb 24, 2012 at 16:02
4

Using python and ArcGIS 10 and using the con function which has the following syntax:

Con (in_conditional_raster, in_true_raster_or_constant, {in_false_raster_or_constant}, {where_clause})

The idea here is to see if the value in the random raster is less than 0.5, if it is choose raster1, otherwise choose raster2. NoData + data = NoData so first set these reclassify any values with NoData to 0:

import arcpy
from arcpy import env
from arcpy.sa import *
env.workspace = "C:/sapyexamples/data"

ras1_NoNull = Con(IsNull("elevation1"),0, "elevation1")  # remove NoData
ras2_NoNull = Con(IsNull("elevation2"),0, "elevation2")  # remove NoData
randRaster = CreateRandomRaster(100, 2, Extent(0, 0, 150, 150)) # raster generated between 0 and 1; 100 is seed value

outCon = Con(randRaster < 0.5, ras1_NoNull,  ras2_NoNull)  

outCon.save("C:/outcon.img")   # save raster

EDIT: Just realized that you are not adding the NoData values so that piece can be left out.

6
  • I'm still working on my Python skills. Is there a way to enter this into Raster Calculator that would also exclude the NoData values from the process? I have 10 rasters and some have NoData where others have values.
    – Sam
    Commented Feb 17, 2012 at 21:30
  • I think you can create conditions using something like this in the raster calculator Con(IsNull(ras1), 0, ras2)
    – djq
    Commented Feb 17, 2012 at 21:41
  • Unfortunately, this doesn't actually exclude NoData values: it just replaces them with zeros. In some cases that might be appropriate, but probably not here!
    – whuber
    Commented Feb 17, 2012 at 22:28
  • hmm, good point @whuber. So what does it mean to exclude NoData? Is it just to make sure that they are not picked when randomly choosing?
    – djq
    Commented Feb 17, 2012 at 22:43
  • That's how I've interpreted it (see my edited answer in this thread), but it remains a good question. Ignoring the ND values in this fashion causes the remaining grids to be selected with greater probability, which might be an undesirable side effect. It all depends on the purpose of the calculation.
    – whuber
    Commented Feb 17, 2012 at 22:49
1

I would just create a random raster (help) of the same extent and cell size. Then using CON (help) set it to pick value from 1st raster if cell from randomized raster has a value < 128 (if a random raster would be 0 - 255) otherwise pick a value from 2nd raster.

Hope that makes sense :)

2
  • Do you know how to only select from the rasters with values? For instance in my figure there are four 2's and two 3's that overlap with NoData. I want to make sure it only selects from those rasters with values at a cell and not the NoData.
    – Sam
    Commented Feb 13, 2012 at 17:25
  • Sorry for not responding. Are you still struggling with NoData issue?
    – jareks
    Commented Feb 21, 2012 at 19:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.