""" @package wxplot.histogram @brief Histogramming using PyPlot Classes: - histogram::HistogramPlotFrame - histogram::HistogramPlotToolbar (C) 2011-2013 by the GRASS Development Team This program is free software under the GNU General Public License (>=v2). Read the file COPYING that comes with GRASS for details. @author Michael Barton, Arizona State University """ import sys import wx import grass.script as grass import wx.lib.plot as plot from gui_core.wrap import StockCursor from gui_core.toolbars import BaseToolbar, BaseIcons from wxplot.base import BasePlotFrame, PlotIcons from wxplot.dialogs import HistRasterDialog, PlotStatsFrame from core.gcmd import RunCommand, GException, GError class HistogramPlotFrame(BasePlotFrame): """Mainframe for displaying histogram of raster map. Uses wx.lib.plot. """ def __init__(self, parent, giface, id=wx.ID_ANY, style=wx.DEFAULT_FRAME_STYLE, size=wx.Size(700, 400), rasterList=[], **kwargs): BasePlotFrame.__init__(self, parent, giface=giface, size=size, **kwargs) self.toolbar = HistogramPlotToolbar(parent=self) # workaround for http://trac.wxwidgets.org/ticket/13888 if sys.platform != 'darwin': self.SetToolBar(self.toolbar) self.SetTitle(_("Histogram Tool")) # # Init variables # self.rasterList = rasterList self.plottype = 'histogram' self.group = '' self.ptitle = _('Histogram of') # title of window self.xlabel = _("Raster cell values") # default X-axis label self.ylabel = _("Cell counts") # default Y-axis label self.maptype = 'raster' # default type of histogram to plot self.histtype = 'count' self.bins = 255 self.colorList = [ "blue", "green", "red", "yellow", "magenta", "cyan", "aqua", "black", "grey", "orange", "brown", "purple", "violet", "indigo"] self._initOpts() if len( self.rasterList) > 0: # set raster name(s) from layer manager if a map is selected self.raster = self.InitRasterOpts(self.rasterList, self.plottype) wx.CallAfter(self.OnCreateHist, None) else: self.raster = {} def _initOpts(self): """Initialize plot options """ self.InitPlotOpts('histogram') def OnCreateHist(self, event): """Main routine for creating a histogram. Uses r.stats to create a list of cell value and count/percent/area pairs. This is passed to plot to create a line graph of the histogram. """ try: self.SetCursor(StockCursor(wx.CURSOR_ARROW)) except: pass self.SetGraphStyle() wx.BeginBusyCursor() wx.SafeYield() self.SetupHistogram() p = self.CreatePlotList() self.DrawPlot(p) wx.EndBusyCursor() def OnSelectRaster(self, event): """Select raster map(s) to profile """ dlg = HistRasterDialog(parent=self) if dlg.ShowModal() == wx.ID_OK: self.rasterList = dlg.rasterList self.group = dlg.group self.bins = dlg.bins self.histtype = dlg.histtype self.maptype = dlg.maptype self.raster = self.InitRasterOpts(self.rasterList, self.plottype) # plot histogram if len(self.rasterList) > 0: self.OnCreateHist(event=None) dlg.Destroy() def SetupHistogram(self): """Build data list for ploting each raster """ # # populate raster dictionary # if len(self.rasterList) == 0: return # nothing selected for r in self.rasterList: self.raster[r]['datalist'] = self.CreateDatalist(r) # # update title # if self.maptype == 'group': self.ptitle = _('Histogram of image group <%s>') % self.group else: if len(self.rasterList) == 1: self.ptitle = _( 'Histogram of raster map <%s>') % self.rasterList[0] else: self.ptitle = _('Histogram of selected raster maps') # # set xlabel based on first raster map in list to be histogrammed # units = self.raster[self.rasterList[0]]['units'] if units != '' and units != '(none)' and units is not None: self.xlabel = _('Raster cell values %s') % units else: self.xlabel = _('Raster cell values') # # set ylabel from self.histtype # if self.histtype == 'count': self.ylabel = _('Cell counts') if self.histtype == 'percent': self.ylabel = _('Percent of total cells') if self.histtype == 'area': self.ylabel = _('Area') def CreateDatalist(self, raster): """Build a list of cell value, frequency pairs for histogram frequency can be in cell counts, percents, or area """ datalist = [] if self.histtype == 'count': freqflag = 'cn' if self.histtype == 'percent': freqflag = 'pn' if self.histtype == 'area': freqflag = 'an' try: ret = RunCommand("r.stats", parent=self, input=raster, flags=freqflag, nsteps=self.bins, sep=',', quiet=True, read=True) if not ret: return datalist for line in ret.splitlines(): cellval, histval = line.strip().split(',') histval = histval.strip() if self.raster[raster]['datatype'] != 'CELL': if cellval[0] == '-': cellval = '-' + cellval.split('-')[1] else: cellval = cellval.split('-')[0] if self.histtype == 'percent': histval = histval.rstrip('%') datalist.append((cellval, histval)) return datalist except GException as e: GError(parent=self, message=e.value) return None def CreatePlotList(self): """Make list of elements to plot """ # graph the cell value, frequency pairs for the histogram self.plotlist = [] for r in self.rasterList: if len(self.raster[r]['datalist']) > 0: col = wx.Colour(self.raster[r]['pcolor'][0], self.raster[r]['pcolor'][1], self.raster[r]['pcolor'][2], 255) self.raster[r]['pline'] = plot.PolyLine( self.raster[r]['datalist'], colour=col, width=self.raster[r]['pwidth'], style=self.linestyledict[self.raster[r]['pstyle']], legend=self.raster[r]['plegend']) self.plotlist.append(self.raster[r]['pline']) if len(self.plotlist) > 0: return self.plotlist else: return None def Update(self): """Update histogram after changing options """ self.SetGraphStyle() p = self.CreatePlotList() self.DrawPlot(p) def OnStats(self, event): """Displays regression information in messagebox """ message = [] title = _('Statistics for Map(s) Histogrammed') for rast in self.rasterList: ret = grass.read_command( 'r.univar', map=rast, flags='e', quiet=True) stats = _('Statistics for raster map <%s>') % rast + ':\n%s\n' % ret message.append(stats) stats = PlotStatsFrame(self, id=wx.ID_ANY, message=message, title=title) if stats.Show() == wx.ID_CLOSE: stats.Destroy() class HistogramPlotToolbar(BaseToolbar): """Toolbar for histogramming raster map """ def __init__(self, parent): BaseToolbar.__init__(self, parent) # workaround for http://trac.wxwidgets.org/ticket/13888 if sys.platform == 'darwin': parent.SetToolBar(self) self.InitToolbar(self._toolbarData()) # realize the toolbar self.Realize() def _toolbarData(self): """Toolbar data""" return self._getToolbarData((('addraster', BaseIcons["addRast"], self.parent.OnSelectRaster), (None, ), ('draw', PlotIcons["draw"], self.parent.OnCreateHist), ('erase', BaseIcons["erase"], self.parent.OnErase), ('drag', BaseIcons['pan'], self.parent.OnDrag), ('zoom', BaseIcons['zoomIn'], self.parent.OnZoom), ('unzoom', BaseIcons['zoomExtent'], self.parent.OnRedraw), (None, ), ('statistics', PlotIcons['statistics'], self.parent.OnStats), ('image', BaseIcons["saveFile"], self.parent.SaveToFile), ('print', BaseIcons["print"], self.parent.PrintMenu), (None, ), ('settings', PlotIcons["options"], self.parent.PlotOptionsMenu), ('quit', PlotIcons["quit"], self.parent.OnQuit), ) )