profile.py 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456
  1. """!
  2. @package profile
  3. Profile analysis of GRASS raster maps and images.
  4. Uses PyPlot (wx.lib.plot.py)
  5. Classes:
  6. - ProfileFrame
  7. - SetRasterDialog
  8. - TextDialog
  9. - OptDialog
  10. (C) 2007-2008 by the GRASS Development Team
  11. This program is free software under the GNU General Public License
  12. (>=v2). Read the file COPYING that comes with GRASS for details.
  13. @author Michael Barton
  14. @author Various updates by Martin Landa <landa.martin gmail.com>
  15. """
  16. import os
  17. import sys
  18. import math
  19. import wx
  20. import wx.lib.colourselect as csel
  21. try:
  22. import numpy
  23. import wx.lib.plot as plot
  24. except ImportError:
  25. msg= _("This module requires the NumPy module, which could not be "
  26. "imported. It probably is not installed (it's not part of the "
  27. "standard Python distribution). See the Numeric Python site "
  28. "(http://numpy.scipy.org) for information on downloading source or "
  29. "binaries.")
  30. print >> sys.stderr, "profile.py: " + msg
  31. import globalvar
  32. import render
  33. import menuform
  34. import disp_print
  35. import gselect
  36. import gcmd
  37. import toolbars
  38. from debug import Debug as Debug
  39. from icon import Icons as Icons
  40. from preferences import globalSettings as UserSettings
  41. from grass.script import core as grass
  42. class ProfileFrame(wx.Frame):
  43. """!Mainframe for displaying profile of raster map. Uses wx.lib.plot.
  44. """
  45. def __init__(self, parent=None, id=wx.ID_ANY, title=_("Profile Analysis"),
  46. rasterList=[],
  47. pos=wx.DefaultPosition, size=wx.DefaultSize,
  48. style=wx.DEFAULT_FRAME_STYLE):
  49. self.parent = parent # MapFrame
  50. self.mapwin = self.parent.MapWindow
  51. self.Map = render.Map() # instance of render.Map to be associated with display
  52. self.pstyledict = { 'solid' : wx.SOLID,
  53. 'dot' : wx.DOT,
  54. 'long-dash' : wx.LONG_DASH,
  55. 'short-dash' : wx.SHORT_DASH,
  56. 'dot-dash' : wx.DOT_DASH }
  57. self.ptfilldict = { 'transparent' : wx.TRANSPARENT,
  58. 'solid' : wx.SOLID }
  59. wx.Frame.__init__(self, parent, id, title, pos, size, style)
  60. #
  61. # Icon
  62. #
  63. self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
  64. #
  65. # Add toolbar
  66. #
  67. self.toolbar = toolbars.ProfileToolbar(parent=self)
  68. self.SetToolBar(self.toolbar)
  69. #
  70. # Set the size & cursor
  71. #
  72. self.SetClientSize(size)
  73. #
  74. # Add statusbar
  75. #
  76. self.statusbar = self.CreateStatusBar(number=2, style=0)
  77. self.statusbar.SetStatusWidths([-2, -1])
  78. #
  79. # Define canvas
  80. #
  81. # plot canvas settings
  82. self.client = plot.PlotCanvas(self)
  83. #define the function for drawing pointLabels
  84. self.client.SetPointLabelFunc(self.DrawPointLabel)
  85. # Create mouse event for showing cursor coords in status bar
  86. self.client.canvas.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown)
  87. # Show closest point when enabled
  88. self.client.canvas.Bind(wx.EVT_MOTION, self.OnMotion)
  89. #
  90. # Init variables
  91. #
  92. # 0 -> default raster map to profile
  93. # 1, 2 -> optional raster map to profile
  94. # units -> map data units (used for y axis legend)
  95. self.raster = {}
  96. for idx in (0, 1, 2):
  97. self.raster[idx] = {}
  98. self.raster[idx]['name'] = ''
  99. self.raster[idx]['units'] = ''
  100. self.raster[idx]['plegend'] = ''
  101. # list of distance,value pairs for plotting profile
  102. self.raster[idx]['datalist'] = []
  103. # first (default) profile line
  104. self.raster[idx]['pline'] = None
  105. self.raster[idx]['prop'] = UserSettings.Get(group='profile', key='raster' + str(idx))
  106. # changing color string to tuple
  107. colstr = str(self.raster[idx]['prop']['pcolor'])
  108. self.raster[idx]['prop']['pcolor'] = tuple(int(colval) for colval in colstr.strip('()').split(','))
  109. # set raster map name (if given)
  110. for idx in range(len(rasterList)):
  111. self.raster[idx]['name'] = rasterList[idx]
  112. # string of coordinates for r.profile
  113. self.coordstr = ''
  114. # segment endpoint list
  115. self.seglist = []
  116. # list of things to plot
  117. self.plotlist = []
  118. # segment endpoints data
  119. self.ppoints = ''
  120. # plot draw object
  121. self.profile = None
  122. # total transect length
  123. self.transect_length = 0.0
  124. # title of window
  125. self.ptitle = _('Profile of')
  126. # determine units (axis labels)
  127. if self.parent.Map.projinfo['units'] != '':
  128. self.xlabel = _('Distance (%s)') % self.parent.Map.projinfo['units']
  129. else:
  130. self.xlabel = _("Distance along transect")
  131. self.ylabel = _("Cell values")
  132. self.properties = {}
  133. self.properties['font'] = {}
  134. self.properties['font']['prop'] = UserSettings.Get(group='profile', key='font')
  135. self.properties['font']['wxfont'] = wx.Font(11, wx.FONTFAMILY_SWISS,
  136. wx.FONTSTYLE_NORMAL,
  137. wx.FONTWEIGHT_NORMAL)
  138. self.properties['marker'] = UserSettings.Get(group='profile', key='marker')
  139. # changing color string to tuple
  140. colstr = str(self.properties['marker']['color'])
  141. self.properties['marker']['color'] = tuple(int(colval) for colval in colstr.strip('()').split(','))
  142. self.properties['grid'] = UserSettings.Get(group='profile', key='grid')
  143. # changing color string to tuple
  144. colstr = str(self.properties['grid']['color'])
  145. self.properties['grid']['color'] = tuple(int(colval) for colval in colstr.strip('()').split(','))
  146. self.properties['x-axis'] = {}
  147. self.properties['x-axis']['prop'] = UserSettings.Get(group='profile', key='x-axis')
  148. self.properties['x-axis']['axis'] = None
  149. self.properties['y-axis'] = {}
  150. self.properties['y-axis']['prop'] = UserSettings.Get(group='profile', key='y-axis')
  151. self.properties['y-axis']['axis'] = None
  152. self.properties['legend'] = UserSettings.Get(group='profile', key='legend')
  153. # zooming disabled
  154. self.zoom = False
  155. # draging disabled
  156. self.drag = False
  157. # vertical and horizontal scrollbars
  158. self.client.SetShowScrollbars(True)
  159. # x and y axis set to normal (non-log)
  160. self.client.setLogScale((False, False))
  161. if self.properties['x-axis']['prop']['type']:
  162. self.client.SetXSpec(self.properties['x-axis']['prop']['type'])
  163. else:
  164. self.client.SetXSpec('auto')
  165. if self.properties['y-axis']['prop']['type']:
  166. self.client.SetYSpec(self.properties['y-axis']['prop']['type'])
  167. else:
  168. self.client.SetYSpec('auto')
  169. #
  170. # Bind various events
  171. #
  172. self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
  173. self.CentreOnScreen()
  174. def OnDrawTransect(self, event):
  175. """!Draws transect to profile in map display
  176. """
  177. self.mapwin.polycoords = []
  178. self.seglist = []
  179. self.mapwin.ClearLines(self.mapwin.pdc)
  180. self.ppoints = ''
  181. self.parent.SetFocus()
  182. self.parent.Raise()
  183. self.mapwin.mouse['use'] = 'profile'
  184. self.mapwin.mouse['box'] = 'line'
  185. self.mapwin.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
  186. self.mapwin.polypen = wx.Pen(colour='dark green', width=2, style=wx.SHORT_DASH)
  187. self.mapwin.SetCursor(self.Parent.cursors["cross"])
  188. def OnSelectRaster(self, event):
  189. """!Select raster map(s) to profile
  190. """
  191. dlg = SetRasterDialog(parent=self)
  192. if dlg.ShowModal() == wx.ID_OK:
  193. for r in self.raster.keys():
  194. self.raster[r]['name'] = dlg.raster[r]['name']
  195. # plot profile
  196. if self.raster[0]['name'] and len(self.mapwin.polycoords) > 0:
  197. self.OnCreateProfile(event=None)
  198. dlg.Destroy()
  199. def SetRaster(self):
  200. """!Create coordinate string for profiling. Create segment list for
  201. transect segment markers.
  202. """
  203. #
  204. # create list of coordinate points for r.profile
  205. #
  206. dist = 0
  207. cumdist = 0
  208. self.coordstr = ''
  209. lasteast = lastnorth = None
  210. if len(self.mapwin.polycoords) > 0:
  211. for point in self.mapwin.polycoords:
  212. # build string of coordinate points for r.profile
  213. if self.coordstr == '':
  214. self.coordstr = '%d,%d' % (point[0], point[1])
  215. else:
  216. self.coordstr = '%s,%d,%d' % (self.coordstr, point[0], point[1])
  217. if self.raster[0]['name'] == '':
  218. return
  219. # title of window
  220. self.ptitle = _('Profile of')
  221. #
  222. # create list of coordinates for transect segment markers
  223. #
  224. if len(self.mapwin.polycoords) > 0:
  225. for point in self.mapwin.polycoords:
  226. # get value of raster cell at coordinate point
  227. ret = gcmd.RunCommand('r.what',
  228. parent = self,
  229. read = True,
  230. input = self.raster[0]['name'],
  231. east_north = '%d,%d' % (point[0],point[1]))
  232. val = ret.splitlines()[0].split('|')[3]
  233. # calculate distance between coordinate points
  234. if lasteast and lastnorth:
  235. dist = math.sqrt(math.pow((lasteast-point[0]),2) + math.pow((lastnorth-point[1]),2))
  236. cumdist += dist
  237. #store total transect length
  238. self.transect_length = cumdist
  239. # build a list of distance,value pairs for each segment of transect
  240. self.seglist.append((cumdist,val))
  241. lasteast = point[0]
  242. lastnorth = point[1]
  243. # delete first and last segment point
  244. try:
  245. self.seglist.pop(0)
  246. self.seglist.pop()
  247. except:
  248. pass
  249. #
  250. # create datalist for each raster map
  251. #
  252. for r in self.raster.itervalues():
  253. if r['name'] == '':
  254. continue
  255. r['datalist'] = self.CreateDatalist(r['name'], self.coordstr)
  256. r['plegend'] = _('Profile of %s') % r['name']
  257. ret = gcmd.RunCommand('r.info',
  258. parent = self,
  259. read = True,
  260. quiet = True,
  261. flags = 'u',
  262. map = r['name'])
  263. if ret:
  264. r['units'] = ret.splitlines()[0].split('=')[1]
  265. # update title
  266. self.ptitle += ' %s and' % r['name']
  267. self.ptitle = self.ptitle.rstrip('and')
  268. #
  269. # set ylabel to match units if they exist
  270. #
  271. self.ylabel = ''
  272. i = 0
  273. for r in self.raster.itervalues():
  274. if r['name'] == '':
  275. continue
  276. if r['units'] != '':
  277. self.ylabel = '%s (%d),' % (r['units'], i)
  278. i += 1
  279. if self.ylabel == '':
  280. self.ylabel = _('Raster values')
  281. else:
  282. self.ylabel = self.ylabel.rstrip(',')
  283. def SetGraphStyle(self):
  284. """!Set plot and text options
  285. """
  286. self.client.SetFont(self.properties['font']['wxfont'])
  287. self.client.SetFontSizeTitle(self.properties['font']['prop']['titleSize'])
  288. self.client.SetFontSizeAxis(self.properties['font']['prop']['axisSize'])
  289. self.client.SetEnableZoom(self.zoom)
  290. self.client.SetEnableDrag(self.drag)
  291. #
  292. # axis settings
  293. #
  294. if self.properties['x-axis']['prop']['type'] == 'custom':
  295. self.client.SetXSpec('min')
  296. else:
  297. self.client.SetXSpec(self.properties['x-axis']['prop']['type'])
  298. if self.properties['y-axis']['prop']['type'] == 'custom':
  299. self.client.SetYSpec('min')
  300. else:
  301. self.client.SetYSpec(self.properties['y-axis']['prop']['type'])
  302. if self.properties['x-axis']['prop']['type'] == 'custom' and \
  303. self.properties['x-axis']['prop']['min'] < self.properties['x-axis']['prop']['max']:
  304. self.properties['x-axis']['axis'] = (self.properties['x-axis']['prop']['min'],
  305. self.properties['x-axis']['prop']['max'])
  306. else:
  307. self.properties['x-axis']['axis'] = None
  308. if self.properties['y-axis']['prop']['type'] == 'custom' and \
  309. self.properties['y-axis']['prop']['min'] < self.properties['y-axis']['prop']['max']:
  310. self.properties['y-axis']['axis'] = (self.properties['y-axis']['prop']['min'],
  311. self.properties['y-axis']['prop']['max'])
  312. else:
  313. self.properties['y-axis']['axis'] = None
  314. self.client.SetEnableGrid(self.properties['grid']['enabled'])
  315. self.client.SetGridColour(wx.Color(self.properties['grid']['color'][0],
  316. self.properties['grid']['color'][1],
  317. self.properties['grid']['color'][2],
  318. 255))
  319. self.client.SetFontSizeLegend(self.properties['font']['prop']['legendSize'])
  320. self.client.SetEnableLegend(self.properties['legend']['enabled'])
  321. if self.properties['x-axis']['prop']['log'] == True:
  322. self.properties['x-axis']['axis'] = None
  323. self.client.SetXSpec('min')
  324. if self.properties['y-axis']['prop']['log'] == True:
  325. self.properties['y-axis']['axis'] = None
  326. self.client.SetYSpec('min')
  327. self.client.setLogScale((self.properties['x-axis']['prop']['log'],
  328. self.properties['y-axis']['prop']['log']))
  329. # self.client.SetPointLabelFunc(self.DrawPointLabel())
  330. def CreateDatalist(self, raster, coords):
  331. """!Build a list of distance, value pairs for points along transect
  332. """
  333. datalist = []
  334. # keep total number of transect points to 500 or less to avoid
  335. # freezing with large, high resolution maps
  336. region = grass.region()
  337. curr_res = min(float(region['nsres']),float(region['ewres']))
  338. transect_rec = 0
  339. if self.transect_length / curr_res > 500:
  340. transect_res = self.transect_length / 500
  341. else: transect_res = curr_res
  342. try:
  343. ret = gcmd.RunCommand("r.profile",
  344. input=raster,
  345. profile=coords,
  346. res=transect_res,
  347. null="nan",
  348. quiet=True,
  349. read = True)
  350. if not ret:
  351. return dataset
  352. for line in ret.splitlines():
  353. dist, elev = line.strip().split(' ')
  354. if elev != 'nan':
  355. datalist.append((dist,elev))
  356. return datalist
  357. except gcmd.CmdError, e:
  358. print e
  359. return None
  360. def OnCreateProfile(self, event):
  361. """!Main routine for creating a profile. Uses r.profile to
  362. create a list of distance,cell value pairs. This is passed to
  363. plot to create a line graph of the profile. If the profile
  364. transect is in multiple segments, these are drawn as
  365. points. Profile transect is drawn, using methods in mapdisp.py
  366. """
  367. if len(self.mapwin.polycoords) == 0 or self.raster[0]['name'] == '':
  368. dlg = wx.MessageDialog(parent=self,
  369. message=_('You must draw a transect to profile in the map display window.'),
  370. caption=_('Nothing to profile'),
  371. style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
  372. dlg.ShowModal()
  373. dlg.Destroy()
  374. return
  375. self.mapwin.SetCursor(self.parent.cursors["default"])
  376. self.SetCursor(self.parent.cursors["default"])
  377. self.SetGraphStyle()
  378. self.SetRaster()
  379. self.DrawPlot()
  380. # reset transect
  381. self.mapwin.mouse['begin'] = self.mapwin.mouse['end'] = (0.0,0.0)
  382. self.mapwin.mouse['use'] = 'pointer'
  383. self.mapwin.mouse['box'] = 'point'
  384. def DrawPlot(self):
  385. """!Draw line and point plot from transect datalist and
  386. transect segment endpoint coordinates.
  387. """
  388. # graph the distance, value pairs for the transect
  389. self.plotlist = []
  390. if len(self.seglist) > 0 :
  391. self.ppoints = plot.PolyMarker(self.seglist,
  392. legend=' ' + self.properties['marker']['legend'],
  393. colour=wx.Color(self.properties['marker']['color'][0],
  394. self.properties['marker']['color'][1],
  395. self.properties['marker']['color'][2],
  396. 255),
  397. size=self.properties['marker']['size'],
  398. fillstyle=self.ptfilldict[self.properties['marker']['fill']],
  399. marker=self.properties['marker']['type'])
  400. self.plotlist.append(self.ppoints)
  401. for r in self.raster.itervalues():
  402. if len(r['datalist']) > 0:
  403. col = wx.Color(r['prop']['pcolor'][0],
  404. r['prop']['pcolor'][1],
  405. r['prop']['pcolor'][2],
  406. 255)
  407. r['pline'] = plot.PolyLine(r['datalist'],
  408. colour=col,
  409. width=r['prop']['pwidth'],
  410. style=self.pstyledict[r['prop']['pstyle']],
  411. legend=r['plegend'])
  412. self.plotlist.append(r['pline'])
  413. self.profile = plot.PlotGraphics(self.plotlist,
  414. self.ptitle,
  415. self.xlabel,
  416. self.ylabel)
  417. if self.properties['x-axis']['prop']['type'] == 'custom':
  418. self.client.SetXSpec('min')
  419. else:
  420. self.client.SetXSpec(self.properties['x-axis']['prop']['type'])
  421. if self.properties['y-axis']['prop']['type'] == 'custom':
  422. self.client.SetYSpec('min')
  423. else:
  424. self.client.SetYSpec(self.properties['y-axis']['prop']['type'])
  425. self.client.Draw(self.profile, self.properties['x-axis']['axis'],
  426. self.properties['y-axis']['axis'])
  427. def OnZoom(self, event):
  428. """!Enable zooming and disable dragging
  429. """
  430. self.zoom = True
  431. self.drag = False
  432. self.client.SetEnableZoom(self.zoom)
  433. self.client.SetEnableDrag(self.drag)
  434. def OnDrag(self, event):
  435. """!Enable dragging and disable zooming
  436. """
  437. self.zoom = False
  438. self.drag = True
  439. self.client.SetEnableDrag(self.drag)
  440. self.client.SetEnableZoom(self.zoom)
  441. def OnRedraw(self, event):
  442. """!Redraw the profile window. Unzoom to original size
  443. """
  444. self.client.Reset()
  445. self.client.Redraw()
  446. def Update(self):
  447. """!Update profile after changing options
  448. """
  449. self.SetGraphStyle()
  450. self.DrawPlot()
  451. def OnErase(self, event):
  452. """!Erase the profile window
  453. """
  454. self.client.Clear()
  455. self.mapwin.ClearLines(self.mapwin.pdc)
  456. self.mapwin.ClearLines(self.mapwin.pdcTmp)
  457. self.mapwin.polycoords = []
  458. self.mapwin.Refresh()
  459. # try:
  460. # self.mapwin.pdc.ClearId(self.mapwin.lineid)
  461. # self.mapwin.pdc.ClearId(self.mapwin.plineid)
  462. # self.mapwin.Refresh()
  463. # except:
  464. # pass
  465. def SaveToFile(self, event):
  466. """!Save profile to graphics file
  467. """
  468. self.client.SaveFile()
  469. def SaveProfileToFile(self, event):
  470. """!Save r.profile data to a csv file
  471. """
  472. wildcard = _("Comma separated value (*.csv)|*.csv")
  473. dlg = wx.FileDialog(
  474. self, message=_("Path and prefix (for raster name) to save profile values..."),
  475. defaultDir=os.getcwd(),
  476. defaultFile="", wildcard=wildcard, style=wx.SAVE
  477. )
  478. if dlg.ShowModal() == wx.ID_OK:
  479. path = dlg.GetPath()
  480. for r in self.raster.itervalues():
  481. if r['name'] == '':
  482. continue
  483. print 'path = '+str(path)
  484. pfile = path+'_'+str(r['name'])+'.csv'
  485. print 'pfile1 = '+str(pfile)
  486. try:
  487. file = open(pfile, "w")
  488. except IOError:
  489. wx.MessageBox(parent=self,
  490. message=_("Unable to open file <%s> for writing.") % pfile,
  491. caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
  492. return False
  493. for datapair in r['datalist']:
  494. file.write('%d,%d\n' % (float(datapair[0]),float(datapair[1])))
  495. file.close()
  496. dlg.Destroy()
  497. def DrawPointLabel(self, dc, mDataDict):
  498. """!This is the fuction that defines how the pointLabels are
  499. plotted dc - DC that will be passed mDataDict - Dictionary
  500. of data that you want to use for the pointLabel
  501. As an example I have decided I want a box at the curve
  502. point with some text information about the curve plotted
  503. below. Any wxDC method can be used.
  504. """
  505. dc.SetPen(wx.Pen(wx.BLACK))
  506. dc.SetBrush(wx.Brush( wx.BLACK, wx.SOLID ) )
  507. sx, sy = mDataDict["scaledXY"] #scaled x,y of closest point
  508. dc.DrawRectangle( sx-5,sy-5, 10, 10) #10by10 square centered on point
  509. px,py = mDataDict["pointXY"]
  510. cNum = mDataDict["curveNum"]
  511. pntIn = mDataDict["pIndex"]
  512. legend = mDataDict["legend"]
  513. #make a string to display
  514. s = "Crv# %i, '%s', Pt. (%.2f,%.2f), PtInd %i" %(cNum, legend, px, py, pntIn)
  515. dc.DrawText(s, sx , sy+1)
  516. def OnMouseLeftDown(self,event):
  517. s= "Left Mouse Down at Point: (%.4f, %.4f)" % self.client._getXY(event)
  518. self.SetStatusText(s)
  519. event.Skip() #allows plotCanvas OnMouseLeftDown to be called
  520. def OnMotion(self, event):
  521. # indicate when mouse is outside the plot area
  522. if self.client.OnLeave(event): print 'out of area'
  523. #show closest point (when enbled)
  524. if self.client.GetEnablePointLabel() == True:
  525. #make up dict with info for the pointLabel
  526. #I've decided to mark the closest point on the closest curve
  527. dlst= self.client.GetClosetPoint( self.client._getXY(event), pointScaled= True)
  528. if dlst != []: #returns [] if none
  529. curveNum, legend, pIndex, pointXY, scaledXY, distance = dlst
  530. #make up dictionary to pass to my user function (see DrawPointLabel)
  531. mDataDict= {"curveNum":curveNum, "legend":legend, "pIndex":pIndex,\
  532. "pointXY":pointXY, "scaledXY":scaledXY}
  533. #pass dict to update the pointLabel
  534. self.client.UpdatePointLabel(mDataDict)
  535. event.Skip() #go to next handler
  536. def ProfileOptionsMenu(self, event):
  537. """!Popup menu for profile and text options
  538. """
  539. point = wx.GetMousePosition()
  540. popt = wx.Menu()
  541. # Add items to the menu
  542. settext = wx.MenuItem(popt, -1, 'Profile text settings')
  543. popt.AppendItem(settext)
  544. self.Bind(wx.EVT_MENU, self.PText, settext)
  545. setgrid = wx.MenuItem(popt, -1, 'Profile plot settings')
  546. popt.AppendItem(setgrid)
  547. self.Bind(wx.EVT_MENU, self.POptions, setgrid)
  548. # Popup the menu. If an item is selected then its handler
  549. # will be called before PopupMenu returns.
  550. self.PopupMenu(popt)
  551. popt.Destroy()
  552. def NotFunctional(self):
  553. """!Creates a 'not functional' message dialog
  554. """
  555. dlg = wx.MessageDialog(parent = self,
  556. message = _('This feature is not yet functional'),
  557. caption = _('Under Construction'),
  558. style = wx.OK | wx.ICON_INFORMATION)
  559. dlg.ShowModal()
  560. dlg.Destroy()
  561. def OnPText(self, dlg):
  562. """!Use user's provided profile text settings.
  563. """
  564. self.ptitle = dlg.ptitle
  565. self.xlabel = dlg.xlabel
  566. self.ylabel = dlg.ylabel
  567. dlg.UpdateSettings()
  568. self.client.SetFont(self.properties['font']['wxfont'])
  569. self.client.SetFontSizeTitle(self.properties['font']['prop']['titleSize'])
  570. self.client.SetFontSizeAxis(self.properties['font']['prop']['axisSize'])
  571. if self.profile:
  572. self.profile.setTitle(dlg.ptitle)
  573. self.profile.setXLabel(dlg.xlabel)
  574. self.profile.setYLabel(dlg.ylabel)
  575. self.OnRedraw(event=None)
  576. def PText(self, event):
  577. """!Set custom text values for profile title and axis labels.
  578. """
  579. dlg = TextDialog(parent=self, id=wx.ID_ANY, title=_('Profile text settings'))
  580. if dlg.ShowModal() == wx.ID_OK:
  581. self.OnPText(dlg)
  582. dlg.Destroy()
  583. def POptions(self, event):
  584. """!Set various profile options, including: line width, color,
  585. style; marker size, color, fill, and style; grid and legend
  586. options. Calls OptDialog class.
  587. """
  588. dlg = OptDialog(parent=self, id=wx.ID_ANY, title=_('Profile settings'))
  589. btnval = dlg.ShowModal()
  590. if btnval == wx.ID_SAVE:
  591. dlg.UpdateSettings()
  592. self.SetGraphStyle()
  593. dlg.Destroy()
  594. elif btnval == wx.ID_CANCEL:
  595. dlg.Destroy()
  596. def PrintMenu(self, event):
  597. """!Print options and output menu
  598. """
  599. point = wx.GetMousePosition()
  600. printmenu = wx.Menu()
  601. # Add items to the menu
  602. setup = wx.MenuItem(printmenu, -1,'Page setup')
  603. printmenu.AppendItem(setup)
  604. self.Bind(wx.EVT_MENU, self.OnPageSetup, setup)
  605. preview = wx.MenuItem(printmenu, -1,'Print preview')
  606. printmenu.AppendItem(preview)
  607. self.Bind(wx.EVT_MENU, self.OnPrintPreview, preview)
  608. doprint = wx.MenuItem(printmenu, -1,'Print display')
  609. printmenu.AppendItem(doprint)
  610. self.Bind(wx.EVT_MENU, self.OnDoPrint, doprint)
  611. # Popup the menu. If an item is selected then its handler
  612. # will be called before PopupMenu returns.
  613. self.PopupMenu(printmenu)
  614. printmenu.Destroy()
  615. def OnPageSetup(self, event):
  616. self.client.PageSetup()
  617. def OnPrintPreview(self, event):
  618. self.client.PrintPreview()
  619. def OnDoPrint(self, event):
  620. self.client.Printout()
  621. def OnQuit(self, event):
  622. self.Close(True)
  623. def OnCloseWindow(self, event):
  624. """
  625. Close profile window and clean up
  626. """
  627. self.mapwin.ClearLines()
  628. self.mapwin.mouse['begin'] = self.mapwin.mouse['end'] = (0.0, 0.0)
  629. self.mapwin.mouse['use'] = 'pointer'
  630. self.mapwin.mouse['box'] = 'point'
  631. self.mapwin.polycoords = []
  632. self.mapwin.SetCursor(self.Parent.cursors["default"])
  633. self.mapwin.UpdateMap(render=False, renderVector=False)
  634. self.Destroy()
  635. class SetRasterDialog(wx.Dialog):
  636. def __init__(self, parent, id=wx.ID_ANY, title=_("Select raster map to profile"),
  637. pos=wx.DefaultPosition, size=wx.DefaultSize,
  638. style=wx.DEFAULT_DIALOG_STYLE):
  639. """!Dialog to select raster maps to profile.
  640. """
  641. wx.Dialog.__init__(self, parent, id, title, pos, size, style)
  642. self.parent = parent
  643. self.coordstr = self.parent.coordstr
  644. # if self.coordstr == '':
  645. # dlg = wx.MessageDialog(parent=self,
  646. # message=_('You must draw a transect to profile in the map display window.'),
  647. # caption=_('Nothing to profile'),
  648. # style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
  649. # dlg.ShowModal()
  650. # dlg.Destroy()
  651. # self.Close(True)
  652. # return
  653. self.raster = { 0 : { 'name' : self.parent.raster[0]['name'],
  654. 'id' : None },
  655. 1 : { 'name' : self.parent.raster[1]['name'],
  656. 'id' : None },
  657. 2 : { 'name' : self.parent.raster[2]['name'],
  658. 'id' : None }
  659. }
  660. sizer = wx.BoxSizer(wx.VERTICAL)
  661. box = wx.GridBagSizer (hgap=3, vgap=3)
  662. i = 0
  663. for txt in [_("Select raster map 1 (required):"),
  664. _("Select raster map 2 (optional):"),
  665. _("Select raster map 3 (optional):")]:
  666. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=txt)
  667. box.Add(item=label,
  668. flag=wx.ALIGN_CENTER_VERTICAL, pos=(i, 0))
  669. selection = gselect.Select(self, id=wx.ID_ANY,
  670. size=globalvar.DIALOG_GSELECT_SIZE,
  671. type='cell')
  672. selection.SetValue(str(self.raster[i]['name']))
  673. self.raster[i]['id'] = selection.GetChildren()[0].GetId()
  674. selection.Bind(wx.EVT_TEXT, self.OnSelection)
  675. box.Add(item=selection, pos=(i, 1))
  676. i += 1
  677. sizer.Add(item=box, proportion=0,
  678. flag=wx.ALL, border=10)
  679. line = wx.StaticLine(parent=self, id=wx.ID_ANY, size=(20, -1), style=wx.LI_HORIZONTAL)
  680. sizer.Add(item=line, proportion=0,
  681. flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border=5)
  682. btnsizer = wx.StdDialogButtonSizer()
  683. btn = wx.Button(self, wx.ID_OK)
  684. btn.SetDefault()
  685. btnsizer.AddButton(btn)
  686. btn = wx.Button(self, wx.ID_CANCEL)
  687. btnsizer.AddButton(btn)
  688. btnsizer.Realize()
  689. sizer.Add(item=btnsizer, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
  690. self.SetSizer(sizer)
  691. sizer.Fit(self)
  692. def OnSelection(self, event):
  693. id = event.GetId()
  694. for r in self.raster.itervalues():
  695. if r['id'] == id:
  696. r['name'] = event.GetString()
  697. break
  698. class TextDialog(wx.Dialog):
  699. def __init__(self, parent, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize,
  700. style=wx.DEFAULT_DIALOG_STYLE):
  701. """!Dialog to set profile text options: font, title
  702. and font size, axis labels and font size
  703. """
  704. wx.Dialog.__init__(self, parent, id, title, pos, size, style)
  705. #
  706. # initialize variables
  707. #
  708. # combo box entry lists
  709. self.ffamilydict = { 'default' : wx.FONTFAMILY_DEFAULT,
  710. 'decorative' : wx.FONTFAMILY_DECORATIVE,
  711. 'roman' : wx.FONTFAMILY_ROMAN,
  712. 'script' : wx.FONTFAMILY_SCRIPT,
  713. 'swiss' : wx.FONTFAMILY_SWISS,
  714. 'modern' : wx.FONTFAMILY_MODERN,
  715. 'teletype' : wx.FONTFAMILY_TELETYPE }
  716. self.fstyledict = { 'normal' : wx.FONTSTYLE_NORMAL,
  717. 'slant' : wx.FONTSTYLE_SLANT,
  718. 'italic' : wx.FONTSTYLE_ITALIC }
  719. self.fwtdict = { 'normal' : wx.FONTWEIGHT_NORMAL,
  720. 'light' : wx.FONTWEIGHT_LIGHT,
  721. 'bold' : wx.FONTWEIGHT_BOLD }
  722. self.parent = parent
  723. self.ptitle = self.parent.ptitle
  724. self.xlabel = self.parent.xlabel
  725. self.ylabel = self.parent.ylabel
  726. self.properties = self.parent.properties # read-only
  727. # font size
  728. self.fontfamily = self.properties['font']['wxfont'].GetFamily()
  729. self.fontstyle = self.properties['font']['wxfont'].GetStyle()
  730. self.fontweight = self.properties['font']['wxfont'].GetWeight()
  731. self._do_layout()
  732. def _do_layout(self):
  733. """!Do layout"""
  734. # dialog layout
  735. sizer = wx.BoxSizer(wx.VERTICAL)
  736. box = wx.StaticBox(parent=self, id=wx.ID_ANY,
  737. label=" %s " % _("Text settings"))
  738. boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  739. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  740. #
  741. # profile title
  742. #
  743. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Profile title:"))
  744. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0))
  745. self.ptitleentry = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(250,-1))
  746. # self.ptitleentry.SetFont(self.font)
  747. self.ptitleentry.SetValue(self.ptitle)
  748. gridSizer.Add(item=self.ptitleentry, pos=(0, 1))
  749. #
  750. # title font
  751. #
  752. tlabel = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Title font size (pts):"))
  753. gridSizer.Add(item=tlabel, flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 0))
  754. self.ptitlesize = wx.SpinCtrl(parent=self, id=wx.ID_ANY, value="", pos=(30, 50),
  755. size=(50,-1), style=wx.SP_ARROW_KEYS)
  756. self.ptitlesize.SetRange(5,100)
  757. self.ptitlesize.SetValue(int(self.properties['font']['prop']['titleSize']))
  758. gridSizer.Add(item=self.ptitlesize, pos=(1, 1))
  759. #
  760. # x-axis label
  761. #
  762. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=("X-axis label:"))
  763. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(2, 0))
  764. self.xlabelentry = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(250,-1))
  765. # self.xlabelentry.SetFont(self.font)
  766. self.xlabelentry.SetValue(self.xlabel)
  767. gridSizer.Add(item=self.xlabelentry, pos=(2, 1))
  768. #
  769. # y-axis label
  770. #
  771. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Y-axis label:"))
  772. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(3, 0))
  773. self.ylabelentry = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(250,-1))
  774. # self.ylabelentry.SetFont(self.font)
  775. self.ylabelentry.SetValue(self.ylabel)
  776. gridSizer.Add(item=self.ylabelentry, pos=(3, 1))
  777. #
  778. # font size
  779. #
  780. llabel = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Label font size (pts):"))
  781. gridSizer.Add(item=llabel, flag=wx.ALIGN_CENTER_VERTICAL, pos=(4, 0))
  782. self.axislabelsize = wx.SpinCtrl(parent=self, id=wx.ID_ANY, value="", pos=(30, 50),
  783. size=(50, -1), style=wx.SP_ARROW_KEYS)
  784. self.axislabelsize.SetRange(5, 100)
  785. self.axislabelsize.SetValue(int(self.properties['font']['prop']['axisSize']))
  786. gridSizer.Add(item=self.axislabelsize, pos=(4,1))
  787. boxSizer.Add(item=gridSizer)
  788. sizer.Add(item=boxSizer, flag=wx.ALL | wx.EXPAND, border=3)
  789. #
  790. # font settings
  791. #
  792. box = wx.StaticBox(parent=self, id=wx.ID_ANY,
  793. label=" %s " % _("Font settings"))
  794. boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  795. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  796. gridSizer.AddGrowableCol(1)
  797. #
  798. # font family
  799. #
  800. label1 = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Font family:"))
  801. gridSizer.Add(item=label1, flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0))
  802. self.ffamilycb = wx.ComboBox(parent=self, id=wx.ID_ANY, size=(250, -1),
  803. choices=self.ffamilydict.keys(), style=wx.CB_DROPDOWN)
  804. self.ffamilycb.SetStringSelection('swiss')
  805. for item in self.ffamilydict.items():
  806. if self.fontfamily == item[1]:
  807. self.ffamilycb.SetStringSelection(item[0])
  808. break
  809. gridSizer.Add(item=self.ffamilycb, pos=(0, 1), flag=wx.ALIGN_RIGHT)
  810. #
  811. # font style
  812. #
  813. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Style:"))
  814. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 0))
  815. self.fstylecb = wx.ComboBox(parent=self, id=wx.ID_ANY, size=(250, -1),
  816. choices=self.fstyledict.keys(), style=wx.CB_DROPDOWN)
  817. self.fstylecb.SetStringSelection('normal')
  818. for item in self.fstyledict.items():
  819. if self.fontstyle == item[1]:
  820. self.fstylecb.SetStringSelection(item[0])
  821. break
  822. gridSizer.Add(item=self.fstylecb, pos=(1, 1), flag=wx.ALIGN_RIGHT)
  823. #
  824. # font weight
  825. #
  826. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Weight:"))
  827. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(2, 0))
  828. self.fwtcb = wx.ComboBox(parent=self, size=(250, -1),
  829. choices=self.fwtdict.keys(), style=wx.CB_DROPDOWN)
  830. self.fwtcb.SetStringSelection('normal')
  831. for item in self.fwtdict.items():
  832. if self.fontweight == item[1]:
  833. self.fwtcb.SetStringSelection(item[0])
  834. break
  835. gridSizer.Add(item=self.fwtcb, pos=(2, 1), flag=wx.ALIGN_RIGHT)
  836. boxSizer.Add(item=gridSizer, flag=wx.EXPAND)
  837. sizer.Add(item=boxSizer, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3)
  838. line = wx.StaticLine(parent=self, id=wx.ID_ANY, size=(20, -1), style=wx.LI_HORIZONTAL)
  839. sizer.Add(item=line, proportion=0,
  840. flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border=3)
  841. #
  842. # buttons
  843. #
  844. btnSave = wx.Button(self, wx.ID_SAVE)
  845. btnApply = wx.Button(self, wx.ID_APPLY)
  846. btnOk = wx.Button(self, wx.ID_OK)
  847. btnCancel = wx.Button(self, wx.ID_CANCEL)
  848. btnOk.SetDefault()
  849. # bindings
  850. btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  851. btnApply.SetToolTipString(_("Apply changes for the current session"))
  852. btnOk.Bind(wx.EVT_BUTTON, self.OnOk)
  853. btnOk.SetToolTipString(_("Apply changes for the current session and close dialog"))
  854. btnOk.SetDefault()
  855. btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
  856. btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
  857. btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
  858. btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
  859. # sizers
  860. btnStdSizer = wx.StdDialogButtonSizer()
  861. btnStdSizer.AddButton(btnOk)
  862. btnStdSizer.AddButton(btnApply)
  863. btnStdSizer.AddButton(btnCancel)
  864. btnStdSizer.Realize()
  865. btnSizer = wx.BoxSizer(wx.HORIZONTAL)
  866. btnSizer.Add(item=btnSave, proportion=0, flag=wx.ALIGN_LEFT | wx.ALL, border=5)
  867. btnSizer.Add(item=btnStdSizer, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
  868. sizer.Add(item=btnSizer, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
  869. #
  870. # bindings
  871. #
  872. self.ptitleentry.Bind(wx.EVT_TEXT, self.OnTitle)
  873. self.xlabelentry.Bind(wx.EVT_TEXT, self.OnXLabel)
  874. self.ylabelentry.Bind(wx.EVT_TEXT, self.OnYLabel)
  875. self.SetSizer(sizer)
  876. sizer.Fit(self)
  877. def OnTitle(self, event):
  878. self.ptitle = event.GetString()
  879. def OnXLabel(self, event):
  880. self.xlabel = event.GetString()
  881. def OnYLabel(self, event):
  882. self.ylabel = event.GetString()
  883. def UpdateSettings(self):
  884. self.properties['font']['prop']['titleSize'] = self.ptitlesize.GetValue()
  885. self.properties['font']['prop']['axisSize'] = self.axislabelsize.GetValue()
  886. family = self.ffamilydict[self.ffamilycb.GetStringSelection()]
  887. self.properties['font']['wxfont'].SetFamily(family)
  888. style = self.fstyledict[self.fstylecb.GetStringSelection()]
  889. self.properties['font']['wxfont'].SetStyle(style)
  890. weight = self.fwtdict[self.fwtcb.GetStringSelection()]
  891. self.properties['font']['wxfont'].SetWeight(weight)
  892. def OnSave(self, event):
  893. """!Button 'Save' pressed"""
  894. self.UpdateSettings()
  895. fileSettings = {}
  896. UserSettings.ReadSettingsFile(settings=fileSettings)
  897. fileSettings['profile'] = UserSettings.Get(group='profile')
  898. file = UserSettings.SaveToFile(fileSettings)
  899. self.parent.parent.GetLayerManager().goutput.WriteLog(_('Profile settings saved to file \'%s\'.') % file)
  900. self.EndModal(wx.ID_OK)
  901. def OnApply(self, event):
  902. """!Button 'Apply' pressed"""
  903. self.UpdateSettings()
  904. self.parent.OnPText(self)
  905. def OnOk(self, event):
  906. """!Button 'OK' pressed"""
  907. self.UpdateSettings()
  908. self.EndModal(wx.ID_OK)
  909. def OnCancel(self, event):
  910. """!Button 'Cancel' pressed"""
  911. self.EndModal(wx.ID_CANCEL)
  912. class OptDialog(wx.Dialog):
  913. def __init__(self, parent, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize,
  914. style=wx.DEFAULT_DIALOG_STYLE):
  915. """!Dialog to set various profile options, including: line
  916. width, color, style; marker size, color, fill, and style; grid
  917. and legend options.
  918. """
  919. wx.Dialog.__init__(self, parent, id, title, pos, size, style)
  920. # init variables
  921. self.pstyledict = parent.pstyledict
  922. self.ptfilldict = parent.ptfilldict
  923. self.pttypelist = ['circle',
  924. 'dot',
  925. 'square',
  926. 'triangle',
  927. 'triangle_down',
  928. 'cross',
  929. 'plus']
  930. self.axislist = ['min',
  931. 'auto',
  932. 'custom']
  933. # widgets ids
  934. self.wxId = {}
  935. self.parent = parent
  936. # read-only
  937. self.raster = self.parent.raster
  938. self.properties = self.parent.properties
  939. self._do_layout()
  940. def _do_layout(self):
  941. """!Do layout"""
  942. # dialog layout
  943. sizer = wx.BoxSizer(wx.VERTICAL)
  944. #
  945. # profile line settings
  946. #
  947. box = wx.StaticBox(parent=self, id=wx.ID_ANY,
  948. label=" %s " % _("Profile line settings"))
  949. boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
  950. idx = 1
  951. self.wxId['pcolor'] = []
  952. self.wxId['pwidth'] = []
  953. self.wxId['pstyle'] = []
  954. self.wxId['plegend'] = []
  955. for r in self.raster.itervalues():
  956. box = wx.StaticBox(parent=self, id=wx.ID_ANY,
  957. label=" %s %d " % (_("Profile"), idx))
  958. boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  959. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  960. row = 0
  961. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Line color"))
  962. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  963. pcolor = csel.ColourSelect(parent=self, id=wx.ID_ANY, colour=r['prop']['pcolor'])
  964. self.wxId['pcolor'].append(pcolor.GetId())
  965. gridSizer.Add(item=pcolor, pos=(row, 1))
  966. row += 1
  967. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Line width"))
  968. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  969. pwidth = wx.SpinCtrl(parent=self, id=wx.ID_ANY, value="",
  970. size=(50,-1), style=wx.SP_ARROW_KEYS)
  971. pwidth.SetRange(1, 10)
  972. pwidth.SetValue(r['prop']['pwidth'])
  973. self.wxId['pwidth'].append(pwidth.GetId())
  974. gridSizer.Add(item=pwidth, pos=(row, 1))
  975. row +=1
  976. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Line style"))
  977. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  978. pstyle = wx.ComboBox(parent=self, id=wx.ID_ANY,
  979. size=(120, -1), choices=self.pstyledict.keys(), style=wx.CB_DROPDOWN)
  980. pstyle.SetStringSelection(r['prop']['pstyle'])
  981. self.wxId['pstyle'].append(pstyle.GetId())
  982. gridSizer.Add(item=pstyle, pos=(row, 1))
  983. row += 1
  984. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Legend"))
  985. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  986. plegend = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(200,-1))
  987. plegend.SetValue(r['plegend'])
  988. gridSizer.Add(item=plegend, pos=(row, 1))
  989. self.wxId['plegend'].append(plegend.GetId())
  990. boxSizer.Add(item=gridSizer)
  991. if idx == 0:
  992. flag = wx.ALL
  993. else:
  994. flag = wx.TOP | wx.BOTTOM | wx.RIGHT
  995. boxMainSizer.Add(item=boxSizer, flag=flag, border=3)
  996. idx += 1
  997. sizer.Add(item=boxMainSizer, flag=wx.ALL | wx.EXPAND, border=3)
  998. middleSizer = wx.BoxSizer(wx.HORIZONTAL)
  999. #
  1000. # segment marker settings
  1001. #
  1002. box = wx.StaticBox(parent=self, id=wx.ID_ANY,
  1003. label=" %s " % _("Transect segment marker settings"))
  1004. boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
  1005. self.wxId['marker'] = {}
  1006. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  1007. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Color"))
  1008. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0))
  1009. ptcolor = csel.ColourSelect(parent=self, id=wx.ID_ANY, colour=self.properties['marker']['color'])
  1010. self.wxId['marker']['color'] = ptcolor.GetId()
  1011. gridSizer.Add(item=ptcolor, pos=(0, 1))
  1012. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Size"))
  1013. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 0))
  1014. ptsize = wx.SpinCtrl(parent=self, id=wx.ID_ANY, value="",
  1015. size=(50, -1), style=wx.SP_ARROW_KEYS)
  1016. ptsize.SetRange(1, 10)
  1017. ptsize.SetValue(self.properties['marker']['size'])
  1018. self.wxId['marker']['size'] = ptsize.GetId()
  1019. gridSizer.Add(item=ptsize, pos=(1, 1))
  1020. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Style"))
  1021. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(2, 0))
  1022. ptfill = wx.ComboBox(parent=self, id=wx.ID_ANY,
  1023. size=(120, -1), choices=self.ptfilldict.keys(), style=wx.CB_DROPDOWN)
  1024. ptfill.SetStringSelection(self.properties['marker']['fill'])
  1025. self.wxId['marker']['fill'] = ptfill.GetId()
  1026. gridSizer.Add(item=ptfill, pos=(2, 1))
  1027. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Legend"))
  1028. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(3, 0))
  1029. ptlegend = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(200,-1))
  1030. ptlegend.SetValue(self.properties['marker']['legend'])
  1031. self.wxId['marker']['legend'] = ptlegend.GetId()
  1032. gridSizer.Add(item=ptlegend, pos=(3, 1))
  1033. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Type"))
  1034. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(4, 0))
  1035. pttype = wx.ComboBox(parent=self,
  1036. size=(200, -1), choices=self.pttypelist, style=wx.CB_DROPDOWN)
  1037. pttype.SetStringSelection(self.properties['marker']['type'])
  1038. self.wxId['marker']['type'] = pttype.GetId()
  1039. gridSizer.Add(item=pttype, pos=(4, 1))
  1040. boxMainSizer.Add(item=gridSizer, flag=wx.ALL, border=3)
  1041. middleSizer.Add(item=boxMainSizer, flag=wx.ALL | wx.EXPAND, border=3)
  1042. #
  1043. # axis options
  1044. #
  1045. box = wx.StaticBox(parent=self, id=wx.ID_ANY,
  1046. label=" %s " % _("Axis settings"))
  1047. boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
  1048. self.wxId['x-axis'] = {}
  1049. self.wxId['y-axis'] = {}
  1050. idx = 0
  1051. for axis, atype in [(_("X-Axis"), 'x-axis'),
  1052. (_("Y-Axis"), 'y-axis')]:
  1053. box = wx.StaticBox(parent=self, id=wx.ID_ANY,
  1054. label=" %s " % axis)
  1055. boxSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
  1056. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  1057. prop = self.properties[atype]['prop']
  1058. row = 0
  1059. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Style"))
  1060. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1061. type = wx.ComboBox(parent=self, id=wx.ID_ANY,
  1062. size=(100, -1), choices=self.axislist, style=wx.CB_DROPDOWN)
  1063. type.SetStringSelection(prop['type'])
  1064. self.wxId[atype]['type'] = type.GetId()
  1065. gridSizer.Add(item=type, pos=(row, 1))
  1066. row += 1
  1067. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Custom min"))
  1068. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1069. min = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(70, -1))
  1070. min.SetValue(str(prop['min']))
  1071. self.wxId[atype]['min'] = min.GetId()
  1072. gridSizer.Add(item=min, pos=(row, 1))
  1073. row += 1
  1074. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Custom max"))
  1075. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1076. max = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(70, -1))
  1077. max.SetValue(str(prop['max']))
  1078. self.wxId[atype]['max'] = max.GetId()
  1079. gridSizer.Add(item=max, pos=(row, 1))
  1080. row += 1
  1081. log = wx.CheckBox(parent=self, id=wx.ID_ANY, label=_("Log scale"))
  1082. log.SetValue(prop['log'])
  1083. self.wxId[atype]['log'] = log.GetId()
  1084. gridSizer.Add(item=log, pos=(row, 0), span=(1, 2))
  1085. if idx == 0:
  1086. flag = wx.ALL | wx.EXPAND
  1087. else:
  1088. flag = wx.TOP | wx.BOTTOM | wx.RIGHT | wx.EXPAND
  1089. boxSizer.Add(item=gridSizer, flag=wx.ALL, border=3)
  1090. boxMainSizer.Add(item=boxSizer, flag=flag, border=3)
  1091. idx += 1
  1092. middleSizer.Add(item=boxMainSizer, flag=wx.ALL | wx.EXPAND, border=3)
  1093. #
  1094. # grid & legend options
  1095. #
  1096. self.wxId['grid'] = {}
  1097. self.wxId['legend'] = {}
  1098. self.wxId['font'] = {}
  1099. box = wx.StaticBox(parent=self, id=wx.ID_ANY,
  1100. label=" %s " % _("Grid and Legend settings"))
  1101. boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
  1102. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  1103. row = 0
  1104. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Grid color"))
  1105. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1106. gridcolor = csel.ColourSelect(parent=self, id=wx.ID_ANY, colour=self.properties['grid']['color'])
  1107. self.wxId['grid']['color'] = gridcolor.GetId()
  1108. gridSizer.Add(item=gridcolor, pos=(row, 1))
  1109. row +=1
  1110. gridshow = wx.CheckBox(parent=self, id=wx.ID_ANY, label=_("Show grid"))
  1111. gridshow.SetValue(self.properties['grid']['enabled'])
  1112. self.wxId['grid']['enabled'] = gridshow.GetId()
  1113. gridSizer.Add(item=gridshow, pos=(row, 0), span=(1, 2))
  1114. row +=1
  1115. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Legend font size"))
  1116. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1117. legendfontsize = wx.SpinCtrl(parent=self, id=wx.ID_ANY, value="",
  1118. size=(50, -1), style=wx.SP_ARROW_KEYS)
  1119. legendfontsize.SetRange(5,100)
  1120. legendfontsize.SetValue(int(self.properties['font']['prop']['legendSize']))
  1121. self.wxId['font']['legendSize'] = legendfontsize.GetId()
  1122. gridSizer.Add(item=legendfontsize, pos=(row, 1))
  1123. row += 1
  1124. legendshow = wx.CheckBox(parent=self, id=wx.ID_ANY, label=_("Show legend"))
  1125. legendshow.SetValue(self.properties['legend']['enabled'])
  1126. self.wxId['legend']['enabled'] = legendshow.GetId()
  1127. gridSizer.Add(item=legendshow, pos=(row, 0), span=(1, 2))
  1128. boxMainSizer.Add(item=gridSizer, flag=flag, border=3)
  1129. middleSizer.Add(item=boxMainSizer, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3)
  1130. sizer.Add(item=middleSizer, flag=wx.ALL, border=0)
  1131. #
  1132. # line & buttons
  1133. #
  1134. line = wx.StaticLine(parent=self, id=wx.ID_ANY, size=(20, -1), style=wx.LI_HORIZONTAL)
  1135. sizer.Add(item=line, proportion=0,
  1136. flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border=3)
  1137. #
  1138. # buttons
  1139. #
  1140. btnSave = wx.Button(self, wx.ID_SAVE)
  1141. btnApply = wx.Button(self, wx.ID_APPLY)
  1142. btnCancel = wx.Button(self, wx.ID_CANCEL)
  1143. btnSave.SetDefault()
  1144. # bindigs
  1145. btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  1146. btnApply.SetToolTipString(_("Apply changes for the current session"))
  1147. btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
  1148. btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
  1149. btnSave.SetDefault()
  1150. btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
  1151. btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
  1152. # sizers
  1153. btnStdSizer = wx.StdDialogButtonSizer()
  1154. btnStdSizer.AddButton(btnCancel)
  1155. btnStdSizer.AddButton(btnSave)
  1156. btnStdSizer.AddButton(btnApply)
  1157. btnStdSizer.Realize()
  1158. sizer.Add(item=btnStdSizer, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
  1159. self.SetSizer(sizer)
  1160. sizer.Fit(self)
  1161. def UpdateSettings(self):
  1162. idx = 0
  1163. for r in self.raster.itervalues():
  1164. r['prop']['pcolor'] = self.FindWindowById(self.wxId['pcolor'][idx]).GetColour()
  1165. r['prop']['pwidth'] = int(self.FindWindowById(self.wxId['pwidth'][idx]).GetValue())
  1166. r['prop']['pstyle'] = self.FindWindowById(self.wxId['pstyle'][idx]).GetStringSelection()
  1167. r['plegend'] = self.FindWindowById(self.wxId['plegend'][idx]).GetValue()
  1168. idx +=1
  1169. self.properties['marker']['color'] = self.FindWindowById(self.wxId['marker']['color']).GetColour()
  1170. self.properties['marker']['fill'] = self.FindWindowById(self.wxId['marker']['fill']).GetStringSelection()
  1171. self.properties['marker']['size'] = self.FindWindowById(self.wxId['marker']['size']).GetValue()
  1172. self.properties['marker']['type'] = self.FindWindowById(self.wxId['marker']['type']).GetValue()
  1173. self.properties['marker']['legend'] = self.FindWindowById(self.wxId['marker']['legend']).GetValue()
  1174. for axis in ('x-axis', 'y-axis'):
  1175. self.properties[axis]['prop']['type'] = self.FindWindowById(self.wxId[axis]['type']).GetValue()
  1176. self.properties[axis]['prop']['min'] = float(self.FindWindowById(self.wxId[axis]['min']).GetValue())
  1177. self.properties[axis]['prop']['max'] = float(self.FindWindowById(self.wxId[axis]['max']).GetValue())
  1178. self.properties[axis]['prop']['log'] = self.FindWindowById(self.wxId[axis]['log']).IsChecked()
  1179. self.properties['grid']['color'] = self.FindWindowById(self.wxId['grid']['color']).GetColour()
  1180. self.properties['grid']['enabled'] = self.FindWindowById(self.wxId['grid']['enabled']).IsChecked()
  1181. self.properties['font']['prop']['legendSize'] = self.FindWindowById(self.wxId['font']['legendSize']).GetValue()
  1182. self.properties['legend']['enabled'] = self.FindWindowById(self.wxId['legend']['enabled']).IsChecked()
  1183. def OnSave(self, event):
  1184. """!Button 'Save' pressed"""
  1185. self.UpdateSettings()
  1186. fileSettings = {}
  1187. UserSettings.ReadSettingsFile(settings=fileSettings)
  1188. fileSettings['profile'] = UserSettings.Get(group='profile')
  1189. file = UserSettings.SaveToFile(fileSettings)
  1190. self.parent.parent.GetLayerManager().goutput.WriteLog(_('Profile settings saved to file \'%s\'.') % file)
  1191. self.parent.SetGraphStyle()
  1192. if self.parent.profile:
  1193. self.parent.DrawPlot()
  1194. self.Close()
  1195. def OnApply(self, event):
  1196. """!Button 'Apply' pressed. Does not close dialog"""
  1197. self.UpdateSettings()
  1198. self.parent.SetGraphStyle()
  1199. if self.parent.profile:
  1200. self.parent.DrawPlot()
  1201. def OnCancel(self, event):
  1202. """!Button 'Cancel' pressed"""
  1203. self.Close()