array.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  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 gscript
  6. >>> from grass.script import array as garray
  7. >>>
  8. >>> # We create a temporary region that is only valid in this python session
  9. ... gscript.use_temp_region()
  10. >>> gscript.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):
  118. self.filename = gcore.tempfile()
  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):
  124. """Define new numpy array
  125. :param cls:
  126. :param dtype: data type (default: numpy.double)
  127. """
  128. reg = gcore.region()
  129. r = reg['rows']
  130. c = reg['cols']
  131. shape = (r, c)
  132. tempfile = _tempfile()
  133. if mapname:
  134. kind = numpy.dtype(dtype).kind
  135. size = numpy.dtype(dtype).itemsize
  136. if kind == 'f':
  137. flags = 'f'
  138. elif kind in 'biu':
  139. flags = 'i'
  140. else:
  141. raise ValueError(_('Invalid kind <%s>') % kind)
  142. if size not in [1, 2, 4, 8]:
  143. raise ValueError(_('Invalid size <%d>') % size)
  144. gcore.run_command(
  145. 'r.out.bin',
  146. flags=flags,
  147. input=mapname,
  148. output=tempfile.filename,
  149. bytes=size,
  150. null=null,
  151. quiet=True,
  152. overwrite=True)
  153. self = numpy.memmap.__new__(
  154. cls,
  155. filename=tempfile.filename,
  156. dtype=dtype,
  157. mode='r+',
  158. shape=shape)
  159. self.tempfile = tempfile
  160. self.filename = tempfile.filename
  161. return self
  162. def read(self, mapname, null=None):
  163. """Read raster map into array
  164. :param str mapname: name of raster map to be read
  165. :param null: null value
  166. :return: 0 on success
  167. :return: non-zero code on failure
  168. .. deprecated:: 7.1
  169. Instead reading the map after creating the array,
  170. pass the map name in the array constructor.
  171. """
  172. if sys.platform == 'win32':
  173. gcore.warning(_("grass.script.array.read is deprecated and does not"
  174. " work on MS Windows, pass raster name in the constructor"))
  175. kind = self.dtype.kind
  176. size = self.dtype.itemsize
  177. if kind == 'f':
  178. flags = 'f'
  179. elif kind in 'biu':
  180. flags = 'i'
  181. else:
  182. raise ValueError(_('Invalid kind <%s>') % kind)
  183. if size not in [1, 2, 4, 8]:
  184. raise ValueError(_('Invalid size <%d>') % size)
  185. try:
  186. gcore.run_command(
  187. 'r.out.bin',
  188. flags=flags,
  189. input=mapname,
  190. output=self.filename,
  191. bytes=size,
  192. null=null,
  193. quiet=True,
  194. overwrite=True)
  195. except CalledModuleError:
  196. return 1
  197. else:
  198. return 0
  199. def write(self, mapname, title=None, null=None, overwrite=None, quiet=None):
  200. """Write array into raster map
  201. :param str mapname: name for raster map
  202. :param str title: title for raster map
  203. :param null: null value
  204. :param bool overwrite: True for overwritting existing raster maps
  205. :return: 0 on success
  206. :return: non-zero code on failure
  207. """
  208. kind = self.dtype.kind
  209. size = self.dtype.itemsize
  210. if kind == 'f':
  211. if size == 4:
  212. flags = 'f'
  213. elif size == 8:
  214. flags = 'd'
  215. else:
  216. raise ValueError(_('Invalid FP size <%d>') % size)
  217. size = None
  218. elif kind in 'biu':
  219. if size not in [1, 2, 4]:
  220. raise ValueError(_('Invalid integer size <%d>') % size)
  221. flags = None
  222. else:
  223. raise ValueError(_('Invalid kind <%s>') % kind)
  224. reg = gcore.region()
  225. try:
  226. gcore.run_command(
  227. 'r.in.bin',
  228. flags=flags,
  229. input=self.filename,
  230. output=mapname,
  231. title=title,
  232. bytes=size,
  233. anull=null,
  234. overwrite=overwrite,
  235. quiet=quiet,
  236. north=reg['n'],
  237. south=reg['s'],
  238. east=reg['e'],
  239. west=reg['w'],
  240. rows=reg['rows'],
  241. cols=reg['cols'])
  242. except CalledModuleError:
  243. return 1
  244. else:
  245. return 0
  246. ###############################################################################
  247. class array3d(numpy.memmap):
  248. def __new__(cls, mapname=None, null=None, dtype=numpy.double):
  249. """Define new 3d numpy array
  250. :param cls:
  251. :param dtype: data type (default: numpy.double)
  252. """
  253. reg = gcore.region(True)
  254. r = reg['rows3']
  255. c = reg['cols3']
  256. d = reg['depths']
  257. shape = (d, r, c)
  258. tempfile = _tempfile()
  259. if mapname:
  260. kind = numpy.dtype(dtype).kind
  261. size = numpy.dtype(dtype).itemsize
  262. if kind == 'f':
  263. flags = None # default is double
  264. elif kind in 'biu':
  265. flags = 'i'
  266. else:
  267. raise ValueError(_('Invalid kind <%s>') % kind)
  268. if size not in [1, 2, 4, 8]:
  269. raise ValueError(_('Invalid size <%d>') % size)
  270. gcore.run_command(
  271. 'r3.out.bin',
  272. flags=flags,
  273. input=mapname,
  274. output=tempfile.filename,
  275. bytes=size,
  276. null=null,
  277. quiet=True,
  278. overwrite=True)
  279. self = numpy.memmap.__new__(
  280. cls,
  281. filename=tempfile.filename,
  282. dtype=dtype,
  283. mode='r+',
  284. shape=shape)
  285. self.tempfile = tempfile
  286. self.filename = tempfile.filename
  287. return self
  288. def read(self, mapname, null=None):
  289. """Read 3D raster map into array
  290. :param str mapname: name of 3D raster map to be read
  291. :param null: null value
  292. :return: 0 on success
  293. :return: non-zero code on failure
  294. .. deprecated:: 7.1
  295. Instead reading the map after creating the array,
  296. pass the map name in the array constructor.
  297. """
  298. if sys.platform == 'win32':
  299. gcore.warning(_("grass.script.array3d.read is deprecated and does not"
  300. " work on MS Windows, pass 3D raster name in the constructor"))
  301. kind = self.dtype.kind
  302. size = self.dtype.itemsize
  303. if kind == 'f':
  304. flags = None # default is double
  305. elif kind in 'biu':
  306. flags = 'i'
  307. else:
  308. raise ValueError(_('Invalid kind <%s>') % kind)
  309. if size not in [1, 2, 4, 8]:
  310. raise ValueError(_('Invalid size <%d>') % size)
  311. try:
  312. gcore.run_command(
  313. 'r3.out.bin',
  314. flags=flags,
  315. input=mapname,
  316. output=self.filename,
  317. bytes=size,
  318. null=null,
  319. quiet=True,
  320. overwrite=True)
  321. except CalledModuleError:
  322. return 1
  323. else:
  324. return 0
  325. def write(self, mapname, null=None, overwrite=None, quiet=None):
  326. """Write array into 3D raster map
  327. :param str mapname: name for 3D raster map
  328. :param null: null value
  329. :param bool overwrite: True for overwriting existing raster maps
  330. :return: 0 on success
  331. :return: non-zero code on failure
  332. """
  333. kind = self.dtype.kind
  334. size = self.dtype.itemsize
  335. flags = None
  336. if kind == 'f':
  337. if size != 4 and size != 8:
  338. raise ValueError(_('Invalid FP size <%d>') % size)
  339. elif kind in 'biu':
  340. if size not in [1, 2, 4, 8]:
  341. raise ValueError(_('Invalid integer size <%d>') % size)
  342. flags = 'i'
  343. else:
  344. raise ValueError(_('Invalid kind <%s>') % kind)
  345. reg = gcore.region(True)
  346. try:
  347. gcore.run_command(
  348. 'r3.in.bin',
  349. flags=flags,
  350. input=self.filename,
  351. output=mapname,
  352. bytes=size,
  353. null=null,
  354. overwrite=overwrite,
  355. quiet=quiet,
  356. north=reg['n'],
  357. south=reg['s'],
  358. top=reg['t'],
  359. bottom=reg['b'],
  360. east=reg['e'],
  361. west=reg['w'],
  362. depths=reg['depths'],
  363. rows=reg['rows3'],
  364. cols=reg['cols3'])
  365. except CalledModuleError:
  366. return 1
  367. else:
  368. return 0