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.