array.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. """
  2. Functions to use GRASS 2D and 3D rasters with NumPy.
  3. Usage:
  4. >>> from __future__ import print_function
  5. >>> import grass.script as gs
  6. >>> from grass.script import array as garray
  7. >>>
  8. >>> # We create a temporary region that is only valid in this python session
  9. ... gs.use_temp_region()
  10. >>> gs.run_command("g.region", n=80, e=120, t=60, s=0, w=0, b=0, res=20, res3=20)
  11. 0
  12. >>>
  13. >>> # Lets create a raster map numpy array
  14. ... # based at the current region settings
  15. ... map2d_1 = garray.array()
  16. >>>
  17. >>> # Write some data
  18. ... for y in range(map2d_1.shape[0]):
  19. ... for x in range(map2d_1.shape[1]):
  20. ... map2d_1[y,x] = y + x
  21. ...
  22. >>> # Lets have a look at the array
  23. ... print(map2d_1)
  24. [[0. 1. 2. 3. 4. 5.]
  25. [1. 2. 3. 4. 5. 6.]
  26. [2. 3. 4. 5. 6. 7.]
  27. [3. 4. 5. 6. 7. 8.]]
  28. >>> # This will write the numpy array as GRASS raster map
  29. ... # with name map2d_1
  30. ... map2d_1.write(mapname="map2d_1", overwrite=True)
  31. 0
  32. >>>
  33. >>> # We create a new array from raster map2d_1 to modify it
  34. ... map2d_2 = garray.array(mapname="map2d_1")
  35. >>> # Don't do map2d_2 = map2d_1 % 3
  36. ... # because: this will overwrite the internal temporary filename
  37. ... map2d_2 %= 3
  38. >>> # Show the result
  39. ... print(map2d_2)
  40. [[0. 1. 2. 0. 1. 2.]
  41. [1. 2. 0. 1. 2. 0.]
  42. [2. 0. 1. 2. 0. 1.]
  43. [0. 1. 2. 0. 1. 2.]]
  44. >>> # Write the result as new raster map with name map2d_2
  45. ... map2d_2.write(mapname="map2d_2", overwrite=True)
  46. 0
  47. >>>
  48. >>> # Here we create a 3D raster map numpy array
  49. ... # based in the current region settings
  50. ... map3d_1 = garray.array3d()
  51. >>>
  52. >>> # Write some data
  53. ... # Note: the 3D array has map[depth][row][column] order
  54. ... for z in range(map3d_1.shape[0]):
  55. ... for y in range(map3d_1.shape[1]):
  56. ... for x in range(map3d_1.shape[2]):
  57. ... map3d_1[z,y,x] = z + y + x
  58. ...
  59. >>> # Lets have a look at the 3D array
  60. ... print(map3d_1)
  61. [[[ 0. 1. 2. 3. 4. 5.]
  62. [ 1. 2. 3. 4. 5. 6.]
  63. [ 2. 3. 4. 5. 6. 7.]
  64. [ 3. 4. 5. 6. 7. 8.]]
  65. <BLANKLINE>
  66. [[ 1. 2. 3. 4. 5. 6.]
  67. [ 2. 3. 4. 5. 6. 7.]
  68. [ 3. 4. 5. 6. 7. 8.]
  69. [ 4. 5. 6. 7. 8. 9.]]
  70. <BLANKLINE>
  71. [[ 2. 3. 4. 5. 6. 7.]
  72. [ 3. 4. 5. 6. 7. 8.]
  73. [ 4. 5. 6. 7. 8. 9.]
  74. [ 5. 6. 7. 8. 9. 10.]]]
  75. >>> # This will write the numpy array as GRASS 3D raster map
  76. ... # with name map3d_1
  77. ... map3d_1.write(mapname="map3d_1", overwrite=True)
  78. 0
  79. >>> # We create a new 3D array from 3D raster map3d_1 to modify it
  80. ... map3d_2 = garray.array3d(mapname="map3d_1")
  81. >>> # Don't do map3d_2 = map3d_1 % 3
  82. ... # because: this will overwrite the internal temporary filename
  83. ... map3d_2 %= 3
  84. >>> # Show the result
  85. ... print(map3d_2)
  86. [[[0. 1. 2. 0. 1. 2.]
  87. [1. 2. 0. 1. 2. 0.]
  88. [2. 0. 1. 2. 0. 1.]
  89. [0. 1. 2. 0. 1. 2.]]
  90. <BLANKLINE>
  91. [[1. 2. 0. 1. 2. 0.]
  92. [2. 0. 1. 2. 0. 1.]
  93. [0. 1. 2. 0. 1. 2.]
  94. [1. 2. 0. 1. 2. 0.]]
  95. <BLANKLINE>
  96. [[2. 0. 1. 2. 0. 1.]
  97. [0. 1. 2. 0. 1. 2.]
  98. [1. 2. 0. 1. 2. 0.]
  99. [2. 0. 1. 2. 0. 1.]]]
  100. >>> # Write the result as new 3D raster map with name map3d_2
  101. ... map3d_2.write(mapname="map3d_2", overwrite=True)
  102. 0
  103. (C) 2010-2012 by Glynn Clements and the GRASS Development Team
  104. This program is free software under the GNU General Public
  105. License (>=v2). Read the file COPYING that comes with GRASS
  106. for details.
  107. .. sectionauthor:: Glynn Clements
  108. """
  109. from __future__ import absolute_import
  110. import sys
  111. import numpy
  112. from .utils import try_remove
  113. from . import core as gcore
  114. from grass.exceptions import CalledModuleError
  115. ###############################################################################
  116. class _tempfile(object):
  117. def __init__(self, env=None):
  118. self.filename = gcore.tempfile(env=env)
  119. def __del__(self):
  120. try_remove(self.filename)
  121. ###############################################################################
  122. class array(numpy.memmap):
  123. def __new__(cls, mapname=None, null=None, dtype=numpy.double, env=None):
  124. """Define new numpy array
  125. :param cls:
  126. :param dtype: data type (default: numpy.double)
  127. :param env: environment
  128. """
  129. reg = gcore.region(env=env)
  130. r = reg['rows']
  131. c = reg['cols']
  132. shape = (r, c)
  133. tempfile = _tempfile(env)
  134. if mapname:
  135. kind = numpy.dtype(dtype).kind
  136. size = numpy.dtype(dtype).itemsize
  137. if kind == 'f':
  138. flags = 'f'
  139. elif kind in 'biu':
  140. flags = 'i'
  141. else:
  142. raise ValueError(_('Invalid kind <%s>') % kind)
  143. if size not in [1, 2, 4, 8]:
  144. raise ValueError(_('Invalid size <%d>') % size)
  145. gcore.run_command(
  146. 'r.out.bin',
  147. flags=flags,
  148. input=mapname,
  149. output=tempfile.filename,
  150. bytes=size,
  151. null=null,
  152. quiet=True,
  153. overwrite=True,
  154. env=env)
  155. self = numpy.memmap.__new__(
  156. cls,
  157. filename=tempfile.filename,
  158. dtype=dtype,
  159. mode='r+',
  160. shape=shape)
  161. self.tempfile = tempfile
  162. self.filename = tempfile.filename
  163. self._env = env
  164. return self
  165. def read(self, mapname, null=None):
  166. """Read raster map into array
  167. :param str mapname: name of raster map to be read
  168. :param null: null value
  169. :return: 0 on success
  170. :return: non-zero code on failure
  171. .. deprecated:: 7.1
  172. Instead reading the map after creating the array,
  173. pass the map name in the array constructor.
  174. """
  175. if sys.platform == 'win32':
  176. gcore.warning(_("grass.script.array.read is deprecated and does not"
  177. " work on MS Windows, pass raster name in the constructor"))
  178. kind = self.dtype.kind
  179. size = self.dtype.itemsize
  180. if kind == 'f':
  181. flags = 'f'
  182. elif kind in 'biu':
  183. flags = 'i'
  184. else:
  185. raise ValueError(_('Invalid kind <%s>') % kind)
  186. if size not in [1, 2, 4, 8]:
  187. raise ValueError(_('Invalid size <%d>') % size)
  188. try:
  189. gcore.run_command(
  190. 'r.out.bin',
  191. flags=flags,
  192. input=mapname,
  193. output=self.filename,
  194. bytes=size,
  195. null=null,
  196. quiet=True,
  197. overwrite=True)
  198. except CalledModuleError:
  199. return 1
  200. else:
  201. return 0
  202. def write(self, mapname, title=None, null=None, overwrite=None, quiet=None):
  203. """Write array into raster map
  204. :param str mapname: name for raster map
  205. :param str title: title for raster map
  206. :param null: null value
  207. :param bool overwrite: True for overwritting existing raster maps
  208. :return: 0 on success
  209. :return: non-zero code on failure
  210. """
  211. kind = self.dtype.kind
  212. size = self.dtype.itemsize
  213. if kind == 'f':
  214. if size == 4:
  215. flags = 'f'
  216. elif size == 8:
  217. flags = 'd'
  218. else:
  219. raise ValueError(_('Invalid FP size <%d>') % size)
  220. size = None
  221. elif kind in 'biu':
  222. if size not in [1, 2, 4]:
  223. raise ValueError(_('Invalid integer size <%d>') % size)
  224. flags = None
  225. else:
  226. raise ValueError(_('Invalid kind <%s>') % kind)
  227. reg = gcore.region(env=self._env)
  228. try:
  229. gcore.run_command(
  230. 'r.in.bin',
  231. flags=flags,
  232. input=self.filename,
  233. output=mapname,
  234. title=title,
  235. bytes=size,
  236. anull=null,
  237. overwrite=overwrite,
  238. quiet=quiet,
  239. north=reg['n'],
  240. south=reg['s'],
  241. east=reg['e'],
  242. west=reg['w'],
  243. rows=reg['rows'],
  244. cols=reg['cols'],
  245. env=self._env)
  246. except CalledModuleError:
  247. return 1
  248. else:
  249. return 0
  250. ###############################################################################
  251. class array3d(numpy.memmap):
  252. def __new__(cls, mapname=None, null=None, dtype=numpy.double, env=None):
  253. """Define new 3d numpy array
  254. :param cls:
  255. :param dtype: data type (default: numpy.double)
  256. :param env: environment
  257. """
  258. reg = gcore.region(True)
  259. r = reg['rows3']
  260. c = reg['cols3']
  261. d = reg['depths']
  262. shape = (d, r, c)
  263. tempfile = _tempfile()
  264. if mapname:
  265. kind = numpy.dtype(dtype).kind
  266. size = numpy.dtype(dtype).itemsize
  267. if kind == 'f':
  268. flags = None # default is double
  269. elif kind in 'biu':
  270. flags = 'i'
  271. else:
  272. raise ValueError(_('Invalid kind <%s>') % kind)
  273. if size not in [1, 2, 4, 8]:
  274. raise ValueError(_('Invalid size <%d>') % size)
  275. gcore.run_command(
  276. 'r3.out.bin',
  277. flags=flags,
  278. input=mapname,
  279. output=tempfile.filename,
  280. bytes=size,
  281. null=null,
  282. quiet=True,
  283. overwrite=True,
  284. env=env)
  285. self = numpy.memmap.__new__(
  286. cls,
  287. filename=tempfile.filename,
  288. dtype=dtype,
  289. mode='r+',
  290. shape=shape)
  291. self.tempfile = tempfile
  292. self.filename = tempfile.filename
  293. self._env = env
  294. return self
  295. def read(self, mapname, null=None):
  296. """Read 3D raster map into array
  297. :param str mapname: name of 3D raster map to be read
  298. :param null: null value
  299. :return: 0 on success
  300. :return: non-zero code on failure
  301. .. deprecated:: 7.1
  302. Instead reading the map after creating the array,
  303. pass the map name in the array constructor.
  304. """
  305. if sys.platform == 'win32':
  306. gcore.warning(_("grass.script.array3d.read is deprecated and does not"
  307. " work on MS Windows, pass 3D raster name in the constructor"))
  308. kind = self.dtype.kind
  309. size = self.dtype.itemsize
  310. if kind == 'f':
  311. flags = None # default is double
  312. elif kind in 'biu':
  313. flags = 'i'
  314. else:
  315. raise ValueError(_('Invalid kind <%s>') % kind)
  316. if size not in [1, 2, 4, 8]:
  317. raise ValueError(_('Invalid size <%d>') % size)
  318. try:
  319. gcore.run_command(
  320. 'r3.out.bin',
  321. flags=flags,
  322. input=mapname,
  323. output=self.filename,
  324. bytes=size,
  325. null=null,
  326. quiet=True,
  327. overwrite=True)
  328. except CalledModuleError:
  329. return 1
  330. else:
  331. return 0
  332. def write(self, mapname, null=None, overwrite=None, quiet=None):
  333. """Write array into 3D raster map
  334. :param str mapname: name for 3D raster map
  335. :param null: null value
  336. :param bool overwrite: True for overwriting existing raster maps
  337. :return: 0 on success
  338. :return: non-zero code on failure
  339. """
  340. kind = self.dtype.kind
  341. size = self.dtype.itemsize
  342. flags = None
  343. if kind == 'f':
  344. if size != 4 and size != 8:
  345. raise ValueError(_('Invalid FP size <%d>') % size)
  346. elif kind in 'biu':
  347. if size not in [1, 2, 4, 8]:
  348. raise ValueError(_('Invalid integer size <%d>') % size)
  349. flags = 'i'
  350. else:
  351. raise ValueError(_('Invalid kind <%s>') % kind)
  352. reg = gcore.region(True, env=self._env)
  353. try:
  354. gcore.run_command(
  355. 'r3.in.bin',
  356. flags=flags,
  357. input=self.filename,
  358. output=mapname,
  359. bytes=size,
  360. null=null,
  361. overwrite=overwrite,
  362. quiet=quiet,
  363. north=reg['n'],
  364. south=reg['s'],
  365. top=reg['t'],
  366. bottom=reg['b'],
  367. east=reg['e'],
  368. west=reg['w'],
  369. depths=reg['depths'],
  370. rows=reg['rows3'],
  371. cols=reg['cols3'],
  372. env=self._env)
  373. except CalledModuleError:
  374. return 1
  375. else:
  376. return 0