array.py 10 KB

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