profile.py 58 KB

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