source: sasview/src/sas/sasgui/guiframe/local_perspectives/plotting/parameters_panel_slicer.py @ 54557b5

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 54557b5 was 54557b5, checked in by krzywon, 7 years ago

Integer params in manipulations to comply with numpy v1.12. Nearly completed saving 1D plots generated by slicers.

  • Property mode set to 100644
File size: 15.9 KB
Line 
1
2
3import wx
4import wx.lib.newevent
5import time
6from sas.sascalc.dataloader.readers.cansas_reader import Reader
7from sas.sasgui.guiframe.events import EVT_SLICER_PARS
8from sas.sasgui.guiframe.utils import format_number
9from sas.sasgui.guiframe.events import EVT_SLICER
10from sas.sasgui.guiframe.events import SlicerParameterEvent, SlicerEvent
11from Plotter1D import ModelPanel1D
12from Plotter2D import ModelPanel2D
13from sas.sascalc.dataloader.data_info import Data1D, Data2D
14apply_params, EVT_APPLY_PARAMS = wx.lib.newevent.NewEvent()
15auto_save, EVT_AUTO_SAVE = wx.lib.newevent.NewEvent()
16auto_close, EVT_ON_CLOSE = wx.lib.newevent.NewEvent()
17
18
19class SlicerParameterPanel(wx.Dialog):
20    """
21    Panel class to show the slicer parameters
22    """
23    # TODO: show units
24    # TODO: order parameters properly
25
26    def __init__(self, parent, *args, **kwargs):
27        """
28        Dialog window that allow to edit parameters slicer
29        by entering new values
30        """
31        wx.Dialog.__init__(self, parent, *args, **kwargs)
32        self.params = {}
33        self.parent = parent
34        self.type = None
35        self.listeners = []
36        self.parameters = []
37        self.bck = wx.GridBagSizer(5, 5)
38        self.SetSizer(self.bck)
39        self.auto_save = None
40        self.path = None
41        self.type_list = ["SectorInteractor", "AnnulusInteractor",
42                          "BoxInteractorX", "BoxInteractorY"]
43        self.type_select = wx.ComboBox(parent=self, choices=self.type_list)
44        self.append_name = wx.TextCtrl(parent=self, id=wx.NewId(),
45                                       name="Append to file name:")
46        self.data_list = None
47        label = "Right-click on 2D plot for slicer options"
48        title = wx.StaticText(self, -1, label, style=wx.ALIGN_LEFT)
49        self.bck.Add(title, (0, 0), (1, 2),
50                     flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL, border=15)
51        # Bindings
52        self.parent.Bind(EVT_SLICER, self.onEVT_SLICER)
53        self.parent.Bind(EVT_SLICER_PARS, self.onParamChange)
54        self.Bind(EVT_APPLY_PARAMS, self.apply_params_list_and_process)
55        self.Bind(EVT_AUTO_SAVE, self.save_files)
56        self.Bind(EVT_ON_CLOSE, self.on_close)
57
58    def onEVT_SLICER(self, event):
59        """
60        Process EVT_SLICER events
61        When the slicer changes, update the panel
62
63        :param event: EVT_SLICER event
64        """
65        event.Skip()
66        if event.obj_class is None:
67            self.set_slicer(None, None)
68        else:
69            self.set_slicer(event.type, event.params)
70
71    def set_slicer(self, type, params):
72        """
73        Rebuild the panel
74        """
75        self.bck.Clear(True)
76        self.bck.Add((5, 5), (0, 0), (1, 1),
77                     wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 5)
78        self.type = type
79        if type is None:
80            label = "Right-click on 2D plot for slicer options"
81            title = wx.StaticText(self, -1, label, style=wx.ALIGN_LEFT)
82            self.bck.Add(title, (1, 0), (1, 2),
83                         flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL, border=15)
84        else:
85            title = wx.StaticText(self, -1,
86                                  "Slicer Parameters:", style=wx.ALIGN_LEFT)
87            self.bck.Add(title, (1, 0), (1, 2),
88                         flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL, border=15)
89            iy = 1
90            self.parameters = []
91            keys = params.keys()
92            keys.sort()
93            for item in keys:
94                iy += 1
95                ix = 0
96                if not item in ["count", "errors"]:
97                    text = wx.StaticText(self, -1, item, style=wx.ALIGN_LEFT)
98                    self.bck.Add(text, (iy, ix), (1, 1),
99                                 wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
100                    ctl = wx.TextCtrl(self, -1, size=(80, 20),
101                                      style=wx.TE_PROCESS_ENTER)
102                    hint_msg = "Modify the value of %s to change" % item
103                    hint_msg += " the 2D slicer"
104                    ctl.SetToolTipString(hint_msg)
105                    ix = 1
106                    ctl.SetValue(format_number(str(params[item])))
107                    self.Bind(wx.EVT_TEXT_ENTER, self.onTextEnter)
108                    self.parameters.append([item, ctl])
109                    self.bck.Add(ctl, (iy, ix), (1, 1),
110                                 wx.EXPAND | wx.ADJUST_MINSIZE, 0)
111                    ix = 3
112                    self.bck.Add((20, 20), (iy, ix), (1, 1),
113                                 wx.EXPAND | wx.ADJUST_MINSIZE, 0)
114                else:
115                    text = wx.StaticText(self, -1, item + " : ",
116                                         style=wx.ALIGN_LEFT)
117                    self.bck.Add(text, (iy, ix), (1, 1),
118                                 wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
119                    ctl = wx.StaticText(self, -1,
120                                        format_number(str(params[item])),
121                                        style=wx.ALIGN_LEFT)
122                    ix = 1
123                    self.bck.Add(ctl, (iy, ix), (1, 1),
124                                 wx.EXPAND | wx.ADJUST_MINSIZE, 0)
125
126            # Change slicer within the window
127            ix = 0
128            iy += 1
129            txt = "Slicer type:"
130            text = wx.StaticText(self, -1, txt, style=wx.ALIGN_LEFT)
131            self.bck.Add(text, (iy, ix), (1, 1),
132                         wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
133            self.Bind(wx.EVT_COMBOBOX, self.onChangeSlicer)
134            index = self.type_select.FindString(type)
135            self.type_select.SetSelection(index)
136            self.bck.Add(self.type_select, (iy, 1), (1, 1),
137                         wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
138
139            # batch slicing parameters
140            title_text = "Batch Slicing Options:"
141            title = wx.StaticText(self, -1, title_text, style=wx.ALIGN_LEFT)
142            iy += 1
143            line = wx.StaticLine(self, -1, style=wx.LI_VERTICAL)
144            line.SetSize((60, 60))
145            self.bck.Add(line, (iy, ix), (1, 2),
146                         wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
147            iy += 1
148            self.bck.Add(title, (iy, ix), (1, 1),
149                         wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
150
151            # Create a list box with all of the 2D plots
152            iy += 1
153            self.process_list()
154            self.bck.Add(self.data_list, (iy, ix), (1, 1),
155                         wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
156
157            # Checkbox for autosaving data
158            iy += 1
159
160            self.auto_save = wx.CheckBox(parent=self, id=wx.NewId(),
161                                         label="Auto save generated 1D:")
162            self.Bind(wx.EVT_CHECKBOX, self.on_auto_save_checked)
163            self.bck.Add(self.auto_save, (iy, ix), (1, 1),
164                         wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
165            iy += 1
166            # File browser
167            save_to = "Save files to:"
168            save = wx.StaticText(self, -1, save_to, style=wx.ALIGN_LEFT)
169            self.path = wx.DirPickerCtrl(self, id=wx.NewId(), path="",
170                                         message=save_to)
171            self.path.Enable(False)
172            self.bck.Add(save, (iy, ix), (1, 1),
173                         wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
174            self.bck.Add(self.path, (iy, 1), (1, 1),
175                         wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
176            # Append to file
177            iy += 1
178            default_value = "_{0}".format(self.type)
179            for key in params:
180                default_value += "_%d.2" % params[key]
181            append_text = "Append to file name:"
182            append = wx.StaticText(self, -1, append_text, style=wx.ALIGN_LEFT)
183            self.append_name.SetValue(default_value)
184            self.append_name.Enable(False)
185            self.bck.Add(append, (iy, ix), (1, 1),
186                         wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
187            self.bck.Add(self.append_name, (iy, 1), (1, 1),
188                         wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
189
190            # TODO: Fix fitting options combobox/radiobox
191            # Combobox for selecting fitting options
192            # iy += 1
193            # self.fitting_radio = wx.RadioBox(parent=self, id=wx.NewId(),
194            #                                  size=(4,1))
195            # self.fitting_radio.SetString(0, "No fitting")
196            # self.fitting_radio.SetString(1, "Batch Fitting")
197            # self.fitting_radio.SetString(2, "Fitting")
198            # self.fitting_radio.SetString(3, "Simultaneous and Constrained Fit")
199            # self.fitting_radio.SetValue(0)
200            # self.bck.Add(self.fitting_radio, (iy, ix), (1, 1),
201            #              wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
202
203            # Button to start batch slicing
204            iy += 1
205            button_label = "Apply Slicer to Selected Plots"
206            self.batch_slicer_button = wx.Button(parent=self,
207                                                 label=button_label)
208            self.Bind(wx.EVT_BUTTON, self.on_batch_slicer)
209            self.bck.Add(self.batch_slicer_button, (iy, ix), (1, 1),
210                         wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
211            iy += 1
212            self.bck.Add((5, 5), (iy, ix), (1, 1),
213                         wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 5)
214        self.bck.Layout()
215        self.bck.Fit(self)
216        self.parent.GetSizer().Layout()
217
218    def onParamChange(self, evt):
219        """
220        receive an event end reset value text fields
221        inside self.parameters
222        """
223        evt.Skip()
224        if evt.type == "UPDATE":
225            for item in self.parameters:
226                if item[0] in evt.params:
227                    item[1].SetValue("%-5.3g" % evt.params[item[0]])
228                    item[1].Refresh()
229
230    def onTextEnter(self, evt):
231        """
232        Parameters have changed
233        """
234        params = {}
235        has_error = False
236        for item in self.parameters:
237            try:
238                params[item[0]] = float(item[1].GetValue())
239                item[1].SetBackgroundColour(
240                    wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
241                item[1].Refresh()
242            except:
243                has_error = True
244                item[1].SetBackgroundColour("pink")
245                item[1].Refresh()
246
247        if not has_error:
248            # Post parameter event
249            # parent here is plotter2D
250            event = SlicerParameterEvent(type=self.type, params=params)
251            wx.PostEvent(self.parent, event)
252
253    def on_batch_slicer(self, evt=None):
254        """
255        Method invoked with batch slicing button is pressed
256        :param evt: Event triggering hide/show of the batch slicer parameters
257        """
258        apply_to_list = []
259        spp = self.parent.parent
260        params = self.parent.slicer.get_params()
261        type = self.type_select.GetStringSelection()
262        save = self.auto_save.IsChecked()
263        append = self.append_name.GetValue()
264        path = self.path.GetPath()
265
266        # Find desired 2D data panels
267        for key, mgr in spp.plot_panels.iteritems():
268            if mgr.graph.prop['title'] in self.data_list.CheckedStrings:
269                apply_to_list.append(mgr)
270
271        # Apply slicer type to selected panels
272        for item in apply_to_list:
273            self._apply_slicer_to_plot(item, type)
274
275        # Post an event to apply appropriate slicer params to each slicer
276        # Event needed due to how apply_slicer_to_plot works
277        event = apply_params(params=params, plot_list=apply_to_list,
278                             auto_save=save, append=append,
279                             path=path)
280        wx.PostEvent(self, event)
281        event = auto_close()
282        wx.PostEvent(self, event)
283
284    def onChangeSlicer(self, evt):
285        """
286        Event driven slicer change when self.type_select changes
287        :param evt: Event triggering this change
288        """
289        self._apply_slicer_to_plot(self.parent)
290
291    def _apply_slicer_to_plot(self, plot, type=None):
292        """
293        Apply a slicer to *any* plot window, not just parent window
294        :param plot: 2D plot panel to apply a slicer to
295        :param type: The type of slicer to apply to the panel
296        """
297        if type is None:
298            type = self.type_select.GetStringSelection()
299        if type == "SectorInteractor":
300            plot.onSectorQ(None)
301        elif type == "AnnulusInteractor":
302            plot.onSectorPhi(None)
303        elif type == "BoxInteractorX":
304            plot.onBoxavgX(None)
305        elif type == "BoxInteractorY":
306            plot.onBoxavgY(None)
307
308    def process_list(self):
309        """
310        Populate the check list from the currently plotted 2D data
311        """
312        self.checkme = None
313        main_window = self.parent.parent
314        self.loaded_data = []
315        id = wx.NewId()
316        # Iterate over the loaded plots and find all 2D panels
317        for key, value in main_window.plot_panels.iteritems():
318            if isinstance(value, ModelPanel2D):
319                self.loaded_data.append(value.data2D.name)
320                if value.data2D.id == self.parent.data2D.id:
321                    # Set current plot panel as uncheckable
322                    self.checkme = self.loaded_data.index(value.data2D.name)
323        self.data_list = wx.CheckListBox(parent=self, id=id,
324                                         choices=self.loaded_data,
325                                         name="Apply Slicer to 2D Plots:")
326        # Check all items by default
327        for item in range(len(self.data_list.Items)):
328            self.data_list.Check(item)
329        self.data_list.Bind(wx.EVT_CHECKLISTBOX, self.on_check_box_list)
330
331    def on_check_box_list(self, evt=None):
332        """
333        Prevent a checkbox item from being unchecked
334        :param e: Event triggered when a checkbox list item is checked
335        """
336        if evt is None:
337            return
338        index = evt.GetSelection()
339        if index == self.checkme:
340            self.data_list.Check(index)
341
342    def apply_params_list_and_process(self, evt=None):
343        """
344        Event based parameter setting.
345        :param evt: Event triggered to apply parameters to a list of plots
346                    evt should have attrs plot_list and params
347        """
348        # Apply parameter list to each plot as desired
349        for item in evt.plot_list:
350            item.slicer.set_params(evt.params)
351            item.slicer.base.update()
352        # Post an event to save each data set to file
353        if evt.auto_save:
354            event = auto_save(append_to_name=evt.append,
355                              file_list=evt.plot_list,
356                              path=evt.path)
357            wx.PostEvent(self, event)
358
359    def save_files(self, evt=None):
360        """
361        Automatically save the sliced data to file.
362        :param evt: Event that triggered the call to the method
363        """
364        if evt is None:
365            return
366        writer = Reader()
367        main_window = self.parent.parent
368        data_list = []
369        append = evt.append_to_name
370        for key, plot in main_window.plot_panels.iteritems():
371            if not hasattr(plot, "data2D"):
372                for item in plot.plots:
373                    data_list.append(item)
374        for item in data_list:
375            data1d = item.plots
376            base = item.name.split(".")[0]
377            save_to = evt.path + base + ".xml"
378            writer.write(path, data1d)
379
380        # TODO: determine data sets
381        # TODO: generate file names
382        # TODO: link one to the other
383        # TODO: save all files
384
385    def on_auto_save_checked(self, evt=None):
386        """
387        Enable/Disable auto append when checkbox is checked
388        :param evt: Event
389        """
390        self.append_name.Enable(self.auto_save.IsChecked())
391        self.path.Enable(self.auto_save.IsChecked())
392   
393    def on_close(self, evt=None):
394        """
395        Auto close the panel
396        """
397        self.Destroy()
Note: See TracBrowser for help on using the repository browser.