scatter.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. """!
  2. @package wxplot.scatter
  3. @brief Scatter plotting using PyPlot
  4. Classes:
  5. - ScatterFrame
  6. - ScatterToolbar
  7. (C) 2011 by the GRASS Development Team
  8. This program is free software under the GNU General Public License
  9. (>=v2). Read the file COPYING that comes with GRASS for details.
  10. @author Michael Barton, Arizona State University
  11. """
  12. import sys
  13. import wx
  14. import wx.lib.plot as plot
  15. import grass.script as grass
  16. from wxplot.base import BasePlotFrame
  17. from gui_core.toolbars import BaseToolbar
  18. class ScatterFrame(BasePlotFrame):
  19. """!Mainframe for displaying bivariate scatter plot of two raster maps. Uses wx.lib.plot.
  20. """
  21. def __init__(self, parent, id, pos, style, size, rasterList = []):
  22. BasePlotFrame.__init__(self, parent)
  23. self.toolbar = ScatterToolbar(parent = self)
  24. self.SetToolBar(self.toolbar)
  25. self.SetLabel(_("GRASS Bivariate Scatterplot Tool"))
  26. #
  27. # Init variables
  28. #
  29. self.rasterList = rasterList
  30. self.plottype = 'scatter'
  31. self.ptitle = _('Bivariate Scatterplot') # title of window
  32. self.xlabel = _("Raster cell values") # default X-axis label
  33. self.ylabel = _("Raster cell values") # default Y-axis label
  34. self.maptype = 'raster' # default type of scatterplot
  35. self.scattertype = 'normal'
  36. self.bins = 255
  37. self.colorList = ["blue", "red", "black", "green", "yellow", "magenta", "cyan", \
  38. "aqua", "grey", "orange", "brown", "purple", "violet", \
  39. "indigo"]
  40. if len(self.rasterList) > 1: # set raster name(s) from layer manager if a map is selected
  41. self.InitRasterOpts(self.rasterList, 'scatter')
  42. self._initOpts()
  43. def _initOpts(self):
  44. """!Initialize plot options
  45. """
  46. self.InitPlotOpts('scatter')
  47. def OnCreateScatter(self, event):
  48. """!Main routine for creating a scatterplot. Uses r.stats to
  49. create a list of cell value pairs. This is passed to
  50. plot to create a scatterplot.
  51. """
  52. self.SetCursor(self.parent.cursors["default"])
  53. self.SetGraphStyle()
  54. self.SetupScatterplot()
  55. p = self.CreatePlotList()
  56. self.DrawPlot(p)
  57. def OnSelectRaster(self, event):
  58. """!Select raster map(s) to profile
  59. """
  60. dlg = dialogs.ScatterRasterDialog(parent = self)
  61. if dlg.ShowModal() == wx.ID_OK:
  62. rlist = dlg.rasterList
  63. if rlist < 2:
  64. dlg.Destroy()
  65. return # need at least 2 rasters for scatterplot
  66. self.bins = dlg.bins # bins for r.stats with float and dcell maps
  67. self.scattertype = dlg.scattertype # scatterplot or bubbleplot
  68. self.rasterList = self.CreatePairs(rlist) # list of raster pairs (tuples)
  69. self.raster = self.InitRasterPairs(self.rasterList, 'scatter') # dictionary of raster pairs
  70. # plot histogram
  71. if len(self.rasterList) > 0:
  72. self.OnCreateScatter(event = None)
  73. dlg.Destroy()
  74. def CreatePairs(self, rlist):
  75. """!Transforms list of rasters into tuples of raster pairs
  76. """
  77. rasterList = []
  78. next = 'first'
  79. for r in rlist:
  80. if next == 'first':
  81. first = r
  82. next = 'second'
  83. else:
  84. second = r
  85. t = (first, second)
  86. rasterList.append(t)
  87. next = 'first'
  88. first = second = ''
  89. return rasterList
  90. def SetupScatterplot(self):
  91. """!Build data list for ploting each raster
  92. """
  93. #
  94. # initialize title string
  95. #
  96. self.ptitle = _('Bivariate Scatterplot of ')
  97. #
  98. # create a datalist for plotting for each raster pair
  99. #
  100. if len(self.rasterList) == 0: return # at least 1 pair of maps needed to plot
  101. for rpair in self.rasterList:
  102. self.raster[rpair]['datalist'] = self.CreateDatalist(rpair)
  103. # update title
  104. self.ptitle += '%s vs %s, ' % (rpair[0].split('@')[0], rpair[1].split('@')[0])
  105. self.ptitle = self.ptitle.strip(', ')
  106. #
  107. # set xlabel & ylabel based on raster maps of first pair to be plotted
  108. #
  109. units = self.raster[self.rasterList[0]][0]['units']
  110. if units != '' and units != '(none)' and units != None:
  111. self.xlabel = _('Raster cell values %s') % units
  112. else:
  113. self.xlabel = _('Raster cell values')
  114. units = self.raster[self.rasterList[0]][1]['units']
  115. if units != '' and units != '(none)' and units != None:
  116. self.ylabel = _('Raster cell values %s') % units
  117. else:
  118. self.ylabel = _('Raster cell values')
  119. def CreateDatalist(self, rpair):
  120. """!Build a list of cell value, frequency pairs for histogram
  121. frequency can be in cell counts, percents, or area
  122. """
  123. datalist = []
  124. if self.scattertype == 'bubble':
  125. freqflag = 'cn'
  126. else:
  127. freqflag = 'n'
  128. try:
  129. ret = gcmd.RunCommand("r.stats",
  130. parent = self,
  131. input = '%s,%s' % rpair,
  132. flags = freqflag,
  133. nsteps = self.bins,
  134. fs = ',',
  135. quiet = True,
  136. read = True)
  137. if not ret:
  138. return datalist
  139. for line in ret.splitlines():
  140. rast1, rast2 = line.strip().split(',')
  141. rast1 = rast1.strip()
  142. if '-' in rast1: rast1 = rast1.split('-')[0]
  143. rast2 = rast2.strip()
  144. if '-' in rast2: rast2 = rast2.split('-')[0]
  145. rast1 = rast1.encode('ascii', 'ignore')
  146. rast2 = rast2.encode('ascii', 'ignore')
  147. datalist.append((rast1,rast2))
  148. return datalist
  149. except gcmd.GException, e:
  150. gcmd.GError(parent = self,
  151. message = e.value)
  152. return None
  153. def CreatePlotList(self):
  154. """!Make list of elements to plot
  155. """
  156. # graph the cell value, frequency pairs for the histogram
  157. self.plotlist = []
  158. for rpair in self.rasterList:
  159. if 'datalist' not in self.raster[rpair] or \
  160. self.raster[rpair]['datalist'] == None: return
  161. if len(self.raster[rpair]['datalist']) > 0:
  162. col = wx.Color(self.raster[rpair]['pcolor'][0],
  163. self.raster[rpair]['pcolor'][1],
  164. self.raster[rpair]['pcolor'][2],
  165. 255)
  166. scatterpoints = plot.PolyMarker(self.raster[rpair]['datalist'],
  167. legend = ' ' + self.raster[rpair]['plegend'],
  168. colour = col,size = self.raster[rpair]['psize'],
  169. fillstyle = self.ptfilldict[self.raster[rpair]['pfill']],
  170. marker = self.raster[rpair]['ptype'])
  171. self.plotlist.append(scatterpoints)
  172. if len(self.plotlist) > 0:
  173. return self.plotlist
  174. else:
  175. return None
  176. def Update(self):
  177. """!Update histogram after changing options
  178. """
  179. self.SetGraphStyle()
  180. p = self.CreatePlotList()
  181. self.DrawPlot(p)
  182. def OnRegression(self, event):
  183. """!Displays regression information in messagebox
  184. """
  185. message = []
  186. title = _('Regression Statistics for Scatterplot(s)')
  187. for rpair in self.rasterList:
  188. if isinstance(rpair, tuple) == False: continue
  189. rast1, rast2 = rpair
  190. rast1 = rast1.split('@')[0]
  191. rast2 = rast2.split('@')[0]
  192. ret = grass.parse_command('r.regression.line',
  193. map1 = rast1,
  194. map2 = rast2,
  195. flags = 'g', quiet = True,
  196. parse = (grass.parse_key_val, { 'sep' : '=' }))
  197. eqtitle = _('Regression equation for %s vs. %s:\n\n') % (rast1, rast2)
  198. eq = _(' %s = %s + %s(%s)\n\n') % (rast2, ret['a'], ret['b'], rast1)
  199. num = _('N = %s\n') % ret['N']
  200. rval = _('R = %s\n') % ret['R']
  201. rsq = _('R-squared = %f\n') % pow(float(ret['R']), 2)
  202. ftest = _('F = %s\n') % ret['F']
  203. str = eqtitle + eq + num + rval + rsq + ftest
  204. message.append(str)
  205. stats = dialogs.PlotStatsFrame(self, id = wx.ID_ANY, message = message,
  206. title = title)
  207. if stats.Show() == wx.ID_CLOSE:
  208. stats.Destroy()
  209. class ScatterplotToolbar(BaseToolbar):
  210. """!Toolbar for bivariate scatterplots of raster map pairs
  211. """
  212. def __init__(self, parent):
  213. AbstractToolbar.__init__(self, parent)
  214. self.InitToolbar(self._toolbarData())
  215. # realize the toolbar
  216. self.Realize()
  217. def _toolbarData(self):
  218. """!Toolbar data"""
  219. icons = Icons['plot']
  220. # icons2 = Icons['modeler']
  221. return self._getToolbarData((('addraster', Icons['layerManager']["addRast"],
  222. self.parent.OnSelectRaster),
  223. (None, ),
  224. ('draw', icons["draw"],
  225. self.parent.OnCreateScatter),
  226. ('erase', Icons['displayWindow']["erase"],
  227. self.parent.OnErase),
  228. ('drag', Icons['displayWindow']['pan'],
  229. self.parent.OnDrag),
  230. ('zoom', Icons['displayWindow']['zoomIn'],
  231. self.parent.OnZoom),
  232. ('unzoom', Icons['displayWindow']['zoomBack'],
  233. self.parent.OnRedraw),
  234. (None, ),
  235. ('statistics', icons['statistics'],
  236. self.parent.OnRegression),
  237. ('image', Icons['displayWindow']["saveFile"],
  238. self.parent.SaveToFile),
  239. ('print', Icons['displayWindow']["print"],
  240. self.parent.PrintMenu),
  241. (None, ),
  242. ('settings', icons["options"],
  243. self.parent.PlotOptionsMenu),
  244. ('quit', icons["quit"],
  245. self.parent.OnQuit),
  246. ))