source: sasview/src/sas/sasgui/guiframe/local_perspectives/plotting/parameters_panel_slicer.py @ 71b25b2

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 71b25b2 was 71b25b2, checked in by krzywon, 7 years ago

Only save plots associated with selected slicer.

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