iscatt_core.py 24 KB

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