array.py 9.9 KB

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