__init__.py 20 KB

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