iscatt_core.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  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 i["datatype"] != "CELL":
  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. pass
  304. elif k in ['rows', 'cols', 'cells', 'min', 'max']:
  305. v = int(v)
  306. else:
  307. v = float(v)
  308. raster_info[k] = v
  309. raster_info['range'] = raster_info['max'] - raster_info['min'] + 1
  310. return raster_info
  311. def GetBands(self):
  312. return self.bands
  313. def GetBandInfo(self, band_id):
  314. band = self.bands[band_id]
  315. return self.bands_info[band]
  316. def _parseRegion(self, region_str):
  317. region = {}
  318. region_str = region_str.splitlines()
  319. for param in region_str:
  320. k, v = param.split("=")
  321. if k in ["rows", "cols", "cells"]:
  322. v = int(v)
  323. else:
  324. v = float(v)
  325. region[k] = v
  326. return region
  327. class ScattPlotsCondsData:
  328. """!Data structure for selected areas in scatter plot(condtions).
  329. """
  330. def __init__(self, an_data):
  331. self.an_data = an_data
  332. #TODO
  333. self.max_n_cats = 10
  334. self.dtype = 'uint8'
  335. self.type = 1;
  336. self.CleanUp()
  337. def CleanUp(self):
  338. self.cats = {}
  339. self.n_scatts = -1
  340. self.n_bands = -1
  341. for cat_id in self.cats.keys():
  342. self.DeleteCategory(cat_id)
  343. def Create(self, n_bands):
  344. self.CleanUp()
  345. self.n_scatts = (n_bands - 1) * n_bands / 2;
  346. self.n_bands = n_bands
  347. self.AddCategory(cat_id = 0)
  348. def AddCategory(self, cat_id):
  349. if cat_id not in self.cats.keys():
  350. self.cats[cat_id] = {}
  351. return cat_id
  352. return -1
  353. def DeleteCategory(self, cat_id):
  354. if cat_id not in self.cats.keys():
  355. return False
  356. for scatt in self.cats[cat_id].itervalues():
  357. grass.try_remove(scatt['np_vals'])
  358. del scatt['np_vals']
  359. del self.cats[cat_id]
  360. return True
  361. def GetCategories(self):
  362. return self.cats.keys()
  363. def GetCatScatts(self, cat_id):
  364. if not self.cats.has_key(cat_id):
  365. return False
  366. return self.cats[cat_id].keys()
  367. def AddScattPlot(self, cat_id, scatt_id):
  368. if not self.cats.has_key(cat_id):
  369. return -1
  370. if self.cats[cat_id].has_key(scatt_id):
  371. return 0
  372. b_i = self.GetBandsInfo(scatt_id)
  373. shape = (b_i['b2']['max'] - b_i['b2']['min'] + 1, b_i['b1']['max'] - b_i['b1']['min'] + 1)
  374. np_vals = np.memmap(grass.tempfile(), dtype=self.dtype, mode='w+', shape = shape)
  375. self.cats[cat_id][scatt_id] = {'np_vals' : np_vals}
  376. return 1
  377. def GetBandsInfo(self, scatt_id):
  378. b1, b2 = idScattToidBands(scatt_id, len(self.an_data.GetBands()))
  379. b1_info = self.an_data.GetBandInfo(b1)
  380. b2_info = self.an_data.GetBandInfo(b2)
  381. bands_info = {'b1' : b1_info,
  382. 'b2' : b2_info}
  383. return bands_info
  384. def DeleScattPlot(self, cat_id, scatt_id):
  385. if not self.cats.has_key(cat_id):
  386. return False
  387. if not self.cats[cat_id].has_key(scatt_id):
  388. return False
  389. del self.cats[cat_id][scatt_id]
  390. return True
  391. def GetValuesArr(self, cat_id, scatt_id):
  392. if not self.cats.has_key(cat_id):
  393. return None
  394. if not self.cats[cat_id].has_key(scatt_id):
  395. return None
  396. return self.cats[cat_id][scatt_id]['np_vals']
  397. def GetData(self, requested_dt):
  398. cats = {}
  399. for cat_id, scatt_ids in requested_dt.iteritems():
  400. if not cats.has_key(cat_id):
  401. cats[cat_id] = {}
  402. for scatt_id in scatt_ids:
  403. # if key is missing condition is always True (full scatter plor is computed)
  404. if self.cats[cat_id].has_key(scatt_id):
  405. cats[cat_id][scatt_id] = {'np_vals' : self.cats[cat_id][scatt_id]['np_vals'],
  406. 'bands_info' : self.GetBandsInfo(scatt_id)}
  407. return cats
  408. def SetData(self, cats):
  409. for cat_id, scatt_ids in cats.iteritems():
  410. for scatt_id in scatt_ids:
  411. # if key is missing condition is always True (full scatter plor is computed)
  412. if self.cats[cat_id].has_key(scatt_id):
  413. self.cats[cat_id][scatt_id]['np_vals'] = cats[cat_id][scatt_id]['np_vals']
  414. def GetScatt(self, scatt_id, cats_ids = None):
  415. scatts = {}
  416. for cat_id in self.cats.iterkeys():
  417. if cats_ids and cat_id not in cats_ids:
  418. continue
  419. if not self.cats[cat_id].has_key(scatt_id):
  420. continue
  421. scatts[cat_id] = {'np_vals' : self.cats[cat_id][scatt_id]['np_vals'],
  422. 'bands_info' : self.GetBandsInfo(scatt_id)}
  423. return scatts
  424. class ScattPlotsData(ScattPlotsCondsData):
  425. """!Data structure for computed points (classes) in scatter plots.\
  426. """
  427. def __init__(self, an_data):
  428. self.cats_rasts = {}
  429. self.cats_rasts_conds = {}
  430. self.scatts_ids = []
  431. ScattPlotsCondsData.__init__(self, an_data)
  432. self.dtype = 'uint32'
  433. #TODO
  434. self.type = 0
  435. def AddCategory(self, cat_id):
  436. cat_id = ScattPlotsCondsData.AddCategory(self, cat_id)
  437. if cat_id < 0:
  438. return cat_id
  439. for scatt_id in self.scatts_ids:
  440. ScattPlotsCondsData.AddScattPlot(self, cat_id, scatt_id)
  441. if cat_id == 0:
  442. self.cats_rasts_conds[cat_id] = None
  443. self.cats_rasts[cat_id] = None
  444. else:
  445. self.cats_rasts_conds[cat_id] = grass.tempfile()
  446. self.cats_rasts[cat_id] = "temp_cat_rast_%d_%d" % (cat_id, os.getpid())
  447. region = self.an_data.GetRegion()
  448. CreateCatRast(region, self.cats_rasts_conds[cat_id])
  449. return cat_id
  450. def DeleteCategory(self, cat_id):
  451. ScattPlotsCondsData.DeleteCategory(self, cat_id)
  452. grass.try_remove(self.cats_rasts_conds[cat_id])
  453. del self.cats_rasts_conds[cat_id]
  454. RunCommand("g.remove",
  455. rast=self.cats_rasts[cat_id])
  456. del self.cats_rasts[cat_id]
  457. return True
  458. def AddScattPlot(self, scatt_id):
  459. if scatt_id in self.scatts_ids:
  460. return False
  461. self.scatts_ids.append(scatt_id)
  462. for cat_id in self.cats.iterkeys():
  463. ScattPlotsCondsData.AddScattPlot(self, cat_id, scatt_id)
  464. self.cats[cat_id][scatt_id]['ellipse'] = None
  465. return True
  466. def DeleteScatterPlot(self, scatt_id):
  467. if scatt_id not in self.scatts_ids:
  468. return False
  469. self.scatts_ids.remove(scatt_id)
  470. for cat_id in self.cats.iterkeys():
  471. ScattPlotsCondsData.DeleteScattPlot(self, cat_id, scatt_id)
  472. return True
  473. def GetEllipses(self, scatt_id, styles):
  474. if scatt_id not in self.scatts_ids:
  475. return False
  476. scatts = {}
  477. for cat_id in self.cats.iterkeys():
  478. if cat_id == 0:
  479. continue
  480. nstd = styles[cat_id]['nstd']
  481. scatts[cat_id] = self._getEllipse(cat_id, scatt_id, nstd)
  482. return scatts
  483. def _getEllipse(self, cat_id, scatt_id, nstd):
  484. # Joe Kington
  485. # http://stackoverflow.com/questions/12301071/multidimensional-confidence-intervals
  486. data = np.copy(self.cats[cat_id][scatt_id]['np_vals'])
  487. b = self.GetBandsInfo(scatt_id)
  488. sel_pts = np.where(data > 0)
  489. x = sel_pts[1]
  490. y = sel_pts[0]
  491. flatten_data = data.reshape([-1])
  492. flatten_sel_pts = np.nonzero(flatten_data)
  493. weights = flatten_data[flatten_sel_pts]
  494. if len(weights) == 0:
  495. return None
  496. x_avg = np.average(x, weights=weights)
  497. y_avg = np.average(y, weights=weights)
  498. pos = np.array([x_avg + b['b1']['min'], y_avg + b['b2']['min']])
  499. x_diff = (x - x_avg)
  500. y_diff = (y - y_avg)
  501. x_diff = (x - x_avg)
  502. y_diff = (y - y_avg)
  503. diffs = x_diff * y_diff.T
  504. cov = np.dot(diffs, weights) / (np.sum(weights) - 1)
  505. diffs = x_diff * x_diff.T
  506. var_x = np.dot(diffs, weights) / (np.sum(weights) - 1)
  507. diffs = y_diff * y_diff.T
  508. var_y = np.dot(diffs, weights) / (np.sum(weights) - 1)
  509. cov = np.array([[var_x, cov],[cov, var_y]])
  510. def eigsorted(cov):
  511. vals, vecs = np.linalg.eigh(cov)
  512. order = vals.argsort()[::-1]
  513. return vals[order], vecs[:,order]
  514. vals, vecs = eigsorted(cov)
  515. theta = np.degrees(np.arctan2(*vecs[:,0][::-1]))
  516. # Width and height are "full" widths, not radius
  517. width, height = 2 * nstd * np.sqrt(vals)
  518. ellipse = {'pos' : pos,
  519. 'width' : width,
  520. 'height' : height,
  521. 'theta' : theta}
  522. del data
  523. del flatten_data
  524. del flatten_sel_pts
  525. del weights
  526. del sel_pts
  527. return ellipse
  528. def CleanUp(self):
  529. ScattPlotsCondsData.CleanUp(self)
  530. for tmp in self.cats_rasts_conds.itervalues():
  531. grass.try_remove(tmp)
  532. for tmp in self.cats_rasts.itervalues():
  533. RunCommand("g.remove",
  534. rast=tmp,
  535. getErrorMsg=True)
  536. self.cats_rasts = {}
  537. self.cats_rasts_conds = {}
  538. def GetCatRast(self, cat_id):
  539. if self.cats_rasts.has_key(cat_id):
  540. return self.cats_rasts[cat_id]
  541. return None
  542. def GetCatRastCond(self, cat_id):
  543. return self.cats_rasts_conds[cat_id]
  544. def GetCatsRastsConds(self):
  545. max_cat_id = max(self.cats_rasts_conds.keys())
  546. cats_rasts_conds = [''] * (max_cat_id + 1)
  547. for i_cat_id, i_rast in self.cats_rasts_conds.iteritems():
  548. cats_rasts_conds[i_cat_id] = i_rast
  549. return cats_rasts_conds
  550. def GetCatsRasts(self):
  551. max_cat_id = max(self.cats_rasts.keys())
  552. cats_rasts = [''] * (max_cat_id + 1)
  553. for i_cat_id, i_rast in self.cats_rasts.iteritems():
  554. cats_rasts[i_cat_id] = i_rast
  555. return cats_rasts
  556. # not used, using iclass_perimeter algorithm instead of scipy convolve2d
  557. """
  558. def RasterizePolygon(pol, height, min_h, width, min_w):
  559. # Joe Kington
  560. # http://stackoverflow.com/questions/3654289/scipy-create-2d-polygon-mask
  561. #poly_verts = [(1,1), (1,4), (4,4),(4,1), (1,1)]
  562. nx = width
  563. ny = height
  564. x, y = np.meshgrid(np.arange(-0.5 + min_w, nx + 0.5 + min_w, dtype=float),
  565. np.arange(-0.5 + min_h, ny + 0.5 + min_h, dtype=float))
  566. x, y = x.flatten(), y.flatten()
  567. points = np.vstack((x,y)).T
  568. p = Path(pol)
  569. grid = p.contains_points(points)
  570. grid = grid.reshape((ny + 1, nx + 1))
  571. raster = np.zeros((height, width), dtype=np.uint8)#TODO bool
  572. #TODO shift by 0.5
  573. B = np.ones((2,2))/4
  574. raster = convolve2d(grid, B, 'valid')
  575. return raster
  576. """
  577. def idScattToidBands(scatt_id, n_bands):
  578. """!Get bands ids from scatter plot id."""
  579. n_b1 = n_bands - 1
  580. band_1 = (int) ((2 * n_b1 + 1 - sqrt(((2 * n_b1 + 1) * (2 * n_b1 + 1) - 8 * scatt_id))) / 2)
  581. band_2 = scatt_id - (band_1 * (2 * n_b1 + 1) - band_1 * band_1) / 2 + band_1 + 1
  582. return band_1, band_2
  583. def idBandsToidScatt(band_1_id, band_2_id, n_bands):
  584. """!Get scatter plot id from band ids."""
  585. if band_2_id < band_1_id:
  586. tmp = band_1_id
  587. band_1_id = band_2_id
  588. band_2_id = tmp
  589. n_b1 = n_bands - 1
  590. scatt_id = (band_1_id * (2 * n_b1 + 1) - band_1_id * band_1_id) / 2 + band_2_id - band_1_id - 1
  591. return scatt_id