iscatt_core.py 24 KB

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