Introduction to Raster classes¶
Details about the GRASS GIS raster architecture can be found in the GRASS GIS 8 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 functionSegment_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 functionSegment_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()