iscatt_core.py 24 KB

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