2 @package wxplot.profile 
    4 @brief Profiling using PyPlot 
    7  - profile::ProfileFrame 
    8  - profile::ProfileToolbar 
   10 (C) 2011-2012 by the GRASS Development Team 
   12 This program is free software under the GNU General Public License 
   13 (>=v2). Read the file COPYING that comes with GRASS for details. 
   15 @author Michael Barton, Arizona State University 
   23 import wx.lib.plot 
as plot
 
   30     msg = _(
"This module requires the NumPy module, which could not be " 
   31             "imported. It probably is not installed (it's not part of the " 
   32             "standard Python distribution). See the Numeric Python site " 
   33             "(http://numpy.scipy.org) for information on downloading source or " 
   35     print >> sys.stderr, 
"wxplot.py: " + msg
 
   40 from core.gcmd         import RunCommand, GWarning, GError, GMessage
 
   43     """!Mainframe for displaying profile of one or more raster maps. Uses wx.lib.plot. 
   45     def __init__(self, parent, id = wx.ID_ANY, style = wx.DEFAULT_FRAME_STYLE,
 
   46                  size = wx.Size(700, 400),
 
   47                  rasterList = [], **kwargs):
 
   48         BasePlotFrame.__init__(self, parent, size = size, **kwargs)
 
   52         self.SetTitle(_(
"GRASS Profile Analysis Tool"))
 
   64         self.
colorList =  [
"blue", 
"red", 
"green", 
"yellow", 
"magenta", 
"cyan",
 
   65                            "aqua", 
"black", 
"grey", 
"orange", 
"brown", 
"purple", 
"violet",
 
   76         if self.parent.Map.projinfo[
'units'] != 
'':
 
   77             self.
xlabel = _(
'Distance (%s)') % self.parent.Map.projinfo[
'units']
 
   79             self.
xlabel = _(
"Distance along transect")
 
   83         """!Initialize plot options 
   85         self.InitPlotOpts(
'profile')
 
   88         """!Draws transect to profile in map display 
   90         self.mapwin.polycoords = []
 
   92         self.mapwin.ClearLines(self.mapwin.pdc)
 
   95         self.parent.SetFocus()
 
   98         self.mapwin.mouse[
'use'] = 
'profile' 
   99         self.mapwin.mouse[
'box'] = 
'line' 
  100         self.mapwin.pen = wx.Pen(colour = 
'Red', width = 2, style = wx.SHORT_DASH)
 
  101         self.mapwin.polypen = wx.Pen(colour = 
'dark green', width = 2, style = wx.SHORT_DASH)
 
  102         self.mapwin.SetCursor(self.Parent.cursors[
"cross"])
 
  105         """!Select raster map(s) to profile 
  107         dlg = ProfileRasterDialog(parent = self)
 
  109         if dlg.ShowModal() == wx.ID_OK:
 
  114             if len(self.mapwin.polycoords) > 0 
and len(self.
rasterList) > 0:
 
  120         """!Create coordinate string for profiling. Create segment list for 
  121            transect segment markers. 
  130         lasteast = lastnorth = 
None 
  132         region = grass.region()
 
  134         if len(self.mapwin.polycoords) > 0:
 
  135             for point 
in self.mapwin.polycoords:
 
  136                 if not (region[
'w'] <= point[0] <= region[
'e'] 
and region[
's'] <= point[1] <= region[
'n']):
 
  140                     self.
coordstr = 
'%d,%d' % (point[0], point[1])
 
  145             GWarning(message = _(
"Not all points of profile lie inside computational region."),
 
  152         self.
ptitle = _(
'Profile of')
 
  157         if len(self.mapwin.polycoords) > 0:
 
  159             for point 
in self.mapwin.polycoords:
 
  165                                  east_north = 
'%d,%d' % (point[0],point[1]))
 
  167                 val = ret.splitlines()[0].
split(
'|')[3]
 
  168                 if val == 
None or val == 
'*': 
continue 
  172                 if lasteast 
and lastnorth:
 
  173                     dist = math.sqrt(math.pow((lasteast-point[0]),2) + math.pow((lastnorth-point[1]),2))
 
  180                 self.seglist.append((cumdist,val))
 
  196         for r 
in self.raster.iterkeys():
 
  197             self.
raster[r][
'datalist'] = []
 
  199             if len(datalist) > 0:   
 
  200                 self.
raster[r][
'datalist'] = datalist
 
  203                 if self.
raster[r][
'units'] != 
'':
 
  204                     self.
ylabel += 
'%s (%d),' % (r[
'units'], i)
 
  208                 self.
ptitle += 
' %s ,' % r.split(
'@')[0]
 
  210         self.
ptitle = self.ptitle.rstrip(
',')
 
  213             self.
ylabel = _(
'Raster values')
 
  215             self.
ylabel = self.ylabel.rstrip(
',')
 
  218         """!Build a list of distance, value pairs for points along transect using r.profile 
  224         region = grass.region()
 
  225         curr_res = 
min(float(region[
'nsres']),float(region[
'ewres']))
 
  229         else: transect_res = curr_res
 
  243         for line 
in ret.splitlines():
 
  244             dist, elev = line.strip().
split(
' ')
 
  245             if dist == 
None or dist == 
'' or dist == 
'nan' or \
 
  246                 elev == 
None or elev == 
'' or elev == 
'nan':
 
  250             datalist.append((dist,elev))
 
  255         """!Main routine for creating a profile. Uses r.profile to 
  256         create a list of distance,cell value pairs. This is passed to 
  257         plot to create a line graph of the profile. If the profile 
  258         transect is in multiple segments, these are drawn as 
  259         points. Profile transect is drawn, using methods in mapdisp.py 
  262         if len(self.mapwin.polycoords) == 0 
or len(self.
rasterList) == 0:
 
  263             dlg = wx.MessageDialog(parent = self,
 
  264                                    message = _(
'You must draw a transect to profile in the map display window.'),
 
  265                                    caption = _(
'Nothing to profile'),
 
  266                                    style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
 
  271         self.mapwin.SetCursor(self.parent.cursors[
"default"])
 
  272         self.SetCursor(self.parent.cursors[
"default"])
 
  279         self.mapwin.mouse[
'begin'] = self.mapwin.mouse[
'end'] = (0.0,0.0)
 
  280         self.mapwin.mouse[
'use'] = 
'pointer' 
  281         self.mapwin.mouse[
'box'] = 
'point' 
  284         """!Create a plot data list from transect datalist and 
  285             transect segment endpoint coordinates. 
  293                                            legend = 
' ' + self.properties[
'marker'][
'legend'],
 
  294                                            colour = wx.Colour(self.properties[
'marker'][
'color'][0],
 
  295                                                            self.properties[
'marker'][
'color'][1],
 
  296                                                            self.properties[
'marker'][
'color'][2],
 
  298                                            size = self.properties[
'marker'][
'size'],
 
  299                                            fillstyle = self.ptfilldict[self.properties[
'marker'][
'fill']],
 
  300                                            marker = self.properties[
'marker'][
'type'])
 
  301             self.plotlist.append(self.
ppoints)
 
  305             col = wx.Colour(self.
raster[r][
'pcolor'][0],
 
  306                            self.
raster[r][
'pcolor'][1],
 
  307                            self.
raster[r][
'pcolor'][2],
 
  309             self.
raster[r][
'pline'] = plot.PolyLine(self.
raster[r][
'datalist'],
 
  311                                                     width = self.
raster[r][
'pwidth'],
 
  312                                                     style = self.linestyledict[self.
raster[r][
'pstyle']],
 
  313                                                     legend = self.
raster[r][
'plegend'])
 
  315             self.plotlist.append(self.
raster[r][
'pline'])
 
  323         """!Update profile after changing options 
  330         """!Save r.profile data to a csv file 
  332         dlg = wx.FileDialog(parent = self,
 
  333                             message = _(
"Choose prefix for file(s) where to save profile values..."),
 
  334                             defaultDir = os.getcwd(), 
 
  335                             wildcard = _(
"Comma separated value (*.csv)|*.csv"), style = wx.SAVE)
 
  337         if dlg.ShowModal() == wx.ID_OK:
 
  340                 pfile.append(path + 
'_' + str(r.replace(
'@', 
'_')) + 
'.csv')
 
  341                 if os.path.exists(pfile[-1]):
 
  342                     dlgOv = wx.MessageDialog(self,
 
  343                                              message = _(
"File <%s> already exists. " 
  344                                                          "Do you want to overwrite this file?") % pfile[-1],
 
  345                                              caption = _(
"Overwrite file?"),
 
  346                                              style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
 
  347                     if dlgOv.ShowModal() != wx.ID_YES:
 
  353                     fd = open(pfile[-1], 
"w")
 
  355                     GError(parent = self,
 
  356                            message = _(
"Unable to open file <%s> for writing.\n" 
  357                                        "Reason: %s") % (pfile[-1], e))
 
  361                 for datapair 
in self.
raster[r][
'datalist']:
 
  362                     fd.write(
'%d,%d\n' % (float(datapair[0]),float(datapair[1])))
 
  368             message = _(
"%d files created:\n%s") % (len(pfile), 
'\n'.join(pfile))
 
  370             message = _(
"No files generated.")
 
  372         GMessage(parent = self, message = message)
 
  375         """!Displays regression information in messagebox 
  378         title = _(
'Statistics for Profile(s)')
 
  380         for r 
in self.raster.iterkeys():
 
  382                 rast = r.split(
'@')[0] 
 
  383                 statstr = 
'Profile of %s\n\n' % rast
 
  385                 iterable = (i[1] 
for i 
in self.
raster[r][
'datalist'])            
 
  386                 a = numpy.fromiter(iterable, numpy.float)
 
  388                 statstr += 
'n: %f\n' % a.size
 
  389                 statstr += 
'minimum: %f\n' % numpy.amin(a)
 
  390                 statstr += 
'maximum: %f\n' % numpy.amax(a)
 
  391                 statstr += 
'range: %f\n' % numpy.ptp(a)
 
  392                 statstr += 
'mean: %f\n' % numpy.mean(a)
 
  393                 statstr += 
'standard deviation: %f\n' % numpy.std(a)
 
  394                 statstr += 
'variance: %f\n' % numpy.var(a)
 
  395                 cv = numpy.std(a)/numpy.mean(a)
 
  396                 statstr += 
'coefficient of variation: %f\n' % cv
 
  397                 statstr += 
'sum: %f\n' % numpy.sum(a)
 
  398                 statstr += 
'median: %f\n' % numpy.median(a)
 
  400                 message.append(statstr)
 
  404         stats = PlotStatsFrame(self, id = wx.ID_ANY, message = message, 
 
  407         if stats.Show() == wx.ID_CLOSE:
 
  412     """!Toolbar for profiling raster map 
  415         BaseToolbar.__init__(self, parent)
 
  422     def _toolbarData(self):
 
  424         return self._getToolbarData(((
'addraster', BaseIcons[
"addRast"],
 
  425                                       self.parent.OnSelectRaster),
 
  426                                      (
'transect', PlotIcons[
"transect"],
 
  427                                       self.parent.OnDrawTransect),
 
  429                                      (
'draw', PlotIcons[
"draw"],
 
  430                                       self.parent.OnCreateProfile),
 
  431                                      (
'erase', BaseIcons[
"erase"],
 
  432                                       self.parent.OnErase),
 
  433                                      (
'drag', BaseIcons[
'pan'],
 
  435                                      (
'zoom', BaseIcons[
'zoomIn'],
 
  437                                      (
'unzoom', BaseIcons[
'zoomBack'],
 
  438                                       self.parent.OnRedraw),
 
  440                                      (
'statistics', PlotIcons[
'statistics'],
 
  441                                       self.parent.OnStats),
 
  442                                      (
'datasave', PlotIcons[
"save"],
 
  443                                       self.parent.SaveProfileToFile),
 
  444                                      (
'image', BaseIcons[
"saveFile"],
 
  445                                       self.parent.SaveToFile),
 
  446                                      (
'print', BaseIcons[
"print"],
 
  447                                       self.parent.PrintMenu),
 
  449                                      (
'settings', PlotIcons[
"options"],
 
  450                                       self.parent.PlotOptionsMenu),
 
  451                                      (
'quit', PlotIcons[
"quit"],
 
Dialogs for different plotting routines. 
 
def Update
Update profile after changing options. 
 
def OnSelectRaster
Select raster map(s) to profile. 
 
Base classes for iinteractive plotting using PyPlot. 
 
def OnDrawTransect
Draws transect to profile in map display. 
 
def OnCreateProfile
Main routine for creating a profile. 
 
def SetupProfile
Create coordinate string for profiling. 
 
def split
Platform spefic shlex.split. 
 
def OnStats
Displays regression information in messagebox. 
 
Mainframe for displaying profile of one or more raster maps. 
 
def CreateDatalist
Build a list of distance, value pairs for points along transect using r.profile. 
 
def SaveProfileToFile
Save r.profile data to a csv file. 
 
def _initOpts
Initialize plot options. 
 
def CreatePlotList
Create a plot data list from transect datalist and transect segment endpoint coordinates. 
 
def RunCommand
Run GRASS command.