plots.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. """!
  2. @package iclass::plots
  3. @brief wxIClass plots (histograms, coincidence plots).
  4. Classes:
  5. - plots::PlotPanel
  6. (C) 2006-2011 by the GRASS Development Team
  7. This program is free software under the GNU General Public
  8. License (>=v2). Read the file COPYING that comes with GRASS
  9. for details.
  10. @author Vaclav Petras <wenzeslaus gmail.com>
  11. @author Anna Kratochvilova <kratochanna gmail.com>
  12. """
  13. import wx
  14. import wx.lib.plot as plot
  15. import wx.lib.scrolledpanel as scrolled
  16. class PlotPanel(scrolled.ScrolledPanel):
  17. """!Panel for drawing multiple plots.
  18. There are two types of plots: histograms and coincidence plots.
  19. Histograms show frequency of cell category values in training areas
  20. for each band and for one category. Coincidence plots show min max range
  21. of classes for each band.
  22. """
  23. def __init__(self, parent, statDict, statList):
  24. scrolled.ScrolledPanel.__init__(self, parent)
  25. self.SetupScrolling(scroll_x = False, scroll_y = True)
  26. self.parent = parent
  27. self.canvasList = []
  28. self.bandList = []
  29. self.statDict = statDict
  30. self.statList = statList
  31. self.currentCat = None
  32. self.mainSizer = wx.BoxSizer(wx.VERTICAL)
  33. self._createControlPanel()
  34. self.SetSizer(self.mainSizer)
  35. self.mainSizer.Fit(self)
  36. self.Layout()
  37. def _createControlPanel(self):
  38. self.graphSwitch = wx.Choice(self, id = wx.ID_ANY,
  39. choices = [_("Histograms"),
  40. _("Coincident plots")])
  41. self.mainSizer.Add(self.graphSwitch, proportion = 0, flag = wx.EXPAND|wx.ALL, border = 5)
  42. self.graphSwitch.Bind(wx.EVT_CHOICE, self.OnPlotTypeSelected)
  43. def OnPlotTypeSelected(self, event):
  44. """!Graph type selected"""
  45. if self.graphSwitch.GetSelection() == 0:
  46. if not self.statDict[self.currentCat].IsReady():
  47. return
  48. self.DrawHistograms(self.statDict[self.currentCat])
  49. else:
  50. self.DrawCoincidencePlots()
  51. def StddevChanged(self):
  52. """!Standard deviation multiplier changed, redraw histograms"""
  53. if self.graphSwitch.GetSelection() == 0:
  54. self.UpdateRanges(self.statDict[self.currentCat])
  55. def EnableZoom(self, type, enable = True):
  56. for canvas in self.canvasList:
  57. canvas.SetEnableZoom(enable)
  58. #canvas.zoom = type
  59. def EnablePan(self, enable = True):
  60. for canvas in self.canvasList:
  61. canvas.SetEnableDrag(enable)
  62. def DestroyPlots(self):
  63. """!Destroy all plot canvases"""
  64. for panel in self.canvasList:
  65. panel.Destroy()
  66. self.canvasList = []
  67. def CreatePlotCanvases(self):
  68. """!Create plot canvases according to the number of bands"""
  69. for band in self.bandList:
  70. canvas = plot.PlotCanvas(self)
  71. canvas.SetMinSize((-1, 140))
  72. canvas.SetFontSizeTitle(10)
  73. canvas.SetFontSizeAxis(8)
  74. self.canvasList.append(canvas)
  75. self.mainSizer.Add(item = canvas, proportion = 1, flag = wx.EXPAND, border = 0)
  76. self.SetVirtualSize(self.GetBestVirtualSize())
  77. self.Layout()
  78. def UpdatePlots(self, group, currentCat, statDict, statList):
  79. """!Update plots after new analysis
  80. @param group imagery group
  81. @param currentCat currently selected category (class)
  82. @param statDict dictionary with Statistics
  83. @param statList list of currently used categories
  84. """
  85. self.statDict = statDict
  86. self.statList = statList
  87. self.currentCat = currentCat
  88. self.bandList = self.parent.GetGroupLayers(group)
  89. graphType = self.graphSwitch.GetSelection()
  90. if not statDict[currentCat].IsReady() and graphType == 0:
  91. return
  92. self.DestroyPlots()
  93. self.CreatePlotCanvases()
  94. self.OnPlotTypeSelected(None)
  95. def UpdateCategory(self, cat):
  96. self.currentCat = cat
  97. def DrawCoincidencePlots(self):
  98. """!Draw coincidence plots"""
  99. for bandIdx in range(len(self.bandList)):
  100. self.canvasList[bandIdx].SetYSpec(type = 'none')
  101. lines = []
  102. level = 0.5
  103. lines.append(self.DrawInvisibleLine(level))
  104. for i, cat in enumerate(self.statList):
  105. if not self.statDict[cat].IsReady():
  106. continue
  107. color = self.statDict[cat].color
  108. level = i + 1
  109. line = self.DrawCoincidenceLine(level, color, self.statDict[cat].bands[bandIdx])
  110. lines.append(line)
  111. # invisible
  112. level += 0.5
  113. lines.append(self.DrawInvisibleLine(level))
  114. plotGraph = plot.PlotGraphics(lines, title = self.bandList[bandIdx])
  115. self.canvasList[bandIdx].Draw(plotGraph)
  116. def DrawCoincidenceLine(self, level, color, bandValues):
  117. """!Draw line between band min and max values
  118. @param level y coordinate of line
  119. @param color class color
  120. @param bandValues BandStatistics instance
  121. """
  122. minim = bandValues.min
  123. maxim = bandValues.max
  124. points = [(minim, level), (maxim, level)]
  125. color = wx.Color(*map(int, color.split(':')))
  126. return plot.PolyLine(points, colour = color, width = 4)
  127. def DrawInvisibleLine(self, level):
  128. """!Draw white line to achieve better margins"""
  129. points = [(100, level), (101, level)]
  130. return plot.PolyLine(points, colour = wx.WHITE, width = 1)
  131. def DrawHistograms(self, statistics):
  132. """!Draw histograms for one class
  133. @param statistics statistics for one class
  134. """
  135. self.histogramLines = []
  136. for bandIdx in range(len(self.bandList)):
  137. self.canvasList[bandIdx].Clear()
  138. self.canvasList[bandIdx].SetYSpec(type = 'auto')
  139. histgramLine = self.CreateHistogramLine(bandValues = statistics.bands[bandIdx])
  140. meanLine = self.CreateMean(bandValues = statistics.bands[bandIdx])
  141. minLine = self.CreateMin(bandValues = statistics.bands[bandIdx])
  142. maxLine = self.CreateMax(bandValues = statistics.bands[bandIdx])
  143. self.histogramLines.append([histgramLine, meanLine, minLine, maxLine])
  144. maxRangeLine = self.CreateMaxRange(bandValues = statistics.bands[bandIdx])
  145. minRangeLine = self.CreateMinRange(bandValues = statistics.bands[bandIdx])
  146. plotGraph = plot.PlotGraphics(self.histogramLines[bandIdx] + [minRangeLine, maxRangeLine],
  147. title = self.bandList[bandIdx])
  148. self.canvasList[bandIdx].Draw(plotGraph)
  149. def CreateMinRange(self, bandValues):
  150. maxVal = max(bandValues.histo)
  151. rMin = bandValues.rangeMin
  152. points = [(rMin, 0), (rMin, maxVal)]
  153. return plot.PolyLine(points, colour = wx.RED, width = 1)
  154. def CreateMaxRange(self, bandValues):
  155. maxVal = max(bandValues.histo)
  156. rMax = bandValues.rangeMax
  157. points = [(rMax, 0), (rMax, maxVal)]
  158. return plot.PolyLine(points, colour = wx.RED, width = 1)
  159. def CreateMean(self, bandValues):
  160. maxVal = max(bandValues.histo)
  161. mean = bandValues.mean
  162. points = [(mean, 0), (mean, maxVal)]
  163. return plot.PolyLine(points, colour = wx.BLUE, width = 1)
  164. def CreateMin(self, bandValues):
  165. maxVal = max(bandValues.histo)
  166. minim = bandValues.min
  167. points = [(minim, 0), (minim, maxVal)]
  168. return plot.PolyLine(points, colour = wx.Colour(200, 200, 200), width = 1)
  169. def CreateMax(self, bandValues):
  170. maxVal = max(bandValues.histo)
  171. maxim = bandValues.max
  172. points = [(maxim, 0), (maxim, maxVal)]
  173. return plot.PolyLine(points, colour = wx.Colour(200, 200, 200), width = 1)
  174. def CreateHistogramLine(self, bandValues):
  175. points = []
  176. for cellCat, count in enumerate(bandValues.histo):
  177. if cellCat < bandValues.min - 5:
  178. continue
  179. if cellCat > bandValues.max + 5:
  180. break
  181. points.append((cellCat, count))
  182. return plot.PolyLine(points, colour = wx.BLACK, width = 1)
  183. def UpdateRanges(self, statistics):
  184. """!Redraw ranges lines in histograms when std dev multiplier changes
  185. @param statistics python Statistics instance
  186. """
  187. for bandIdx in range(len(self.bandList)):
  188. self.canvasList[bandIdx].Clear()
  189. maxRangeLine = self.CreateMaxRange(bandValues = statistics.bands[bandIdx])
  190. minRangeLine = self.CreateMinRange(bandValues = statistics.bands[bandIdx])
  191. plotGraph = plot.PlotGraphics(self.histogramLines[bandIdx] + [minRangeLine, maxRangeLine],
  192. title = self.bandList[bandIdx])
  193. self.canvasList[bandIdx].Draw(plotGraph)