iscatt_core.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891
  1. """
  2. @package iscatt.iscatt_core
  3. @brief Non GUI functions.
  4. Classes:
  5. - iscatt_core::Core
  6. - iscatt_core::CatRastUpdater
  7. - iscatt_core::AnalyzedData
  8. - iscatt_core::ScattPlotsCondsData
  9. - iscatt_core::ScattPlotsData
  10. (C) 2013 by the GRASS Development Team
  11. This program is free software under the GNU General Public License
  12. (>=v2). Read the file COPYING that comes with GRASS for details.
  13. @author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
  14. """
  15. import os
  16. import six
  17. import numpy as np
  18. # used iclass perimeters algorithm instead of convolve2d
  19. #from matplotlib.path import Path
  20. #from scipy.signal import convolve2d
  21. from math import sqrt, ceil, floor
  22. from core.gcmd import GException, RunCommand
  23. import grass.script as grass
  24. from iscatt.core_c import CreateCatRast, ComputeScatts, UpdateCatRast, \
  25. Rasterize
  26. MAX_SCATT_SIZE = 4100 * 4100
  27. WARN_SCATT_SIZE = 2000 * 2000
  28. MAX_NCELLS = 65536 * 65536
  29. WARN_NCELLS = 12000 * 12000
  30. class Core:
  31. """Represents scatter plot backend.
  32. """
  33. def __init__(self):
  34. self.an_data = AnalyzedData()
  35. self.scatts_dt = ScattPlotsData(self.an_data)
  36. self.scatt_conds_dt = ScattPlotsCondsData(self.an_data)
  37. self.cat_rast_updater = CatRastUpdater(
  38. self.scatts_dt, self.an_data, self)
  39. def SetData(self, bands):
  40. """Set bands for analysis.
  41. """
  42. ret = self.an_data.Create(bands)
  43. if not ret:
  44. return False
  45. n_bands = len(self.GetBands())
  46. self.scatts_dt.Create(n_bands)
  47. self.scatt_conds_dt.Create(n_bands)
  48. return True
  49. def AddCategory(self, cat_id):
  50. self.scatts_dt.AddCategory(cat_id)
  51. return self.scatt_conds_dt.AddCategory(cat_id)
  52. def DeleteCategory(self, cat_id):
  53. self.scatts_dt.DeleteCategory(cat_id)
  54. self.scatt_conds_dt.DeleteCategory(cat_id)
  55. def CleanUp(self):
  56. self.scatts_dt.CleanUp()
  57. self.scatt_conds_dt.CleanUp()
  58. def GetBands(self):
  59. return self.an_data.GetBands()
  60. def GetScattsData(self):
  61. return self.scatts_dt, self.scatt_conds_dt
  62. def GetRegion(self):
  63. return self.an_data.GetRegion()
  64. def GetCatRast(self, cat_id):
  65. return self.scatts_dt.GetCatRast(cat_id)
  66. def AddScattPlots(self, scatt_ids):
  67. for s_id in scatt_ids:
  68. self.scatts_dt.AddScattPlot(scatt_id=s_id)
  69. cats_ids = self.scatts_dt.GetCategories()
  70. self.ComputeCatsScatts(cats_ids)
  71. def SetEditCatData(self, cat_id, scatt_id, bbox, value):
  72. if cat_id not in self.scatts_dt.GetCategories():
  73. raise GException(_("Select category for editing."))
  74. if self.scatt_conds_dt.AddScattPlot(cat_id, scatt_id) < 0:
  75. return None
  76. arr = self.scatt_conds_dt.GetValuesArr(cat_id, scatt_id)
  77. for k, v in six.iteritems(bbox):
  78. bbox[k] = self._validExtend(v)
  79. arr[bbox['btm_y']: bbox['up_y'], bbox['btm_x']: bbox['up_x']] = value
  80. self.ComputeCatsScatts([cat_id])
  81. return cat_id
  82. def ComputeCatsScatts(self, cats_ids):
  83. requested_dt = {}
  84. requested_dt_conds = {}
  85. for c in cats_ids:
  86. requested_dt_conds[c] = self.scatt_conds_dt.GetCatScatts(c)
  87. requested_dt[c] = self.scatts_dt.GetCatScatts(c)
  88. scatt_conds = self.scatt_conds_dt.GetData(requested_dt_conds)
  89. scatts = self.scatts_dt.GetData(requested_dt)
  90. bands = self.an_data.GetBands()
  91. cats_rasts = self.scatts_dt.GetCatsRasts()
  92. cats_rasts_conds = self.scatts_dt.GetCatsRastsConds()
  93. returncode, scatts = ComputeScatts(self.an_data.GetRegion(),
  94. scatt_conds,
  95. bands,
  96. len(self.GetBands()),
  97. scatts,
  98. cats_rasts_conds,
  99. cats_rasts)
  100. if returncode < 0:
  101. GException(_("Computing of scatter plots failed."))
  102. def CatRastUpdater(self):
  103. return self.cat_rast_updater
  104. def UpdateCategoryWithPolygons(self, cat_id, scatts_pols, value):
  105. if cat_id not in self.scatts_dt.GetCategories():
  106. raise GException(_("Select category for editing."))
  107. for scatt_id, coords in six.iteritems(scatts_pols):
  108. if self.scatt_conds_dt.AddScattPlot(cat_id, scatt_id) < 0:
  109. return False
  110. b1, b2 = idScattToidBands(scatt_id, len(self.an_data.GetBands()))
  111. b = self.scatts_dt.GetBandsInfo(scatt_id)
  112. region = {}
  113. region['s'] = b['b2']['min'] - 0.5
  114. region['n'] = b['b2']['max'] + 0.5
  115. region['w'] = b['b1']['min'] - 0.5
  116. region['e'] = b['b1']['max'] + 0.5
  117. arr = self.scatt_conds_dt.GetValuesArr(cat_id, scatt_id)
  118. arr = Rasterize(polygon=coords,
  119. rast=arr,
  120. region=region,
  121. value=value)
  122. # previous way of rasterization / used scipy
  123. # raster_pol = RasterizePolygon(coords, b['b1']['range'], b['b1']['min'],
  124. # b['b2']['range'], b['b2']['min'])
  125. #raster_ind = np.where(raster_pol > 0)
  126. #arr = self.scatt_conds_dt.GetValuesArr(cat_id, scatt_id)
  127. #arr[raster_ind] = value
  128. # arr.flush()
  129. self.ComputeCatsScatts([cat_id])
  130. return cat_id
  131. def ExportCatRast(self, cat_id, rast_name):
  132. cat_rast = self.scatts_dt.GetCatRast(cat_id)
  133. if not cat_rast:
  134. return 1
  135. return RunCommand("g.copy",
  136. raster=cat_rast + ',' + rast_name,
  137. getErrorMsg=True,
  138. overwrite=True)
  139. def _validExtend(self, val):
  140. # TODO do it general
  141. if val > 255:
  142. val = 255
  143. elif val < 0:
  144. val = 0
  145. return val
  146. class CatRastUpdater:
  147. """Update backend data structures according to selected areas in mapwindow.
  148. """
  149. def __init__(self, scatts_dt, an_data, core):
  150. self.scatts_dt = scatts_dt
  151. self.an_data = an_data # TODO may be confusing
  152. self.core = core
  153. self.vectMap = None
  154. def SetVectMap(self, vectMap):
  155. self.vectMap = vectMap
  156. def SyncWithMap(self):
  157. # TODO possible optimization - bbox only of vertex and its two
  158. # neighbours
  159. region = self.an_data.GetRegion()
  160. bbox = {}
  161. bbox['maxx'] = region['e']
  162. bbox['minx'] = region['w']
  163. bbox['maxy'] = region['n']
  164. bbox['miny'] = region['s']
  165. updated_cats = []
  166. for cat_id in self.scatts_dt.GetCategories():
  167. if cat_id == 0:
  168. continue
  169. cat = [{1: [cat_id]}]
  170. self._updateCatRast(bbox, cat, updated_cats)
  171. return updated_cats
  172. def EditedFeature(self, new_bboxs, new_areas_cats,
  173. old_bboxs, old_areas_cats):
  174. # TODO possible optimization - bbox only of vertex and its two
  175. # neighbours
  176. bboxs = old_bboxs + new_bboxs
  177. areas_cats = old_areas_cats + new_areas_cats
  178. updated_cats = []
  179. for i in range(len(areas_cats)):
  180. self._updateCatRast(bboxs[i], areas_cats[i], updated_cats)
  181. return updated_cats
  182. def _updateCatRast(self, bbox, areas_cats, updated_cats):
  183. rasterized_cats = []
  184. for c in range(len(areas_cats)):
  185. if not areas_cats[c]:
  186. continue
  187. layer = list(areas_cats[c])[0]
  188. cat = areas_cats[c][layer][0]
  189. if cat in rasterized_cats:
  190. continue
  191. rasterized_cats.append(cat)
  192. updated_cats.append(cat)
  193. grass_region = self._create_grass_region_env(bbox)
  194. # TODO hack check if raster exists?
  195. patch_rast = "temp_scatt_patch_%d" % (os.getpid())
  196. self._rasterize(grass_region, layer, cat, patch_rast)
  197. region = self.an_data.GetRegion()
  198. ret = UpdateCatRast(
  199. patch_rast,
  200. region,
  201. self.scatts_dt.GetCatRastCond(cat))
  202. if ret < 0:
  203. GException(
  204. _("Patching category raster conditions file failed."))
  205. RunCommand("g.remove", flags='f', type='raster', name=patch_rast)
  206. def _rasterize(self, grass_region, layer, cat, out_rast):
  207. # TODO different thread may be problem when user edits map
  208. environs = os.environ.copy()
  209. environs['GRASS_VECTOR_TEMPORARY'] = '1'
  210. ret, text, msg = RunCommand("v.category",
  211. input=self.vectMap,
  212. getErrorMsg=True,
  213. option='report',
  214. read=True,
  215. env=environs)
  216. ret, text, msg = RunCommand("v.build",
  217. map=self.vectMap,
  218. getErrorMsg=True,
  219. read=True,
  220. env=environs)
  221. if ret != 0:
  222. GException(_("v.build failed:\n%s" % msg))
  223. environs = os.environ.copy()
  224. environs["GRASS_REGION"] = grass_region["GRASS_REGION"]
  225. environs['GRASS_VECTOR_TEMPORARY'] = '1'
  226. ret, text, msg = RunCommand("v.to.rast",
  227. input=self.vectMap,
  228. use="cat",
  229. layer=str(layer),
  230. cat=str(cat),
  231. output=out_rast,
  232. getErrorMsg=True,
  233. read=True,
  234. overwrite=True,
  235. env=environs)
  236. if ret != 0:
  237. GException(_("v.to.rast failed:\n%s" % msg))
  238. def _create_grass_region_env(self, bbox):
  239. r = self.an_data.GetRegion()
  240. new_r = {}
  241. if bbox["maxy"] <= r["s"]:
  242. return 0
  243. elif bbox["maxy"] >= r["n"]:
  244. new_r["n"] = bbox["maxy"]
  245. else:
  246. new_r["n"] = ceil(
  247. (bbox["maxy"] - r["s"]) / r["nsres"]) * r["nsres"] + r["s"]
  248. if bbox["miny"] >= r["n"]:
  249. return 0
  250. elif bbox["miny"] <= r["s"]:
  251. new_r["s"] = bbox["miny"]
  252. else:
  253. new_r["s"] = floor(
  254. (bbox["miny"] - r["s"]) / r["nsres"]) * r["nsres"] + r["s"]
  255. if bbox["maxx"] <= r["w"]:
  256. return 0
  257. elif bbox["maxx"] >= r["e"]:
  258. new_r["e"] = bbox["maxx"]
  259. else:
  260. new_r["e"] = ceil(
  261. (bbox["maxx"] - r["w"]) / r["ewres"]) * r["ewres"] + r["w"]
  262. if bbox["minx"] >= r["e"]:
  263. return 0
  264. elif bbox["minx"] <= r["w"]:
  265. new_r["w"] = bbox["minx"]
  266. else:
  267. new_r["w"] = floor(
  268. (bbox["minx"] - r["w"]) / r["ewres"]) * r["ewres"] + r["w"]
  269. # TODO check regions resolution
  270. new_r["nsres"] = r["nsres"]
  271. new_r["ewres"] = r["ewres"]
  272. return {"GRASS_REGION": grass.region_env(**new_r)}
  273. class AnalyzedData:
  274. """Represents analyzed data (bands, region).
  275. """
  276. def __init__(self):
  277. self.bands = []
  278. self.bands_info = {}
  279. self.region = None
  280. def GetRegion(self):
  281. return self.region
  282. def Create(self, bands):
  283. self.bands = bands[:]
  284. self.region = None
  285. self.region = GetRegion()
  286. if self.region["rows"] * self.region["cols"] > MAX_NCELLS:
  287. GException("too big region")
  288. self.bands_info = {}
  289. for b in self.bands[:]:
  290. i = GetRasterInfo(b)
  291. if i is None:
  292. GException("raster %s is not CELL type" % (b))
  293. self.bands_info[b] = i
  294. # TODO check size of raster
  295. return True
  296. def GetBands(self):
  297. return self.bands
  298. def GetBandInfo(self, band_id):
  299. band = self.bands[band_id]
  300. return self.bands_info[band]
  301. class ScattPlotsCondsData:
  302. """Data structure for selected areas in scatter plot(conditions).
  303. """
  304. def __init__(self, an_data):
  305. self.an_data = an_data
  306. # TODO
  307. self.max_n_cats = 10
  308. self.dtype = 'uint8'
  309. self.type = 1
  310. self.CleanUp()
  311. def CleanUp(self):
  312. self.cats = {}
  313. self.n_scatts = -1
  314. self.n_bands = -1
  315. for cat_id in self.cats.keys():
  316. self.DeleteCategory(cat_id)
  317. def Create(self, n_bands):
  318. self.CleanUp()
  319. self.n_scatts = (n_bands - 1) * n_bands / 2
  320. self.n_bands = n_bands
  321. self.AddCategory(cat_id=0)
  322. def AddCategory(self, cat_id):
  323. if cat_id not in self.cats.keys():
  324. self.cats[cat_id] = {}
  325. return cat_id
  326. return -1
  327. def DeleteCategory(self, cat_id):
  328. if cat_id not in self.cats.keys():
  329. return False
  330. for scatt in six.itervalues(self.cats[cat_id]):
  331. grass.try_remove(scatt['np_vals'])
  332. del scatt['np_vals']
  333. del self.cats[cat_id]
  334. return True
  335. def GetCategories(self):
  336. return self.cats.keys()
  337. def GetCatScatts(self, cat_id):
  338. if cat_id not in self.cats:
  339. return False
  340. return self.cats[cat_id].keys()
  341. def AddScattPlot(self, cat_id, scatt_id):
  342. if cat_id not in self.cats:
  343. return -1
  344. if scatt_id in self.cats[cat_id]:
  345. return 0
  346. b_i = self.GetBandsInfo(scatt_id)
  347. shape = (
  348. b_i['b2']['max'] -
  349. b_i['b2']['min'] +
  350. 1,
  351. b_i['b1']['max'] -
  352. b_i['b1']['min'] +
  353. 1)
  354. np_vals = np.memmap(
  355. grass.tempfile(),
  356. dtype=self.dtype,
  357. mode='w+',
  358. shape=shape)
  359. self.cats[cat_id][scatt_id] = {'np_vals': np_vals}
  360. return 1
  361. def GetBandsInfo(self, scatt_id):
  362. b1, b2 = idScattToidBands(scatt_id, len(self.an_data.GetBands()))
  363. b1_info = self.an_data.GetBandInfo(b1)
  364. b2_info = self.an_data.GetBandInfo(b2)
  365. bands_info = {'b1': b1_info,
  366. 'b2': b2_info}
  367. return bands_info
  368. def DeleScattPlot(self, cat_id, scatt_id):
  369. if cat_id not in self.cats:
  370. return False
  371. if scatt_id not in self.cats[cat_id]:
  372. return False
  373. del self.cats[cat_id][scatt_id]
  374. return True
  375. def GetValuesArr(self, cat_id, scatt_id):
  376. if cat_id not in self.cats:
  377. return None
  378. if scatt_id not in self.cats[cat_id]:
  379. return None
  380. return self.cats[cat_id][scatt_id]['np_vals']
  381. def GetData(self, requested_dt):
  382. cats = {}
  383. for cat_id, scatt_ids in six.iteritems(requested_dt):
  384. if cat_id not in cats:
  385. cats[cat_id] = {}
  386. for scatt_id in scatt_ids:
  387. # if key is missing condition is always True (full scatter plor
  388. # is computed)
  389. if scatt_id in self.cats[cat_id]:
  390. cats[cat_id][scatt_id] = {
  391. 'np_vals': self.cats[cat_id][scatt_id]['np_vals'],
  392. 'bands_info': self.GetBandsInfo(scatt_id)}
  393. return cats
  394. def SetData(self, cats):
  395. for cat_id, scatt_ids in six.iteritems(cats):
  396. for scatt_id in scatt_ids:
  397. # if key is missing condition is always True (full scatter plor
  398. # is computed)
  399. if scatt_id in self.cats[cat_id]:
  400. self.cats[cat_id][scatt_id]['np_vals'] = cats[
  401. cat_id][scatt_id]['np_vals']
  402. def GetScatt(self, scatt_id, cats_ids=None):
  403. scatts = {}
  404. for cat_id in six.iterkeys(self.cats):
  405. if cats_ids and cat_id not in cats_ids:
  406. continue
  407. if scatt_id not in self.cats[cat_id]:
  408. continue
  409. scatts[cat_id] = {'np_vals': self.cats[cat_id][scatt_id][
  410. 'np_vals'], 'bands_info': self.GetBandsInfo(scatt_id)}
  411. return scatts
  412. class ScattPlotsData(ScattPlotsCondsData):
  413. """Data structure for computed points (classes) in scatter plots.\
  414. """
  415. def __init__(self, an_data):
  416. self.cats_rasts = {}
  417. self.cats_rasts_conds = {}
  418. self.scatts_ids = []
  419. ScattPlotsCondsData.__init__(self, an_data)
  420. self.dtype = 'uint32'
  421. # TODO
  422. self.type = 0
  423. def AddCategory(self, cat_id):
  424. cat_id = ScattPlotsCondsData.AddCategory(self, cat_id)
  425. if cat_id < 0:
  426. return cat_id
  427. for scatt_id in self.scatts_ids:
  428. ScattPlotsCondsData.AddScattPlot(self, cat_id, scatt_id)
  429. if cat_id == 0:
  430. self.cats_rasts_conds[cat_id] = None
  431. self.cats_rasts[cat_id] = None
  432. else:
  433. self.cats_rasts_conds[cat_id] = grass.tempfile()
  434. self.cats_rasts[cat_id] = "temp_cat_rast_%d_%d" % (
  435. cat_id, os.getpid())
  436. region = self.an_data.GetRegion()
  437. CreateCatRast(region, self.cats_rasts_conds[cat_id])
  438. return cat_id
  439. def DeleteCategory(self, cat_id):
  440. ScattPlotsCondsData.DeleteCategory(self, cat_id)
  441. grass.try_remove(self.cats_rasts_conds[cat_id])
  442. del self.cats_rasts_conds[cat_id]
  443. RunCommand("g.remove", flags='f', type='raster',
  444. name=self.cats_rasts[cat_id])
  445. del self.cats_rasts[cat_id]
  446. return True
  447. def AddScattPlot(self, scatt_id):
  448. if scatt_id in self.scatts_ids:
  449. return False
  450. self.scatts_ids.append(scatt_id)
  451. for cat_id in six.iterkeys(self.cats):
  452. ScattPlotsCondsData.AddScattPlot(self, cat_id, scatt_id)
  453. self.cats[cat_id][scatt_id]['ellipse'] = None
  454. return True
  455. def DeleteScatterPlot(self, scatt_id):
  456. if scatt_id not in self.scatts_ids:
  457. return False
  458. self.scatts_ids.remove(scatt_id)
  459. for cat_id in six.iterkeys(self.cats):
  460. ScattPlotsCondsData.DeleteScattPlot(self, cat_id, scatt_id)
  461. return True
  462. def GetEllipses(self, scatt_id, styles):
  463. if scatt_id not in self.scatts_ids:
  464. return False
  465. scatts = {}
  466. for cat_id in six.iterkeys(self.cats):
  467. if cat_id == 0:
  468. continue
  469. nstd = styles[cat_id]['nstd']
  470. scatts[cat_id] = self._getEllipse(cat_id, scatt_id, nstd)
  471. return scatts
  472. def _getEllipse(self, cat_id, scatt_id, nstd):
  473. # Joe Kington
  474. # http://stackoverflow.com/questions/12301071/multidimensional-confidence-intervals
  475. data = np.copy(self.cats[cat_id][scatt_id]['np_vals'])
  476. b = self.GetBandsInfo(scatt_id)
  477. sel_pts = np.where(data > 0)
  478. x = sel_pts[1]
  479. y = sel_pts[0]
  480. flatten_data = data.reshape([-1])
  481. flatten_sel_pts = np.nonzero(flatten_data)
  482. weights = flatten_data[flatten_sel_pts]
  483. if len(weights) == 0:
  484. return None
  485. x_avg = np.average(x, weights=weights)
  486. y_avg = np.average(y, weights=weights)
  487. pos = np.array([x_avg + b['b1']['min'], y_avg + b['b2']['min']])
  488. x_diff = (x - x_avg)
  489. y_diff = (y - y_avg)
  490. x_diff = (x - x_avg)
  491. y_diff = (y - y_avg)
  492. diffs = x_diff * y_diff.T
  493. cov = np.dot(diffs, weights) / (np.sum(weights) - 1)
  494. diffs = x_diff * x_diff.T
  495. var_x = np.dot(diffs, weights) / (np.sum(weights) - 1)
  496. diffs = y_diff * y_diff.T
  497. var_y = np.dot(diffs, weights) / (np.sum(weights) - 1)
  498. cov = np.array([[var_x, cov], [cov, var_y]])
  499. def eigsorted(cov):
  500. vals, vecs = np.linalg.eigh(cov)
  501. order = vals.argsort()[::-1]
  502. return vals[order], vecs[:, order]
  503. vals, vecs = eigsorted(cov)
  504. theta = np.degrees(np.arctan2(*vecs[:, 0][::-1]))
  505. # Width and height are "full" widths, not radius
  506. width, height = 2 * nstd * np.sqrt(vals)
  507. ellipse = {'pos': pos,
  508. 'width': width,
  509. 'height': height,
  510. 'theta': theta}
  511. del data
  512. del flatten_data
  513. del flatten_sel_pts
  514. del weights
  515. del sel_pts
  516. return ellipse
  517. def CleanUp(self):
  518. ScattPlotsCondsData.CleanUp(self)
  519. for tmp in six.itervalues(self.cats_rasts_conds):
  520. grass.try_remove(tmp)
  521. for tmp in six.itervalues(self.cats_rasts):
  522. RunCommand("g.remove", flags='f',
  523. type='raster', name=tmp,
  524. getErrorMsg=True)
  525. self.cats_rasts = {}
  526. self.cats_rasts_conds = {}
  527. def GetCatRast(self, cat_id):
  528. if cat_id in self.cats_rasts:
  529. return self.cats_rasts[cat_id]
  530. return None
  531. def GetCatRastCond(self, cat_id):
  532. return self.cats_rasts_conds[cat_id]
  533. def GetCatsRastsConds(self):
  534. max_cat_id = max(self.cats_rasts_conds.keys())
  535. cats_rasts_conds = [''] * (max_cat_id + 1)
  536. for i_cat_id, i_rast in six.iteritems(self.cats_rasts_conds):
  537. cats_rasts_conds[i_cat_id] = i_rast
  538. return cats_rasts_conds
  539. def GetCatsRasts(self):
  540. max_cat_id = max(self.cats_rasts.keys())
  541. cats_rasts = [''] * (max_cat_id + 1)
  542. for i_cat_id, i_rast in six.iteritems(self.cats_rasts):
  543. cats_rasts[i_cat_id] = i_rast
  544. return cats_rasts
  545. # not used, using iclass_perimeter algorithm instead of scipy convolve2d
  546. """
  547. def RasterizePolygon(pol, height, min_h, width, min_w):
  548. # Joe Kington
  549. # http://stackoverflow.com/questions/3654289/scipy-create-2d-polygon-mask
  550. #poly_verts = [(1,1), (1,4), (4,4),(4,1), (1,1)]
  551. nx = width
  552. ny = height
  553. x, y = np.meshgrid(np.arange(-0.5 + min_w, nx + 0.5 + min_w, dtype=float),
  554. np.arange(-0.5 + min_h, ny + 0.5 + min_h, dtype=float))
  555. x, y = x.flatten(), y.flatten()
  556. points = np.vstack((x,y)).T
  557. p = Path(pol)
  558. grid = p.contains_points(points)
  559. grid = grid.reshape((ny + 1, nx + 1))
  560. raster = np.zeros((height, width), dtype=np.uint8)#TODO bool
  561. #TODO shift by 0.5
  562. B = np.ones((2,2))/4
  563. raster = convolve2d(grid, B, 'valid')
  564. return raster
  565. """
  566. def idScattToidBands(scatt_id, n_bands):
  567. """Get bands ids from scatter plot id."""
  568. n_b1 = n_bands - 1
  569. band_1 = (int)(
  570. (2 * n_b1 + 1 - sqrt(((2 * n_b1 + 1) * (2 * n_b1 + 1) - 8 * scatt_id))) / 2)
  571. band_2 = int(scatt_id - (band_1 * (2 * n_b1 + 1) - band_1 * band_1) / 2 + band_1 + 1)
  572. return band_1, band_2
  573. def idBandsToidScatt(band_1_id, band_2_id, n_bands):
  574. """Get scatter plot id from band ids."""
  575. if band_2_id < band_1_id:
  576. tmp = band_1_id
  577. band_1_id = band_2_id
  578. band_2_id = tmp
  579. n_b1 = n_bands - 1
  580. scatt_id = int((
  581. band_1_id * (2 * n_b1 + 1) - band_1_id * band_1_id) / 2 + band_2_id - band_1_id - 1)
  582. return scatt_id
  583. def GetRegion():
  584. ret, region, msg = RunCommand("g.region",
  585. flags="gp",
  586. getErrorMsg=True,
  587. read=True)
  588. if ret != 0:
  589. raise GException("g.region failed:\n%s" % msg)
  590. return _parseRegion(region)
  591. def _parseRegion(region_str):
  592. region = {}
  593. region_str = region_str.splitlines()
  594. for param in region_str:
  595. k, v = param.split("=")
  596. if k in ["rows", "cols", "cells"]:
  597. v = int(v)
  598. else:
  599. v = float(v)
  600. region[k] = v
  601. return region
  602. def GetRasterInfo(rast):
  603. ret, out, msg = RunCommand("r.info",
  604. map=rast,
  605. flags="rg",
  606. getErrorMsg=True,
  607. read=True)
  608. if ret != 0:
  609. raise GException("r.info failed:\n%s" % msg)
  610. out = out.splitlines()
  611. raster_info = {}
  612. for b in out:
  613. if not b.strip():
  614. continue
  615. k, v = b.split("=")
  616. if k == "datatype":
  617. if v != "CELL":
  618. return None
  619. pass
  620. elif k in ['rows', 'cols', 'cells', 'min', 'max']:
  621. v = int(v)
  622. else:
  623. v = float(v)
  624. raster_info[k] = v
  625. raster_info['range'] = raster_info['max'] - raster_info['min'] + 1
  626. return raster_info