profile.py 57 KB

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