Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

I am working with a raster map vegetation types. I have about 20 types with unique raster code values that can be sorted into three classes:

1 - vegetation types I want to expand using the nibble function (e.g. forest)

2 - vegetation types I consider static that I do not want to either nibble or be nibbled (e.g. water, developed areas)

3 - vegetation types that I want to eliminate through the nibble function (early seral stages, such as grass and chaparral)

The first time I ran this I was under a deadline and didn't have time to figure out a better solution, and wasn't able to find one googling/searching. I'm hoping to find a way to make this a shorter geoprocessing slog.

As inputs to the Nibble, I reclassified my veg layer so that the type 2 (static) values were nodata, since I didn't want them to nibble. That was my input layer. For the input MASK, I reclassified the original raster but made the type 3 values nodata, since they are the ones I want to eliminate through nibbling.

The catch is that I tend to have large amounts of type 3 clustered together, and on top of that there are several places where the type 2 and type 3 values are clustered near each other. The upshot is that the nibble gave me an incomplete output. It ran correctly, as far as I could tell, but it would stop before nibbling away all of the masked values.

I think the problem is that the nibble function has some predetermined search radius for the nearest neighbor, and if a cell is surrounded by type 2 and 3 cells then it can be so far away from a type 1 cell that the nibble doesn't reach it. However, looking into the tools, the whole Nibble tool is just one function that is called with those two inputs, so I can't modify the python code to change the search radius. I am not skilled enough in python to write a loop that would run the nibble over and over again.

So, is there a way to get the Nibble to fill in more of the masked values at a time? Is there a place I can get the Nibble code to try and modify it? I would imagine at some point a distance threshold was specified.

Thanks in advance! I hope my explanation was clear!

Edit: More information on the data I am using

+-------------+-------------------+--+-------------+--------+-------------+--------+-------------+---------+
|    Name     | Integer in Raster |  |   Static    | Value  |  Dissolve   | Value  |  Nibblers   |  Value  |
+-------------+-------------------+--+-------------+--------+-------------+--------+-------------+---------+
| SMCM        |                 0 |  | URB         |      4 | MCH         |      3 | SMCM        |       0 |
| OCFW        |                 1 |  | BAR         |      8 | GRASS       |      7 | OCFW        |       1 |
| SMCX        |                 2 |  | WAT         |      9 | MCP         |     10 | SMCX        |       2 |
| MCH         |                 3 |  | AGR         |     11 | ADS         |     19 | MHW         |       5 |
| URB         |                 4 |  | MRIP        |     12 | ASPE        |     23 | BLU         |       6 |
| MHW         |                 5 |  | MED         |     13 | ASPW        |     24 | DFTO        |      14 |
| BLU         |                 6 |  | Pixel Count | 322591 | Pixel Count | 333625 | RF          |      15 |
| GRASS       |                 7 |  |             |        |             |        | LPN         |      16 |
| BAR         |                 8 |  |             |        |             |        | SCN         |      17 |
| WAT         |                 9 |  |             |        |             |        | WWP         |      18 |
| MCP         |                10 |  |             |        |             |        | YPN         |      20 |
| AGR         |                11 |  |             |        |             |        | SAGE        |      21 |
| MRIP        |                12 |  |             |        |             |        | CMM         |      22 |
| MED         |                13 |  |             |        |             |        | LSG         |      25 |
| DFTO        |                14 |  |             |        |             |        | Pixel Count | 3744816 |
| RF          |                15 |  |             |        |             |        |             |         |
| LPN         |                16 |  |             |        |             |        |             |         |
| SCN         |                17 |  |             |        |             |        |             |         |
| WWP         |                18 |  |             |        |             |        |             |         |
| ADS         |                19 |  |             |        |             |        |             |         |
| YPN         |                20 |  |             |        |             |        |             |         |
| SAGE        |                21 |  |             |        |             |        |             |         |
| CMM         |                22 |  |             |        |             |        |             |         |
| ASPE        |                23 |  |             |        |             |        |             |         |
| ASPW        |                24 |  |             |        |             |        |             |         |
| LSG         |                25 |  |             |        |             |        |             |         |
| Pixel Count |           4401032 |  |             |        |             |        |             |         |
+-------------+-------------------+--+-------------+--------+-------------+--------+-------------+---------+

I tried the first answer below and it works, but doesn't necessarily solve the problem. Some of my patches of veg that need to be dissolved are pretty large. Therefore, I need an enormous neighborhood to eliminate the whole thing. Given this, it would seem I'm looking at using the raster calculator in an iterative way as well. So, now my question becomes, which is better, and if both, in what order?

For example, I could Nibble for a few iterations, then switch to the raster calculator and iterate that over some reasonable-sized neighborhood (not sure how big that would be - 10x10? 50x50) until I eliminated all the type 3 pixels. Or I could do things in the opposite way. Raster Calculator is a little faster, but does it do a better job with respect to landcover assessment if there is a large neighborhood?

share|improve this question

2 Answers 2

You could use the FocalStatistics tool in the raster calculator.

Something like:

Con("landcov" == 3, FocalStatistics(SetNull(("landcov"==2)|("landcov"==3),"landcov"), NbrRectangle(5,5), "MAJORITY"), "landcov")

What this does is for cells that have the landcover class you want to replace (Con("landcov" == 3...), replace that value with the most frequently occurring value in a 5x5 rectangular neighbourhood (FocalStatistics(..., NbrRectangle(5,5), "MAJORITY")) that is not class 2 or 3 (SetNull(("landcov"==2)|("landcov"==3),"landcov")).

share|improve this answer
1  
Hi, thanks for responding! I am trying to use your suggestion but I am having trouble building the expression in the raster calculator. I might not have been clear enough before, but I have many veg types that can conceptually be grouped into 3 classes. But, their raster values are 0-25. I can't reclass them into 1, 2, and 3 because it's critical to know what the specific veg type is of the cells that are reclassed via the Nibble or FocalStatistics tool. Given this, would you still try to write the code in the Raster Calculator as described above? –  mmallek Mar 13 '13 at 16:05
    
Okay, I think I figured out how to make a wider OR statement. Lots of parentheses, but it works. –  mmallek Mar 13 '13 at 17:01
up vote 1 down vote accepted

I also posted this question at the ESRI forums, and "curtvprice" figured out a really great solution. Here is a link to that exchange. I'm reposting it here too for those who use stackexchange and not the esri site.


UPDATE: it gets better, you can do this in one raster calculator expression that is easy to tweak if you change your mind about how to handle your classes. This all goes on one line -- I have separated it to make it easier to read:

Con("landcover","landcover",
  Nibble("landcover",SetNull("landcover","landcover","VALUE NOT IN (1,2)")),
  "VALUE IN (3,4,5)")
  1. Keep 3,4,5 cells as-is
  2. Expand 1,2 cells everywhere else
  3. All values not mentioned will be overwritten by values 1 or 2
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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