~ubuntu-branches/ubuntu/wily/grass/wily

« back to all changes in this revision

Viewing changes to lib/python/pygrass/raster/__init__.py

Tags: 7.0.0~rc1+ds1-1~exp1
* New upstream release candidate.
* Repack upstream tarball, remove precompiled Python objects.
* Add upstream metadata.
* Update gbp.conf and Vcs-Git URL to use the experimental branch.
* Update watch file for GRASS 7.0.
* Drop build dependencies for Tcl/Tk, add build dependencies:
  python-numpy, libnetcdf-dev, netcdf-bin, libblas-dev, liblapack-dev
* Update Vcs-Browser URL to use cgit instead of gitweb.
* Update paths to use grass70.
* Add configure options: --with-netcdf, --with-blas, --with-lapack,
  remove --with-tcltk-includes.
* Update patches for GRASS 7.
* Update copyright file, changes:
  - Update copyright years
  - Group files by license
  - Remove unused license sections
* Add patches for various typos.
* Fix desktop file with patch instead of d/rules.
* Use minimal dh rules.
* Bump Standards-Version to 3.9.6, no changes.
* Use dpkg-maintscript-helper to replace directories with symlinks.
  (closes: #776349)
* Update my email to use @debian.org address.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
from __future__ import (nested_scopes, generators, division, absolute_import,
 
3
                        with_statement, print_function, unicode_literals)
 
4
import os
 
5
import ctypes
 
6
import numpy as np
 
7
 
 
8
#
 
9
# import GRASS modules
 
10
#
 
11
from grass.script import fatal, warning
 
12
from grass.script import core as grasscore
 
13
 
 
14
import grass.lib.gis as libgis
 
15
import grass.lib.raster as libraster
 
16
import grass.lib.rowio as librowio
 
17
 
 
18
libgis.G_gisinit('')
 
19
 
 
20
#
 
21
# import pygrass modules
 
22
#
 
23
from grass.pygrass.errors import OpenError, must_be_open
 
24
from grass.pygrass.gis.region import Region
 
25
from grass.pygrass import utils
 
26
 
 
27
#
 
28
# import raster classes
 
29
#
 
30
from grass.pygrass.raster.abstract import RasterAbstractBase
 
31
from grass.pygrass.raster.raster_type import TYPE as RTYPE, RTYPE_STR
 
32
from grass.pygrass.raster.buffer import Buffer
 
33
from grass.pygrass.raster.segment import Segment
 
34
from grass.pygrass.raster.rowio import RowIO
 
35
 
 
36
 
 
37
class RasterRow(RasterAbstractBase):
 
38
    """Raster_row_access": Inherits: "Raster_abstract_base" and implements
 
39
    the default row access of the Rast library.
 
40
 
 
41
        * Implements row access using row id
 
42
        * The get_row() method must accept a Row object as argument that will
 
43
          be used for value storage, so no new buffer will be allocated
 
44
        * Implements sequential writing of rows
 
45
        * Implements indexed value read only access using the [row][col]
 
46
          operator
 
47
        * Implements the [row] read method that returns a new Row object
 
48
        * Writing is limited using the put_row() method which accepts a
 
49
          Row as argument
 
50
        * No mathematical operation like __add__ and stuff for the Raster
 
51
          object (only for rows), since r.mapcalc is more sophisticated and
 
52
          faster
 
53
 
 
54
    Examples:
 
55
 
 
56
    >>> elev = RasterRow('elevation')
 
57
    >>> elev.exist()
 
58
    True
 
59
    >>> elev.is_open()
 
60
    False
 
61
    >>> elev.open()
 
62
    >>> elev.is_open()
 
63
    True
 
64
    >>> elev.has_cats()
 
65
    False
 
66
    >>> elev.mode
 
67
    u'r'
 
68
    >>> elev.mtype
 
69
    'FCELL'
 
70
    >>> elev.num_cats()
 
71
    0
 
72
    >>> elev.info.range
 
73
    (56, 156)
 
74
    >>> elev.info
 
75
    elevation@
 
76
    rows: 1350
 
77
    cols: 1500
 
78
    north: 228500.0 south: 215000.0 nsres:10.0
 
79
    east:  645000.0 west: 630000.0 ewres:10.0
 
80
    range: 56, 156
 
81
    proj: 99
 
82
    <BLANKLINE>
 
83
 
 
84
    Each Raster map have an attribute call ``cats`` that allow user
 
85
    to interact with the raster categories.
 
86
 
 
87
    >>> land = RasterRow('geology')
 
88
    >>> land.open()
 
89
    >>> land.cats               # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
 
90
    [('Zml', 1, None),
 
91
     ...
 
92
     ('Tpyw', 1832, None)]
 
93
 
 
94
    Open a raster map using the *with statement*:
 
95
 
 
96
    >>> with RasterRow('elevation') as elev:
 
97
    ...     for row in elev[:3]:
 
98
    ...         row[:4]
 
99
    ...
 
100
    Buffer([ 141.99613953,  141.27848816,  141.37904358,  142.29821777], dtype=float32)
 
101
    Buffer([ 142.90461731,  142.39450073,  142.68611145,  143.59086609], dtype=float32)
 
102
    Buffer([ 143.81854248,  143.54707336,  143.83972168,  144.59527588], dtype=float32)
 
103
    >>> elev.is_open()
 
104
    False
 
105
 
 
106
    """
 
107
    def __init__(self, name, mapset='', *args, **kargs):
 
108
        super(RasterRow, self).__init__(name, mapset, *args, **kargs)
 
109
 
 
110
    # mode = "r", method = "row",
 
111
    @must_be_open
 
112
    def get_row(self, row, row_buffer=None):
 
113
        """Private method that return the row using the read mode
 
114
        call the `Rast_get_row` C function.
 
115
 
 
116
        :param row: the number of row to obtain
 
117
        :type row: int
 
118
        :param row_buffer: Buffer object instance with the right dim and type
 
119
        :type row_buffer: Buffer
 
120
 
 
121
        >>> elev = RasterRow('elevation')
 
122
        >>> elev.open()
 
123
        >>> elev[0]                 # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
 
124
        Buffer([ 141.99613953, 141.27848816,  141.37904358, ..., 58.40825272,
 
125
                 58.30711365,  58.18310547], dtype=float32)
 
126
        >>> elev.get_row(0)         # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
 
127
        Buffer([ 141.99613953, 141.27848816, 141.37904358, ..., 58.40825272,
 
128
                 58.30711365, 58.18310547], dtype=float32)
 
129
 
 
130
        """
 
131
        if row_buffer is None:
 
132
            row_buffer = Buffer((self._cols,), self.mtype)
 
133
        libraster.Rast_get_row(self._fd, row_buffer.p, row, self._gtype)
 
134
        return row_buffer
 
135
 
 
136
    @must_be_open
 
137
    def put_row(self, row):
 
138
        """Private method to write the row sequentially.
 
139
 
 
140
        :param row: a Row object to insert into raster
 
141
        :type row: Buffer object
 
142
        """
 
143
        libraster.Rast_put_row(self._fd, row.p, self._gtype)
 
144
 
 
145
    def open(self, mode=None, mtype=None, overwrite=None):
 
146
        """Open the raster if exist or created a new one.
 
147
 
 
148
        :param str mode: Specify if the map will be open with read or write mode
 
149
                     ('r', 'w')
 
150
        :param str type: If a new map is open, specify the type of the map(`CELL`,
 
151
                     `FCELL`, `DCELL`)
 
152
        :param bool overwrite: Use this flag to set the overwrite mode of existing
 
153
                          raster maps
 
154
 
 
155
        if the map already exist, automatically check the type and set:
 
156
 
 
157
            * self.mtype
 
158
 
 
159
        Set all the privite, attributes:
 
160
 
 
161
            * self._fd;
 
162
            * self._gtype
 
163
            * self._rows and self._cols
 
164
 
 
165
        """
 
166
        self.mode = mode if mode else self.mode
 
167
        self.mtype = mtype if mtype else self.mtype
 
168
        self.overwrite = overwrite if overwrite is not None else self.overwrite
 
169
 
 
170
        if self.mode == 'r':
 
171
            if self.exist():
 
172
                self.info.read()
 
173
                self.cats.mtype = self.mtype
 
174
                self.cats.read()
 
175
                self.hist.read()
 
176
                self._fd = libraster.Rast_open_old(self.name, self.mapset)
 
177
                self._gtype = libraster.Rast_get_map_type(self._fd)
 
178
                self.mtype = RTYPE_STR[self._gtype]
 
179
            else:
 
180
                str_err = _("The map does not exist, I can't open in 'r' mode")
 
181
                raise OpenError(str_err)
 
182
        elif self.mode == 'w':
 
183
            if self.exist():
 
184
                if not self.overwrite:
 
185
                    str_err = _("Raster map <{0}> already exists"
 
186
                                " and will be not overwritten")
 
187
                    raise OpenError(str_err.format(self))
 
188
            if self._gtype is None:
 
189
                raise OpenError(_("Raster type not defined"))
 
190
            self._fd = libraster.Rast_open_new(self.name, self._gtype)
 
191
        else:
 
192
            raise OpenError("Open mode: %r not supported,"
 
193
                            " valid mode are: r, w")
 
194
        # read rows and cols from the active region
 
195
        self._rows = libraster.Rast_window_rows()
 
196
        self._cols = libraster.Rast_window_cols()
 
197
 
 
198
 
 
199
class RasterRowIO(RasterRow):
 
200
    """Raster_row_cache_access": The same as "Raster_row_access" but uses
 
201
    the ROWIO library for cached row access
 
202
    """
 
203
    def __init__(self, name, *args, **kargs):
 
204
        self.rowio = RowIO()
 
205
        super(RasterRowIO, self).__init__(name, *args, **kargs)
 
206
 
 
207
    def open(self, mode=None, mtype=None, overwrite=False):
 
208
        """Open the raster if exist or created a new one.
 
209
 
 
210
        :param mode: specify if the map will be open with read or write mode
 
211
                     ('r', 'w')
 
212
        :type mode: str
 
213
        :param type: if a new map is open, specify the type of the map(`CELL`,
 
214
                     `FCELL`, `DCELL`)
 
215
        :type type: str
 
216
        :param overwrite: use this flag to set the overwrite mode of existing
 
217
                          raster maps
 
218
        :type overwrite: bool
 
219
        """
 
220
        super(RasterRowIO, self).open(mode, mtype, overwrite)
 
221
        self.rowio.open(self._fd, self._rows, self._cols, self.mtype)
 
222
 
 
223
    @must_be_open
 
224
    def close(self):
 
225
        """Function to close the raster"""
 
226
        self.rowio.release()
 
227
        libraster.Rast_close(self._fd)
 
228
        # update rows and cols attributes
 
229
        self._rows = None
 
230
        self._cols = None
 
231
        self._fd = None
 
232
 
 
233
    @must_be_open
 
234
    def get_row(self, row, row_buffer=None):
 
235
        """This method returns the row using:
 
236
 
 
237
            * the read mode and
 
238
            * `rowcache` method
 
239
 
 
240
        :param row: the number of row to obtain
 
241
        :type row: int
 
242
        :param row_buffer: Specify the Buffer object that will be instantiate
 
243
        :type row_buffer: Buffer object
 
244
        """
 
245
        if row_buffer is None:
 
246
            row_buffer = Buffer((self._cols,), self.mtype)
 
247
        rowio_buf = librowio.Rowio_get(ctypes.byref(self.rowio.c_rowio), row)
 
248
        ctypes.memmove(row_buffer.p, rowio_buf, self.rowio.row_size)
 
249
        return row_buffer
 
250
 
 
251
 
 
252
class RasterSegment(RasterAbstractBase):
 
253
    """Raster_segment_access": Inherits "Raster_abstract_base" and uses the
 
254
    segment library for cached randomly reading and writing access.
 
255
 
 
256
        * Implements the [row][col] operator for read and write access using
 
257
          Segment_get() and Segment_put() functions internally
 
258
        * Implements row read and write access with the [row] operator using
 
259
          Segment_get_row() Segment_put_row() internally
 
260
        * Implements the get_row() and put_row() method  using
 
261
          Segment_get_row() Segment_put_row() internally
 
262
        * Implements the flush_segment() method
 
263
        * Implements the copying of raster maps to segments and vice verse
 
264
        * Overwrites the open and close methods
 
265
        * No mathematical operation like __add__ and stuff for the Raster
 
266
          object (only for rows), since r.mapcalc is more sophisticated and
 
267
          faster
 
268
 
 
269
    """
 
270
    def __init__(self, name, srows=64, scols=64, maxmem=100,
 
271
                 *args, **kargs):
 
272
        self.segment = Segment(srows, scols, maxmem)
 
273
        super(RasterSegment, self).__init__(name, *args, **kargs)
 
274
 
 
275
    def _get_mode(self):
 
276
        return self._mode
 
277
 
 
278
    def _set_mode(self, mode):
 
279
        if mode and mode.lower() not in ('r', 'w', 'rw'):
 
280
            str_err = _("Mode type: {0} not supported ('r', 'w','rw')")
 
281
            raise ValueError(str_err.format(mode))
 
282
        self._mode = mode
 
283
 
 
284
    mode = property(fget=_get_mode, fset=_set_mode,
 
285
                    doc="Set or obtain the opening mode of raster")
 
286
 
 
287
    def __setitem__(self, key, row):
 
288
        """Return the row of Raster object, slice allowed."""
 
289
        if isinstance(key, slice):
 
290
            #Get the start, stop, and step from the slice
 
291
            return [self.put_row(ii, row)
 
292
                    for ii in range(*key.indices(len(self)))]
 
293
        elif isinstance(key, tuple):
 
294
            x, y = key
 
295
            return self.put(x, y, row)
 
296
        elif isinstance(key, int):
 
297
            if key < 0:  # Handle negative indices
 
298
                key += self._rows
 
299
            if key >= self._rows:
 
300
                raise IndexError(_("Index out of range: %r.") % key)
 
301
            return self.put_row(key, row)
 
302
        else:
 
303
            raise TypeError("Invalid argument type.")
 
304
 
 
305
    @must_be_open
 
306
    def map2segment(self):
 
307
        """Transform an existing map to segment file.
 
308
        """
 
309
        row_buffer = Buffer((self._cols), self.mtype)
 
310
        for row in range(self._rows):
 
311
            libraster.Rast_get_row(
 
312
                self._fd, row_buffer.p, row, self._gtype)
 
313
            self.segment.put_row(row, row_buffer)
 
314
 
 
315
    @must_be_open
 
316
    def segment2map(self):
 
317
        """Transform the segment file to a map.
 
318
        """
 
319
        row_buffer = Buffer((self._cols), self.mtype)
 
320
        for row in range(self._rows):
 
321
            row_buffer = self.segment.get_row(row, row_buffer)
 
322
            libraster.Rast_put_row(self._fd, row_buffer.p, self._gtype)
 
323
 
 
324
    @must_be_open
 
325
    def get_row(self, row, row_buffer=None):
 
326
        """Return the row using the `segment.get_row` method
 
327
 
 
328
        :param row: specify the row number
 
329
        :type row: int
 
330
        :param row_buffer: specify the Buffer object that will be instantiate
 
331
        :type row_buffer: Buffer object
 
332
        """
 
333
        if row_buffer is None:
 
334
            row_buffer = Buffer((self._cols), self.mtype)
 
335
        return self.segment.get_row(row, row_buffer)
 
336
 
 
337
    @must_be_open
 
338
    def put_row(self, row, row_buffer):
 
339
        """Write the row using the `segment.put_row` method
 
340
 
 
341
        :param row: a Row object to insert into raster
 
342
        :type row: Buffer object
 
343
        """
 
344
        self.segment.put_row(row, row_buffer)
 
345
 
 
346
    @must_be_open
 
347
    def get(self, row, col):
 
348
        """Return the map value using the `segment.get` method
 
349
 
 
350
        :param row: Specify the row number
 
351
        :type row: int
 
352
        :param col: Specify the column number
 
353
        :type col: int
 
354
        """
 
355
        return self.segment.get(row, col)
 
356
 
 
357
    @must_be_open
 
358
    def put(self, row, col, val):
 
359
        """Write the value to the map using the `segment.put` method
 
360
 
 
361
        :param row: Specify the row number
 
362
        :type row: int
 
363
        :param col: Specify the column number
 
364
        :type col: int
 
365
        :param val: Specify the value that will be write to the map cell
 
366
        :type val: value
 
367
        """
 
368
        self.segment.val.value = val
 
369
        self.segment.put(row, col)
 
370
 
 
371
    def open(self, mode=None, mtype=None, overwrite=None):
 
372
        """Open the map, if the map already exist: determine the map type
 
373
        and copy the map to the segment files;
 
374
        else, open a new segment map.
 
375
 
 
376
        :param mode: specify if the map will be open with read, write or
 
377
                     read/write mode ('r', 'w', 'rw')
 
378
        :type mode: str
 
379
        :param mtype: specify the map type, valid only for new maps: CELL,
 
380
                      FCELL, DCELL
 
381
        :type mtype: str
 
382
        :param overwrite: use this flag to set the overwrite mode of existing
 
383
                          raster maps
 
384
        :type overwrite: bool
 
385
        """
 
386
        # read rows and cols from the active region
 
387
        self._rows = libraster.Rast_window_rows()
 
388
        self._cols = libraster.Rast_window_cols()
 
389
 
 
390
        self.mode = mode if mode else self.mode
 
391
        self.mtype = mtype if mtype else self.mtype
 
392
        self.overwrite = overwrite if overwrite is not None else self.overwrite
 
393
 
 
394
        if self.exist():
 
395
            self.info.read()
 
396
            self.cats.mtype = self.mtype
 
397
            self.cats.read()
 
398
            self.hist.read()
 
399
            if ((self.mode == "w" or self.mode == "rw") and
 
400
                    self.overwrite is False):
 
401
                str_err = _("Raster map <{0}> already exists. Use overwrite.")
 
402
                fatal(str_err.format(self))
 
403
 
 
404
            # We copy the raster map content into the segments
 
405
            if self.mode == "rw" or self.mode == "r":
 
406
                self._fd = libraster.Rast_open_old(self.name, self.mapset)
 
407
                self._gtype = libraster.Rast_get_map_type(self._fd)
 
408
                self.mtype = RTYPE_STR[self._gtype]
 
409
                # initialize the segment, I need to determine the mtype of the
 
410
                # map
 
411
                # before to open the segment
 
412
                self.segment.open(self)
 
413
                self.map2segment()
 
414
                self.segment.flush()
 
415
                self.cats.read(self)
 
416
                self.hist.read(self.name)
 
417
 
 
418
                if self.mode == "rw":
 
419
                    warning(_(WARN_OVERWRITE.format(self)))
 
420
                    # Close the file descriptor and open it as new again
 
421
                    libraster.Rast_close(self._fd)
 
422
                    self._fd = libraster.Rast_open_new(
 
423
                        self.name, self._gtype)
 
424
            # Here we simply overwrite the existing map without content copying
 
425
            elif self.mode == "w":
 
426
                #warning(_(WARN_OVERWRITE.format(self)))
 
427
                self._gtype = RTYPE[self.mtype]['grass type']
 
428
                self.segment.open(self)
 
429
                self._fd = libraster.Rast_open_new(self.name, self._gtype)
 
430
        else:
 
431
            if self.mode == "r":
 
432
                str_err = _("Raster map <{0}> does not exists")
 
433
                raise OpenError(str_err.format(self.name))
 
434
 
 
435
            self._gtype = RTYPE[self.mtype]['grass type']
 
436
            self.segment.open(self)
 
437
            self._fd = libraster.Rast_open_new(self.name, self._gtype)
 
438
 
 
439
    @must_be_open
 
440
    def close(self, rm_temp_files=True):
 
441
        """Close the map, copy the segment files to the map.
 
442
 
 
443
        :param rm_temp_files: if True all the segments file will be removed
 
444
        :type rm_temp_files: bool
 
445
        """
 
446
        if self.mode == "w" or self.mode == "rw":
 
447
            self.segment.flush()
 
448
            self.segment2map()
 
449
        if rm_temp_files:
 
450
            self.segment.close()
 
451
        else:
 
452
            self.segment.release()
 
453
        libraster.Rast_close(self._fd)
 
454
        # update rows and cols attributes
 
455
        self._rows = None
 
456
        self._cols = None
 
457
        self._fd = None
 
458
 
 
459
 
 
460
def random_map_only_columns(mapname, mtype, overwrite=True, factor=100):
 
461
    region = Region()
 
462
    random_map = RasterRow(mapname)
 
463
    row_buf = Buffer((region.cols, ), mtype,
 
464
                     buffer=(np.random.random(region.cols,) * factor).data)
 
465
    random_map.open('w', mtype, overwrite)
 
466
    for _ in range(region.rows):
 
467
        random_map.put_row(row_buf)
 
468
    random_map.close()
 
469
    return random_map
 
470
 
 
471
 
 
472
def random_map(mapname, mtype, overwrite=True, factor=100):
 
473
    region = Region()
 
474
    random_map = RasterRow(mapname)
 
475
    random_map.open('w', mtype, overwrite)
 
476
    for _ in range(region.rows):
 
477
        row_buf = Buffer((region.cols, ), mtype,
 
478
                         buffer=(np.random.random(region.cols,) * factor).data)
 
479
        random_map.put_row(row_buf)
 
480
    random_map.close()
 
481
    return random_map