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

ESS_GUIESS_GUI_DocsESS_GUI_InvariantESS_GUI_Pr_fixesESS_GUI_batch_fittingESS_GUI_iss879ESS_GUI_iss959ESS_GUI_orderingSVCC-1SasView-664config-errorcostrafo411py37-allpy37-sascalcpy37-sasguipytestsetup_clean_upsimplify-c-buildticket-1094-headlessticket-1111ticket-1205-fit-weightsticket-1218ticket-1220ticket-818ticket885unittest-saveloadwin64bit_conda_vm
Last change on this file since 54557b5 was 54557b5, checked in by krzywon, 21 months 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.