wxplot.py 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317
  1. """!
  2. @package wxplot.py
  3. Iinteractive plotting using PyPlot (wx.lib.plot.py).
  4. Classes:
  5. - AbstractPlotFrame
  6. - HistFrame
  7. - ProfileFrame
  8. (C) 2011 by the GRASS Development Team
  9. This program is free software under the GNU General Public License
  10. (>=v2). Read the file COPYING that comes with GRASS for details.
  11. @author Michael Barton, Arizona State University
  12. """
  13. import os
  14. import sys
  15. import math
  16. import wx
  17. import wx.lib.colourselect as csel
  18. import globalvar
  19. import gcmd
  20. from render import Map
  21. from toolbars import Histogram2Toolbar
  22. from toolbars import ProfileToolbar
  23. from toolbars import ScatterplotToolbar
  24. from preferences import globalSettings as UserSettings
  25. import wxplot_dialogs as dialogs
  26. from grass.script import core as grass
  27. from grass.script import raster as raster
  28. try:
  29. import numpy
  30. import wx.lib.plot as plot
  31. except ImportError:
  32. msg = _("This module requires the NumPy module, which could not be "
  33. "imported. It probably is not installed (it's not part of the "
  34. "standard Python distribution). See the Numeric Python site "
  35. "(http://numpy.scipy.org) for information on downloading source or "
  36. "binaries.")
  37. print >> sys.stderr, "wxplot.py: " + msg
  38. class AbstractPlotFrame(wx.Frame):
  39. """!Abstract PyPlot display frame class"""
  40. def __init__(self, parent = None, id = wx.ID_ANY, size = (700, 300),
  41. style = wx.DEFAULT_FRAME_STYLE, rasterList = [], **kwargs):
  42. wx.Frame.__init__(self, parent, id, size = size, style = style, **kwargs)
  43. self.parent = parent # MapFrame
  44. self.mapwin = self.parent.MapWindow
  45. self.Map = Map() # instance of render.Map to be associated with display
  46. self.rasterList = rasterList #list of rasters to plot
  47. self.raster = {} # dictionary of raster maps and their plotting parameters
  48. self.plottype = ''
  49. self.linestyledict = { 'solid' : wx.SOLID,
  50. 'dot' : wx.DOT,
  51. 'long-dash' : wx.LONG_DASH,
  52. 'short-dash' : wx.SHORT_DASH,
  53. 'dot-dash' : wx.DOT_DASH }
  54. self.ptfilldict = { 'transparent' : wx.TRANSPARENT,
  55. 'solid' : wx.SOLID }
  56. #
  57. # Icon
  58. #
  59. self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
  60. #
  61. # Add statusbar
  62. #
  63. self.statusbar = self.CreateStatusBar(number = 2, style = 0)
  64. self.statusbar.SetStatusWidths([-2, -1])
  65. #
  66. # Define canvas and settings
  67. #
  68. #
  69. self.client = plot.PlotCanvas(self)
  70. #define the function for drawing pointLabels
  71. self.client.SetPointLabelFunc(self.DrawPointLabel)
  72. # Create mouse event for showing cursor coords in status bar
  73. self.client.canvas.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown)
  74. # Show closest point when enabled
  75. self.client.canvas.Bind(wx.EVT_MOTION, self.OnMotion)
  76. self.plotlist = [] # list of things to plot
  77. self.plot = None # plot draw object
  78. self.ptitle = "" # title of window
  79. self.xlabel = "" # default X-axis label
  80. self.ylabel = "" # default Y-axis label
  81. #
  82. # Bind various events
  83. #
  84. self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
  85. self.CentreOnScreen()
  86. self._createColorDict()
  87. def _createColorDict(self):
  88. """!Create color dictionary to return wx.Color tuples
  89. for assigning colors to images in imagery groups"""
  90. self.colorDict = {}
  91. for clr in grass.named_colors.iterkeys():
  92. if clr == 'white' or clr == 'black': continue
  93. r = grass.named_colors[clr][0] * 255
  94. g = grass.named_colors[clr][1] * 255
  95. b = grass.named_colors[clr][2] * 255
  96. self.colorDict[clr] = (r,g,b,255)
  97. def InitPlotOpts(self, plottype):
  98. """!Initialize options for entire plot
  99. """
  100. self.plottype = plottype # histogram, profile, or scatter
  101. self.properties = {} # plot properties
  102. self.properties['font'] = {}
  103. self.properties['font']['prop'] = UserSettings.Get(group = self.plottype, key = 'font')
  104. self.properties['font']['wxfont'] = wx.Font(11, wx.FONTFAMILY_SWISS,
  105. wx.FONTSTYLE_NORMAL,
  106. wx.FONTWEIGHT_NORMAL)
  107. if self.plottype == 'profile':
  108. self.properties['marker'] = UserSettings.Get(group = self.plottype, key = 'marker')
  109. # changing color string to tuple for markers/points
  110. colstr = str(self.properties['marker']['color'])
  111. self.properties['marker']['color'] = tuple(int(colval) for colval in colstr.strip('()').split(','))
  112. self.properties['grid'] = UserSettings.Get(group = self.plottype, key = 'grid')
  113. colstr = str(self.properties['grid']['color']) # changing color string to tuple
  114. self.properties['grid']['color'] = tuple(int(colval) for colval in colstr.strip('()').split(','))
  115. self.properties['x-axis'] = {}
  116. self.properties['x-axis']['prop'] = UserSettings.Get(group = self.plottype, key = 'x-axis')
  117. self.properties['x-axis']['axis'] = None
  118. self.properties['y-axis'] = {}
  119. self.properties['y-axis']['prop'] = UserSettings.Get(group = self.plottype, key = 'y-axis')
  120. self.properties['y-axis']['axis'] = None
  121. self.properties['legend'] = UserSettings.Get(group = self.plottype, key = 'legend')
  122. self.zoom = False # zooming disabled
  123. self.drag = False # draging disabled
  124. self.client.SetShowScrollbars(True) # vertical and horizontal scrollbars
  125. # x and y axis set to normal (non-log)
  126. self.client.setLogScale((False, False))
  127. if self.properties['x-axis']['prop']['type']:
  128. self.client.SetXSpec(self.properties['x-axis']['prop']['type'])
  129. else:
  130. self.client.SetXSpec('auto')
  131. if self.properties['y-axis']['prop']['type']:
  132. self.client.SetYSpec(self.properties['y-axis']['prop']['type'])
  133. else:
  134. self.client.SetYSpec('auto')
  135. def InitRasterOpts(self, rasterList, plottype):
  136. """!Initialize or update raster dictionary for plotting
  137. """
  138. rdict = {} # initialize a dictionary
  139. for r in rasterList:
  140. idx = rasterList.index(r)
  141. try:
  142. ret = raster.raster_info(r)
  143. except:
  144. continue
  145. # if r.info cannot parse map, skip it
  146. self.raster[r] = UserSettings.Get(group = plottype, key = 'raster') # some default settings
  147. rdict[r] = {} # initialize sub-dictionaries for each raster in the list
  148. if ret['units'] == '(none)' or ret['units'] == '' or ret['units'] == None:
  149. rdict[r]['units'] = ''
  150. else:
  151. self.raster[r]['units'] = ret['units']
  152. rdict[r]['plegend'] = r.split('@')[0]
  153. rdict[r]['datalist'] = [] # list of cell value,frequency pairs for plotting histogram
  154. rdict[r]['pline'] = None
  155. rdict[r]['datatype'] = ret['datatype']
  156. rdict[r]['pwidth'] = 1
  157. rdict[r]['pstyle'] = 'solid'
  158. if idx <= len(self.colorList):
  159. rdict[r]['pcolor'] = self.colorDict[self.colorList[idx]]
  160. else:
  161. r = randint(0, 255)
  162. b = randint(0, 255)
  163. g = randint(0, 255)
  164. rdict[r]['pcolor'] = ((r,g,b,255))
  165. return rdict
  166. def InitRasterPairs(self, rasterList, plottype):
  167. """!Initialize or update raster dictionary with raster pairs for
  168. bivariate scatterplots
  169. """
  170. if len(rasterList) == 0: return
  171. rdict = {} # initialize a dictionary
  172. for rpair in rasterList:
  173. idx = rasterList.index(rpair)
  174. try:
  175. ret0 = raster.raster_info(rpair[0])
  176. ret1 = raster.raster_info(rpair[1])
  177. except:
  178. continue
  179. # if r.info cannot parse map, skip it
  180. self.raster[rpair] = UserSettings.Get(group = plottype, key = 'rasters') # some default settings
  181. rdict[rpair] = {} # initialize sub-dictionaries for each raster in the list
  182. rdict[rpair][0] = {}
  183. rdict[rpair][1] = {}
  184. if ret0['units'] == '(none)' or ret['units'] == '' or ret['units'] == None:
  185. rdict[rpair][0]['units'] = ''
  186. else:
  187. self.raster[rpair][0]['units'] = ret0['units']
  188. if ret1['units'] == '(none)' or ret['units'] == '' or ret['units'] == None:
  189. rdict[rpair][1]['units'] = ''
  190. else:
  191. self.raster[rpair][1]['units'] = ret1['units']
  192. rdict[rpair]['plegend'] = rpair[0].split('@')[0] + ' vs ' + rpair[1].split('@')[0]
  193. rdict[rpair]['datalist'] = [] # list of cell value,frequency pairs for plotting histogram
  194. rdict[rpair]['ptype'] = 'dot'
  195. rdict[rpair][0]['datatype'] = ret0['datatype']
  196. rdict[rpair][1]['datatype'] = ret1['datatype']
  197. rdict[rpair]['psize'] = 1
  198. rdict[rpair]['pfill'] = 'solid'
  199. if idx <= len(self.colorList):
  200. rdict[rpair]['pcolor'] = self.colorDict[self.colorList[idx]]
  201. else:
  202. r = randint(0, 255)
  203. b = randint(0, 255)
  204. g = randint(0, 255)
  205. rdict[rpair]['pcolor'] = ((r,g,b,255))
  206. return rdict
  207. def SetGraphStyle(self):
  208. """!Set plot and text options
  209. """
  210. self.client.SetFont(self.properties['font']['wxfont'])
  211. self.client.SetFontSizeTitle(self.properties['font']['prop']['titleSize'])
  212. self.client.SetFontSizeAxis(self.properties['font']['prop']['axisSize'])
  213. self.client.SetEnableZoom(self.zoom)
  214. self.client.SetEnableDrag(self.drag)
  215. #
  216. # axis settings
  217. #
  218. if self.properties['x-axis']['prop']['type'] == 'custom':
  219. self.client.SetXSpec('min')
  220. else:
  221. self.client.SetXSpec(self.properties['x-axis']['prop']['type'])
  222. if self.properties['y-axis']['prop']['type'] == 'custom':
  223. self.client.SetYSpec('min')
  224. else:
  225. self.client.SetYSpec(self.properties['y-axis']['prop'])
  226. if self.properties['x-axis']['prop']['type'] == 'custom' and \
  227. self.properties['x-axis']['prop']['min'] < self.properties['x-axis']['prop']['max']:
  228. self.properties['x-axis']['axis'] = (self.properties['x-axis']['prop']['min'],
  229. self.properties['x-axis']['prop']['max'])
  230. else:
  231. self.properties['x-axis']['axis'] = None
  232. if self.properties['y-axis']['prop']['type'] == 'custom' and \
  233. self.properties['y-axis']['prop']['min'] < self.properties['y-axis']['prop']['max']:
  234. self.properties['y-axis']['axis'] = (self.properties['y-axis']['prop']['min'],
  235. self.properties['y-axis']['prop']['max'])
  236. else:
  237. self.properties['y-axis']['axis'] = None
  238. self.client.SetEnableGrid(self.properties['grid']['enabled'])
  239. self.client.SetGridColour(wx.Color(self.properties['grid']['color'][0],
  240. self.properties['grid']['color'][1],
  241. self.properties['grid']['color'][2],
  242. 255))
  243. self.client.SetFontSizeLegend(self.properties['font']['prop']['legendSize'])
  244. self.client.SetEnableLegend(self.properties['legend']['enabled'])
  245. if self.properties['x-axis']['prop']['log'] == True:
  246. self.properties['x-axis']['axis'] = None
  247. self.client.SetXSpec('min')
  248. if self.properties['y-axis']['prop']['log'] == True:
  249. self.properties['y-axis']['axis'] = None
  250. self.client.SetYSpec('min')
  251. self.client.setLogScale((self.properties['x-axis']['prop']['log'],
  252. self.properties['y-axis']['prop']['log']))
  253. def DrawPlot(self, plotlist):
  254. """!Draw line and point plot from list plot elements.
  255. """
  256. self.plot = plot.PlotGraphics(plotlist,
  257. self.ptitle,
  258. self.xlabel,
  259. self.ylabel)
  260. if self.properties['x-axis']['prop']['type'] == 'custom':
  261. self.client.SetXSpec('min')
  262. else:
  263. self.client.SetXSpec(self.properties['x-axis']['prop']['type'])
  264. if self.properties['y-axis']['prop']['type'] == 'custom':
  265. self.client.SetYSpec('min')
  266. else:
  267. self.client.SetYSpec(self.properties['y-axis']['prop']['type'])
  268. self.client.Draw(self.plot, self.properties['x-axis']['axis'],
  269. self.properties['y-axis']['axis'])
  270. def DrawPointLabel(self, dc, mDataDict):
  271. """!This is the fuction that defines how the pointLabels are
  272. plotted dc - DC that will be passed mDataDict - Dictionary
  273. of data that you want to use for the pointLabel
  274. As an example I have decided I want a box at the curve
  275. point with some text information about the curve plotted
  276. below. Any wxDC method can be used.
  277. """
  278. dc.SetPen(wx.Pen(wx.BLACK))
  279. dc.SetBrush(wx.Brush( wx.BLACK, wx.SOLID ) )
  280. sx, sy = mDataDict["scaledXY"] #scaled x,y of closest point
  281. dc.DrawRectangle( sx-5,sy-5, 10, 10) #10by10 square centered on point
  282. px,py = mDataDict["pointXY"]
  283. cNum = mDataDict["curveNum"]
  284. pntIn = mDataDict["pIndex"]
  285. legend = mDataDict["legend"]
  286. #make a string to display
  287. s = "Crv# %i, '%s', Pt. (%.2f,%.2f), PtInd %i" %(cNum, legend, px, py, pntIn)
  288. dc.DrawText(s, sx , sy+1)
  289. def OnZoom(self, event):
  290. """!Enable zooming and disable dragging
  291. """
  292. self.zoom = True
  293. self.drag = False
  294. self.client.SetEnableZoom(self.zoom)
  295. self.client.SetEnableDrag(self.drag)
  296. def OnDrag(self, event):
  297. """!Enable dragging and disable zooming
  298. """
  299. self.zoom = False
  300. self.drag = True
  301. self.client.SetEnableDrag(self.drag)
  302. self.client.SetEnableZoom(self.zoom)
  303. def OnRedraw(self, event):
  304. """!Redraw the plot window. Unzoom to original size
  305. """
  306. self.client.Reset()
  307. self.client.Redraw()
  308. def OnErase(self, event):
  309. """!Erase the plot window
  310. """
  311. self.client.Clear()
  312. self.mapwin.ClearLines(self.mapwin.pdc)
  313. self.mapwin.ClearLines(self.mapwin.pdcTmp)
  314. self.mapwin.polycoords = []
  315. self.mapwin.Refresh()
  316. def SaveToFile(self, event):
  317. """!Save plot to graphics file
  318. """
  319. self.client.SaveFile()
  320. def OnMouseLeftDown(self,event):
  321. self.SetStatusText(_("Left Mouse Down at Point: (%.4f, %.4f)") % \
  322. self.client._getXY(event))
  323. event.Skip() # allows plotCanvas OnMouseLeftDown to be called
  324. def OnMotion(self, event):
  325. """!Indicate when mouse is outside the plot area
  326. """
  327. if self.client.OnLeave(event): print 'out of area'
  328. #show closest point (when enbled)
  329. if self.client.GetEnablePointLabel() == True:
  330. #make up dict with info for the pointLabel
  331. #I've decided to mark the closest point on the closest curve
  332. dlst = self.client.GetClosetPoint( self.client._getXY(event), pointScaled = True)
  333. if dlst != []: #returns [] if none
  334. curveNum, legend, pIndex, pointXY, scaledXY, distance = dlst
  335. #make up dictionary to pass to my user function (see DrawPointLabel)
  336. mDataDict = {"curveNum":curveNum, "legend":legend, "pIndex":pIndex,\
  337. "pointXY":pointXY, "scaledXY":scaledXY}
  338. #pass dict to update the pointLabel
  339. self.client.UpdatePointLabel(mDataDict)
  340. event.Skip() #go to next handler
  341. def PlotOptionsMenu(self, event):
  342. """!Popup menu for plot and text options
  343. """
  344. point = wx.GetMousePosition()
  345. popt = wx.Menu()
  346. # Add items to the menu
  347. settext = wx.MenuItem(popt, wx.ID_ANY, _('Text settings'))
  348. popt.AppendItem(settext)
  349. self.Bind(wx.EVT_MENU, self.PlotText, settext)
  350. setgrid = wx.MenuItem(popt, wx.ID_ANY, _('Plot settings'))
  351. popt.AppendItem(setgrid)
  352. self.Bind(wx.EVT_MENU, self.PlotOptions, setgrid)
  353. # Popup the menu. If an item is selected then its handler
  354. # will be called before PopupMenu returns.
  355. self.PopupMenu(popt)
  356. popt.Destroy()
  357. def NotFunctional(self):
  358. """!Creates a 'not functional' message dialog
  359. """
  360. dlg = wx.MessageDialog(parent = self,
  361. message = _('This feature is not yet functional'),
  362. caption = _('Under Construction'),
  363. style = wx.OK | wx.ICON_INFORMATION)
  364. dlg.ShowModal()
  365. dlg.Destroy()
  366. def OnPlotText(self, dlg):
  367. """!Custom text settings for histogram plot.
  368. """
  369. self.ptitle = dlg.ptitle
  370. self.xlabel = dlg.xlabel
  371. self.ylabel = dlg.ylabel
  372. dlg.UpdateSettings()
  373. self.client.SetFont(self.properties['font']['wxfont'])
  374. self.client.SetFontSizeTitle(self.properties['font']['prop']['titleSize'])
  375. self.client.SetFontSizeAxis(self.properties['font']['prop']['axisSize'])
  376. if self.plot:
  377. self.plot.setTitle(dlg.ptitle)
  378. self.plot.setXLabel(dlg.xlabel)
  379. self.plot.setYLabel(dlg.ylabel)
  380. self.OnRedraw(event = None)
  381. def PlotText(self, event):
  382. """!Set custom text values for profile title and axis labels.
  383. """
  384. dlg = dialogs.TextDialog(parent = self, id = wx.ID_ANY,
  385. plottype = self.plottype,
  386. title = _('Histogram text settings'))
  387. if dlg.ShowModal() == wx.ID_OK:
  388. self.OnPlotText(dlg)
  389. dlg.Destroy()
  390. def PlotOptions(self, event):
  391. """!Set various profile options, including: line width, color,
  392. style; marker size, color, fill, and style; grid and legend
  393. options. Calls OptDialog class.
  394. """
  395. dlg = dialogs.OptDialog(parent = self, id = wx.ID_ANY,
  396. plottype = self.plottype,
  397. title = _('Plot settings'))
  398. btnval = dlg.ShowModal()
  399. if btnval == wx.ID_SAVE:
  400. dlg.UpdateSettings()
  401. self.SetGraphStyle()
  402. dlg.Destroy()
  403. elif btnval == wx.ID_CANCEL:
  404. dlg.Destroy()
  405. def PrintMenu(self, event):
  406. """!Print options and output menu
  407. """
  408. point = wx.GetMousePosition()
  409. printmenu = wx.Menu()
  410. for title, handler in ((_("Page setup"), self.OnPageSetup),
  411. (_("Print preview"), self.OnPrintPreview),
  412. (_("Print display"), self.OnDoPrint)):
  413. item = wx.MenuItem(printmenu, wx.ID_ANY, title)
  414. printmenu.AppendItem(item)
  415. self.Bind(wx.EVT_MENU, handler, item)
  416. # Popup the menu. If an item is selected then its handler
  417. # will be called before PopupMenu returns.
  418. self.PopupMenu(printmenu)
  419. printmenu.Destroy()
  420. def OnPageSetup(self, event):
  421. self.client.PageSetup()
  422. def OnPrintPreview(self, event):
  423. self.client.PrintPreview()
  424. def OnDoPrint(self, event):
  425. self.client.Printout()
  426. def OnQuit(self, event):
  427. self.Close(True)
  428. def OnCloseWindow(self, event):
  429. """!Close plot window and clean up
  430. """
  431. try:
  432. self.mapwin.ClearLines()
  433. self.mapwin.mouse['begin'] = self.mapwin.mouse['end'] = (0.0, 0.0)
  434. self.mapwin.mouse['use'] = 'pointer'
  435. self.mapwin.mouse['box'] = 'point'
  436. self.mapwin.polycoords = []
  437. self.mapwin.UpdateMap(render = False, renderVector = False)
  438. except:
  439. pass
  440. self.mapwin.SetCursor(self.Parent.cursors["default"])
  441. self.Destroy()
  442. class HistFrame(AbstractPlotFrame):
  443. def __init__(self, parent, id, pos, style, size, rasterList = []):
  444. """!Mainframe for displaying histogram of raster map. Uses wx.lib.plot.
  445. """
  446. AbstractPlotFrame.__init__(self, parent)
  447. self.toolbar = Histogram2Toolbar(parent = self)
  448. self.SetToolBar(self.toolbar)
  449. self.SetLabel(_("GRASS Histogramming Tool"))
  450. #
  451. # Init variables
  452. #
  453. self.rasterList = rasterList
  454. self.plottype = 'histogram'
  455. self.group = ''
  456. self.ptitle = _('Histogram of') # title of window
  457. self.xlabel = _("Raster cell values") # default X-axis label
  458. self.ylabel = _("Cell counts") # default Y-axis label
  459. self.maptype = 'raster' # default type of histogram to plot
  460. self.histtype = 'count'
  461. self.bins = 255
  462. self.colorList = ["blue", "green", "red", "yellow", "magenta", "cyan", \
  463. "aqua", "black", "grey", "orange", "brown", "purple", "violet", \
  464. "indigo"]
  465. if len(self.rasterList) > 0: # set raster name(s) from layer manager if a map is selected
  466. self.InitRasterOpts(self.rasterList, self.plottype)
  467. self._initOpts()
  468. def _initOpts(self):
  469. """!Initialize plot options
  470. """
  471. self.InitPlotOpts('histogram')
  472. def OnCreateHist(self, event):
  473. """!Main routine for creating a histogram. Uses r.stats to
  474. create a list of cell value and count/percent/area pairs. This is passed to
  475. plot to create a line graph of the histogram.
  476. """
  477. self.SetCursor(self.parent.cursors["default"])
  478. self.SetGraphStyle()
  479. self.SetupHistogram()
  480. p = self.CreatePlotList()
  481. self.DrawPlot(p)
  482. def OnSelectRaster(self, event):
  483. """!Select raster map(s) to profile
  484. """
  485. dlg = dialogs.HistRasterDialog(parent = self)
  486. if dlg.ShowModal() == wx.ID_OK:
  487. self.rasterList = dlg.rasterList
  488. self.group = dlg.group
  489. self.bins = dlg.bins
  490. self.histtype = dlg.histtype
  491. self.maptype = dlg.maptype
  492. self.raster = self.InitRasterOpts(self.rasterList, self.plottype)
  493. # plot histogram
  494. if len(self.rasterList) > 0:
  495. self.OnCreateHist(event = None)
  496. dlg.Destroy()
  497. def SetupHistogram(self):
  498. """!Build data list for ploting each raster
  499. """
  500. #
  501. # populate raster dictionary
  502. #
  503. if len(self.rasterList) == 0: return # nothing selected
  504. for r in self.rasterList:
  505. self.raster[r]['datalist'] = self.CreateDatalist(r)
  506. #
  507. # update title
  508. #
  509. if self.maptype == 'group':
  510. self.ptitle = _('Histogram of %s') % self.group.split('@')[0]
  511. else:
  512. self.ptitle = _('Histogram of %s') % self.rasterList[0].split('@')[0]
  513. #
  514. # set xlabel based on first raster map in list to be histogrammed
  515. #
  516. units = self.raster[self.rasterList[0]]['units']
  517. if units != '' and units != '(none)' and units != None:
  518. self.xlabel = _('Raster cell values %s') % units
  519. else:
  520. self.xlabel = _('Raster cell values')
  521. #
  522. # set ylabel from self.histtype
  523. #
  524. if self.histtype == 'count': self.ylabel = _('Cell counts')
  525. if self.histtype == 'percent': self.ylabel = _('Percent of total cells')
  526. if self.histtype == 'area': self.ylabel = _('Area')
  527. def CreateDatalist(self, raster):
  528. """!Build a list of cell value, frequency pairs for histogram
  529. frequency can be in cell counts, percents, or area
  530. """
  531. datalist = []
  532. if self.histtype == 'count': freqflag = 'cn'
  533. if self.histtype == 'percent': freqflag = 'pn'
  534. if self.histtype == 'area': freqflag = 'an'
  535. try:
  536. ret = gcmd.RunCommand("r.stats",
  537. parent = self,
  538. input = raster,
  539. flags = freqflag,
  540. nsteps = self.bins,
  541. fs = ',',
  542. quiet = True,
  543. read = True)
  544. if not ret:
  545. return datalist
  546. for line in ret.splitlines():
  547. cellval, histval = line.strip().split(',')
  548. histval = histval.strip()
  549. if self.raster[raster]['datatype'] != 'CELL':
  550. cellval = cellval.split('-')[0]
  551. if self.histtype == 'percent':
  552. histval = histval.rstrip('%')
  553. datalist.append((cellval,histval))
  554. return datalist
  555. except gcmd.GException, e:
  556. gcmd.GError(parent = self,
  557. message = e.value)
  558. return None
  559. def CreatePlotList(self):
  560. """!Make list of elements to plot
  561. """
  562. # graph the cell value, frequency pairs for the histogram
  563. self.plotlist = []
  564. for r in self.rasterList:
  565. if len(self.raster[r]['datalist']) > 0:
  566. col = wx.Color(self.raster[r]['pcolor'][0],
  567. self.raster[r]['pcolor'][1],
  568. self.raster[r]['pcolor'][2],
  569. 255)
  570. self.raster[r]['pline'] = plot.PolyLine(self.raster[r]['datalist'],
  571. colour = col,
  572. width = self.raster[r]['pwidth'],
  573. style = self.linestyledict[self.raster[r]['pstyle']],
  574. legend = self.raster[r]['plegend'])
  575. self.plotlist.append(self.raster[r]['pline'])
  576. if len(self.plotlist) > 0:
  577. return self.plotlist
  578. else:
  579. return None
  580. def Update(self):
  581. """!Update histogram after changing options
  582. """
  583. self.SetGraphStyle()
  584. p = self.CreatePlotList()
  585. self.DrawPlot(p)
  586. def OnStats(self, event):
  587. """!Displays regression information in messagebox
  588. """
  589. message = []
  590. title = _('Statistics for Map(s) Histogrammed')
  591. for r in self.rasterList:
  592. rast = r.split('@')[0]
  593. ret = grass.read_command('r.univar', map = r, flags = 'e', quiet = True)
  594. stats = _('Statistics for %s\n\n%s\n') % (rast, ret)
  595. message.append(stats)
  596. stats = dialogs.PlotStatsFrame(self, id = wx.ID_ANY, message = message,
  597. title = title)
  598. if stats.Show() == wx.ID_CLOSE:
  599. stats.Destroy()
  600. class ProfileFrame(AbstractPlotFrame):
  601. """!Mainframe for displaying profile of one or more raster maps. Uses wx.lib.plot.
  602. """
  603. def __init__(self, parent, id, pos, style, size, rasterList = []):
  604. AbstractPlotFrame.__init__(self, parent)
  605. self.toolbar = ProfileToolbar(parent = self)
  606. self.SetToolBar(self.toolbar)
  607. self.SetLabel(_("GRASS Profile Analysis Tool"))
  608. #
  609. # Init variables
  610. #
  611. self.rasterList = rasterList
  612. self.plottype = 'profile'
  613. self.coordstr = '' # string of coordinates for r.profile
  614. self.seglist = [] # segment endpoint list
  615. self.ppoints = '' # segment endpoints data
  616. self.transect_length = 0.0 # total transect length
  617. self.ptitle = _('Profile of') # title of window
  618. self.raster = {}
  619. self.colorList = ["blue", "red", "green", "yellow", "magenta", "cyan", \
  620. "aqua", "black", "grey", "orange", "brown", "purple", "violet", \
  621. "indigo"]
  622. if len(self.rasterList) > 0: # set raster name(s) from layer manager if a map is selected
  623. self.InitRasterOpts(self.rasterList, self.plottype)
  624. self._initOpts()
  625. # determine units (axis labels)
  626. if self.parent.Map.projinfo['units'] != '':
  627. self.xlabel = _('Distance (%s)') % self.parent.Map.projinfo['units']
  628. else:
  629. self.xlabel = _("Distance along transect")
  630. self.ylabel = _("Cell values")
  631. def _initOpts(self):
  632. """!Initialize plot options
  633. """
  634. self.InitPlotOpts('profile')
  635. def OnDrawTransect(self, event):
  636. """!Draws transect to profile in map display
  637. """
  638. self.mapwin.polycoords = []
  639. self.seglist = []
  640. self.mapwin.ClearLines(self.mapwin.pdc)
  641. self.ppoints = ''
  642. self.parent.SetFocus()
  643. self.parent.Raise()
  644. self.mapwin.mouse['use'] = 'profile'
  645. self.mapwin.mouse['box'] = 'line'
  646. self.mapwin.pen = wx.Pen(colour = 'Red', width = 2, style = wx.SHORT_DASH)
  647. self.mapwin.polypen = wx.Pen(colour = 'dark green', width = 2, style = wx.SHORT_DASH)
  648. self.mapwin.SetCursor(self.Parent.cursors["cross"])
  649. def OnSelectRaster(self, event):
  650. """!Select raster map(s) to profile
  651. """
  652. dlg = dialogs.ProfileRasterDialog(parent = self)
  653. if dlg.ShowModal() == wx.ID_OK:
  654. self.rasterList = dlg.rasterList
  655. self.raster = self.InitRasterOpts(self.rasterList, self.plottype)
  656. # plot profile
  657. if len(self.mapwin.polycoords) > 0 and len(self.rasterList) > 0:
  658. self.OnCreateProfile(event = None)
  659. dlg.Destroy()
  660. def SetupProfile(self):
  661. """!Create coordinate string for profiling. Create segment list for
  662. transect segment markers.
  663. """
  664. #
  665. # create list of coordinate points for r.profile
  666. #
  667. dist = 0
  668. cumdist = 0
  669. self.coordstr = ''
  670. lasteast = lastnorth = None
  671. if len(self.mapwin.polycoords) > 0:
  672. for point in self.mapwin.polycoords:
  673. # build string of coordinate points for r.profile
  674. if self.coordstr == '':
  675. self.coordstr = '%d,%d' % (point[0], point[1])
  676. else:
  677. self.coordstr = '%s,%d,%d' % (self.coordstr, point[0], point[1])
  678. if len(self.rasterList) == 0:
  679. return
  680. # title of window
  681. self.ptitle = _('Profile of')
  682. #
  683. # create list of coordinates for transect segment markers
  684. #
  685. if len(self.mapwin.polycoords) > 0:
  686. self.seglist = []
  687. for point in self.mapwin.polycoords:
  688. # get value of raster cell at coordinate point
  689. ret = gcmd.RunCommand('r.what',
  690. parent = self,
  691. read = True,
  692. input = self.rasterList[0],
  693. east_north = '%d,%d' % (point[0],point[1]))
  694. val = ret.splitlines()[0].split('|')[3]
  695. if val == None or val == '*': continue
  696. val = float(val)
  697. # calculate distance between coordinate points
  698. if lasteast and lastnorth:
  699. dist = math.sqrt(math.pow((lasteast-point[0]),2) + math.pow((lastnorth-point[1]),2))
  700. cumdist += dist
  701. #store total transect length
  702. self.transect_length = cumdist
  703. # build a list of distance,value pairs for each segment of transect
  704. self.seglist.append((cumdist,val))
  705. lasteast = point[0]
  706. lastnorth = point[1]
  707. # delete extra first segment point
  708. try:
  709. self.seglist.pop(0)
  710. except:
  711. pass
  712. #
  713. # create datalist of dist/value pairs and y labels for each raster map
  714. #
  715. self.ylabel = ''
  716. i = 0
  717. for r in self.raster.iterkeys():
  718. self.raster[r]['datalist'] = []
  719. datalist = self.CreateDatalist(r, self.coordstr)
  720. if len(datalist) > 0:
  721. self.raster[r]['datalist'] = datalist
  722. # update ylabel to match units if they exist
  723. if self.raster[r]['units'] != '':
  724. self.ylabel += '%s (%d),' % (r['units'], i)
  725. i += 1
  726. # update title
  727. self.ptitle += ' %s ,' % r.split('@')[0]
  728. self.ptitle = self.ptitle.rstrip(',')
  729. if self.ylabel == '':
  730. self.ylabel = _('Raster values')
  731. else:
  732. self.ylabel = self.ylabel.rstrip(',')
  733. def CreateDatalist(self, raster, coords):
  734. """!Build a list of distance, value pairs for points along transect using r.profile
  735. """
  736. datalist = []
  737. # keep total number of transect points to 500 or less to avoid
  738. # freezing with large, high resolution maps
  739. region = grass.region()
  740. curr_res = min(float(region['nsres']),float(region['ewres']))
  741. transect_rec = 0
  742. if self.transect_length / curr_res > 500:
  743. transect_res = self.transect_length / 500
  744. else: transect_res = curr_res
  745. ret = gcmd.RunCommand("r.profile",
  746. parent = self,
  747. input = raster,
  748. profile = coords,
  749. res = transect_res,
  750. null = "nan",
  751. quiet = True,
  752. read = True)
  753. if not ret:
  754. return []
  755. for line in ret.splitlines():
  756. dist, elev = line.strip().split(' ')
  757. if dist == None or dist == '' or dist == 'nan' or \
  758. elev == None or elev == '' or elev == 'nan':
  759. continue
  760. dist = float(dist)
  761. elev = float(elev)
  762. datalist.append((dist,elev))
  763. return datalist
  764. def OnCreateProfile(self, event):
  765. """!Main routine for creating a profile. Uses r.profile to
  766. create a list of distance,cell value pairs. This is passed to
  767. plot to create a line graph of the profile. If the profile
  768. transect is in multiple segments, these are drawn as
  769. points. Profile transect is drawn, using methods in mapdisp.py
  770. """
  771. if len(self.mapwin.polycoords) == 0 or len(self.rasterList) == 0:
  772. dlg = wx.MessageDialog(parent = self,
  773. message = _('You must draw a transect to profile in the map display window.'),
  774. caption = _('Nothing to profile'),
  775. style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
  776. dlg.ShowModal()
  777. dlg.Destroy()
  778. return
  779. self.mapwin.SetCursor(self.parent.cursors["default"])
  780. self.SetCursor(self.parent.cursors["default"])
  781. self.SetGraphStyle()
  782. self.SetupProfile()
  783. p = self.CreatePlotList()
  784. self.DrawPlot(p)
  785. # reset transect
  786. self.mapwin.mouse['begin'] = self.mapwin.mouse['end'] = (0.0,0.0)
  787. self.mapwin.mouse['use'] = 'pointer'
  788. self.mapwin.mouse['box'] = 'point'
  789. def CreatePlotList(self):
  790. """!Create a plot data list from transect datalist and
  791. transect segment endpoint coordinates.
  792. """
  793. # graph the distance, value pairs for the transect
  794. self.plotlist = []
  795. # Add segment marker points to plot data list
  796. if len(self.seglist) > 0 :
  797. self.ppoints = plot.PolyMarker(self.seglist,
  798. legend = ' ' + self.properties['marker']['legend'],
  799. colour = wx.Color(self.properties['marker']['color'][0],
  800. self.properties['marker']['color'][1],
  801. self.properties['marker']['color'][2],
  802. 255),
  803. size = self.properties['marker']['size'],
  804. fillstyle = self.ptfilldict[self.properties['marker']['fill']],
  805. marker = self.properties['marker']['type'])
  806. self.plotlist.append(self.ppoints)
  807. # Add profile distance/elevation pairs to plot data list for each raster profiled
  808. for r in self.rasterList:
  809. col = wx.Color(self.raster[r]['pcolor'][0],
  810. self.raster[r]['pcolor'][1],
  811. self.raster[r]['pcolor'][2],
  812. 255)
  813. self.raster[r]['pline'] = plot.PolyLine(self.raster[r]['datalist'],
  814. colour = col,
  815. width = self.raster[r]['pwidth'],
  816. style = self.linestyledict[self.raster[r]['pstyle']],
  817. legend = self.raster[r]['plegend'])
  818. self.plotlist.append(self.raster[r]['pline'])
  819. if len(self.plotlist) > 0:
  820. return self.plotlist
  821. else:
  822. return None
  823. def Update(self):
  824. """!Update profile after changing options
  825. """
  826. self.SetGraphStyle()
  827. p = self.CreatePlotList()
  828. self.DrawPlot(p)
  829. def SaveProfileToFile(self, event):
  830. """!Save r.profile data to a csv file
  831. """
  832. wildcard = _("Comma separated value (*.csv)|*.csv")
  833. dlg = wx.FileDialog(parent = self,
  834. message = _("Path and prefix (for raster name) to save profile values..."),
  835. defaultDir = os.getcwd(),
  836. defaultFile = "", wildcard = wildcard, style = wx.SAVE)
  837. if dlg.ShowModal() == wx.ID_OK:
  838. path = dlg.GetPath()
  839. for r in self.rasterList:
  840. pfile = path+'_'+str(r['name'])+'.csv'
  841. try:
  842. file = open(pfile, "w")
  843. except IOError:
  844. wx.MessageBox(parent = self,
  845. message = _("Unable to open file <%s> for writing.") % pfile,
  846. caption = _("Error"), style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
  847. return False
  848. for datapair in self.raster[r]['datalist']:
  849. file.write('%d,%d\n' % (float(datapair[0]),float(datapair[1])))
  850. file.close()
  851. dlg.Destroy()
  852. def OnStats(self, event):
  853. """!Displays regression information in messagebox
  854. """
  855. message = []
  856. title = _('Statistics for Profile(s)')
  857. for r in self.raster.iterkeys():
  858. try:
  859. rast = r.split('@')[0]
  860. statstr = 'Profile of %s\n\n' % rast
  861. iterable = (i[1] for i in self.raster[r]['datalist'])
  862. a = numpy.fromiter(iterable, numpy.float)
  863. statstr += 'n: %f\n' % a.size
  864. statstr += 'minimum: %f\n' % numpy.amin(a)
  865. statstr += 'maximum: %f\n' % numpy.amax(a)
  866. statstr += 'range: %f\n' % numpy.ptp(a)
  867. statstr += 'mean: %f\n' % numpy.mean(a)
  868. statstr += 'standard deviation: %f\n' % numpy.std(a)
  869. statstr += 'variance: %f\n' % numpy.var(a)
  870. cv = numpy.std(a)/numpy.mean(a)
  871. statstr += 'coefficient of variation: %f\n' % cv
  872. statstr += 'sum: %f\n' % numpy.sum(a)
  873. statstr += 'median: %f\n' % numpy.median(a)
  874. statstr += 'distance along transect: %f\n\n' % self.transect_length
  875. message.append(statstr)
  876. except:
  877. pass
  878. stats = dialogs.PlotStatsFrame(self, id = wx.ID_ANY, message = message,
  879. title = title)
  880. if stats.Show() == wx.ID_CLOSE:
  881. stats.Destroy()
  882. class ScatterFrame(AbstractPlotFrame):
  883. """!Mainframe for displaying bivariate scatter plot of two raster maps. Uses wx.lib.plot.
  884. """
  885. def __init__(self, parent, id, pos, style, size, rasterList = []):
  886. AbstractPlotFrame.__init__(self, parent)
  887. self.toolbar = ScatterplotToolbar(parent = self)
  888. self.SetToolBar(self.toolbar)
  889. self.SetLabel(_("GRASS Bivariate Scatterplot Tool"))
  890. #
  891. # Init variables
  892. #
  893. self.rasterList = rasterList
  894. self.plottype = 'scatter'
  895. self.ptitle = _('Bivariate Scatterplot') # title of window
  896. self.xlabel = _("Raster cell values") # default X-axis label
  897. self.ylabel = _("Raster cell values") # default Y-axis label
  898. self.maptype = 'raster' # default type of scatterplot
  899. self.scattertype = 'normal'
  900. self.bins = 255
  901. self.colorList = ["blue", "red", "black", "green", "yellow", "magenta", "cyan", \
  902. "aqua", "grey", "orange", "brown", "purple", "violet", \
  903. "indigo"]
  904. if len(self.rasterList) > 1: # set raster name(s) from layer manager if a map is selected
  905. self.InitRasterOpts(self.rasterList, 'scatter')
  906. self._initOpts()
  907. def _initOpts(self):
  908. """!Initialize plot options
  909. """
  910. self.InitPlotOpts('scatter')
  911. def OnCreateScatter(self, event):
  912. """!Main routine for creating a scatterplot. Uses r.stats to
  913. create a list of cell value pairs. This is passed to
  914. plot to create a scatterplot.
  915. """
  916. self.SetCursor(self.parent.cursors["default"])
  917. self.SetGraphStyle()
  918. self.SetupScatterplot()
  919. p = self.CreatePlotList()
  920. self.DrawPlot(p)
  921. def OnSelectRaster(self, event):
  922. """!Select raster map(s) to profile
  923. """
  924. dlg = dialogs.ScatterRasterDialog(parent = self)
  925. if dlg.ShowModal() == wx.ID_OK:
  926. rlist = dlg.rasterList
  927. if rlist < 2:
  928. dlg.Destroy()
  929. return # need at least 2 rasters for scatterplot
  930. self.bins = dlg.bins # bins for r.stats with float and dcell maps
  931. self.scattertype = dlg.scattertype # scatterplot or bubbleplot
  932. self.rasterList = self.CreatePairs(rlist) # list of raster pairs (tuples)
  933. self.raster = self.InitRasterPairs(self.rasterList, 'scatter') # dictionary of raster pairs
  934. # plot histogram
  935. if len(self.rasterList) > 0:
  936. self.OnCreateScatter(event = None)
  937. dlg.Destroy()
  938. def CreatePairs(self, rlist):
  939. """!Transforms list of rasters into tuples of raster pairs
  940. """
  941. rasterList = []
  942. next = 'first'
  943. for r in rlist:
  944. if next == 'first':
  945. first = r
  946. next = 'second'
  947. else:
  948. second = r
  949. t = (first, second)
  950. rasterList.append(t)
  951. next = 'first'
  952. first = second = ''
  953. return rasterList
  954. def SetupScatterplot(self):
  955. """!Build data list for ploting each raster
  956. """
  957. #
  958. # initialize title string
  959. #
  960. self.ptitle = _('Bivariate Scatterplot of ')
  961. #
  962. # create a datalist for plotting for each raster pair
  963. #
  964. if len(self.rasterList) == 0: return # at least 1 pair of maps needed to plot
  965. for rpair in self.rasterList:
  966. self.raster[rpair]['datalist'] = self.CreateDatalist(rpair)
  967. # update title
  968. self.ptitle += '%s vs %s, ' % (rpair[0].split('@')[0], rpair[1].split('@')[0])
  969. self.ptitle = self.ptitle.strip(', ')
  970. #
  971. # set xlabel & ylabel based on raster maps of first pair to be plotted
  972. #
  973. units = self.raster[self.rasterList[0]][0]['units']
  974. if units != '' and units != '(none)' and units != None:
  975. self.xlabel = _('Raster cell values %s') % units
  976. else:
  977. self.xlabel = _('Raster cell values')
  978. units = self.raster[self.rasterList[0]][1]['units']
  979. if units != '' and units != '(none)' and units != None:
  980. self.ylabel = _('Raster cell values %s') % units
  981. else:
  982. self.ylabel = _('Raster cell values')
  983. def CreateDatalist(self, rpair):
  984. """!Build a list of cell value, frequency pairs for histogram
  985. frequency can be in cell counts, percents, or area
  986. """
  987. datalist = []
  988. if self.scattertype == 'bubble':
  989. freqflag = 'cn'
  990. else:
  991. freqflag = 'n'
  992. try:
  993. ret = gcmd.RunCommand("r.stats",
  994. parent = self,
  995. input = '%s,%s' % rpair,
  996. flags = freqflag,
  997. nsteps = self.bins,
  998. fs = ',',
  999. quiet = True,
  1000. read = True)
  1001. if not ret:
  1002. return datalist
  1003. for line in ret.splitlines():
  1004. rast1, rast2 = line.strip().split(',')
  1005. rast1 = rast1.strip()
  1006. if '-' in rast1: rast1 = rast1.split('-')[0]
  1007. rast2 = rast2.strip()
  1008. if '-' in rast2: rast2 = rast2.split('-')[0]
  1009. rast1 = rast1.encode('ascii', 'ignore')
  1010. rast2 = rast2.encode('ascii', 'ignore')
  1011. datalist.append((rast1,rast2))
  1012. return datalist
  1013. except gcmd.GException, e:
  1014. gcmd.GError(parent = self,
  1015. message = e.value)
  1016. return None
  1017. def CreatePlotList(self):
  1018. """!Make list of elements to plot
  1019. """
  1020. # graph the cell value, frequency pairs for the histogram
  1021. self.plotlist = []
  1022. for rpair in self.rasterList:
  1023. if 'datalist' not in self.raster[rpair] or \
  1024. self.raster[rpair]['datalist'] == None: return
  1025. if len(self.raster[rpair]['datalist']) > 0:
  1026. col = wx.Color(self.raster[rpair]['pcolor'][0],
  1027. self.raster[rpair]['pcolor'][1],
  1028. self.raster[rpair]['pcolor'][2],
  1029. 255)
  1030. scatterpoints = plot.PolyMarker(self.raster[rpair]['datalist'],
  1031. legend = ' ' + self.raster[rpair]['plegend'],
  1032. colour = col,size = self.raster[rpair]['psize'],
  1033. fillstyle = self.ptfilldict[self.raster[rpair]['pfill']],
  1034. marker = self.raster[rpair]['ptype'])
  1035. self.plotlist.append(scatterpoints)
  1036. if len(self.plotlist) > 0:
  1037. return self.plotlist
  1038. else:
  1039. return None
  1040. def Update(self):
  1041. """!Update histogram after changing options
  1042. """
  1043. self.SetGraphStyle()
  1044. p = self.CreatePlotList()
  1045. self.DrawPlot(p)
  1046. def OnRegression(self, event):
  1047. """!Displays regression information in messagebox
  1048. """
  1049. message = []
  1050. title = _('Regression Statistics for Scatterplot(s)')
  1051. for rpair in self.rasterList:
  1052. if isinstance(rpair, tuple) == False: continue
  1053. rast1, rast2 = rpair
  1054. rast1 = rast1.split('@')[0]
  1055. rast2 = rast2.split('@')[0]
  1056. ret = grass.parse_command('r.regression.line',
  1057. map1 = rast1,
  1058. map2 = rast2,
  1059. flags = 'g', quiet = True,
  1060. parse = (grass.parse_key_val, { 'sep' : '=' }))
  1061. eqtitle = _('Regression equation for %s vs. %s:\n\n') % (rast1, rast2)
  1062. eq = _(' %s = %s + %s(%s)\n\n') % (rast2, ret['a'], ret['b'], rast1)
  1063. num = _('N = %s\n') % ret['N']
  1064. rval = _('R = %s\n') % ret['R']
  1065. rsq = _('R-squared = %f\n') % pow(float(ret['R']), 2)
  1066. ftest = _('F = %s\n') % ret['F']
  1067. str = eqtitle + eq + num + rval + rsq + ftest
  1068. message.append(str)
  1069. stats = dialogs.PlotStatsFrame(self, id = wx.ID_ANY, message = message,
  1070. title = title)
  1071. if stats.Show() == wx.ID_CLOSE:
  1072. stats.Destroy()