histogram2.py 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354
  1. """!
  2. @package histogram2.py
  3. Raster histogramming using PyPlot (wx.lib.plot.py); replacement for
  4. d.hist
  5. Classes:
  6. - HistFrame
  7. - SetRasterDialog
  8. - TextDialog
  9. - OptDialog
  10. (C) 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, Arizona State University
  14. """
  15. import os
  16. import sys
  17. import wx
  18. import wx.lib.colourselect as csel
  19. import globalvar
  20. import gcmd
  21. from gselect import Select
  22. from render import Map
  23. from toolbars import Histogram2Toolbar
  24. from debug import Debug
  25. from preferences import globalSettings as UserSettings
  26. from grass.script import core as grass
  27. from grass.script import raster as raster
  28. try:
  29. import numpy
  30. import wx.lib.plot as plot
  31. except ImportError:
  32. msg = _("This module requires the NumPy module, which could not be "
  33. "imported. It probably is not installed (it's not part of the "
  34. "standard Python distribution). See the Numeric Python site "
  35. "(http://numpy.scipy.org) for information on downloading source or "
  36. "binaries.")
  37. print >> sys.stderr, "histogram2.py: " + msg
  38. class HistFrame(wx.Frame):
  39. """!Mainframe for displaying profile of raster map. Uses wx.lib.plot.
  40. """
  41. def __init__(self, parent = None, id = wx.ID_ANY,
  42. title = _("GRASS Histogramming Tool"), rasterList = [],
  43. style = wx.DEFAULT_FRAME_STYLE, **kwargs):
  44. self.parent = parent # MapFrame
  45. self.mapwin = self.parent.MapWindow
  46. self.Map = Map() # instance of render.Map to be associated with display
  47. self.rasterList = rasterList #list of rasters to histogram; could come from layer manager
  48. self.pstyledict = { 'solid' : wx.SOLID,
  49. 'dot' : wx.DOT,
  50. 'long-dash' : wx.LONG_DASH,
  51. 'short-dash' : wx.SHORT_DASH,
  52. 'dot-dash' : wx.DOT_DASH }
  53. self.ptfilldict = { 'transparent' : wx.TRANSPARENT,
  54. 'solid' : wx.SOLID }
  55. wx.Frame.__init__(self, parent, id, title, style = style, **kwargs)
  56. #
  57. # Icon
  58. #
  59. self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
  60. #
  61. # Add toolbar
  62. #
  63. self.toolbar = Histogram2Toolbar(parent = self)
  64. self.SetToolBar(self.toolbar)
  65. #
  66. # Add statusbar
  67. #
  68. self.statusbar = self.CreateStatusBar(number = 2, style = 0)
  69. self.statusbar.SetStatusWidths([-2, -1])
  70. #
  71. # Define canvas
  72. #
  73. self.client = plot.PlotCanvas(self) # plot canvas settings
  74. # Create mouse event for showing cursor coords in status bar
  75. self.client.canvas.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown)
  76. # Show closest point when enabled
  77. self.client.canvas.Bind(wx.EVT_MOTION, self.OnMotion)
  78. #
  79. # Init variables
  80. #
  81. self.group = ''
  82. self.raster = {}
  83. if len(self.rasterList) > 0: # set 1 raster name from layer manager if a map is selected
  84. self.raster[self.rasterList[0]] = UserSettings.Get(group = 'histogram', key = 'raster') # some default settings
  85. self.raster[self.rasterList[0]]['units'] = ''
  86. self.raster[self.rasterList[0]]['plegend'] = ''
  87. self.raster[self.rasterList[0]]['datalist'] = [] # list of cell value,frequency pairs for plotting histogram
  88. self.raster[self.rasterList[0]]['pline'] = None
  89. colstr = str(self.raster[self.rasterList[0]]['pcolor']) # changing color string to tuple
  90. self.raster[self.rasterList[0]]['pcolor'] = tuple(int(colval) for colval in colstr.strip('()').split(','))
  91. self.plotlist = [] # list of things to plot
  92. self.histogram = None # plot draw object
  93. self.ptitle = _('Histogram of') # title of window
  94. self.xlabel = _("Raster cell values") # default X-axis label
  95. self.ylabel = _("Cell counts") # default Y-axis label
  96. self.maptype = 'raster' # default type of histogram to plot
  97. self.properties = {} # plot properties
  98. self.properties['font'] = {}
  99. self.properties['font']['prop'] = UserSettings.Get(group = 'histogram', key = 'font')
  100. self.properties['font']['wxfont'] = wx.Font(11, wx.FONTFAMILY_SWISS,
  101. wx.FONTSTYLE_NORMAL,
  102. wx.FONTWEIGHT_NORMAL)
  103. self.properties['grid'] = UserSettings.Get(group = 'histogram', key = 'grid')
  104. colstr = str(self.properties['grid']['color']) # changing color string to tuple
  105. self.properties['grid']['color'] = tuple(int(colval) for colval in colstr.strip('()').split(','))
  106. self.properties['x-axis'] = {}
  107. self.properties['x-axis']['prop'] = UserSettings.Get(group = 'histogram', key = 'x-axis')
  108. self.properties['x-axis']['axis'] = None
  109. self.properties['y-axis'] = {}
  110. self.properties['y-axis']['prop'] = UserSettings.Get(group = 'histogram', key = 'y-axis')
  111. self.properties['y-axis']['axis'] = None
  112. self.properties['legend'] = UserSettings.Get(group = 'histogram', key = 'legend')
  113. self.histtype = 'count'
  114. self.bins = 255
  115. self.zoom = False # zooming disabled
  116. self.drag = False # draging disabled
  117. self.client.SetShowScrollbars(True) # vertical and horizontal scrollbars
  118. # x and y axis set to normal (non-log)
  119. self.client.setLogScale((False, False))
  120. if self.properties['x-axis']['prop']['type']:
  121. self.client.SetXSpec(self.properties['x-axis']['prop']['type'])
  122. else:
  123. self.client.SetXSpec('auto')
  124. if self.properties['y-axis']['prop']['type']:
  125. self.client.SetYSpec(self.properties['y-axis']['prop']['type'])
  126. else:
  127. self.client.SetYSpec('auto')
  128. #
  129. # Bind various events
  130. #
  131. self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
  132. self.CentreOnScreen()
  133. self._createColorDict()
  134. def _createColorDict(self):
  135. """!Create color dictionary to return wx.Color tuples
  136. for assigning colors to images in imagery groups"""
  137. self.colorDict = {}
  138. for clr in grass.named_colors.iterkeys():
  139. if clr == 'white' or clr == 'black': continue
  140. r = grass.named_colors[clr][0] * 255
  141. g = grass.named_colors[clr][1] * 255
  142. b = grass.named_colors[clr][2] * 255
  143. self.colorDict[clr] = (r,g,b,255)
  144. def OnSelectRaster(self, event):
  145. """!Select raster map(s) to profile
  146. """
  147. dlg = SetRasterDialog(parent = self)
  148. if dlg.ShowModal() == wx.ID_OK:
  149. self.rasterList = dlg.rasterList
  150. self.group = dlg.group
  151. self.bins = dlg.bins
  152. self.histtype = dlg.histtype
  153. self.maptype = dlg.maptype
  154. # plot profile
  155. if len(self.rasterList) > 0:
  156. self.OnCreateHist(event = None)
  157. dlg.Destroy()
  158. def OnCreateHist(self, event):
  159. """!Main routine for creating a histogram. Uses r.stats to
  160. create a list of cell value and count/percent/area pairs. This is passed to
  161. plot to create a line graph of the histogram.
  162. """
  163. self.SetCursor(self.parent.cursors["default"])
  164. self.SetGraphStyle()
  165. self.SetRaster()
  166. self.DrawPlot()
  167. def SetGraphStyle(self):
  168. """!Set plot and text options
  169. """
  170. self.client.SetFont(self.properties['font']['wxfont'])
  171. self.client.SetFontSizeTitle(self.properties['font']['prop']['titleSize'])
  172. self.client.SetFontSizeAxis(self.properties['font']['prop']['axisSize'])
  173. self.client.SetEnableZoom(self.zoom)
  174. self.client.SetEnableDrag(self.drag)
  175. #
  176. # axis settings
  177. #
  178. if self.properties['x-axis']['prop']['type'] == 'custom':
  179. self.client.SetXSpec('min')
  180. else:
  181. self.client.SetXSpec(self.properties['x-axis']['prop']['type'])
  182. if self.properties['y-axis']['prop']['type'] == 'custom':
  183. self.client.SetYSpec('min')
  184. else:
  185. self.client.SetYSpec(self.properties['y-axis']['prop']['type'])
  186. if self.properties['x-axis']['prop']['type'] == 'custom' and \
  187. self.properties['x-axis']['prop']['min'] < self.properties['x-axis']['prop']['max']:
  188. self.properties['x-axis']['axis'] = (self.properties['x-axis']['prop']['min'],
  189. self.properties['x-axis']['prop']['max'])
  190. else:
  191. self.properties['x-axis']['axis'] = None
  192. if self.properties['y-axis']['prop']['type'] == 'custom' and \
  193. self.properties['y-axis']['prop']['min'] < self.properties['y-axis']['prop']['max']:
  194. self.properties['y-axis']['axis'] = (self.properties['y-axis']['prop']['min'],
  195. self.properties['y-axis']['prop']['max'])
  196. else:
  197. self.properties['y-axis']['axis'] = None
  198. self.client.SetEnableGrid(self.properties['grid']['enabled'])
  199. self.client.SetGridColour(wx.Color(self.properties['grid']['color'][0],
  200. self.properties['grid']['color'][1],
  201. self.properties['grid']['color'][2],
  202. 255))
  203. self.client.SetFontSizeLegend(self.properties['font']['prop']['legendSize'])
  204. self.client.SetEnableLegend(self.properties['legend']['enabled'])
  205. if self.properties['x-axis']['prop']['log'] == True:
  206. self.properties['x-axis']['axis'] = None
  207. self.client.SetXSpec('min')
  208. if self.properties['y-axis']['prop']['log'] == True:
  209. self.properties['y-axis']['axis'] = None
  210. self.client.SetYSpec('min')
  211. self.client.setLogScale((self.properties['x-axis']['prop']['log'],
  212. self.properties['y-axis']['prop']['log']))
  213. def SetRaster(self):
  214. """!Build data list for ploting each raster."""
  215. #
  216. # populate raster dictionary
  217. #
  218. if len(self.rasterList) == 0: return # nothing selected
  219. colorList = []
  220. for clr in ["blue", "green", "red", "yellow", "magenta", "cyan", \
  221. "aqua", "grey", "orange", "brown", "purple", "violet", \
  222. "indigo"]:
  223. colorList.append(self.colorDict[clr])
  224. if len(self.rasterList) > len(colorList):
  225. # just in case the imagery group has many maps
  226. diff = len(self.rasterList) - len(colorList)
  227. for x in range(0, diff):
  228. r = randint(0, 255)
  229. b = randint(0, 255)
  230. g = randint(0, 255)
  231. colorList.append((r,g,b,255))
  232. rastcolor = zip(self.rasterList, colorList)
  233. for r,c in rastcolor:
  234. if r in self.raster: continue # only reset values if rasters have changed
  235. self.raster[r] = {}
  236. try:
  237. ret = raster.raster_info(r)
  238. except:
  239. continue
  240. self.raster[r]['datatype'] = 'CELL'
  241. self.raster[r]['datatype'] = ret['datatype']
  242. self.raster[r]['units'] = ret['units']
  243. self.raster[r]['plegend'] = r # raster name to use in legend
  244. self.raster[r]['datalist'] = [] # list of cell value,frequency pairs for plotting histogram
  245. self.raster[r]['pline'] = None
  246. if 'pcolor' not in self.raster[r]:
  247. self.raster[r]['pcolor'] = c
  248. if 'pwidth' not in self.raster[r]:
  249. self.raster[r]['pwidth'] = 1
  250. if 'pstyle' not in self.raster[r]:
  251. self.raster[r]['pstyle'] = 'solid'
  252. self.ptitle = _('Histogram of') # reset window title
  253. #
  254. # create datalist for each raster map
  255. #
  256. for r in self.rasterList:
  257. self.raster[r]['datalist'] = self.CreateDatalist(r)
  258. #
  259. # update title
  260. #
  261. if self.maptype == 'group':
  262. self.ptitle = _('Histogram of %s') % self.group.split('@')[0]
  263. else:
  264. self.ptitle = _('Histogram of %s') % self.rasterList[0].split('@')[0]
  265. #
  266. # set xlabel based on first raster map in list to be histogrammed
  267. #
  268. units = self.raster[self.rasterList[0]]['units']
  269. if units != '' and units != '(none)' and units != None:
  270. self.xlabel = _('Raster cell values %s') % units
  271. else:
  272. self.xlabel = _('Raster cell values')
  273. #
  274. # set ylabel from self.histtype
  275. #
  276. if self.histtype == 'count': self.ylabel = _('Cell counts')
  277. if self.histtype == 'percent': self.ylabel = _('Percent of total cells')
  278. if self.histtype == 'area': self.ylabel = _('Area')
  279. def CreateDatalist(self, raster):
  280. """!Build a list of cell value, frequency pairs for histogram
  281. frequency can be in cell counts, percents, or area
  282. """
  283. datalist = []
  284. if self.histtype == 'count': freqflag = 'cn'
  285. if self.histtype == 'percent': freqflag = 'pn'
  286. if self.histtype == 'area': freqflag = 'an'
  287. try:
  288. ret = gcmd.RunCommand("r.stats",
  289. parent = self,
  290. input = raster,
  291. flags = freqflag,
  292. nsteps = self.bins,
  293. fs = ',',
  294. quiet = True,
  295. read = True)
  296. if not ret:
  297. return datalist
  298. for line in ret.splitlines():
  299. cellval, histval = line.strip().split(',')
  300. histval = histval.strip()
  301. if self.raster[raster]['datatype'] != 'CELL':
  302. cellval = cellval.split('-')[0]
  303. if self.histtype == 'percent':
  304. histval = histval.rstrip('%')
  305. datalist.append((cellval,histval))
  306. return datalist
  307. except gcmd.GException, e:
  308. gcmd.GError(parent = self,
  309. message = e.value)
  310. return None
  311. #### Maybe add a barplot routine to make an 'area' graph. Could make it slow down a lot
  312. def DrawPlot(self):
  313. """!Draw line and point plot from transect datalist and
  314. transect segment endpoint coordinates.
  315. """
  316. # graph the cell value, frequency pairs for the histogram
  317. self.plotlist = []
  318. for r in self.rasterList:
  319. if len(self.raster[r]['datalist']) > 0:
  320. col = wx.Color(self.raster[r]['pcolor'][0],
  321. self.raster[r]['pcolor'][1],
  322. self.raster[r]['pcolor'][2],
  323. 255)
  324. self.raster[r]['pline'] = plot.PolyLine(self.raster[r]['datalist'],
  325. colour = col,
  326. width = self.raster[r]['pwidth'],
  327. style = self.pstyledict[self.raster[r]['pstyle']],
  328. legend = self.raster[r]['plegend'])
  329. self.plotlist.append(self.raster[r]['pline'])
  330. self.histogram = plot.PlotGraphics(self.plotlist,
  331. self.ptitle,
  332. self.xlabel,
  333. self.ylabel)
  334. if self.properties['x-axis']['prop']['type'] == 'custom':
  335. self.client.SetXSpec('min')
  336. else:
  337. self.client.SetXSpec(self.properties['x-axis']['prop']['type'])
  338. if self.properties['y-axis']['prop']['type'] == 'custom':
  339. self.client.SetYSpec('min')
  340. else:
  341. self.client.SetYSpec(self.properties['y-axis']['prop']['type'])
  342. self.client.Draw(self.histogram, self.properties['x-axis']['axis'],
  343. self.properties['y-axis']['axis'])
  344. def OnZoom(self, event):
  345. """!Enable zooming and disable dragging
  346. """
  347. self.zoom = True
  348. self.drag = False
  349. self.client.SetEnableZoom(self.zoom)
  350. self.client.SetEnableDrag(self.drag)
  351. def OnDrag(self, event):
  352. """!Enable dragging and disable zooming
  353. """
  354. self.zoom = False
  355. self.drag = True
  356. self.client.SetEnableDrag(self.drag)
  357. self.client.SetEnableZoom(self.zoom)
  358. def OnRedraw(self, event):
  359. """!Redraw the hisogram window. Unzoom to original size
  360. """
  361. self.client.Reset()
  362. self.client.Redraw()
  363. def Update(self):
  364. """!Update histogram after changing options
  365. """
  366. self.SetGraphStyle()
  367. self.DrawPlot()
  368. def OnErase(self, event):
  369. """!Erase the histogram window
  370. """
  371. self.client.Clear()
  372. self.mapwin.ClearLines(self.mapwin.pdc)
  373. self.mapwin.ClearLines(self.mapwin.pdcTmp)
  374. self.mapwin.polycoords = []
  375. self.mapwin.Refresh()
  376. def SaveToFile(self, event):
  377. """!Save histogram to graphics file
  378. """
  379. self.client.SaveFile()
  380. def OnMouseLeftDown(self,event):
  381. self.SetStatusText(_("Left Mouse Down at Point: (%.4f, %.4f)") % \
  382. self.client._getXY(event))
  383. event.Skip() # allows plotCanvas OnMouseLeftDown to be called
  384. def OnMotion(self, event):
  385. # indicate when mouse is outside the plot area
  386. if self.client.OnLeave(event): print 'out of area'
  387. #show closest point (when enbled)
  388. if self.client.GetEnablePointLabel() == True:
  389. #make up dict with info for the pointLabel
  390. #I've decided to mark the closest point on the closest curve
  391. dlst = self.client.GetClosetPoint( self.client._getXY(event), pointScaled = True)
  392. if dlst != []: #returns [] if none
  393. curveNum, legend, pIndex, pointXY, scaledXY, distance = dlst
  394. #make up dictionary to pass to my user function (see DrawPointLabel)
  395. mDataDict = {"curveNum":curveNum, "legend":legend, "pIndex":pIndex,\
  396. "pointXY":pointXY, "scaledXY":scaledXY}
  397. #pass dict to update the pointLabel
  398. self.client.UpdatePointLabel(mDataDict)
  399. event.Skip() #go to next handler
  400. def HistOptionsMenu(self, event):
  401. """!Popup menu for histogram and text options
  402. """
  403. point = wx.GetMousePosition()
  404. popt = wx.Menu()
  405. # Add items to the menu
  406. settext = wx.MenuItem(popt, wx.ID_ANY, _('Histogram text settings'))
  407. popt.AppendItem(settext)
  408. self.Bind(wx.EVT_MENU, self.PText, settext)
  409. setgrid = wx.MenuItem(popt, wx.ID_ANY, _('Histogram plot settings'))
  410. popt.AppendItem(setgrid)
  411. self.Bind(wx.EVT_MENU, self.POptions, setgrid)
  412. # Popup the menu. If an item is selected then its handler
  413. # will be called before PopupMenu returns.
  414. self.PopupMenu(popt)
  415. popt.Destroy()
  416. def NotFunctional(self):
  417. """!Creates a 'not functional' message dialog
  418. """
  419. dlg = wx.MessageDialog(parent = self,
  420. message = _('This feature is not yet functional'),
  421. caption = _('Under Construction'),
  422. style = wx.OK | wx.ICON_INFORMATION)
  423. dlg.ShowModal()
  424. dlg.Destroy()
  425. def OnPText(self, dlg):
  426. """!Custom text settings for histogram plot.
  427. """
  428. self.ptitle = dlg.ptitle
  429. self.xlabel = dlg.xlabel
  430. self.ylabel = dlg.ylabel
  431. dlg.UpdateSettings()
  432. self.client.SetFont(self.properties['font']['wxfont'])
  433. self.client.SetFontSizeTitle(self.properties['font']['prop']['titleSize'])
  434. self.client.SetFontSizeAxis(self.properties['font']['prop']['axisSize'])
  435. if self.histogram:
  436. self.histogram.setTitle(dlg.ptitle)
  437. self.histogram.setXLabel(dlg.xlabel)
  438. self.histogram.setYLabel(dlg.ylabel)
  439. self.OnRedraw(event = None)
  440. def PText(self, event):
  441. """!Set custom text values for profile title and axis labels.
  442. """
  443. dlg = TextDialog(parent = self, id = wx.ID_ANY, title = _('Histogram text settings'))
  444. if dlg.ShowModal() == wx.ID_OK:
  445. self.OnPText(dlg)
  446. dlg.Destroy()
  447. def POptions(self, event):
  448. """!Set various profile options, including: line width, color,
  449. style; marker size, color, fill, and style; grid and legend
  450. options. Calls OptDialog class.
  451. """
  452. dlg = OptDialog(parent = self, id = wx.ID_ANY, title = _('Histogram settings'))
  453. btnval = dlg.ShowModal()
  454. if btnval == wx.ID_SAVE:
  455. dlg.UpdateSettings()
  456. self.SetGraphStyle()
  457. dlg.Destroy()
  458. elif btnval == wx.ID_CANCEL:
  459. dlg.Destroy()
  460. def PrintMenu(self, event):
  461. """!Print options and output menu
  462. """
  463. point = wx.GetMousePosition()
  464. printmenu = wx.Menu()
  465. for title, handler in ((_("Page setup"), self.OnPageSetup),
  466. (_("Print preview"), self.OnPrintPreview),
  467. (_("Print display"), self.OnDoPrint)):
  468. item = wx.MenuItem(printmenu, wx.ID_ANY, title)
  469. printmenu.AppendItem(item)
  470. self.Bind(wx.EVT_MENU, handler, item)
  471. # Popup the menu. If an item is selected then its handler
  472. # will be called before PopupMenu returns.
  473. self.PopupMenu(printmenu)
  474. printmenu.Destroy()
  475. def OnPageSetup(self, event):
  476. self.client.PageSetup()
  477. def OnPrintPreview(self, event):
  478. self.client.PrintPreview()
  479. def OnDoPrint(self, event):
  480. self.client.Printout()
  481. def OnQuit(self, event):
  482. self.Close(True)
  483. def OnCloseWindow(self, event):
  484. """
  485. Close histogram window and clean up
  486. """
  487. self.mapwin.SetCursor(self.Parent.cursors["default"])
  488. self.Destroy()
  489. class SetRasterDialog(wx.Dialog):
  490. def __init__(self, parent, id = wx.ID_ANY,
  491. title = _("Select raster map or imagery group to histogram"),
  492. style = wx.DEFAULT_DIALOG_STYLE, **kwargs):
  493. """!Dialog to select raster maps to histogram.
  494. """
  495. wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
  496. self.parent = parent
  497. self.rasterList = self.parent.rasterList
  498. self.group = self.parent.group
  499. self.bins = self.parent.bins
  500. self.histtype = self.parent.histtype
  501. self.maptype = self.parent.maptype
  502. self.spinbins = ''
  503. self._do_layout()
  504. def _do_layout(self):
  505. sizer = wx.BoxSizer(wx.VERTICAL)
  506. box = wx.GridBagSizer (hgap = 3, vgap = 3)
  507. #
  508. # select single raster or image group to histogram radio buttons
  509. #
  510. self.rasterRadio = wx.RadioButton(self, id = wx.ID_ANY, label = " %s " % _("Histogram single raster"), style = wx.RB_GROUP)
  511. self.groupRadio = wx.RadioButton(self, id = wx.ID_ANY, label = " %s " % _("Histogram imagery group"))
  512. if self.maptype == 'raster':
  513. self.rasterRadio.SetValue(True)
  514. elif self.maptype == 'group':
  515. self.groupRadio.SetValue(True)
  516. box.Add(item = self.rasterRadio, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
  517. box.Add(item = self.groupRadio, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 1))
  518. #
  519. # Select a raster to histogram
  520. #
  521. label = wx.StaticText(parent = self, id = wx.ID_ANY,
  522. label = _("Select raster map:"))
  523. box.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (1, 0))
  524. self.rselection = Select(self, id = wx.ID_ANY,
  525. size = globalvar.DIALOG_GSELECT_SIZE,
  526. type = 'cell')
  527. if self.groupRadio.GetValue() == True:
  528. self.rselection.Disable()
  529. else:
  530. if len(self.rasterList) > 0: self.rselection.SetValue(self.rasterList[0])
  531. box.Add(item = self.rselection, pos = (1, 1))
  532. #
  533. # Select an image group to histogram
  534. #
  535. label = wx.StaticText(parent = self, id = wx.ID_ANY,
  536. label = _("Select image group:"))
  537. box.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (2, 0))
  538. self.gselection = Select(self, id = wx.ID_ANY,
  539. size = globalvar.DIALOG_GSELECT_SIZE,
  540. type = 'group')
  541. if self.rasterRadio.GetValue() == True:
  542. self.gselection.Disable()
  543. else:
  544. if self.group != None: self.gselection.SetValue(self.group)
  545. box.Add(item = self.gselection, pos = (2, 1))
  546. #
  547. # Nsteps for FP maps and histogram type selection
  548. #
  549. label = wx.StaticText(parent = self, id = wx.ID_ANY,
  550. label = _("Number of bins (for FP maps)"))
  551. box.Add(item = label,
  552. flag = wx.ALIGN_CENTER_VERTICAL, pos = (3, 0))
  553. self.spinbins = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "", pos = (30, 50),
  554. size = (100,-1), style = wx.SP_ARROW_KEYS)
  555. self.spinbins.SetRange(1,1000)
  556. self.spinbins.SetValue(self.bins)
  557. box.Add(item = self.spinbins,
  558. flag = wx.ALIGN_CENTER_VERTICAL, pos = (3, 1))
  559. label = wx.StaticText(parent = self, id = wx.ID_ANY,
  560. label = _("Histogram type"))
  561. box.Add(item = label,
  562. flag = wx.ALIGN_CENTER_VERTICAL, pos = (4, 0))
  563. types = ['count', 'percent', 'area']
  564. histtype = wx.ComboBox(parent = self, id = wx.ID_ANY, size = (250, -1),
  565. choices = types, style = wx.CB_DROPDOWN)
  566. histtype.SetStringSelection(self.histtype)
  567. box.Add(item = histtype,
  568. flag = wx.ALIGN_CENTER_VERTICAL, pos = (4, 1))
  569. sizer.Add(item = box, proportion = 0,
  570. flag = wx.ALL, border = 10)
  571. line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL)
  572. sizer.Add(item = line, proportion = 0,
  573. flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border = 5)
  574. btnsizer = wx.StdDialogButtonSizer()
  575. btn = wx.Button(self, wx.ID_OK)
  576. btn.SetDefault()
  577. btnsizer.AddButton(btn)
  578. btn = wx.Button(self, wx.ID_CANCEL)
  579. btnsizer.AddButton(btn)
  580. btnsizer.Realize()
  581. sizer.Add(item = btnsizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
  582. #
  583. # bindings
  584. #
  585. self.Bind(wx.EVT_RADIOBUTTON, self.OnHistMap, self.rasterRadio)
  586. self.Bind(wx.EVT_RADIOBUTTON, self.OnHistMap, self.groupRadio)
  587. self.rselection.Bind(wx.EVT_TEXT, self.OnRasterSelection)
  588. self.gselection.Bind(wx.EVT_TEXT, self.OnGroupSelection)
  589. self.spinbins.Bind(wx.EVT_TEXT, self.OnSetBins)
  590. self.spinbins.Bind(wx.EVT_SPINCTRL, self.OnSetBins)
  591. histtype.Bind(wx.EVT_TEXT, self.OnSetHisttypes)
  592. self.SetSizer(sizer)
  593. sizer.Fit(self)
  594. def OnHistMap(self, event):
  595. """!Hander for radio buttons to choose between histogramming a
  596. single raster and an imagery group
  597. """
  598. if self.rasterRadio.GetValue() == True:
  599. self.maptype = 'raster'
  600. self.rselection.Enable()
  601. self.gselection.Disable()
  602. self.gselection.SetValue('')
  603. elif self.groupRadio.GetValue() == True:
  604. self.maptype = 'group'
  605. self.gselection.Enable()
  606. self.rselection.Disable()
  607. self.rselection.SetValue('')
  608. else:
  609. pass
  610. def OnRasterSelection(self, event):
  611. """!Handler for selecting a single raster map
  612. """
  613. self.rasterList = []
  614. self.rasterList.append(event.GetString())
  615. def OnGroupSelection(self, event):
  616. """!Handler for selecting imagery group
  617. """
  618. self.rasterList = []
  619. self.group = event.GetString()
  620. self.rasterList = grass.read_command('i.group',
  621. group = '%s' % self.group,
  622. quiet = True,
  623. flags = 'g').strip().split('\n')
  624. def OnSetBins(self, event):
  625. """!Bins for histogramming FP maps (=nsteps in r.stats)
  626. """
  627. self.bins = self.spinbins.GetValue()
  628. def OnSetHisttypes(self, event):
  629. self.histtype = event.GetString()
  630. print 'histtype = ' + self.histtype
  631. class TextDialog(wx.Dialog):
  632. def __init__(self, parent, id, title,
  633. style = wx.DEFAULT_DIALOG_STYLE, **kwargs):
  634. """!Dialog to set histogram text options: font, title
  635. and font size, axis labels and font size
  636. """
  637. wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
  638. #
  639. # initialize variables
  640. #
  641. # combo box entry lists
  642. self.ffamilydict = { 'default' : wx.FONTFAMILY_DEFAULT,
  643. 'decorative' : wx.FONTFAMILY_DECORATIVE,
  644. 'roman' : wx.FONTFAMILY_ROMAN,
  645. 'script' : wx.FONTFAMILY_SCRIPT,
  646. 'swiss' : wx.FONTFAMILY_SWISS,
  647. 'modern' : wx.FONTFAMILY_MODERN,
  648. 'teletype' : wx.FONTFAMILY_TELETYPE }
  649. self.fstyledict = { 'normal' : wx.FONTSTYLE_NORMAL,
  650. 'slant' : wx.FONTSTYLE_SLANT,
  651. 'italic' : wx.FONTSTYLE_ITALIC }
  652. self.fwtdict = { 'normal' : wx.FONTWEIGHT_NORMAL,
  653. 'light' : wx.FONTWEIGHT_LIGHT,
  654. 'bold' : wx.FONTWEIGHT_BOLD }
  655. self.parent = parent
  656. self.ptitle = self.parent.ptitle
  657. self.xlabel = self.parent.xlabel
  658. self.ylabel = self.parent.ylabel
  659. self.properties = self.parent.properties # read-only
  660. # font size
  661. self.fontfamily = self.properties['font']['wxfont'].GetFamily()
  662. self.fontstyle = self.properties['font']['wxfont'].GetStyle()
  663. self.fontweight = self.properties['font']['wxfont'].GetWeight()
  664. self._do_layout()
  665. #### This stays with relevant changes to dictionary/list names
  666. def _do_layout(self):
  667. """!Do layout"""
  668. # dialog layout
  669. sizer = wx.BoxSizer(wx.VERTICAL)
  670. box = wx.StaticBox(parent = self, id = wx.ID_ANY,
  671. label = " %s " % _("Text settings"))
  672. boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  673. gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
  674. #
  675. # profile title
  676. #
  677. label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Profile title:"))
  678. gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
  679. self.ptitleentry = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (250,-1))
  680. # self.ptitleentry.SetFont(self.font)
  681. self.ptitleentry.SetValue(self.ptitle)
  682. gridSizer.Add(item = self.ptitleentry, pos = (0, 1))
  683. #
  684. # title font
  685. #
  686. tlabel = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Title font size (pts):"))
  687. gridSizer.Add(item = tlabel, flag = wx.ALIGN_CENTER_VERTICAL, pos = (1, 0))
  688. self.ptitlesize = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "", pos = (30, 50),
  689. size = (50,-1), style = wx.SP_ARROW_KEYS)
  690. self.ptitlesize.SetRange(5,100)
  691. self.ptitlesize.SetValue(int(self.properties['font']['prop']['titleSize']))
  692. gridSizer.Add(item = self.ptitlesize, pos = (1, 1))
  693. #
  694. # x-axis label
  695. #
  696. label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("X-axis label:"))
  697. gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (2, 0))
  698. self.xlabelentry = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (250,-1))
  699. # self.xlabelentry.SetFont(self.font)
  700. self.xlabelentry.SetValue(self.xlabel)
  701. gridSizer.Add(item = self.xlabelentry, pos = (2, 1))
  702. #
  703. # y-axis label
  704. #
  705. label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Y-axis label:"))
  706. gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (3, 0))
  707. self.ylabelentry = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (250,-1))
  708. # self.ylabelentry.SetFont(self.font)
  709. self.ylabelentry.SetValue(self.ylabel)
  710. gridSizer.Add(item = self.ylabelentry, pos = (3, 1))
  711. #
  712. # font size
  713. #
  714. llabel = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Label font size (pts):"))
  715. gridSizer.Add(item = llabel, flag = wx.ALIGN_CENTER_VERTICAL, pos = (4, 0))
  716. self.axislabelsize = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "", pos = (30, 50),
  717. size = (50, -1), style = wx.SP_ARROW_KEYS)
  718. self.axislabelsize.SetRange(5, 100)
  719. self.axislabelsize.SetValue(int(self.properties['font']['prop']['axisSize']))
  720. gridSizer.Add(item = self.axislabelsize, pos = (4,1))
  721. boxSizer.Add(item = gridSizer)
  722. sizer.Add(item = boxSizer, flag = wx.ALL | wx.EXPAND, border = 3)
  723. #
  724. # font settings
  725. #
  726. box = wx.StaticBox(parent = self, id = wx.ID_ANY,
  727. label = " %s " % _("Font settings"))
  728. boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  729. gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
  730. gridSizer.AddGrowableCol(1)
  731. #
  732. # font family
  733. #
  734. label1 = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Font family:"))
  735. gridSizer.Add(item = label1, flag = wx.ALIGN_CENTER_VERTICAL, pos = (0, 0))
  736. self.ffamilycb = wx.ComboBox(parent = self, id = wx.ID_ANY, size = (250, -1),
  737. choices = self.ffamilydict.keys(), style = wx.CB_DROPDOWN)
  738. self.ffamilycb.SetStringSelection('swiss')
  739. for item in self.ffamilydict.items():
  740. if self.fontfamily == item[1]:
  741. self.ffamilycb.SetStringSelection(item[0])
  742. break
  743. gridSizer.Add(item = self.ffamilycb, pos = (0, 1), flag = wx.ALIGN_RIGHT)
  744. #
  745. # font style
  746. #
  747. label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Style:"))
  748. gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (1, 0))
  749. self.fstylecb = wx.ComboBox(parent = self, id = wx.ID_ANY, size = (250, -1),
  750. choices = self.fstyledict.keys(), style = wx.CB_DROPDOWN)
  751. self.fstylecb.SetStringSelection('normal')
  752. for item in self.fstyledict.items():
  753. if self.fontstyle == item[1]:
  754. self.fstylecb.SetStringSelection(item[0])
  755. break
  756. gridSizer.Add(item = self.fstylecb, pos = (1, 1), flag = wx.ALIGN_RIGHT)
  757. #
  758. # font weight
  759. #
  760. label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Weight:"))
  761. gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (2, 0))
  762. self.fwtcb = wx.ComboBox(parent = self, size = (250, -1),
  763. choices = self.fwtdict.keys(), style = wx.CB_DROPDOWN)
  764. self.fwtcb.SetStringSelection('normal')
  765. for item in self.fwtdict.items():
  766. if self.fontweight == item[1]:
  767. self.fwtcb.SetStringSelection(item[0])
  768. break
  769. gridSizer.Add(item = self.fwtcb, pos = (2, 1), flag = wx.ALIGN_RIGHT)
  770. boxSizer.Add(item = gridSizer, flag = wx.EXPAND)
  771. sizer.Add(item = boxSizer, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
  772. line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL)
  773. sizer.Add(item = line, proportion = 0,
  774. flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border = 3)
  775. #
  776. # buttons
  777. #
  778. btnSave = wx.Button(self, wx.ID_SAVE)
  779. btnApply = wx.Button(self, wx.ID_APPLY)
  780. btnOk = wx.Button(self, wx.ID_OK)
  781. btnCancel = wx.Button(self, wx.ID_CANCEL)
  782. btnOk.SetDefault()
  783. # bindings
  784. btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  785. btnApply.SetToolTipString(_("Apply changes for the current session"))
  786. btnOk.Bind(wx.EVT_BUTTON, self.OnOk)
  787. btnOk.SetToolTipString(_("Apply changes for the current session and close dialog"))
  788. btnOk.SetDefault()
  789. btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
  790. btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
  791. btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
  792. btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
  793. # sizers
  794. btnStdSizer = wx.StdDialogButtonSizer()
  795. btnStdSizer.AddButton(btnOk)
  796. btnStdSizer.AddButton(btnApply)
  797. btnStdSizer.AddButton(btnCancel)
  798. btnStdSizer.Realize()
  799. btnSizer = wx.BoxSizer(wx.HORIZONTAL)
  800. btnSizer.Add(item = btnSave, proportion = 0, flag = wx.ALIGN_LEFT | wx.ALL, border = 5)
  801. btnSizer.Add(item = btnStdSizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
  802. sizer.Add(item = btnSizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
  803. #
  804. # bindings
  805. #
  806. self.ptitleentry.Bind(wx.EVT_TEXT, self.OnTitle)
  807. self.xlabelentry.Bind(wx.EVT_TEXT, self.OnXLabel)
  808. self.ylabelentry.Bind(wx.EVT_TEXT, self.OnYLabel)
  809. self.SetSizer(sizer)
  810. sizer.Fit(self)
  811. def OnTitle(self, event):
  812. self.ptitle = event.GetString()
  813. def OnXLabel(self, event):
  814. self.xlabel = event.GetString()
  815. def OnYLabel(self, event):
  816. self.ylabel = event.GetString()
  817. def UpdateSettings(self):
  818. self.properties['font']['prop']['titleSize'] = self.ptitlesize.GetValue()
  819. self.properties['font']['prop']['axisSize'] = self.axislabelsize.GetValue()
  820. family = self.ffamilydict[self.ffamilycb.GetStringSelection()]
  821. self.properties['font']['wxfont'].SetFamily(family)
  822. style = self.fstyledict[self.fstylecb.GetStringSelection()]
  823. self.properties['font']['wxfont'].SetStyle(style)
  824. weight = self.fwtdict[self.fwtcb.GetStringSelection()]
  825. self.properties['font']['wxfont'].SetWeight(weight)
  826. def OnSave(self, event):
  827. """!Button 'Save' pressed"""
  828. self.UpdateSettings()
  829. fileSettings = {}
  830. UserSettings.ReadSettingsFile(settings=fileSettings)
  831. fileSettings['histogram'] = UserSettings.Get(group = 'histogram')
  832. file = UserSettings.SaveToFile(fileSettings)
  833. self.parent.parent.GetLayerManager().goutput.WriteLog(_('Histogram settings saved to file \'%s\'.') % file)
  834. self.EndModal(wx.ID_OK)
  835. def OnApply(self, event):
  836. """!Button 'Apply' pressed"""
  837. self.UpdateSettings()
  838. self.parent.OnPText(self)
  839. def OnOk(self, event):
  840. """!Button 'OK' pressed"""
  841. self.UpdateSettings()
  842. self.EndModal(wx.ID_OK)
  843. def OnCancel(self, event):
  844. """!Button 'Cancel' pressed"""
  845. self.EndModal(wx.ID_CANCEL)
  846. class OptDialog(wx.Dialog):
  847. def __init__(self, parent, id, title,
  848. style = wx.DEFAULT_DIALOG_STYLE, **kwargs):
  849. """!Dialog to set various histogram options, including: line
  850. width, color, style; marker size, color, fill, and style; grid
  851. and legend options.
  852. """
  853. wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
  854. # init variables
  855. self.pstyledict = parent.pstyledict
  856. self.ptfilldict = parent.ptfilldict
  857. self.axislist = ['min',
  858. 'auto',
  859. 'custom']
  860. # widgets ids
  861. self.wxId = {}
  862. self.parent = parent
  863. # read-only
  864. self.raster = self.parent.raster
  865. self.rasterList = self.parent.rasterList
  866. self.properties = self.parent.properties
  867. self.map = ''
  868. if len(self.rasterList) == 0:
  869. wx.MessageBox(parent = self,
  870. message = _("No map or image group selected to histogram."),
  871. caption = _("Warning"), style = wx.OK | wx.ICON_ERROR)
  872. self._do_layout()
  873. def _do_layout(self):
  874. """!Do layout"""
  875. # dialog layout
  876. sizer = wx.BoxSizer(wx.VERTICAL)
  877. #
  878. # histogram line settings
  879. #
  880. box = wx.StaticBox(parent = self, id = wx.ID_ANY,
  881. label = " %s " % _("Histogram settings"))
  882. boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
  883. self.wxId['pcolor'] = 0
  884. self.wxId['pwidth'] = 0
  885. self.wxId['pstyle'] = 0
  886. self.wxId['plegend'] = 0
  887. if len(self.rasterList) > 0:
  888. box = wx.StaticBox(parent = self, id = wx.ID_ANY,
  889. label = _("Map/image histogrammed"))
  890. boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  891. gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
  892. row = 0
  893. self.mapchoice = wx.Choice(parent = self, id = wx.ID_ANY, size = (300, -1),
  894. choices = self.rasterList)
  895. if not self.map:
  896. self.map = self.rasterList[self.mapchoice.GetCurrentSelection()]
  897. else:
  898. self.mapchoice.SetStringSelection(self.map)
  899. gridSizer.Add(item = self.mapchoice, flag = wx.ALIGN_CENTER_VERTICAL,
  900. pos = (row, 0), span = (1, 2))
  901. row +=1
  902. label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Line color"))
  903. gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
  904. pcolor = csel.ColourSelect(parent = self, id = wx.ID_ANY, colour = self.raster[self.map]['pcolor'])
  905. self.wxId['pcolor'] = pcolor.GetId()
  906. gridSizer.Add(item = pcolor, pos = (row, 1))
  907. row += 1
  908. label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Line width"))
  909. gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
  910. pwidth = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "",
  911. size = (50,-1), style = wx.SP_ARROW_KEYS)
  912. pwidth.SetRange(1, 10)
  913. pwidth.SetValue(self.raster[self.map]['pwidth'])
  914. self.wxId['pwidth'] = pwidth.GetId()
  915. gridSizer.Add(item = pwidth, pos = (row, 1))
  916. row +=1
  917. label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Line style"))
  918. gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
  919. pstyle = wx.Choice(parent = self, id = wx.ID_ANY,
  920. size = (120, -1), choices = self.pstyledict.keys(), style = wx.CB_DROPDOWN)
  921. pstyle.SetStringSelection(self.raster[self.map]['pstyle'])
  922. self.wxId['pstyle'] = pstyle.GetId()
  923. gridSizer.Add(item = pstyle, pos = (row, 1))
  924. row += 1
  925. label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Legend"))
  926. gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
  927. plegend = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (200,-1))
  928. plegend.SetValue(self.raster[self.map]['plegend'])
  929. gridSizer.Add(item = plegend, pos = (row, 1))
  930. self.wxId['plegend'] = plegend.GetId()
  931. boxSizer.Add(item = gridSizer)
  932. flag = wx.ALL
  933. boxMainSizer.Add(item = boxSizer, flag = flag, border = 3)
  934. sizer.Add(item = boxMainSizer, flag = wx.ALL | wx.EXPAND, border = 3)
  935. middleSizer = wx.BoxSizer(wx.HORIZONTAL)
  936. #
  937. # axis options
  938. #
  939. box = wx.StaticBox(parent = self, id = wx.ID_ANY,
  940. label = " %s " % _("Axis settings"))
  941. boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
  942. self.wxId['x-axis'] = {}
  943. self.wxId['y-axis'] = {}
  944. idx = 0
  945. for axis, atype in [(_("X-Axis"), 'x-axis'),
  946. (_("Y-Axis"), 'y-axis')]:
  947. box = wx.StaticBox(parent = self, id = wx.ID_ANY,
  948. label = " %s " % axis)
  949. boxSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
  950. gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
  951. prop = self.properties[atype]['prop']
  952. row = 0
  953. label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Style"))
  954. gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
  955. type = wx.Choice(parent = self, id = wx.ID_ANY,
  956. size = (100, -1), choices = self.axislist, style = wx.CB_DROPDOWN)
  957. type.SetStringSelection(prop['type'])
  958. self.wxId[atype]['type'] = type.GetId()
  959. gridSizer.Add(item = type, pos = (row, 1))
  960. row += 1
  961. label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Custom min"))
  962. gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
  963. min = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (70, -1))
  964. min.SetValue(str(prop['min']))
  965. self.wxId[atype]['min'] = min.GetId()
  966. gridSizer.Add(item = min, pos = (row, 1))
  967. row += 1
  968. label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Custom max"))
  969. gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
  970. max = wx.TextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (70, -1))
  971. max.SetValue(str(prop['max']))
  972. self.wxId[atype]['max'] = max.GetId()
  973. gridSizer.Add(item = max, pos = (row, 1))
  974. row += 1
  975. log = wx.CheckBox(parent = self, id = wx.ID_ANY, label = _("Log scale"))
  976. log.SetValue(prop['log'])
  977. self.wxId[atype]['log'] = log.GetId()
  978. gridSizer.Add(item = log, pos = (row, 0), span = (1, 2))
  979. if idx == 0:
  980. flag = wx.ALL | wx.EXPAND
  981. else:
  982. flag = wx.TOP | wx.BOTTOM | wx.RIGHT | wx.EXPAND
  983. boxSizer.Add(item = gridSizer, flag = wx.ALL, border = 3)
  984. boxMainSizer.Add(item = boxSizer, flag = flag, border = 3)
  985. idx += 1
  986. middleSizer.Add(item = boxMainSizer, flag = wx.ALL | wx.EXPAND, border = 3)
  987. #
  988. # grid & legend options
  989. #
  990. self.wxId['grid'] = {}
  991. self.wxId['legend'] = {}
  992. self.wxId['font'] = {}
  993. box = wx.StaticBox(parent = self, id = wx.ID_ANY,
  994. label = " %s " % _("Grid and Legend settings"))
  995. boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
  996. gridSizer = wx.GridBagSizer(vgap = 5, hgap = 5)
  997. row = 0
  998. label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Grid color"))
  999. gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
  1000. gridcolor = csel.ColourSelect(parent = self, id = wx.ID_ANY, colour = self.properties['grid']['color'])
  1001. self.wxId['grid']['color'] = gridcolor.GetId()
  1002. gridSizer.Add(item = gridcolor, pos = (row, 1))
  1003. row +=1
  1004. gridshow = wx.CheckBox(parent = self, id = wx.ID_ANY, label = _("Show grid"))
  1005. gridshow.SetValue(self.properties['grid']['enabled'])
  1006. self.wxId['grid']['enabled'] = gridshow.GetId()
  1007. gridSizer.Add(item = gridshow, pos = (row, 0), span = (1, 2))
  1008. row +=1
  1009. label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Legend font size"))
  1010. gridSizer.Add(item = label, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0))
  1011. legendfontsize = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "",
  1012. size = (50, -1), style = wx.SP_ARROW_KEYS)
  1013. legendfontsize.SetRange(5,100)
  1014. legendfontsize.SetValue(int(self.properties['font']['prop']['legendSize']))
  1015. self.wxId['font']['legendSize'] = legendfontsize.GetId()
  1016. gridSizer.Add(item = legendfontsize, pos = (row, 1))
  1017. row += 1
  1018. legendshow = wx.CheckBox(parent = self, id = wx.ID_ANY, label = _("Show legend"))
  1019. legendshow.SetValue(self.properties['legend']['enabled'])
  1020. self.wxId['legend']['enabled'] = legendshow.GetId()
  1021. gridSizer.Add(item = legendshow, pos = (row, 0), span = (1, 2))
  1022. boxMainSizer.Add(item = gridSizer, flag = flag, border = 3)
  1023. middleSizer.Add(item = boxMainSizer, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
  1024. sizer.Add(item = middleSizer, flag = wx.ALL, border = 0)
  1025. #
  1026. # line & buttons
  1027. #
  1028. line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL)
  1029. sizer.Add(item = line, proportion = 0,
  1030. flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border = 3)
  1031. #
  1032. # buttons
  1033. #
  1034. btnSave = wx.Button(self, wx.ID_SAVE)
  1035. btnApply = wx.Button(self, wx.ID_APPLY)
  1036. btnCancel = wx.Button(self, wx.ID_CANCEL)
  1037. btnSave.SetDefault()
  1038. # tooltips for buttons
  1039. btnApply.SetToolTipString(_("Apply changes for the current session"))
  1040. btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
  1041. btnSave.SetDefault()
  1042. btnCancel.SetToolTipString(_("Close dialog and ignore changes"))
  1043. # sizers
  1044. btnStdSizer = wx.StdDialogButtonSizer()
  1045. btnStdSizer.AddButton(btnCancel)
  1046. btnStdSizer.AddButton(btnSave)
  1047. btnStdSizer.AddButton(btnApply)
  1048. btnStdSizer.Realize()
  1049. sizer.Add(item = btnStdSizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
  1050. #
  1051. # bindings for buttons and map plot settings controls
  1052. #
  1053. self.mapchoice.Bind(wx.EVT_CHOICE, self.OnSetMap)
  1054. pcolor.Bind(csel.EVT_COLOURSELECT, self.OnSetOpt)
  1055. pwidth.Bind(wx.EVT_SPINCTRL, self.OnSetOpt)
  1056. pstyle.Bind(wx.EVT_CHOICE, self.OnSetOpt)
  1057. plegend.Bind(wx.EVT_TEXT, self.OnSetOpt)
  1058. btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  1059. btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
  1060. btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
  1061. self.SetSizer(sizer)
  1062. sizer.Fit(self)
  1063. def OnSetMap(self, event):
  1064. """!Handler for changing map selection"""
  1065. self.map = event.GetString()
  1066. # update plot settings controls for selected map
  1067. self.FindWindowById(self.wxId['pcolor']).SetColour(self.raster[self.map]['pcolor'])
  1068. self.FindWindowById(self.wxId['pwidth']).SetValue(self.raster[self.map]['pwidth'])
  1069. self.FindWindowById(self.wxId['pstyle']).SetStringSelection(self.raster[self.map]['pstyle'])
  1070. self.FindWindowById(self.wxId['plegend']).SetValue(self.raster[self.map]['plegend'])
  1071. self.Refresh()
  1072. def OnSetOpt(self, event):
  1073. """!Handler for changing any other option"""
  1074. self.map = self.rasterList[self.mapchoice.GetCurrentSelection()]
  1075. self.UpdateSettings()
  1076. self.parent.SetGraphStyle()
  1077. if self.parent.histogram:
  1078. self.parent.DrawPlot()
  1079. def UpdateSettings(self):
  1080. """!Apply settings to each map and to entire plot"""
  1081. # update plot settings for selected map
  1082. self.raster[self.map]['pcolor'] = self.FindWindowById(self.wxId['pcolor']).GetColour()
  1083. self.raster[self.map]['pwidth'] = int(self.FindWindowById(self.wxId['pwidth']).GetValue())
  1084. self.raster[self.map]['pstyle'] = self.FindWindowById(self.wxId['pstyle']).GetStringSelection()
  1085. self.raster[self.map]['plegend'] = self.FindWindowById(self.wxId['plegend']).GetValue()
  1086. # update settings for entire plot
  1087. for axis in ('x-axis', 'y-axis'):
  1088. self.properties[axis]['prop']['type'] = self.FindWindowById(self.wxId[axis]['type']).GetStringSelection()
  1089. self.properties[axis]['prop']['min'] = float(self.FindWindowById(self.wxId[axis]['min']).GetValue())
  1090. self.properties[axis]['prop']['max'] = float(self.FindWindowById(self.wxId[axis]['max']).GetValue())
  1091. self.properties[axis]['prop']['log'] = self.FindWindowById(self.wxId[axis]['log']).IsChecked()
  1092. self.properties['grid']['color'] = self.FindWindowById(self.wxId['grid']['color']).GetColour()
  1093. self.properties['grid']['enabled'] = self.FindWindowById(self.wxId['grid']['enabled']).IsChecked()
  1094. self.properties['font']['prop']['legendSize'] = self.FindWindowById(self.wxId['font']['legendSize']).GetValue()
  1095. self.properties['legend']['enabled'] = self.FindWindowById(self.wxId['legend']['enabled']).IsChecked()
  1096. def OnSave(self, event):
  1097. """!Button 'Save' pressed"""
  1098. self.UpdateSettings()
  1099. fileSettings = {}
  1100. UserSettings.ReadSettingsFile(settings = fileSettings)
  1101. fileSettings['histogram'] = UserSettings.Get(group = 'histogram')
  1102. file = UserSettings.SaveToFile(fileSettings)
  1103. self.parent.parent.GetLayerManager().goutput.WriteLog(_('Histogram settings saved to file \'%s\'.') % file)
  1104. self.parent.SetGraphStyle()
  1105. if self.parent.histogram:
  1106. self.parent.DrawPlot()
  1107. self.Close()
  1108. def OnApply(self, event):
  1109. """!Button 'Apply' pressed. Does not close dialog"""
  1110. self.UpdateSettings()
  1111. self.parent.SetGraphStyle()
  1112. if self.parent.histogram:
  1113. self.parent.DrawPlot()
  1114. def OnCancel(self, event):
  1115. """!Button 'Cancel' pressed"""
  1116. self.Close()