iscatt_core.py 24 KB

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