dialogs.py 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510
  1. """
  2. @package wxplot.dialogs
  3. @brief Dialogs for different plotting routines
  4. Classes:
  5. - dialogs::ProfileRasterDialog
  6. - dialogs::ScatterRasterDialog
  7. - dialogs::PlotStatsFrame
  8. - dialogs::HistRasterDialog
  9. - dialogs::TextDialog
  10. - dialogs::OptDialog
  11. (C) 2011-2016 by the GRASS Development Team
  12. This program is free software under the GNU General Public License
  13. (>=v2). Read the file COPYING that comes with GRASS for details.
  14. @author Michael Barton, Arizona State University
  15. """
  16. import os
  17. import wx
  18. from core import globalvar
  19. from core.settings import UserSettings
  20. from core.globalvar import ICONDIR
  21. from gui_core.gselect import Select
  22. from gui_core.wrap import (
  23. ColourSelect,
  24. ComboBox,
  25. Button,
  26. CheckBox,
  27. Choice,
  28. ScrolledPanel,
  29. SpinCtrl,
  30. StaticBox,
  31. StaticText,
  32. TextCtrl,
  33. )
  34. from grass.script import core as grass
  35. class ProfileRasterDialog(wx.Dialog):
  36. def __init__(
  37. self,
  38. parent,
  39. id=wx.ID_ANY,
  40. title=_("Select raster maps to profile"),
  41. style=wx.DEFAULT_DIALOG_STYLE,
  42. **kwargs,
  43. ):
  44. """Dialog to select raster maps to profile."""
  45. wx.Dialog.__init__(self, parent, id, title, style=style, **kwargs)
  46. self.parent = parent
  47. self.colorList = [
  48. "blue",
  49. "red",
  50. "green",
  51. "yellow",
  52. "magenta",
  53. "cyan",
  54. "aqua",
  55. "black",
  56. "grey",
  57. "orange",
  58. "brown",
  59. "purple",
  60. "violet",
  61. "indigo",
  62. ]
  63. self.rasterList = self.parent.rasterList
  64. self._do_layout()
  65. def _do_layout(self):
  66. sizer = wx.BoxSizer(wx.VERTICAL)
  67. box = wx.GridBagSizer(hgap=3, vgap=3)
  68. rastText = ""
  69. for r in self.rasterList:
  70. rastText += "%s," % r
  71. rastText = rastText.rstrip(",")
  72. txt = _("Select raster map(s) to profile:")
  73. label = StaticText(parent=self, id=wx.ID_ANY, label=txt)
  74. box.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0))
  75. selection = Select(
  76. self,
  77. id=wx.ID_ANY,
  78. size=globalvar.DIALOG_GSELECT_SIZE,
  79. type="cell",
  80. multiple=True,
  81. )
  82. selection.SetValue(rastText)
  83. selection.Bind(wx.EVT_TEXT, self.OnSelection)
  84. box.Add(selection, pos=(0, 1))
  85. sizer.Add(box, proportion=0, flag=wx.ALL, border=10)
  86. line = wx.StaticLine(
  87. parent=self, id=wx.ID_ANY, size=(20, -1), style=wx.LI_HORIZONTAL
  88. )
  89. sizer.Add(line, proportion=0, flag=wx.GROW | wx.LEFT | wx.RIGHT, border=5)
  90. btnsizer = wx.StdDialogButtonSizer()
  91. btn = Button(self, wx.ID_OK)
  92. btn.SetDefault()
  93. btnsizer.AddButton(btn)
  94. btn = Button(self, wx.ID_CANCEL)
  95. btnsizer.AddButton(btn)
  96. btnsizer.Realize()
  97. sizer.Add(btnsizer, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
  98. self.SetSizer(sizer)
  99. sizer.Fit(self)
  100. def OnSelection(self, event):
  101. """Choose maps to profile. Convert these into a list"""
  102. self.rasterList = self.FindWindowById(event.GetId()).GetValue().split(",")
  103. class ScatterRasterDialog(wx.Dialog):
  104. def __init__(
  105. self,
  106. parent,
  107. id=wx.ID_ANY,
  108. title=_("Select pairs of raster maps for scatterplots"),
  109. style=wx.DEFAULT_DIALOG_STYLE,
  110. **kwargs,
  111. ):
  112. """Dialog to select raster maps to profile."""
  113. wx.Dialog.__init__(self, parent, id, title, style=style, **kwargs)
  114. self.parent = parent
  115. self.rasterList = self.parent.rasterList
  116. self.bins = self.parent.bins
  117. self.scattertype = self.parent.scattertype
  118. self.maptype = self.parent.maptype
  119. self.spinbins = ""
  120. self.colorList = [
  121. "blue",
  122. "red",
  123. "green",
  124. "yellow",
  125. "magenta",
  126. "cyan",
  127. "aqua",
  128. "black",
  129. "grey",
  130. "orange",
  131. "brown",
  132. "purple",
  133. "violet",
  134. "indigo",
  135. ]
  136. self._do_layout()
  137. def _do_layout(self):
  138. sizer = wx.BoxSizer(wx.VERTICAL)
  139. box = wx.GridBagSizer(hgap=3, vgap=3)
  140. # parse raster pair tuples
  141. rastText = ""
  142. if len(self.rasterList) > 0:
  143. for r in self.rasterList:
  144. if isinstance(r, tuple):
  145. rastText += "%s,%s," % r
  146. else:
  147. rastText += "%s," % r
  148. rastText = rastText.rstrip(",")
  149. # select rasters
  150. txt = _("Select pairs of raster maps for bivariate scatterplots:")
  151. label = StaticText(parent=self, id=wx.ID_ANY, label=txt)
  152. box.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0))
  153. selection = Select(
  154. self,
  155. id=wx.ID_ANY,
  156. size=globalvar.DIALOG_GSELECT_SIZE,
  157. type="cell",
  158. multiple=True,
  159. )
  160. selection.SetValue(rastText)
  161. selection.Bind(wx.EVT_TEXT, self.OnSelection)
  162. box.Add(selection, pos=(0, 1))
  163. # Nsteps for FP maps
  164. label = StaticText(
  165. parent=self, id=wx.ID_ANY, label=_("Number of bins (for FP maps)")
  166. )
  167. box.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 0))
  168. self.spinbins = SpinCtrl(
  169. parent=self,
  170. id=wx.ID_ANY,
  171. value="",
  172. pos=(30, 50),
  173. size=(100, -1),
  174. style=wx.SP_ARROW_KEYS,
  175. )
  176. self.spinbins.SetRange(1, 1000)
  177. self.spinbins.SetValue(self.bins)
  178. box.Add(self.spinbins, flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 1))
  179. # TODO possibly make bubble plots with marker size proportional to cell counts
  180. # # scatterplot type
  181. # label = wx.StaticText(parent = self, id = wx.ID_ANY,
  182. # label = _("Scatterplot type"))
  183. # box.Add(item = label,
  184. # flag = wx.ALIGN_CENTER_VERTICAL, pos = (2, 0))
  185. # types = ['normal', 'bubble']
  186. # scattertype = ComboBox(parent = self, id = wx.ID_ANY, size = (250, -1),
  187. # choices = types, style = wx.CB_DROPDOWN)
  188. # scattertype.SetStringSelection(self.scattertype)
  189. # box.Add(item = scattertype,
  190. # flag = wx.ALIGN_CENTER_VERTICAL, pos = (2, 1))
  191. sizer.Add(box, proportion=0, flag=wx.ALL, border=10)
  192. line = wx.StaticLine(
  193. parent=self, id=wx.ID_ANY, size=(20, -1), style=wx.LI_HORIZONTAL
  194. )
  195. sizer.Add(line, proportion=0, flag=wx.GROW | wx.LEFT | wx.RIGHT, border=5)
  196. btnsizer = wx.StdDialogButtonSizer()
  197. btn = Button(self, wx.ID_OK)
  198. btn.SetDefault()
  199. btnsizer.AddButton(btn)
  200. btn = Button(self, wx.ID_CANCEL)
  201. btnsizer.AddButton(btn)
  202. btnsizer.Realize()
  203. sizer.Add(btnsizer, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
  204. self.spinbins.Bind(wx.EVT_TEXT, self.OnSetBins)
  205. self.spinbins.Bind(wx.EVT_SPINCTRL, self.OnSetBins)
  206. # scattertype.Bind(wx.EVT_TEXT, self.OnSetScattertypes)
  207. self.SetSizer(sizer)
  208. sizer.Fit(self)
  209. def OnSelection(self, event):
  210. """Select raster maps for scatterplot. Must select maps in pairs."""
  211. self.rasterList = self.FindWindowById(event.GetId()).GetValue().split(",", 1)
  212. def OnSetBins(self, event):
  213. """Bins for histogramming FP maps (=nsteps in r.stats)"""
  214. self.bins = self.spinbins.GetValue()
  215. def OnSetScattertypes(self, event):
  216. self.scattertype = event.GetString()
  217. def GetRasterPairs(self):
  218. """Get raster pairs"""
  219. pairsList = list()
  220. pair = list()
  221. for r in self.rasterList:
  222. pair.append(r)
  223. if len(pair) == 2:
  224. pairsList.append(tuple(pair))
  225. pair = list()
  226. return list(pairsList)
  227. def GetSettings(self):
  228. """Get type and bins"""
  229. return self.scattertype, self.bins
  230. class PlotStatsFrame(wx.Frame):
  231. def __init__(
  232. self, parent, id, message="", title="", style=wx.DEFAULT_FRAME_STYLE, **kwargs
  233. ):
  234. """Dialog to display and save statistics for plots"""
  235. wx.Frame.__init__(self, parent, id, style=style, **kwargs)
  236. self.SetLabel(_("Statistics"))
  237. self.SetIcon(wx.Icon(os.path.join(ICONDIR, "grass.ico"), wx.BITMAP_TYPE_ICO))
  238. self.panel = wx.Panel(self)
  239. sp = ScrolledPanel(
  240. self.panel,
  241. -1,
  242. size=(400, 400),
  243. style=wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER,
  244. name="Statistics",
  245. )
  246. #
  247. # initialize variables
  248. #
  249. self.parent = parent
  250. self.message = message
  251. self.title = title
  252. self.CenterOnParent()
  253. #
  254. # Display statistics
  255. #
  256. sizer = wx.BoxSizer(wx.VERTICAL)
  257. txtSizer = wx.BoxSizer(wx.VERTICAL)
  258. statstitle = StaticText(parent=self.panel, id=wx.ID_ANY, label=self.title)
  259. sizer.Add(statstitle, proportion=0, flag=wx.GROW | wx.ALL, border=3)
  260. line = wx.StaticLine(
  261. parent=self.panel, id=wx.ID_ANY, size=(20, -1), style=wx.LI_HORIZONTAL
  262. )
  263. sizer.Add(line, proportion=0, flag=wx.GROW | wx.ALL, border=3)
  264. for stats in self.message:
  265. statstxt = StaticText(parent=sp, id=wx.ID_ANY, label=stats)
  266. statstxt.SetBackgroundColour("WHITE")
  267. txtSizer.Add(
  268. statstxt, proportion=1, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=3
  269. )
  270. line = wx.StaticLine(
  271. parent=sp, id=wx.ID_ANY, size=(20, -1), style=wx.LI_HORIZONTAL
  272. )
  273. txtSizer.Add(line, proportion=0, flag=wx.GROW | wx.ALL, border=3)
  274. sp.SetSizer(txtSizer)
  275. sp.SetAutoLayout(1)
  276. sp.SetupScrolling()
  277. sizer.Add(
  278. sp, proportion=1, flag=wx.GROW | wx.LEFT | wx.RIGHT | wx.BOTTOM, border=3
  279. )
  280. line = wx.StaticLine(
  281. parent=self.panel, id=wx.ID_ANY, size=(20, -1), style=wx.LI_HORIZONTAL
  282. )
  283. sizer.Add(line, proportion=0, flag=wx.GROW | wx.LEFT | wx.RIGHT, border=3)
  284. #
  285. # buttons
  286. #
  287. btnSizer = wx.BoxSizer(wx.HORIZONTAL)
  288. btn_clipboard = Button(self.panel, id=wx.ID_COPY, label=_("C&opy"))
  289. btn_clipboard.SetToolTip(_("Copy regression statistics the clipboard (Ctrl+C)"))
  290. btnSizer.Add(btn_clipboard, proportion=0, flag=wx.ALL, border=5)
  291. btnCancel = Button(self.panel, wx.ID_CLOSE)
  292. btnCancel.SetDefault()
  293. btnSizer.Add(btnCancel, proportion=0, flag=wx.ALL, border=5)
  294. sizer.Add(btnSizer, proportion=0, flag=wx.ALL, border=5)
  295. # bindings
  296. btnCancel.Bind(wx.EVT_BUTTON, self.OnClose)
  297. btn_clipboard.Bind(wx.EVT_BUTTON, self.OnCopy)
  298. self.panel.SetSizer(sizer)
  299. sizer.Fit(self)
  300. def OnCopy(self, event):
  301. """Copy the regression stats to the clipboard"""
  302. str = self.title + "\n"
  303. for item in self.message:
  304. str += item
  305. rdata = wx.TextDataObject()
  306. rdata.SetText(str)
  307. if wx.TheClipboard.Open():
  308. wx.TheClipboard.SetData(rdata)
  309. wx.TheClipboard.Close()
  310. wx.MessageBox(_("Regression statistics copied to clipboard"))
  311. def OnClose(self, event):
  312. """Button 'Close' pressed"""
  313. self.Close(True)
  314. class HistRasterDialog(wx.Dialog):
  315. def __init__(
  316. self,
  317. parent,
  318. id=wx.ID_ANY,
  319. title=_("Select raster map or imagery group to histogram"),
  320. style=wx.DEFAULT_DIALOG_STYLE,
  321. **kwargs,
  322. ):
  323. """Dialog to select raster maps to histogram."""
  324. wx.Dialog.__init__(self, parent, id, title, style=style, **kwargs)
  325. self.parent = parent
  326. self.rasterList = self.parent.rasterList
  327. self.group = self.parent.group
  328. self.bins = self.parent.bins
  329. self.histtype = self.parent.histtype
  330. self.maptype = self.parent.maptype
  331. self.spinbins = ""
  332. self._do_layout()
  333. def _do_layout(self):
  334. sizer = wx.BoxSizer(wx.VERTICAL)
  335. box = wx.GridBagSizer(hgap=3, vgap=3)
  336. #
  337. # select single raster or image group to histogram radio buttons
  338. #
  339. self.rasterRadio = wx.RadioButton(
  340. self,
  341. id=wx.ID_ANY,
  342. label=" %s " % _("Histogram single raster"),
  343. style=wx.RB_GROUP,
  344. )
  345. self.groupRadio = wx.RadioButton(
  346. self, id=wx.ID_ANY, label=" %s " % _("Histogram imagery group")
  347. )
  348. if self.maptype == "raster":
  349. self.rasterRadio.SetValue(True)
  350. elif self.maptype == "group":
  351. self.groupRadio.SetValue(True)
  352. box.Add(self.rasterRadio, flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0))
  353. box.Add(self.groupRadio, flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 1))
  354. #
  355. # Select a raster to histogram
  356. #
  357. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Select raster map:"))
  358. box.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 0))
  359. self.rselection = Select(
  360. self, id=wx.ID_ANY, size=globalvar.DIALOG_GSELECT_SIZE, type="cell"
  361. )
  362. if self.groupRadio.GetValue():
  363. self.rselection.Disable()
  364. else:
  365. rastText = ""
  366. for r in self.rasterList:
  367. rastText += "%s," % r
  368. rastText = rastText.rstrip(",")
  369. self.rselection.SetValue(rastText)
  370. box.Add(self.rselection, pos=(1, 1))
  371. #
  372. # Select an image group to histogram
  373. #
  374. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Select image group:"))
  375. box.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(2, 0))
  376. self.gselection = Select(
  377. self, id=wx.ID_ANY, size=globalvar.DIALOG_GSELECT_SIZE, type="group"
  378. )
  379. if self.rasterRadio.GetValue():
  380. self.gselection.Disable()
  381. else:
  382. if self.group is not None:
  383. self.gselection.SetValue(self.group)
  384. box.Add(self.gselection, pos=(2, 1))
  385. #
  386. # Nsteps for FP maps and histogram type selection
  387. #
  388. label = StaticText(
  389. parent=self, id=wx.ID_ANY, label=_("Number of bins (for FP maps)")
  390. )
  391. box.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(3, 0))
  392. self.spinbins = SpinCtrl(
  393. parent=self,
  394. id=wx.ID_ANY,
  395. value="",
  396. pos=(30, 50),
  397. size=(100, -1),
  398. style=wx.SP_ARROW_KEYS,
  399. )
  400. self.spinbins.SetRange(1, 1000)
  401. self.spinbins.SetValue(self.bins)
  402. box.Add(self.spinbins, flag=wx.ALIGN_CENTER_VERTICAL, pos=(3, 1))
  403. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Histogram type"))
  404. box.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(4, 0))
  405. types = ["count", "percent", "area"]
  406. histtype = ComboBox(
  407. parent=self,
  408. id=wx.ID_ANY,
  409. size=(250, -1),
  410. choices=types,
  411. style=wx.CB_DROPDOWN,
  412. )
  413. histtype.SetStringSelection(self.histtype)
  414. box.Add(histtype, flag=wx.ALIGN_CENTER_VERTICAL, pos=(4, 1))
  415. sizer.Add(box, proportion=0, flag=wx.ALL, border=10)
  416. line = wx.StaticLine(
  417. parent=self, id=wx.ID_ANY, size=(20, -1), style=wx.LI_HORIZONTAL
  418. )
  419. sizer.Add(line, proportion=0, flag=wx.GROW | wx.LEFT | wx.RIGHT, border=5)
  420. btnsizer = wx.StdDialogButtonSizer()
  421. btn = Button(self, wx.ID_OK)
  422. btn.SetDefault()
  423. btnsizer.AddButton(btn)
  424. btn = Button(self, wx.ID_CANCEL)
  425. btnsizer.AddButton(btn)
  426. btnsizer.Realize()
  427. sizer.Add(btnsizer, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
  428. #
  429. # bindings
  430. #
  431. self.Bind(wx.EVT_RADIOBUTTON, self.OnHistMap, self.rasterRadio)
  432. self.Bind(wx.EVT_RADIOBUTTON, self.OnHistMap, self.groupRadio)
  433. self.rselection.Bind(wx.EVT_TEXT, self.OnRasterSelection)
  434. self.gselection.Bind(wx.EVT_TEXT, self.OnGroupSelection)
  435. self.spinbins.Bind(wx.EVT_TEXT, self.OnSetBins)
  436. self.spinbins.Bind(wx.EVT_SPINCTRL, self.OnSetBins)
  437. histtype.Bind(wx.EVT_TEXT, self.OnSetHisttypes)
  438. self.SetSizer(sizer)
  439. sizer.Fit(self)
  440. def OnHistMap(self, event):
  441. """Hander for radio buttons to choose between histogramming a
  442. single raster and an imagery group
  443. """
  444. if self.rasterRadio.GetValue() is True:
  445. self.maptype = "raster"
  446. self.rselection.Enable()
  447. self.gselection.Disable()
  448. self.gselection.SetValue("")
  449. elif self.groupRadio.GetValue() is True:
  450. self.maptype = "group"
  451. self.gselection.Enable()
  452. self.rselection.Disable()
  453. self.rselection.SetValue("")
  454. else:
  455. pass
  456. def OnRasterSelection(self, event):
  457. """Handler for selecting a single raster map"""
  458. self.rasterList = []
  459. self.rasterList.append(event.GetString())
  460. def OnGroupSelection(self, event):
  461. """Handler for selecting imagery group"""
  462. self.rasterList = []
  463. self.group = event.GetString()
  464. ret = (
  465. grass.read_command(
  466. "i.group", group="%s" % self.group, quiet=True, flags="g"
  467. )
  468. .strip()
  469. .splitlines()
  470. )
  471. if ret not in [None, "", [""]]:
  472. self.rasterList = ret
  473. else:
  474. wx.MessageBox(
  475. message=_("Selected group must be in current mapset"),
  476. caption=_("Invalid input"),
  477. style=wx.OK | wx.ICON_ERROR,
  478. )
  479. def OnSetBins(self, event):
  480. """Bins for histogramming FP maps (=nsteps in r.stats)"""
  481. self.bins = self.spinbins.GetValue()
  482. def OnSetHisttypes(self, event):
  483. self.histtype = event.GetString()
  484. class TextDialog(wx.Dialog):
  485. def __init__(
  486. self,
  487. parent,
  488. giface,
  489. id,
  490. title,
  491. plottype="",
  492. style=wx.DEFAULT_DIALOG_STYLE,
  493. **kwargs,
  494. ):
  495. """Dialog to set histogram text options: font, title
  496. and font size, axis labels and font size
  497. """
  498. wx.Dialog.__init__(self, parent, id, title, style=style, **kwargs)
  499. #
  500. # initialize variables
  501. #
  502. self._giface = giface
  503. # combo box entry lists
  504. self.ffamilydict = {
  505. "default": wx.FONTFAMILY_DEFAULT,
  506. "decorative": wx.FONTFAMILY_DECORATIVE,
  507. "roman": wx.FONTFAMILY_ROMAN,
  508. "script": wx.FONTFAMILY_SCRIPT,
  509. "swiss": wx.FONTFAMILY_SWISS,
  510. "modern": wx.FONTFAMILY_MODERN,
  511. "teletype": wx.FONTFAMILY_TELETYPE,
  512. }
  513. self.fstyledict = {
  514. "normal": wx.FONTSTYLE_NORMAL,
  515. "slant": wx.FONTSTYLE_SLANT,
  516. "italic": wx.FONTSTYLE_ITALIC,
  517. }
  518. self.fwtdict = {
  519. "normal": wx.FONTWEIGHT_NORMAL,
  520. "light": wx.FONTWEIGHT_LIGHT,
  521. "bold": wx.FONTWEIGHT_BOLD,
  522. }
  523. self.parent = parent
  524. self.plottype = plottype
  525. self.ptitle = self.parent.ptitle
  526. self.xlabel = self.parent.xlabel
  527. self.ylabel = self.parent.ylabel
  528. self.properties = self.parent.properties # read-only
  529. # font size
  530. self.fontfamily = self.parent.wx_font.GetFamily()
  531. self.fontstyle = self.parent.wx_font.GetStyle()
  532. self.fontweight = self.parent.wx_font.GetWeight()
  533. self._do_layout()
  534. def _do_layout(self):
  535. """Do layout"""
  536. # dialog layout
  537. sizer = wx.BoxSizer(wx.VERTICAL)
  538. box = StaticBox(parent=self, id=wx.ID_ANY, label=" %s " % _("Text settings"))
  539. boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  540. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  541. #
  542. # profile title
  543. #
  544. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Profile title:"))
  545. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0))
  546. self.ptitleentry = TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(250, -1))
  547. # self.ptitleentry.SetFont(self.font)
  548. self.ptitleentry.SetValue(self.ptitle)
  549. gridSizer.Add(self.ptitleentry, pos=(0, 1))
  550. #
  551. # title font
  552. #
  553. tlabel = StaticText(
  554. parent=self, id=wx.ID_ANY, label=_("Title font size (pts):")
  555. )
  556. gridSizer.Add(tlabel, flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 0))
  557. self.ptitlesize = SpinCtrl(
  558. parent=self,
  559. id=wx.ID_ANY,
  560. value="",
  561. pos=(30, 50),
  562. size=(50, -1),
  563. style=wx.SP_ARROW_KEYS,
  564. )
  565. self.ptitlesize.SetRange(5, 100)
  566. self.ptitlesize.SetValue(int(self.properties["font"]["prop"]["titleSize"]))
  567. gridSizer.Add(self.ptitlesize, pos=(1, 1))
  568. #
  569. # x-axis label
  570. #
  571. label = StaticText(parent=self, id=wx.ID_ANY, label=_("X-axis label:"))
  572. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(2, 0))
  573. self.xlabelentry = TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(250, -1))
  574. # self.xlabelentry.SetFont(self.font)
  575. self.xlabelentry.SetValue(self.xlabel)
  576. gridSizer.Add(self.xlabelentry, pos=(2, 1))
  577. #
  578. # y-axis label
  579. #
  580. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Y-axis label:"))
  581. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(3, 0))
  582. self.ylabelentry = TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(250, -1))
  583. # self.ylabelentry.SetFont(self.font)
  584. self.ylabelentry.SetValue(self.ylabel)
  585. gridSizer.Add(self.ylabelentry, pos=(3, 1))
  586. #
  587. # font size
  588. #
  589. llabel = StaticText(
  590. parent=self, id=wx.ID_ANY, label=_("Label font size (pts):")
  591. )
  592. gridSizer.Add(llabel, flag=wx.ALIGN_CENTER_VERTICAL, pos=(4, 0))
  593. self.axislabelsize = SpinCtrl(
  594. parent=self,
  595. id=wx.ID_ANY,
  596. value="",
  597. pos=(30, 50),
  598. size=(50, -1),
  599. style=wx.SP_ARROW_KEYS,
  600. )
  601. self.axislabelsize.SetRange(5, 100)
  602. self.axislabelsize.SetValue(int(self.properties["font"]["prop"]["axisSize"]))
  603. gridSizer.Add(self.axislabelsize, pos=(4, 1))
  604. boxSizer.Add(gridSizer)
  605. sizer.Add(boxSizer, flag=wx.ALL | wx.EXPAND, border=3)
  606. #
  607. # font settings
  608. #
  609. box = StaticBox(parent=self, id=wx.ID_ANY, label=" %s " % _("Font settings"))
  610. boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  611. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  612. #
  613. # font family
  614. #
  615. label1 = StaticText(parent=self, id=wx.ID_ANY, label=_("Font family:"))
  616. gridSizer.Add(label1, flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0))
  617. self.ffamilycb = ComboBox(
  618. parent=self,
  619. id=wx.ID_ANY,
  620. size=(250, -1),
  621. choices=list(self.ffamilydict.keys()),
  622. style=wx.CB_DROPDOWN,
  623. )
  624. self.ffamilycb.SetStringSelection("swiss")
  625. for item in self.ffamilydict.items():
  626. if self.fontfamily == item[1]:
  627. self.ffamilycb.SetStringSelection(item[0])
  628. break
  629. gridSizer.Add(self.ffamilycb, pos=(0, 1), flag=wx.ALIGN_RIGHT)
  630. #
  631. # font style
  632. #
  633. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Style:"))
  634. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 0))
  635. self.fstylecb = ComboBox(
  636. parent=self,
  637. id=wx.ID_ANY,
  638. size=(250, -1),
  639. choices=list(self.fstyledict.keys()),
  640. style=wx.CB_DROPDOWN,
  641. )
  642. self.fstylecb.SetStringSelection("normal")
  643. for item in self.fstyledict.items():
  644. if self.fontstyle == item[1]:
  645. self.fstylecb.SetStringSelection(item[0])
  646. break
  647. gridSizer.Add(self.fstylecb, pos=(1, 1), flag=wx.ALIGN_RIGHT)
  648. #
  649. # font weight
  650. #
  651. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Weight:"))
  652. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(2, 0))
  653. self.fwtcb = ComboBox(
  654. parent=self,
  655. size=(250, -1),
  656. choices=list(self.fwtdict.keys()),
  657. style=wx.CB_DROPDOWN,
  658. )
  659. self.fwtcb.SetStringSelection("normal")
  660. for item in self.fwtdict.items():
  661. if self.fontweight == item[1]:
  662. self.fwtcb.SetStringSelection(item[0])
  663. break
  664. gridSizer.Add(self.fwtcb, pos=(2, 1), flag=wx.ALIGN_RIGHT)
  665. gridSizer.AddGrowableCol(1)
  666. boxSizer.Add(gridSizer, flag=wx.EXPAND)
  667. sizer.Add(boxSizer, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3)
  668. line = wx.StaticLine(
  669. parent=self, id=wx.ID_ANY, size=(20, -1), style=wx.LI_HORIZONTAL
  670. )
  671. sizer.Add(line, proportion=0, flag=wx.GROW | wx.LEFT | wx.RIGHT, border=3)
  672. #
  673. # buttons
  674. #
  675. btnSave = Button(self, wx.ID_SAVE)
  676. btnApply = Button(self, wx.ID_APPLY)
  677. btnOk = Button(self, wx.ID_OK)
  678. btnCancel = Button(self, wx.ID_CANCEL)
  679. btnOk.SetDefault()
  680. # bindings
  681. btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  682. btnApply.SetToolTip(_("Apply changes for the current session"))
  683. btnOk.Bind(wx.EVT_BUTTON, self.OnOk)
  684. btnOk.SetToolTip(_("Apply changes for the current session and close dialog"))
  685. btnOk.SetDefault()
  686. btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
  687. btnSave.SetToolTip(
  688. _(
  689. "Apply and save changes to user settings file (default for next sessions)"
  690. )
  691. )
  692. btnCancel.SetToolTip(_("Close dialog and ignore changes"))
  693. # sizers
  694. btnStdSizer = wx.StdDialogButtonSizer()
  695. btnStdSizer.AddButton(btnOk)
  696. btnStdSizer.AddButton(btnApply)
  697. btnStdSizer.AddButton(btnCancel)
  698. btnStdSizer.Realize()
  699. btnSizer = wx.BoxSizer(wx.HORIZONTAL)
  700. btnSizer.Add(btnSave, proportion=0, flag=wx.ALL, border=5)
  701. btnSizer.Add(btnStdSizer, proportion=0, flag=wx.ALL, border=5)
  702. sizer.Add(btnSizer, proportion=0, flag=wx.ALL, border=5)
  703. #
  704. # bindings
  705. #
  706. self.ptitleentry.Bind(wx.EVT_TEXT, self.OnTitle)
  707. self.xlabelentry.Bind(wx.EVT_TEXT, self.OnXLabel)
  708. self.ylabelentry.Bind(wx.EVT_TEXT, self.OnYLabel)
  709. self.SetSizer(sizer)
  710. sizer.Fit(self)
  711. def OnTitle(self, event):
  712. self.ptitle = event.GetString()
  713. def OnXLabel(self, event):
  714. self.xlabel = event.GetString()
  715. def OnYLabel(self, event):
  716. self.ylabel = event.GetString()
  717. def UpdateSettings(self):
  718. self.properties["font"]["prop"]["titleSize"] = self.ptitlesize.GetValue()
  719. self.properties["font"]["prop"]["axisSize"] = self.axislabelsize.GetValue()
  720. family = self.ffamilydict[self.ffamilycb.GetStringSelection()]
  721. self.properties["font"]["prop"]["family"] = family
  722. self.parent.wx_font.SetFamily(family)
  723. style = self.fstyledict[self.fstylecb.GetStringSelection()]
  724. self.properties["font"]["prop"]["style"] = style
  725. self.parent.wx_font.SetStyle(style)
  726. weight = self.fwtdict[self.fwtcb.GetStringSelection()]
  727. self.properties["font"]["prop"]["weight"] = weight
  728. self.parent.wx_font.SetWeight(weight)
  729. def OnSave(self, event):
  730. """Button 'Save' pressed"""
  731. self.OnApply(None)
  732. fileSettings = {}
  733. UserSettings.ReadSettingsFile(settings=fileSettings)
  734. fileSettings[self.plottype] = UserSettings.Get(group=self.plottype)
  735. UserSettings.SaveToFile(fileSettings)
  736. self._giface.WriteLog(
  737. _("Plot text sizes saved to file '%s'.") % UserSettings.filePath
  738. )
  739. self.EndModal(wx.ID_OK)
  740. def OnApply(self, event):
  741. """Button 'Apply' pressed"""
  742. self.UpdateSettings()
  743. self.parent.OnPlotText(self)
  744. def OnOk(self, event):
  745. """Button 'OK' pressed"""
  746. self.OnApply(None)
  747. self.EndModal(wx.ID_OK)
  748. class OptDialog(wx.Dialog):
  749. def __init__(
  750. self,
  751. parent,
  752. giface,
  753. id,
  754. title,
  755. plottype="",
  756. style=wx.DEFAULT_DIALOG_STYLE,
  757. **kwargs,
  758. ):
  759. """Dialog to set various options for data plotted, including: line
  760. width, color, style; marker size, color, fill, and style; grid
  761. and legend options.
  762. """
  763. wx.Dialog.__init__(self, parent, id, title, style=style, **kwargs)
  764. # init variables
  765. self.parent = parent
  766. self._giface = giface
  767. self.linestyledict = parent.linestyledict
  768. self.ptfilldict = parent.ptfilldict
  769. self.parent = parent
  770. self.plottype = plottype
  771. self.pttypelist = [
  772. "circle",
  773. "dot",
  774. "square",
  775. "triangle",
  776. "triangle_down",
  777. "cross",
  778. "plus",
  779. ]
  780. self.axislist = ["min", "auto", "custom"]
  781. # widgets ids
  782. self.wxId = {}
  783. self.parent = parent
  784. # read-only
  785. self.raster = self.parent.raster
  786. self.rasterList = self.parent.rasterList
  787. self.properties = self.parent.properties
  788. self.map = ""
  789. if len(self.rasterList) == 0:
  790. wx.MessageBox(
  791. parent=self,
  792. message=_("No map or image group selected to plot."),
  793. caption=_("Warning"),
  794. style=wx.OK | wx.ICON_ERROR,
  795. )
  796. self._do_layout()
  797. def ConvertTuples(self, tlist):
  798. """Converts tuples to strings when rasterList contains raster
  799. pairs for scatterplot
  800. """
  801. list = []
  802. for i in tlist:
  803. i = str(i).strip("()")
  804. list.append(i)
  805. return list
  806. def _do_layout(self):
  807. """Options dialog layout"""
  808. sizer = wx.BoxSizer(wx.VERTICAL)
  809. box = StaticBox(parent=self, id=wx.ID_ANY, label=" %s " % _("Plot settings"))
  810. boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
  811. self.wxId["pcolor"] = 0
  812. self.wxId["pwidth"] = 0
  813. self.wxId["pstyle"] = 0
  814. self.wxId["psize"] = 0
  815. self.wxId["ptype"] = 0
  816. self.wxId["pfill"] = 0
  817. self.wxId["plegend"] = 0
  818. self.wxId["marker"] = {}
  819. self.wxId["x-axis"] = {}
  820. self.wxId["y-axis"] = {}
  821. #
  822. # plot line settings and point settings
  823. #
  824. if len(self.rasterList) == 0:
  825. return
  826. box = StaticBox(parent=self, id=wx.ID_ANY, label=_("Map/image plotted"))
  827. boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  828. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  829. row = 0
  830. choicelist = []
  831. for i in self.rasterList:
  832. choicelist.append(str(i))
  833. self.mapchoice = Choice(
  834. parent=self, id=wx.ID_ANY, size=(300, -1), choices=choicelist
  835. )
  836. self.mapchoice.SetToolTip(_("Settings for selected map"))
  837. if not self.map:
  838. self.map = self.rasterList[self.mapchoice.GetCurrentSelection()]
  839. else:
  840. self.mapchoice.SetStringSelection(str(self.map))
  841. gridSizer.Add(
  842. self.mapchoice, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0), span=(1, 2)
  843. )
  844. #
  845. # options for line plots (profiles and histograms)
  846. #
  847. if self.plottype != "scatter":
  848. row += 1
  849. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Line color"))
  850. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  851. color = ColourSelect(
  852. parent=self, id=wx.ID_ANY, colour=self.raster[self.map]["pcolor"]
  853. )
  854. self.wxId["pcolor"] = color.GetId()
  855. gridSizer.Add(color, pos=(row, 1))
  856. row += 1
  857. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Line width"))
  858. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  859. width = SpinCtrl(
  860. parent=self,
  861. id=wx.ID_ANY,
  862. value="",
  863. size=(50, -1),
  864. style=wx.SP_ARROW_KEYS,
  865. )
  866. width.SetRange(1, 10)
  867. width.SetValue(self.raster[self.map]["pwidth"])
  868. self.wxId["pwidth"] = width.GetId()
  869. gridSizer.Add(width, pos=(row, 1))
  870. row += 1
  871. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Line style"))
  872. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  873. style = Choice(
  874. parent=self,
  875. id=wx.ID_ANY,
  876. size=(120, -1),
  877. choices=list(self.linestyledict.keys()),
  878. )
  879. style.SetStringSelection(self.raster[self.map]["pstyle"])
  880. self.wxId["pstyle"] = style.GetId()
  881. gridSizer.Add(style, pos=(row, 1))
  882. row += 1
  883. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Legend"))
  884. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  885. legend = TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(200, -1))
  886. legend.SetValue(self.raster[self.map]["plegend"])
  887. gridSizer.Add(legend, pos=(row, 1))
  888. self.wxId["plegend"] = legend.GetId()
  889. boxSizer.Add(gridSizer)
  890. boxMainSizer.Add(boxSizer, flag=wx.ALL, border=3)
  891. #
  892. # segment marker settings for profiles only
  893. #
  894. if self.plottype == "profile":
  895. box = StaticBox(
  896. parent=self,
  897. id=wx.ID_ANY,
  898. label=" %s " % _("Transect segment marker settings"),
  899. )
  900. boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  901. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  902. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Color"))
  903. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0))
  904. ptcolor = ColourSelect(
  905. parent=self, id=wx.ID_ANY, colour=self.properties["marker"]["color"]
  906. )
  907. self.wxId["marker"]["color"] = ptcolor.GetId()
  908. gridSizer.Add(ptcolor, pos=(0, 1))
  909. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Size"))
  910. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 0))
  911. ptsize = SpinCtrl(
  912. parent=self,
  913. id=wx.ID_ANY,
  914. value="",
  915. size=(50, -1),
  916. style=wx.SP_ARROW_KEYS,
  917. )
  918. ptsize.SetRange(1, 10)
  919. ptsize.SetValue(self.properties["marker"]["size"])
  920. self.wxId["marker"]["size"] = ptsize.GetId()
  921. gridSizer.Add(ptsize, pos=(1, 1))
  922. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Fill"))
  923. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(2, 0))
  924. ptfill = Choice(
  925. parent=self,
  926. id=wx.ID_ANY,
  927. size=(120, -1),
  928. choices=list(self.ptfilldict.keys()),
  929. )
  930. ptfill.SetStringSelection(self.properties["marker"]["fill"])
  931. self.wxId["marker"]["fill"] = ptfill.GetId()
  932. gridSizer.Add(ptfill, pos=(2, 1))
  933. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Legend"))
  934. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(3, 0))
  935. ptlegend = TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(200, -1))
  936. ptlegend.SetValue(self.properties["marker"]["legend"])
  937. self.wxId["marker"]["legend"] = ptlegend.GetId()
  938. gridSizer.Add(ptlegend, pos=(3, 1))
  939. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Style"))
  940. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(4, 0))
  941. pttype = Choice(parent=self, size=(200, -1), choices=self.pttypelist)
  942. pttype.SetStringSelection(self.properties["marker"]["type"])
  943. self.wxId["marker"]["type"] = pttype.GetId()
  944. gridSizer.Add(pttype, pos=(4, 1))
  945. boxSizer.Add(gridSizer)
  946. boxMainSizer.Add(boxSizer, flag=wx.ALL, border=3)
  947. #
  948. # point options for scatterplots
  949. #
  950. elif self.plottype == "scatter":
  951. box = StaticBox(
  952. parent=self, id=wx.ID_ANY, label=" %s " % _("Scatterplot points")
  953. )
  954. boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  955. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  956. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Color"))
  957. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0))
  958. ptcolor = ColourSelect(
  959. parent=self, id=wx.ID_ANY, colour=self.raster[self.map]["pcolor"]
  960. )
  961. self.wxId["pcolor"] = ptcolor.GetId()
  962. gridSizer.Add(ptcolor, pos=(0, 1))
  963. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Size"))
  964. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 0))
  965. ptsize = SpinCtrl(
  966. parent=self,
  967. id=wx.ID_ANY,
  968. value="",
  969. size=(50, -1),
  970. style=wx.SP_ARROW_KEYS,
  971. )
  972. ptsize.SetRange(1, 10)
  973. ptsize.SetValue(self.raster[self.map]["psize"])
  974. self.wxId["psize"] = ptsize.GetId()
  975. gridSizer.Add(ptsize, pos=(1, 1))
  976. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Fill"))
  977. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(2, 0))
  978. ptfill = Choice(
  979. parent=self,
  980. id=wx.ID_ANY,
  981. size=(120, -1),
  982. choices=list(self.ptfilldict.keys()),
  983. )
  984. ptfill.SetStringSelection(self.raster[self.map]["pfill"])
  985. self.wxId["pfill"] = ptfill.GetId()
  986. gridSizer.Add(ptfill, pos=(2, 1))
  987. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Legend"))
  988. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(3, 0))
  989. ptlegend = TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(200, -1))
  990. ptlegend.SetValue(self.raster[self.map]["plegend"])
  991. self.wxId["plegend"] = ptlegend.GetId()
  992. gridSizer.Add(ptlegend, pos=(3, 1))
  993. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Style"))
  994. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(4, 0))
  995. pttype = Choice(parent=self, size=(200, -1), choices=self.pttypelist)
  996. pttype.SetStringSelection(self.raster[self.map]["ptype"])
  997. self.wxId["ptype"] = pttype.GetId()
  998. gridSizer.Add(pttype, pos=(4, 1))
  999. boxSizer.Add(gridSizer)
  1000. boxMainSizer.Add(boxSizer, flag=wx.ALL, border=3)
  1001. sizer.Add(boxMainSizer, flag=wx.ALL | wx.EXPAND, border=3)
  1002. #
  1003. # axis options for all plots
  1004. #
  1005. box = StaticBox(parent=self, id=wx.ID_ANY, label=" %s " % _("Axis settings"))
  1006. boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
  1007. middleSizer = wx.BoxSizer(wx.HORIZONTAL)
  1008. idx = 0
  1009. for axis, atype in [(_("X-Axis"), "x-axis"), (_("Y-Axis"), "y-axis")]:
  1010. box = StaticBox(parent=self, id=wx.ID_ANY, label=" %s " % axis)
  1011. boxSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
  1012. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  1013. prop = self.properties[atype]["prop"]
  1014. row = 0
  1015. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Scale"))
  1016. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1017. type = Choice(
  1018. parent=self, id=wx.ID_ANY, size=(100, -1), choices=self.axislist
  1019. )
  1020. type.SetStringSelection(prop["type"])
  1021. type.SetToolTip(
  1022. _(
  1023. "Automatic axis scaling, custom max and min, or scale matches data range (min)"
  1024. )
  1025. )
  1026. self.wxId[atype]["type"] = type.GetId()
  1027. gridSizer.Add(type, pos=(row, 1))
  1028. row += 1
  1029. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Custom min"))
  1030. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1031. min = TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(70, -1))
  1032. min.SetValue(str(prop["min"]))
  1033. self.wxId[atype]["min"] = min.GetId()
  1034. gridSizer.Add(min, pos=(row, 1))
  1035. row += 1
  1036. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Custom max"))
  1037. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1038. max = TextCtrl(parent=self, id=wx.ID_ANY, value="", size=(70, -1))
  1039. max.SetValue(str(prop["max"]))
  1040. self.wxId[atype]["max"] = max.GetId()
  1041. gridSizer.Add(max, pos=(row, 1))
  1042. row += 1
  1043. log = CheckBox(parent=self, id=wx.ID_ANY, label=_("Log scale"))
  1044. log.SetValue(prop["log"])
  1045. self.wxId[atype]["log"] = log.GetId()
  1046. gridSizer.Add(log, pos=(row, 0), span=(1, 2))
  1047. if idx == 0:
  1048. flag = wx.ALL | wx.EXPAND
  1049. else:
  1050. flag = wx.TOP | wx.BOTTOM | wx.RIGHT | wx.EXPAND
  1051. boxSizer.Add(gridSizer, flag=wx.ALL, border=3)
  1052. boxMainSizer.Add(boxSizer, flag=flag, border=3)
  1053. idx += 1
  1054. middleSizer.Add(boxMainSizer, flag=wx.ALL | wx.EXPAND, border=3)
  1055. #
  1056. # grid & legend options for all plots
  1057. #
  1058. self.wxId["grid"] = {}
  1059. self.wxId["legend"] = {}
  1060. self.wxId["font"] = {}
  1061. box = StaticBox(
  1062. parent=self, id=wx.ID_ANY, label=" %s " % _("Grid and Legend settings")
  1063. )
  1064. boxMainSizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
  1065. gridSizer = wx.GridBagSizer(vgap=5, hgap=5)
  1066. row = 0
  1067. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Grid color"))
  1068. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1069. gridcolor = ColourSelect(
  1070. parent=self, id=wx.ID_ANY, colour=self.properties["grid"]["color"]
  1071. )
  1072. self.wxId["grid"]["color"] = gridcolor.GetId()
  1073. gridSizer.Add(gridcolor, pos=(row, 1))
  1074. row += 1
  1075. gridshow = CheckBox(parent=self, id=wx.ID_ANY, label=_("Show grid"))
  1076. gridshow.SetValue(self.properties["grid"]["enabled"])
  1077. self.wxId["grid"]["enabled"] = gridshow.GetId()
  1078. gridSizer.Add(gridshow, pos=(row, 0), span=(1, 2))
  1079. row += 1
  1080. label = StaticText(parent=self, id=wx.ID_ANY, label=_("Legend font size"))
  1081. gridSizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
  1082. legendfontsize = SpinCtrl(
  1083. parent=self, id=wx.ID_ANY, value="", size=(50, -1), style=wx.SP_ARROW_KEYS
  1084. )
  1085. legendfontsize.SetRange(5, 100)
  1086. legendfontsize.SetValue(int(self.properties["font"]["prop"]["legendSize"]))
  1087. self.wxId["font"]["legendSize"] = legendfontsize.GetId()
  1088. gridSizer.Add(legendfontsize, pos=(row, 1))
  1089. row += 1
  1090. legendshow = CheckBox(parent=self, id=wx.ID_ANY, label=_("Show legend"))
  1091. legendshow.SetValue(self.properties["legend"]["enabled"])
  1092. self.wxId["legend"]["enabled"] = legendshow.GetId()
  1093. gridSizer.Add(legendshow, pos=(row, 0), span=(1, 2))
  1094. boxMainSizer.Add(gridSizer, flag=flag, border=3)
  1095. middleSizer.Add(
  1096. boxMainSizer, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=3
  1097. )
  1098. sizer.Add(middleSizer, flag=wx.ALL, border=0)
  1099. #
  1100. # line & buttons
  1101. #
  1102. line = wx.StaticLine(
  1103. parent=self, id=wx.ID_ANY, size=(20, -1), style=wx.LI_HORIZONTAL
  1104. )
  1105. sizer.Add(line, proportion=0, flag=wx.GROW | wx.LEFT | wx.RIGHT, border=3)
  1106. #
  1107. # buttons
  1108. #
  1109. btnSave = Button(self, wx.ID_SAVE)
  1110. btnApply = Button(self, wx.ID_APPLY)
  1111. btnOk = Button(self, wx.ID_OK)
  1112. btnCancel = Button(self, wx.ID_CANCEL)
  1113. btnOk.SetDefault()
  1114. # tooltips for buttons
  1115. btnApply.SetToolTip(_("Apply changes for the current session"))
  1116. btnOk.SetToolTip(_("Apply changes for the current session and close dialog"))
  1117. btnSave.SetToolTip(
  1118. _(
  1119. "Apply and save changes to user settings file (default for next sessions)"
  1120. )
  1121. )
  1122. btnCancel.SetToolTip(_("Close dialog and ignore changes"))
  1123. # sizers
  1124. btnStdSizer = wx.StdDialogButtonSizer()
  1125. btnStdSizer.AddButton(btnOk)
  1126. btnStdSizer.AddButton(btnApply)
  1127. btnStdSizer.AddButton(btnCancel)
  1128. btnStdSizer.Realize()
  1129. btnSizer = wx.BoxSizer(wx.HORIZONTAL)
  1130. btnSizer.Add(btnSave, proportion=0, flag=wx.ALL, border=5)
  1131. btnSizer.Add(btnStdSizer, proportion=0, flag=wx.ALL, border=5)
  1132. sizer.Add(btnSizer, proportion=0, flag=wx.ALL, border=5)
  1133. #
  1134. # bindings for buttons and map plot settings controls
  1135. #
  1136. self.mapchoice.Bind(wx.EVT_CHOICE, self.OnSetMap)
  1137. btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  1138. btnOk.Bind(wx.EVT_BUTTON, self.OnOk)
  1139. btnOk.SetDefault()
  1140. btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
  1141. self.SetSizer(sizer)
  1142. sizer.Fit(self)
  1143. def OnSetMap(self, event):
  1144. """Handler for changing map selection"""
  1145. idx = event.GetSelection()
  1146. self.map = self.rasterList[idx]
  1147. # update settings controls for all plots
  1148. self.FindWindowById(self.wxId["pcolor"]).SetColour(
  1149. self.raster[self.map]["pcolor"]
  1150. )
  1151. self.FindWindowById(self.wxId["plegend"]).SetValue(
  1152. self.raster[self.map]["plegend"]
  1153. )
  1154. # update settings controls for histograms and profiles
  1155. if self.plottype != "scatter":
  1156. self.FindWindowById(self.wxId["pwidth"]).SetValue(
  1157. self.raster[self.map]["pwidth"]
  1158. )
  1159. self.FindWindowById(self.wxId["pstyle"]).SetStringSelection(
  1160. self.raster[self.map]["pstyle"]
  1161. )
  1162. # update settings controls for scatterplots
  1163. elif self.plottype == "scatter":
  1164. self.FindWindowById(self.wxId["psize"]).SetValue(
  1165. self.raster[self.map]["psize"]
  1166. )
  1167. self.FindWindowById(self.wxId["ptype"]).SetStringSelection(
  1168. self.raster[self.map]["ptype"]
  1169. )
  1170. self.FindWindowById(self.wxId["pfill"]).SetStringSelection(
  1171. self.raster[self.map]["pfill"]
  1172. )
  1173. self.Refresh()
  1174. def OnSetOpt(self, event):
  1175. """Handler for changing any other option"""
  1176. self.map = self.rasterList[self.mapchoice.GetCurrentSelection()]
  1177. self.UpdateSettings()
  1178. self.parent.SetGraphStyle()
  1179. p = self.parent.CreatePlotList()
  1180. self.parent.DrawPlot(p)
  1181. def UpdateSettings(self):
  1182. """Apply settings to each map and to entire plot"""
  1183. self.raster[self.map]["pcolor"] = (
  1184. self.FindWindowById(self.wxId["pcolor"]).GetColour().Get()
  1185. )
  1186. self.properties["raster"]["pcolor"] = self.raster[self.map]["pcolor"]
  1187. self.raster[self.map]["plegend"] = self.FindWindowById(
  1188. self.wxId["plegend"]
  1189. ).GetValue()
  1190. if self.plottype != "scatter":
  1191. self.raster[self.map]["pwidth"] = int(
  1192. self.FindWindowById(self.wxId["pwidth"]).GetValue()
  1193. )
  1194. self.properties["raster"]["pwidth"] = self.raster[self.map]["pwidth"]
  1195. self.raster[self.map]["pstyle"] = self.FindWindowById(
  1196. self.wxId["pstyle"]
  1197. ).GetStringSelection()
  1198. self.properties["raster"]["pstyle"] = self.raster[self.map]["pstyle"]
  1199. elif self.plottype == "scatter":
  1200. self.raster[self.map]["psize"] = self.FindWindowById(
  1201. self.wxId["psize"]
  1202. ).GetValue()
  1203. self.properties["raster"]["psize"] = self.raster[self.map]["psize"]
  1204. self.raster[self.map]["ptype"] = self.FindWindowById(
  1205. self.wxId["ptype"]
  1206. ).GetStringSelection()
  1207. self.properties["raster"]["ptype"] = self.raster[self.map]["ptype"]
  1208. self.raster[self.map]["pfill"] = self.FindWindowById(
  1209. self.wxId["pfill"]
  1210. ).GetStringSelection()
  1211. self.properties["raster"]["pfill"] = self.raster[self.map]["pfill"]
  1212. # update settings for entire plot
  1213. for axis in ("x-axis", "y-axis"):
  1214. self.properties[axis]["prop"]["type"] = self.FindWindowById(
  1215. self.wxId[axis]["type"]
  1216. ).GetStringSelection()
  1217. self.properties[axis]["prop"]["min"] = float(
  1218. self.FindWindowById(self.wxId[axis]["min"]).GetValue()
  1219. )
  1220. self.properties[axis]["prop"]["max"] = float(
  1221. self.FindWindowById(self.wxId[axis]["max"]).GetValue()
  1222. )
  1223. self.properties[axis]["prop"]["log"] = self.FindWindowById(
  1224. self.wxId[axis]["log"]
  1225. ).IsChecked()
  1226. if self.plottype == "profile":
  1227. self.properties["marker"]["color"] = (
  1228. self.FindWindowById(self.wxId["marker"]["color"]).GetColour().Get()
  1229. )
  1230. self.properties["marker"]["fill"] = self.FindWindowById(
  1231. self.wxId["marker"]["fill"]
  1232. ).GetStringSelection()
  1233. self.properties["marker"]["size"] = self.FindWindowById(
  1234. self.wxId["marker"]["size"]
  1235. ).GetValue()
  1236. self.properties["marker"]["type"] = self.FindWindowById(
  1237. self.wxId["marker"]["type"]
  1238. ).GetStringSelection()
  1239. self.properties["marker"]["legend"] = self.FindWindowById(
  1240. self.wxId["marker"]["legend"]
  1241. ).GetValue()
  1242. self.properties["grid"]["color"] = (
  1243. self.FindWindowById(self.wxId["grid"]["color"]).GetColour().Get()
  1244. )
  1245. self.properties["grid"]["enabled"] = self.FindWindowById(
  1246. self.wxId["grid"]["enabled"]
  1247. ).IsChecked()
  1248. # this makes more sense in the text properties, including for settings update. But will need to change
  1249. # layout for controls to text dialog too.
  1250. self.properties["font"]["prop"]["legendSize"] = self.FindWindowById(
  1251. self.wxId["font"]["legendSize"]
  1252. ).GetValue()
  1253. self.properties["legend"]["enabled"] = self.FindWindowById(
  1254. self.wxId["legend"]["enabled"]
  1255. ).IsChecked()
  1256. self.parent.UpdateLabels()
  1257. def OnSave(self, event):
  1258. """Button 'Save' pressed"""
  1259. self.OnApply(None)
  1260. fileSettings = {}
  1261. UserSettings.ReadSettingsFile(settings=fileSettings)
  1262. fileSettings[self.plottype] = UserSettings.Get(group=self.plottype)
  1263. UserSettings.SaveToFile(fileSettings)
  1264. self._giface.WriteLog(
  1265. _("Plot settings saved to file '%s'.") % UserSettings.filePath
  1266. )
  1267. self.EndModal(wx.ID_OK)
  1268. def OnApply(self, event):
  1269. """Button 'Apply' pressed. Does not close dialog"""
  1270. self.UpdateSettings()
  1271. self.parent.SetGraphStyle()
  1272. p = self.parent.CreatePlotList()
  1273. self.parent.DrawPlot(p)
  1274. def OnOk(self, event):
  1275. """Button 'OK' pressed"""
  1276. self.OnApply(None)
  1277. self.EndModal(wx.ID_OK)