Introduction to Raster classes

Details about the GRASS GIS raster architecture can be found in the GRASS GIS 7 Programmer’s Manual: GRASS Raster Library.

PyGRASS uses 3 different raster classes, that respect the 3 different approaches of GRASS-C API. The classes use a standardized interface to keep methods consistent between them. The read access is row wise for RasterRow and RasterRowIO and additionally cached in the RowIO class. Only the first class writes sequentially. RowIO is row cached, RasterSegment is tile cached for reading and writing; therefore, random access is possible. Hence RasterRow and RasterRowIO should be used for fast (cached) row read access and RasterRow for fast sequential writing. RasterSegment should be used for random access. The classes are part of the raster module.

Class Name C library Read Write
RasterRow Raster library randomly sequentially
RasterRowIO RowIO library cached no
RasterSegment Segmentation library cached randomly

These classes share common methods and attributes to address common tasks as rename, remove, open, close, exist, is_open. In the following example we instantiate a RasterRow object.

>>> from grass.pygrass import raster
>>> elev = raster.RasterRow('elevation')
>>> elev.name
'elevation'
>>> print(elev)
elevation@PERMANENT
>>> elev.exist()
True
>>> elev.is_open()
False
>>> new = raster.RasterRow('new')
>>> new.exist()
False
>>> new.is_open()
False

We can rename the map:

>>> # setting the attribute
>>> new.name = 'new_map'
>>> print(new)
new_map
>>> # or using the rename methods
>>> new.rename('new')
>>> print(new)
new

RasterRow

The PyGRASS RasterRow class allow user to open maps row by row in either read or write mode using the Raster library. Reading and writing to the same map at the same time is not supported. For this functionality, please see the RasterSegment class. The RasterRow class allows map rows to be read in any order, but map rows can only be written in sequential order. Therefore, each row written to a map is added to the file as the last row.

>>> raster = reload(raster)
>>> elev = raster.RasterRow('elevation')
>>> # the private _cols attribute is set from the current region only when the map is open
>>> # the .info.cols attribute is set to total number of map cols only when the map is open
>>> # cols in .info.cols equals the number reported by r.info module
>>> elev._cols
>>> elev.info.cols
0
>>> elev.open()
>>> elev.is_open()
True
>>> elev._cols
200
>>> elev.info.cols
1500
>>> elev._rows
300
>>> # number of available rows/cols also can be determined by len()
>>> len(elev)
300
>>> len(elev[0])
200
>>> # we can read the elevation map, row by row
>>> for row in elev[:5]: print(row[:3])
[ 141.99613953  141.27848816  141.37904358]
[ 142.90461731  142.39450073  142.68611145]
[ 143.81854248  143.54707336  143.83972168]
[ 144.56524658  144.58493042  144.86477661]
[ 144.99488831  145.22894287  145.57142639]
>>> # we can open a new map in write mode
>>> new = raster.RasterRow('new')
>>> new.open('w', 'CELL')
>>> # for each elev row we can perform computation, and write the result into
>>> # the new map
>>> for row in elev:
...     new.put_row(row < 144)
...
>>> # close the maps
>>> new.close()
>>> elev.close()
>>> # check if the map exist
>>> new.exist()
True
>>> # we can open the map in read mode
>>> new.open('r')
>>> for row in new[:5]: print(row[:3])
[1 1 1]
[1 1 1]
[1 1 1]
[0 0 0]
[0 0 0]
>>> new.close()
>>> new.remove()
>>> new.exist()
False

RasterRowIO

The RasterRowIO class uses the GRASS RowIO library, and implements a row cache. The RasterRowIO class only supports reading rasters; because raster rows can only be written in sequential order, writing by row id is not supported by design. Hence, the RowIO lib can only be used to cache rows for reading, and any write access should use the RasterRow class.

>>> raster = reload(raster)
>>> elev = raster.RasterRowIO('elevation')
>>> elev.open('r')
>>> for row in elev[:5]: print(row[:3])
[ 141.99613953  141.27848816  141.37904358]
[ 142.90461731  142.39450073  142.68611145]
[ 143.81854248  143.54707336  143.83972168]
[ 144.56524658  144.58493042  144.86477661]
[ 144.99488831  145.22894287  145.57142639]
>>> elev.close()

RasterSegment

The RasterSegment class uses the GRASS Segmentation library. The class divides a raster map into small tiles stored on disk. Initialization of this class is therefore intensive. However, this class has lower memory requirements, as GRASS loads only currently-accessed tiles into memory. The segment library allow opening maps in a read-write mode.

>>> raster = reload(raster)
>>> elev = raster.RasterSegment('elevation')
>>> elev.open()
>>> for row in elev[:5]: print(row[:3])
[ 141.99613953  141.27848816  141.37904358]
[ 142.90461731  142.39450073  142.68611145]
[ 143.81854248  143.54707336  143.83972168]
[ 144.56524658  144.58493042  144.86477661]
[ 144.99488831  145.22894287  145.57142639]
>>> new = raster.RasterSegment('new')
>>> new.open('w', 'CELL')
>>> for irow, row in enumerate(elev):
...     new[irow] = row < 144
...
>>> for row in new[:5]: print(row[:3])
[1 1 1]
[1 1 1]
[1 1 1]
[0 0 0]
[0 0 0]

Due to the unique behavior of this class, the RasterSegment class defines two methods to read a map:

  • get_row calls the C function Segment_get_row() and returns a buffer object with the row.

    >>> # call explicitly the method
    >>> elev_row0 = elev.get_row(0)
    >>> # call implicitly the method
    >>> elev_row0 = elev[0]
    
  • get calls the C function Segment_get() and returns the value of the map cell.

    >>> # call explicitly the method
    >>> elev_val_0_0 = elev.get(0, 0)
    >>> # call implicitly the method
    >>> elev_val_0_0 = elev[0, 0]
    

Similarly, writing to a map uses two methods: put_row() to write a row and put() to write a single value to the map.

>>> # compare the cell value get using the ``get`` method, and take the first
>>> # value of the row with the ``get_row`` method
>>> # the methods are used internally by the index operators
>>> elev[0, 0] == elev[0][0]
True
>>> # write a new value to a cell,
>>> new[0, 0] = 10  # ``put`` is used internally by the index operators
>>> new[0, 0]
10
>>> new.close()
>>> new.exist()
True
>>> new.remove()
>>> elev.close()
>>> elev.remove()