profile.py 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457
  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.GException, e:
  358. gcmd.GError(parent = self,
  359. message = e)
  360. return None
  361. def OnCreateProfile(self, event):
  362. """!Main routine for creating a profile. Uses r.profile to
  363. create a list of distance,cell value pairs. This is passed to
  364. plot to create a line graph of the profile. If the profile
  365. transect is in multiple segments, these are drawn as
  366. points. Profile transect is drawn, using methods in mapdisp.py
  367. """
  368. if len(self.mapwin.polycoords) == 0 or self.raster[0]['name'] == '':
  369. dlg = wx.MessageDialog(parent=self,
  370. message=_('You must draw a transect to profile in the map display window.'),
  371. caption=_('Nothing to profile'),
  372. style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
  373. dlg.ShowModal()
  374. dlg.Destroy()
  375. return
  376. self.mapwin.SetCursor(self.parent.cursors["default"])
  377. self.SetCursor(self.parent.cursors["default"])
  378. self.SetGraphStyle()
  379. self.SetRaster()
  380. self.DrawPlot()
  381. # reset transect
  382. self.mapwin.mouse['begin'] = self.mapwin.mouse['end'] = (0.0,0.0)
  383. self.mapwin.mouse['use'] = 'pointer'
  384. self.mapwin.mouse['box'] = 'point'
  385. def DrawPlot(self):
  386. """!Draw line and point plot from transect datalist and
  387. transect segment endpoint coordinates.
  388. """
  389. # graph the distance, value pairs for the transect
  390. self.plotlist = []
  391. if len(self.seglist) > 0 :
  392. self.ppoints = plot.PolyMarker(self.seglist,
  393. legend=' ' + self.properties['marker']['legend'],
  394. colour=wx.Color(self.properties['marker']['color'][0],
  395. self.properties['marker']['color'][1],
  396. self.properties['marker']['color'][2],
  397. 255),
  398. size=self.properties['marker']['size'],
  399. fillstyle=self.ptfilldict[self.properties['marker']['fill']],
  400. marker=self.properties['marker']['type'])
  401. self.plotlist.append(self.ppoints)
  402. for r in self.raster.itervalues():
  403. if len(r['datalist']) > 0:
  404. col = wx.Color(r['prop']['pcolor'][0],
  405. r['prop']['pcolor'][1],
  406. r['prop']['pcolor'][2],
  407. 255)
  408. r['pline'] = plot.PolyLine(r['datalist'],
  409. colour=col,
  410. width=r['prop']['pwidth'],
  411. style=self.pstyledict[r['prop']['pstyle']],
  412. legend=r['plegend'])
  413. self.plotlist.append(r['pline'])
  414. self.profile = plot.PlotGraphics(self.plotlist,
  415. self.ptitle,
  416. self.xlabel,
  417. self.ylabel)
  418. if self.properties['x-axis']['prop']['type'] == 'custom':
  419. self.client.SetXSpec('min')
  420. else:
  421. self.client.SetXSpec(self.properties['x-axis']['prop']['type'])
  422. if self.properties['y-axis']['prop']['type'] == 'custom':
  423. self.client.SetYSpec('min')
  424. else:
  425. self.client.SetYSpec(self.properties['y-axis']['prop']['type'])
  426. self.client.Draw(self.profile, self.properties['x-axis']['axis'],
  427. self.properties['y-axis']['axis'])
  428. def OnZoom(self, event):
  429. """!Enable zooming and disable dragging
  430. """
  431. self.zoom = True
  432. self.drag = False
  433. self.client.SetEnableZoom(self.zoom)
  434. self.client.SetEnableDrag(self.drag)
  435. def OnDrag(self, event):
  436. """!Enable dragging and disable zooming
  437. """
  438. self.zoom = False
  439. self.drag = True
  440. self.client.SetEnableDrag(self.drag)
  441. self.client.SetEnableZoom(self.zoom)
  442. def OnRedraw(self, event):
  443. """!Redraw the profile window. Unzoom to original size
  444. """
  445. self.client.Reset()
  446. self.client.Redraw()
  447. def Update(self):
  448. """!Update profile after changing options
  449. """
  450. self.SetGraphStyle()
  451. self.DrawPlot()
  452. def OnErase(self, event):
  453. """!Erase the profile window
  454. """
  455. self.client.Clear()
  456. self.mapwin.ClearLines(self.mapwin.pdc)
  457. self.mapwin.ClearLines(self.mapwin.pdcTmp)
  458. self.mapwin.polycoords = []
  459. self.mapwin.Refresh()
  460. # try:
  461. # self.mapwin.pdc.ClearId(self.mapwin.lineid)
  462. # self.mapwin.pdc.ClearId(self.mapwin.plineid)
  463. # self.mapwin.Refresh()
  464. # except:
  465. # pass
  466. def SaveToFile(self, event):
  467. """!Save profile to graphics file
  468. """
  469. self.client.SaveFile()
  470. def SaveProfileToFile(self, event):
  471. """!Save r.profile data to a csv file
  472. """
  473. wildcard = _("Comma separated value (*.csv)|*.csv")
  474. dlg = wx.FileDialog(
  475. self, message=_("Path and prefix (for raster name) to save profile values..."),
  476. defaultDir=os.getcwd(),
  477. defaultFile="", wildcard=wildcard, style=wx.SAVE
  478. )
  479. if dlg.ShowModal() == wx.ID_OK:
  480. path = dlg.GetPath()
  481. for r in self.raster.itervalues():
  482. if r['name'] == '':
  483. continue
  484. print 'path = '+str(path)
  485. pfile = path+'_'+str(r['name'])+'.csv'
  486. print 'pfile1 = '+str(pfile)
  487. try:
  488. file = open(pfile, "w")
  489. except IOError:
  490. wx.MessageBox(parent=self,
  491. message=_("Unable to open file <%s> for writing.") % pfile,
  492. caption=_("Error"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
  493. return False
  494. for datapair in r['datalist']:
  495. file.write('%d,%d\n' % (float(datapair[0]),float(datapair[1])))
  496. file.close()
  497. dlg.Destroy()
  498. def DrawPointLabel(self, dc, mDataDict):
  499. """!This is the fuction that defines how the pointLabels are
  500. plotted dc - DC that will be passed mDataDict - Dictionary
  501. of data that you want to use for the pointLabel
  502. As an example I have decided I want a box at the curve
  503. point with some text information about the curve plotted
  504. below. Any wxDC method can be used.
  505. """
  506. dc.SetPen(wx.Pen(wx.BLACK))
  507. dc.SetBrush(wx.Brush( wx.BLACK, wx.SOLID ) )
  508. sx, sy = mDataDict["scaledXY"] #scaled x,y of closest point
  509. dc.DrawRectangle( sx-5,sy-5, 10, 10) #10by10 square centered on point
  510. px,py = mDataDict["pointXY"]
  511. cNum = mDataDict["curveNum"]
  512. pntIn = mDataDict["pIndex"]
  513. legend = mDataDict["legend"]
  514. #make a string to display
  515. s = "Crv# %i, '%s', Pt. (%.2f,%.2f), PtInd %i" %(cNum, legend, px, py, pntIn)
  516. dc.DrawText(s, sx , sy+1)
  517. def OnMouseLeftDown(self,event):
  518. s= "Left Mouse Down at Point: (%.4f, %.4f)" % self.client._getXY(event)
  519. self.SetStatusText(s)
  520. event.Skip() #allows plotCanvas OnMouseLeftDown to be called
  521. def OnMotion(self, event):
  522. # indicate when mouse is outside the plot area
  523. if self.client.OnLeave(event): print 'out of area'
  524. #show closest point (when enbled)
  525. if self.client.GetEnablePointLabel() == True:
  526. #make up dict with info for the pointLabel
  527. #I've decided to mark the closest point on the closest curve
  528. dlst= self.client.GetClosetPoint( self.client._getXY(event), pointScaled= True)
  529. if dlst != []: #returns [] if none
  530. curveNum, legend, pIndex, pointXY, scaledXY, distance = dlst
  531. #make up dictionary to pass to my user function (see DrawPointLabel)
  532. mDataDict= {"curveNum":curveNum, "legend":legend, "pIndex":pIndex,\
  533. "pointXY":pointXY, "scaledXY":scaledXY}
  534. #pass dict to update the pointLabel
  535. self.client.UpdatePointLabel(mDataDict)
  536. event.Skip() #go to next handler
  537. def ProfileOptionsMenu(self, event):
  538. """!Popup menu for profile and text options
  539. """
  540. point = wx.GetMousePosition()
  541. popt = wx.Menu()
  542. # Add items to the menu
  543. settext = wx.MenuItem(popt, -1, 'Profile text settings')
  544. popt.AppendItem(settext)
  545. self.Bind(wx.EVT_MENU, self.PText, settext)
  546. setgrid = wx.MenuItem(popt, -1, 'Profile plot settings')
  547. popt.AppendItem(setgrid)
  548. self.Bind(wx.EVT_MENU, self.POptions, setgrid)
  549. # Popup the menu. If an item is selected then its handler
  550. # will be called before PopupMenu returns.
  551. self.PopupMenu(popt)
  552. popt.Destroy()
  553. def NotFunctional(self):
  554. """!Creates a 'not functional' message dialog
  555. """
  556. dlg = wx.MessageDialog(parent = self,
  557. message = _('This feature is not yet functional'),
  558. caption = _('Under Construction'),
  559. style = wx.OK | wx.ICON_INFORMATION)
  560. dlg.ShowModal()
  561. dlg.Destroy()
  562. def OnPText(self, dlg):
  563. """!Use user's provided profile text settings.
  564. """
  565. self.ptitle = dlg.ptitle
  566. self.xlabel = dlg.xlabel
  567. self.ylabel = dlg.ylabel
  568. dlg.UpdateSettings()
  569. self.client.SetFont(self.properties['font']['wxfont'])
  570. self.client.SetFontSizeTitle(self.properties['font']['prop']['titleSize'])
  571. self.client.SetFontSizeAxis(self.properties['font']['prop']['axisSize'])
  572. if self.profile:
  573. self.profile.setTitle(dlg.ptitle)
  574. self.profile.setXLabel(dlg.xlabel)
  575. self.profile.setYLabel(dlg.ylabel)
  576. self.OnRedraw(event=None)
  577. def PText(self, event):
  578. """!Set custom text values for profile title and axis labels.
  579. """
  580. dlg = TextDialog(parent=self, id=wx.ID_ANY, title=_('Profile text settings'))
  581. if dlg.ShowModal() == wx.ID_OK:
  582. self.OnPText(dlg)
  583. dlg.Destroy()
  584. def POptions(self, event):
  585. """!Set various profile options, including: line width, color,
  586. style; marker size, color, fill, and style; grid and legend
  587. options. Calls OptDialog class.
  588. """
  589. dlg = OptDialog(parent=self, id=wx.ID_ANY, title=_('Profile settings'))
  590. btnval = dlg.ShowModal()
  591. if btnval == wx.ID_SAVE:
  592. dlg.UpdateSettings()
  593. self.SetGraphStyle()
  594. dlg.Destroy()
  595. elif btnval == wx.ID_CANCEL:
  596. dlg.Destroy()
  597. def PrintMenu(self, event):
  598. """!Print options and output menu
  599. """
  600. point = wx.GetMousePosition()
  601. printmenu = wx.Menu()
  602. # Add items to the menu
  603. setup = wx.MenuItem(printmenu, -1,'Page setup')
  604. printmenu.AppendItem(setup)
  605. self.Bind(wx.EVT_MENU, self.OnPageSetup, setup)
  606. preview = wx.MenuItem(printmenu, -1,'Print preview')
  607. printmenu.AppendItem(preview)
  608. self.Bind(wx.EVT_MENU, self.OnPrintPreview, preview)
  609. doprint = wx.MenuItem(printmenu, -1,'Print display')
  610. printmenu.AppendItem(doprint)
  611. self.Bind(wx.EVT_MENU, self.OnDoPrint, doprint)
  612. # Popup the menu. If an item is selected then its handler
  613. # will be called before PopupMenu returns.
  614. self.PopupMenu(printmenu)
  615. printmenu.Destroy()
  616. def OnPageSetup(self, event):
  617. self.client.PageSetup()
  618. def OnPrintPreview(self, event):
  619. self.client.PrintPreview()
  620. def OnDoPrint(self, event):
  621. self.client.Printout()
  622. def OnQuit(self, event):
  623. self.Close(True)
  624. def OnCloseWindow(self, event):
  625. """
  626. Close profile window and clean up
  627. """
  628. self.mapwin.ClearLines()
  629. self.mapwin.mouse['begin'] = self.mapwin.mouse['end'] = (0.0, 0.0)
  630. self.mapwin.mouse['use'] = 'pointer'
  631. self.mapwin.mouse['box'] = 'point'
  632. self.mapwin.polycoords = []
  633. self.mapwin.SetCursor(self.Parent.cursors["default"])
  634. self.mapwin.UpdateMap(render=False, renderVector=False)
  635. self.Destroy()
  636. class SetRasterDialog(wx.Dialog):
  637. def __init__(self, parent, id=wx.ID_ANY, title=_("Select raster map to profile"),
  638. pos=wx.DefaultPosition, size=wx.DefaultSize,
  639. style=wx.DEFAULT_DIALOG_STYLE):
  640. """!Dialog to select raster maps to profile.
  641. """
  642. wx.Dialog.__init__(self, parent, id, title, pos, size, style)
  643. self.parent = parent
  644. self.coordstr = self.parent.coordstr
  645. # if self.coordstr == '':
  646. # dlg = wx.MessageDialog(parent=self,
  647. # message=_('You must draw a transect to profile in the map display window.'),
  648. # caption=_('Nothing to profile'),
  649. # style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
  650. # dlg.ShowModal()
  651. # dlg.Destroy()
  652. # self.Close(True)
  653. # return
  654. self.raster = { 0 : { 'name' : self.parent.raster[0]['name'],
  655. 'id' : None },
  656. 1 : { 'name' : self.parent.raster[1]['name'],
  657. 'id' : None },
  658. 2 : { 'name' : self.parent.raster[2]['name'],
  659. 'id' : None }
  660. }
  661. sizer = wx.BoxSizer(wx.VERTICAL)
  662. box = wx.GridBagSizer (hgap=3, vgap=3)
  663. i = 0
  664. for txt in [_("Select raster map 1 (required):"),
  665. _("Select raster map 2 (optional):"),
  666. _("Select raster map 3 (optional):")]:
  667. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=txt)
  668. box.Add(item=label,
  669. flag=wx.ALIGN_CENTER_VERTICAL, pos=(i, 0))
  670. selection = gselect.Select(self, id=wx.ID_ANY,
  671. size=globalvar.DIALOG_GSELECT_SIZE,
  672. type='cell')
  673. selection.SetValue(str(self.raster[i]['name']))
  674. self.raster[i]['id'] = selection.GetChildren()[0].GetId()
  675. selection.Bind(wx.EVT_TEXT, self.OnSelection)
  676. box.Add(item=selection, pos=(i, 1))
  677. i += 1
  678. sizer.Add(item=box, proportion=0,
  679. flag=wx.ALL, border=10)
  680. line = wx.StaticLine(parent=self, id=wx.ID_ANY, size=(20, -1), style=wx.LI_HORIZONTAL)
  681. sizer.Add(item=line, proportion=0,
  682. flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border=5)
  683. btnsizer = wx.StdDialogButtonSizer()
  684. btn = wx.Button(self, wx.ID_OK)
  685. btn.SetDefault()
  686. btnsizer.AddButton(btn)
  687. btn = wx.Button(self, wx.ID_CANCEL)
  688. btnsizer.AddButton(btn)
  689. btnsizer.Realize()
  690. sizer.Add(item=btnsizer, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
  691. self.SetSizer(sizer)
  692. sizer.Fit(self)
  693. def OnSelection(self, event):
  694. id = event.GetId()
  695. for r in self.raster.itervalues():
  696. if r['id'] == id:
  697. r['name'] = event.GetString()
  698. break
  699. class TextDialog(wx.Dialog):
  700. def __init__(self, parent, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize,
  701. style=wx.DEFAULT_DIALOG_STYLE):
  702. """!Dialog to set profile text options: font, title
  703. and font size, axis labels and font size
  704. """
  705. wx.Dialog.__init__(self, parent, id, title, pos, size, style)
  706. #
  707. # initialize variables
  708. #
  709. # combo box entry lists
  710. self.ffamilydict = { 'default' : wx.FONTFAMILY_DEFAULT,
  711. 'decorative' : wx.FONTFAMILY_DECORATIVE,
  712. 'roman' : wx.FONTFAMILY_ROMAN,
  713. 'script' : wx.FONTFAMILY_SCRIPT,
  714. 'swiss' : wx.FONTFAMILY_SWISS,
  715. 'modern' : wx.FONTFAMILY_MODERN,
  716. 'teletype' : wx.FONTFAMILY_TELETYPE }
  717. self.fstyledict = { 'normal' : wx.FONTSTYLE_NORMAL,
  718. 'slant' : wx.FONTSTYLE_SLANT,
  719. 'italic' : wx.FONTSTYLE_ITALIC }
  720. self.fwtdict = { 'normal' : wx.FONTWEIGHT_NORMAL,
  721. 'light' : wx.FONTWEIGHT_LIGHT,
  722. 'bold' : wx.FONTWEIGHT_BOLD }
  723. self.parent = parent
  724. self.ptitle = self.parent.ptitle
  725. self.xlabel = self.parent.xlabel
  726. self.ylabel = self.parent.ylabel
  727. self.properties = self.parent.properties # read-only
  728. # font size
  729. self.fontfamily = self.properties['font']['wxfont'].GetFamily()
  730. self.fontstyle = self.properties['font']['wxfont'].GetStyle()
  731. self.fontweight = self.properties['font']['wxfont'].GetWeight()
  732. self._do_layout()
  733. def _do_layout(self):
  734. """!Do layout"""
  735. # dialog layout
  736. sizer = wx.BoxSizer(wx.VERTICAL)
  737. box = wx.StaticBox(parent=self, id=wx.ID_ANY,
  738. label=" %s " % _("Text settings"))
  739. boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  740. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  741. #
  742. # profile title
  743. #
  744. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Profile title:"))
  745. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0))
  746. self.ptitleentry = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(250,-1))
  747. # self.ptitleentry.SetFont(self.font)
  748. self.ptitleentry.SetValue(self.ptitle)
  749. gridSizer.Add(item=self.ptitleentry, pos=(0, 1))
  750. #
  751. # title font
  752. #
  753. tlabel = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Title font size (pts):"))
  754. gridSizer.Add(item=tlabel, flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 0))
  755. self.ptitlesize = wx.SpinCtrl(parent=self, id=wx.ID_ANY, value="", pos=(30, 50),
  756. size=(50,-1), style=wx.SP_ARROW_KEYS)
  757. self.ptitlesize.SetRange(5,100)
  758. self.ptitlesize.SetValue(int(self.properties['font']['prop']['titleSize']))
  759. gridSizer.Add(item=self.ptitlesize, pos=(1, 1))
  760. #
  761. # x-axis label
  762. #
  763. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("X-axis label:"))
  764. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(2, 0))
  765. self.xlabelentry = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(250,-1))
  766. # self.xlabelentry.SetFont(self.font)
  767. self.xlabelentry.SetValue(self.xlabel)
  768. gridSizer.Add(item=self.xlabelentry, pos=(2, 1))
  769. #
  770. # y-axis label
  771. #
  772. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Y-axis label:"))
  773. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(3, 0))
  774. self.ylabelentry = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(250,-1))
  775. # self.ylabelentry.SetFont(self.font)
  776. self.ylabelentry.SetValue(self.ylabel)
  777. gridSizer.Add(item=self.ylabelentry, pos=(3, 1))
  778. #
  779. # font size
  780. #
  781. llabel = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Label font size (pts):"))
  782. gridSizer.Add(item=llabel, flag=wx.ALIGN_CENTER_VERTICAL, pos=(4, 0))
  783. self.axislabelsize = wx.SpinCtrl(parent=self, id=wx.ID_ANY, value="", pos=(30, 50),
  784. size=(50, -1), style=wx.SP_ARROW_KEYS)
  785. self.axislabelsize.SetRange(5, 100)
  786. self.axislabelsize.SetValue(int(self.properties['font']['prop']['axisSize']))
  787. gridSizer.Add(item=self.axislabelsize, pos=(4,1))
  788. boxSizer.Add(item=gridSizer)
  789. sizer.Add(item=boxSizer, flag=wx.ALL | wx.EXPAND, border=3)
  790. #
  791. # font settings
  792. #
  793. box = wx.StaticBox(parent=self, id=wx.ID_ANY,
  794. label=" %s " % _("Font settings"))
  795. boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  796. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  797. gridSizer.AddGrowableCol(1)
  798. #
  799. # font family
  800. #
  801. label1 = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Font family:"))
  802. gridSizer.Add(item=label1, flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0))
  803. self.ffamilycb = wx.ComboBox(parent=self, id=wx.ID_ANY, size=(250, -1),
  804. choices=self.ffamilydict.keys(), style=wx.CB_DROPDOWN)
  805. self.ffamilycb.SetStringSelection('swiss')
  806. for item in self.ffamilydict.items():
  807. if self.fontfamily == item[1]:
  808. self.ffamilycb.SetStringSelection(item[0])
  809. break
  810. gridSizer.Add(item=self.ffamilycb, pos=(0, 1), flag=wx.ALIGN_RIGHT)
  811. #
  812. # font style
  813. #
  814. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Style:"))
  815. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 0))
  816. self.fstylecb = wx.ComboBox(parent=self, id=wx.ID_ANY, size=(250, -1),
  817. choices=self.fstyledict.keys(), style=wx.CB_DROPDOWN)
  818. self.fstylecb.SetStringSelection('normal')
  819. for item in self.fstyledict.items():
  820. if self.fontstyle == item[1]:
  821. self.fstylecb.SetStringSelection(item[0])
  822. break
  823. gridSizer.Add(item=self.fstylecb, pos=(1, 1), flag=wx.ALIGN_RIGHT)
  824. #
  825. # font weight
  826. #
  827. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Weight:"))
  828. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(2, 0))
  829. self.fwtcb = wx.ComboBox(parent=self, size=(250, -1),
  830. choices=self.fwtdict.keys(), style=wx.CB_DROPDOWN)
  831. self.fwtcb.SetStringSelection('normal')
  832. for item in self.fwtdict.items():
  833. if self.fontweight == item[1]:
  834. self.fwtcb.SetStringSelection(item[0])
  835. break
  836. gridSizer.Add(item=self.fwtcb, pos=(2, 1), flag=wx.ALIGN_RIGHT)
  837. boxSizer.Add(item=gridSizer, flag=wx.EXPAND)
  838. sizer.Add(item=boxSizer, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3)
  839. line = wx.StaticLine(parent=self, id=wx.ID_ANY, size=(20, -1), style=wx.LI_HORIZONTAL)
  840. sizer.Add(item=line, proportion=0,
  841. flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border=3)
  842. #
  843. # buttons
  844. #
  845. btnSave = wx.Button(self, wx.ID_SAVE)
  846. btnApply = wx.Button(self, wx.ID_APPLY)
  847. btnOk = wx.Button(self, wx.ID_OK)
  848. btnCancel = wx.Button(self, wx.ID_CANCEL)
  849. btnOk.SetDefault()
  850. # bindings
  851. btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  852. btnApply.SetToolTipString(_("Apply changes for the current session"))
  853. btnOk.Bind(wx.EVT_BUTTON, self.OnOk)
  854. btnOk.SetToolTipString(_("Apply changes for the current session and close dialog"))
  855. btnOk.SetDefault()
  856. btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
  857. btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
  858. btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
  859. btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
  860. # sizers
  861. btnStdSizer = wx.StdDialogButtonSizer()
  862. btnStdSizer.AddButton(btnOk)
  863. btnStdSizer.AddButton(btnApply)
  864. btnStdSizer.AddButton(btnCancel)
  865. btnStdSizer.Realize()
  866. btnSizer = wx.BoxSizer(wx.HORIZONTAL)
  867. btnSizer.Add(item=btnSave, proportion=0, flag=wx.ALIGN_LEFT | wx.ALL, border=5)
  868. btnSizer.Add(item=btnStdSizer, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
  869. sizer.Add(item=btnSizer, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
  870. #
  871. # bindings
  872. #
  873. self.ptitleentry.Bind(wx.EVT_TEXT, self.OnTitle)
  874. self.xlabelentry.Bind(wx.EVT_TEXT, self.OnXLabel)
  875. self.ylabelentry.Bind(wx.EVT_TEXT, self.OnYLabel)
  876. self.SetSizer(sizer)
  877. sizer.Fit(self)
  878. def OnTitle(self, event):
  879. self.ptitle = event.GetString()
  880. def OnXLabel(self, event):
  881. self.xlabel = event.GetString()
  882. def OnYLabel(self, event):
  883. self.ylabel = event.GetString()
  884. def UpdateSettings(self):
  885. self.properties['font']['prop']['titleSize'] = self.ptitlesize.GetValue()
  886. self.properties['font']['prop']['axisSize'] = self.axislabelsize.GetValue()
  887. family = self.ffamilydict[self.ffamilycb.GetStringSelection()]
  888. self.properties['font']['wxfont'].SetFamily(family)
  889. style = self.fstyledict[self.fstylecb.GetStringSelection()]
  890. self.properties['font']['wxfont'].SetStyle(style)
  891. weight = self.fwtdict[self.fwtcb.GetStringSelection()]
  892. self.properties['font']['wxfont'].SetWeight(weight)
  893. def OnSave(self, event):
  894. """!Button 'Save' pressed"""
  895. self.UpdateSettings()
  896. fileSettings = {}
  897. UserSettings.ReadSettingsFile(settings=fileSettings)
  898. fileSettings['profile'] = UserSettings.Get(group='profile')
  899. file = UserSettings.SaveToFile(fileSettings)
  900. self.parent.parent.GetLayerManager().goutput.WriteLog(_('Profile settings saved to file \'%s\'.') % file)
  901. self.EndModal(wx.ID_OK)
  902. def OnApply(self, event):
  903. """!Button 'Apply' pressed"""
  904. self.UpdateSettings()
  905. self.parent.OnPText(self)
  906. def OnOk(self, event):
  907. """!Button 'OK' pressed"""
  908. self.UpdateSettings()
  909. self.EndModal(wx.ID_OK)
  910. def OnCancel(self, event):
  911. """!Button 'Cancel' pressed"""
  912. self.EndModal(wx.ID_CANCEL)
  913. class OptDialog(wx.Dialog):
  914. def __init__(self, parent, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize,
  915. style=wx.DEFAULT_DIALOG_STYLE):
  916. """!Dialog to set various profile options, including: line
  917. width, color, style; marker size, color, fill, and style; grid
  918. and legend options.
  919. """
  920. wx.Dialog.__init__(self, parent, id, title, pos, size, style)
  921. # init variables
  922. self.pstyledict = parent.pstyledict
  923. self.ptfilldict = parent.ptfilldict
  924. self.pttypelist = ['circle',
  925. 'dot',
  926. 'square',
  927. 'triangle',
  928. 'triangle_down',
  929. 'cross',
  930. 'plus']
  931. self.axislist = ['min',
  932. 'auto',
  933. 'custom']
  934. # widgets ids
  935. self.wxId = {}
  936. self.parent = parent
  937. # read-only
  938. self.raster = self.parent.raster
  939. self.properties = self.parent.properties
  940. self._do_layout()
  941. def _do_layout(self):
  942. """!Do layout"""
  943. # dialog layout
  944. sizer = wx.BoxSizer(wx.VERTICAL)
  945. #
  946. # profile line settings
  947. #
  948. box = wx.StaticBox(parent=self, id=wx.ID_ANY,
  949. label=" %s " % _("Profile line settings"))
  950. boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
  951. idx = 1
  952. self.wxId['pcolor'] = []
  953. self.wxId['pwidth'] = []
  954. self.wxId['pstyle'] = []
  955. self.wxId['plegend'] = []
  956. for r in self.raster.itervalues():
  957. box = wx.StaticBox(parent=self, id=wx.ID_ANY,
  958. label=" %s %d " % (_("Profile"), idx))
  959. boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  960. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  961. row = 0
  962. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Line color"))
  963. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  964. pcolor = csel.ColourSelect(parent=self, id=wx.ID_ANY, colour=r['prop']['pcolor'])
  965. self.wxId['pcolor'].append(pcolor.GetId())
  966. gridSizer.Add(item=pcolor, pos=(row, 1))
  967. row += 1
  968. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Line width"))
  969. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  970. pwidth = wx.SpinCtrl(parent=self, id=wx.ID_ANY, value="",
  971. size=(50,-1), style=wx.SP_ARROW_KEYS)
  972. pwidth.SetRange(1, 10)
  973. pwidth.SetValue(r['prop']['pwidth'])
  974. self.wxId['pwidth'].append(pwidth.GetId())
  975. gridSizer.Add(item=pwidth, pos=(row, 1))
  976. row +=1
  977. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Line style"))
  978. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  979. pstyle = wx.ComboBox(parent=self, id=wx.ID_ANY,
  980. size=(120, -1), choices=self.pstyledict.keys(), style=wx.CB_DROPDOWN)
  981. pstyle.SetStringSelection(r['prop']['pstyle'])
  982. self.wxId['pstyle'].append(pstyle.GetId())
  983. gridSizer.Add(item=pstyle, pos=(row, 1))
  984. row += 1
  985. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Legend"))
  986. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  987. plegend = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(200,-1))
  988. plegend.SetValue(r['plegend'])
  989. gridSizer.Add(item=plegend, pos=(row, 1))
  990. self.wxId['plegend'].append(plegend.GetId())
  991. boxSizer.Add(item=gridSizer)
  992. if idx == 0:
  993. flag = wx.ALL
  994. else:
  995. flag = wx.TOP | wx.BOTTOM | wx.RIGHT
  996. boxMainSizer.Add(item=boxSizer, flag=flag, border=3)
  997. idx += 1
  998. sizer.Add(item=boxMainSizer, flag=wx.ALL | wx.EXPAND, border=3)
  999. middleSizer = wx.BoxSizer(wx.HORIZONTAL)
  1000. #
  1001. # segment marker settings
  1002. #
  1003. box = wx.StaticBox(parent=self, id=wx.ID_ANY,
  1004. label=" %s " % _("Transect segment marker settings"))
  1005. boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
  1006. self.wxId['marker'] = {}
  1007. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  1008. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Color"))
  1009. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0))
  1010. ptcolor = csel.ColourSelect(parent=self, id=wx.ID_ANY, colour=self.properties['marker']['color'])
  1011. self.wxId['marker']['color'] = ptcolor.GetId()
  1012. gridSizer.Add(item=ptcolor, pos=(0, 1))
  1013. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Size"))
  1014. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 0))
  1015. ptsize = wx.SpinCtrl(parent=self, id=wx.ID_ANY, value="",
  1016. size=(50, -1), style=wx.SP_ARROW_KEYS)
  1017. ptsize.SetRange(1, 10)
  1018. ptsize.SetValue(self.properties['marker']['size'])
  1019. self.wxId['marker']['size'] = ptsize.GetId()
  1020. gridSizer.Add(item=ptsize, pos=(1, 1))
  1021. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Style"))
  1022. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(2, 0))
  1023. ptfill = wx.ComboBox(parent=self, id=wx.ID_ANY,
  1024. size=(120, -1), choices=self.ptfilldict.keys(), style=wx.CB_DROPDOWN)
  1025. ptfill.SetStringSelection(self.properties['marker']['fill'])
  1026. self.wxId['marker']['fill'] = ptfill.GetId()
  1027. gridSizer.Add(item=ptfill, pos=(2, 1))
  1028. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Legend"))
  1029. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(3, 0))
  1030. ptlegend = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(200,-1))
  1031. ptlegend.SetValue(self.properties['marker']['legend'])
  1032. self.wxId['marker']['legend'] = ptlegend.GetId()
  1033. gridSizer.Add(item=ptlegend, pos=(3, 1))
  1034. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Type"))
  1035. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(4, 0))
  1036. pttype = wx.ComboBox(parent=self,
  1037. size=(200, -1), choices=self.pttypelist, style=wx.CB_DROPDOWN)
  1038. pttype.SetStringSelection(self.properties['marker']['type'])
  1039. self.wxId['marker']['type'] = pttype.GetId()
  1040. gridSizer.Add(item=pttype, pos=(4, 1))
  1041. boxMainSizer.Add(item=gridSizer, flag=wx.ALL, border=3)
  1042. middleSizer.Add(item=boxMainSizer, flag=wx.ALL | wx.EXPAND, border=3)
  1043. #
  1044. # axis options
  1045. #
  1046. box = wx.StaticBox(parent=self, id=wx.ID_ANY,
  1047. label=" %s " % _("Axis settings"))
  1048. boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
  1049. self.wxId['x-axis'] = {}
  1050. self.wxId['y-axis'] = {}
  1051. idx = 0
  1052. for axis, atype in [(_("X-Axis"), 'x-axis'),
  1053. (_("Y-Axis"), 'y-axis')]:
  1054. box = wx.StaticBox(parent=self, id=wx.ID_ANY,
  1055. label=" %s " % axis)
  1056. boxSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
  1057. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  1058. prop = self.properties[atype]['prop']
  1059. row = 0
  1060. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Style"))
  1061. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1062. type = wx.ComboBox(parent=self, id=wx.ID_ANY,
  1063. size=(100, -1), choices=self.axislist, style=wx.CB_DROPDOWN)
  1064. type.SetStringSelection(prop['type'])
  1065. self.wxId[atype]['type'] = type.GetId()
  1066. gridSizer.Add(item=type, pos=(row, 1))
  1067. row += 1
  1068. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Custom min"))
  1069. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1070. min = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(70, -1))
  1071. min.SetValue(str(prop['min']))
  1072. self.wxId[atype]['min'] = min.GetId()
  1073. gridSizer.Add(item=min, pos=(row, 1))
  1074. row += 1
  1075. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Custom max"))
  1076. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1077. max = wx.TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(70, -1))
  1078. max.SetValue(str(prop['max']))
  1079. self.wxId[atype]['max'] = max.GetId()
  1080. gridSizer.Add(item=max, pos=(row, 1))
  1081. row += 1
  1082. log = wx.CheckBox(parent=self, id=wx.ID_ANY, label=_("Log scale"))
  1083. log.SetValue(prop['log'])
  1084. self.wxId[atype]['log'] = log.GetId()
  1085. gridSizer.Add(item=log, pos=(row, 0), span=(1, 2))
  1086. if idx == 0:
  1087. flag = wx.ALL | wx.EXPAND
  1088. else:
  1089. flag = wx.TOP | wx.BOTTOM | wx.RIGHT | wx.EXPAND
  1090. boxSizer.Add(item=gridSizer, flag=wx.ALL, border=3)
  1091. boxMainSizer.Add(item=boxSizer, flag=flag, border=3)
  1092. idx += 1
  1093. middleSizer.Add(item=boxMainSizer, flag=wx.ALL | wx.EXPAND, border=3)
  1094. #
  1095. # grid & legend options
  1096. #
  1097. self.wxId['grid'] = {}
  1098. self.wxId['legend'] = {}
  1099. self.wxId['font'] = {}
  1100. box = wx.StaticBox(parent=self, id=wx.ID_ANY,
  1101. label=" %s " % _("Grid and Legend settings"))
  1102. boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
  1103. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  1104. row = 0
  1105. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Grid color"))
  1106. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1107. gridcolor = csel.ColourSelect(parent=self, id=wx.ID_ANY, colour=self.properties['grid']['color'])
  1108. self.wxId['grid']['color'] = gridcolor.GetId()
  1109. gridSizer.Add(item=gridcolor, pos=(row, 1))
  1110. row +=1
  1111. gridshow = wx.CheckBox(parent=self, id=wx.ID_ANY, label=_("Show grid"))
  1112. gridshow.SetValue(self.properties['grid']['enabled'])
  1113. self.wxId['grid']['enabled'] = gridshow.GetId()
  1114. gridSizer.Add(item=gridshow, pos=(row, 0), span=(1, 2))
  1115. row +=1
  1116. label = wx.StaticText(parent=self, id=wx.ID_ANY, label=_("Legend font size"))
  1117. gridSizer.Add(item=label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1118. legendfontsize = wx.SpinCtrl(parent=self, id=wx.ID_ANY, value="",
  1119. size=(50, -1), style=wx.SP_ARROW_KEYS)
  1120. legendfontsize.SetRange(5,100)
  1121. legendfontsize.SetValue(int(self.properties['font']['prop']['legendSize']))
  1122. self.wxId['font']['legendSize'] = legendfontsize.GetId()
  1123. gridSizer.Add(item=legendfontsize, pos=(row, 1))
  1124. row += 1
  1125. legendshow = wx.CheckBox(parent=self, id=wx.ID_ANY, label=_("Show legend"))
  1126. legendshow.SetValue(self.properties['legend']['enabled'])
  1127. self.wxId['legend']['enabled'] = legendshow.GetId()
  1128. gridSizer.Add(item=legendshow, pos=(row, 0), span=(1, 2))
  1129. boxMainSizer.Add(item=gridSizer, flag=flag, border=3)
  1130. middleSizer.Add(item=boxMainSizer, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3)
  1131. sizer.Add(item=middleSizer, flag=wx.ALL, border=0)
  1132. #
  1133. # line & buttons
  1134. #
  1135. line = wx.StaticLine(parent=self, id=wx.ID_ANY, size=(20, -1), style=wx.LI_HORIZONTAL)
  1136. sizer.Add(item=line, proportion=0,
  1137. flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border=3)
  1138. #
  1139. # buttons
  1140. #
  1141. btnSave = wx.Button(self, wx.ID_SAVE)
  1142. btnApply = wx.Button(self, wx.ID_APPLY)
  1143. btnCancel = wx.Button(self, wx.ID_CANCEL)
  1144. btnSave.SetDefault()
  1145. # bindigs
  1146. btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  1147. btnApply.SetToolTipString(_("Apply changes for the current session"))
  1148. btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
  1149. btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
  1150. btnSave.SetDefault()
  1151. btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
  1152. btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
  1153. # sizers
  1154. btnStdSizer = wx.StdDialogButtonSizer()
  1155. btnStdSizer.AddButton(btnCancel)
  1156. btnStdSizer.AddButton(btnSave)
  1157. btnStdSizer.AddButton(btnApply)
  1158. btnStdSizer.Realize()
  1159. sizer.Add(item=btnStdSizer, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
  1160. self.SetSizer(sizer)
  1161. sizer.Fit(self)
  1162. def UpdateSettings(self):
  1163. idx = 0
  1164. for r in self.raster.itervalues():
  1165. r['prop']['pcolor'] = self.FindWindowById(self.wxId['pcolor'][idx]).GetColour()
  1166. r['prop']['pwidth'] = int(self.FindWindowById(self.wxId['pwidth'][idx]).GetValue())
  1167. r['prop']['pstyle'] = self.FindWindowById(self.wxId['pstyle'][idx]).GetStringSelection()
  1168. r['plegend'] = self.FindWindowById(self.wxId['plegend'][idx]).GetValue()
  1169. idx +=1
  1170. self.properties['marker']['color'] = self.FindWindowById(self.wxId['marker']['color']).GetColour()
  1171. self.properties['marker']['fill'] = self.FindWindowById(self.wxId['marker']['fill']).GetStringSelection()
  1172. self.properties['marker']['size'] = self.FindWindowById(self.wxId['marker']['size']).GetValue()
  1173. self.properties['marker']['type'] = self.FindWindowById(self.wxId['marker']['type']).GetValue()
  1174. self.properties['marker']['legend'] = self.FindWindowById(self.wxId['marker']['legend']).GetValue()
  1175. for axis in ('x-axis', 'y-axis'):
  1176. self.properties[axis]['prop']['type'] = self.FindWindowById(self.wxId[axis]['type']).GetValue()
  1177. self.properties[axis]['prop']['min'] = float(self.FindWindowById(self.wxId[axis]['min']).GetValue())
  1178. self.properties[axis]['prop']['max'] = float(self.FindWindowById(self.wxId[axis]['max']).GetValue())
  1179. self.properties[axis]['prop']['log'] = self.FindWindowById(self.wxId[axis]['log']).IsChecked()
  1180. self.properties['grid']['color'] = self.FindWindowById(self.wxId['grid']['color']).GetColour()
  1181. self.properties['grid']['enabled'] = self.FindWindowById(self.wxId['grid']['enabled']).IsChecked()
  1182. self.properties['font']['prop']['legendSize'] = self.FindWindowById(self.wxId['font']['legendSize']).GetValue()
  1183. self.properties['legend']['enabled'] = self.FindWindowById(self.wxId['legend']['enabled']).IsChecked()
  1184. def OnSave(self, event):
  1185. """!Button 'Save' pressed"""
  1186. self.UpdateSettings()
  1187. fileSettings = {}
  1188. UserSettings.ReadSettingsFile(settings=fileSettings)
  1189. fileSettings['profile'] = UserSettings.Get(group='profile')
  1190. file = UserSettings.SaveToFile(fileSettings)
  1191. self.parent.parent.GetLayerManager().goutput.WriteLog(_('Profile settings saved to file \'%s\'.') % file)
  1192. self.parent.SetGraphStyle()
  1193. if self.parent.profile:
  1194. self.parent.DrawPlot()
  1195. self.Close()
  1196. def OnApply(self, event):
  1197. """!Button 'Apply' pressed. Does not close dialog"""
  1198. self.UpdateSettings()
  1199. self.parent.SetGraphStyle()
  1200. if self.parent.profile:
  1201. self.parent.DrawPlot()
  1202. def OnCancel(self, event):
  1203. """!Button 'Cancel' pressed"""
  1204. self.Close()