source: sasview/src/sas/sasgui/perspectives/fitting/batchfitpage.py @ db5294e

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.1.1release-4.1.2release-4.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since db5294e was ee4b3cb, checked in by Paul Kienzle <pkienzle@…>, 8 years ago

fix 'invalid Q range' when parameter value is min or max. Fixes #636

  • Property mode set to 100644
File size: 16.2 KB
Line 
1"""
2Batch panel
3"""
4import wx
5import wx.lib.newevent
6import math
7from sas.sasgui.guiframe.events import StatusEvent
8from sas.sasgui.guiframe.events import NewPlotEvent
9
10(Chi2UpdateEvent, EVT_CHI2_UPDATE) = wx.lib.newevent.NewEvent()
11_BOX_WIDTH = 76
12_DATA_BOX_WIDTH = 300
13SMEAR_SIZE_L = 0.00
14SMEAR_SIZE_H = 0.00
15
16from sas.sasgui.perspectives.fitting.basepage import PageInfoEvent
17from sas.sascalc.data_util.qsmearing import smear_selection
18from sas.sasgui.perspectives.fitting.fitpage import FitPage
19from sas.sasgui.perspectives.fitting.fitpage import check_data_validity
20
21class BatchFitPage(FitPage):
22    """
23    Batch Page
24    """
25    window_name = "BatchFit"
26    window_caption = "BatchFit"
27
28    def __init__(self, parent, color=None):
29        """
30        Initialization of the Panel
31        """
32        FitPage.__init__(self, parent, color=color)
33
34        ## draw sizer
35
36    def _fill_data_sizer(self):
37        """
38        fill sizer 0 with data info
39        """
40        self.data_box_description = wx.StaticBox(self, wx.ID_ANY, 'I(q) Data Source')
41        if check_data_validity(self.data):
42            dname_color = wx.BLUE
43        else:
44            dname_color = wx.RED
45        self.data_box_description.SetForegroundColour(dname_color)
46        boxsizer1 = wx.StaticBoxSizer(self.data_box_description, wx.VERTICAL)
47        #----------------------------------------------------------
48        sizer_data = wx.BoxSizer(wx.VERTICAL)
49        text1 = wx.StaticText(self, wx.ID_ANY, ' - Choose a file to set initial fit parameters -')
50        text1.SetForegroundColour(wx.RED)
51        sizer_data.Add(text1)
52        text2 = wx.StaticText(self, wx.ID_ANY, ' - This panel is not designed to view individual fits. - ')
53        text2.SetForegroundColour(wx.RED)
54        sizer_data.Add(text2)
55
56        combo = wx.BoxSizer(wx.HORIZONTAL)
57        self.dataSource = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_READONLY)
58        wx.EVT_COMBOBOX(self.dataSource, wx.ID_ANY, self.on_select_data)
59        self.dataSource.SetMinSize((_DATA_BOX_WIDTH, -1))
60
61        combo.Add(wx.StaticText(self, wx.ID_ANY, 'Name : '))
62        combo.Add((0, 5))
63        combo.Add(self.dataSource)
64
65        sizer_data.Add(combo, 0, wx.ALL, 10)
66        boxsizer1.Add(sizer_data, 0, wx.ALL, 0)
67        self.sizer0.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
68        self.sizer0.Layout()
69
70#    COMMENTED OUT TO USE METHODS INHERITED FROM fitpage.py
71
72#     def _fill_range_sizer(self):
73#         """
74#         Fill the sizer containing the plotting range
75#         add  access to npts
76#         """
77#         is_2Ddata = False
78#         
79#         # Check if data is 2D
80#         if self.data.__class__.__name__ ==  "Data2D" or \
81#                         self.enable2D:
82#             is_2Ddata = True
83#             
84#         title = "Fitting"     
85#         self._get_smear_info()
86#         
87#         #Sizers
88#         box_description_range = wx.StaticBox(self, wx.ID_ANY, str(title))
89#         boxsizer_range = wx.StaticBoxSizer(box_description_range, wx.VERTICAL)     
90#         self.sizer_set_smearer = wx.BoxSizer(wx.VERTICAL)
91#         #sizer_smearer = wx.BoxSizer(wx.HORIZONTAL)
92#         self.sizer_new_smear = wx.BoxSizer(wx.HORIZONTAL)
93#         self.sizer_set_masking = wx.BoxSizer(wx.HORIZONTAL)
94#         sizer_chi2 = wx.BoxSizer(wx.VERTICAL)
95#
96#         sizer_fit = wx.GridSizer(2, 4, 2, 6)
97#         #Fit button
98#         self.btFit = wx.Button(self, self._ids.next(), 'Fit', size=(88, 25))
99#         self.default_bt_colour =  self.btFit.GetDefaultAttributes()
100#         self.btFit.Bind(wx.EVT_BUTTON, self._onFit, id= self.btFit.GetId())
101#         self.btFit.SetToolTipString("Start fitting.")
102#
103#         # Update and Draw button
104#         self.draw_button = wx.Button(self, self._ids.next(), 'Compute', size=(88, 24))
105#         self.draw_button.Bind(wx.EVT_BUTTON, \
106#                               self._onDraw,id=self.draw_button.GetId())
107#         self.draw_button.SetToolTipString("Compute and Draw.") 
108#         sizer_fit.Add(self.draw_button, 0, 0)
109#         sizer_fit.Add(self.btFit, 0, 0)
110#         sizer_chi2.Add((-1, 5))
111#         # get smear_selection
112#         self.current_smearer = smear_selection( self.data, self.model )
113#         boxsizer_range.Add(self.sizer_set_masking)
114#          #2D data? default
115#         is_2Ddata = False
116#         
117#         #check if it is 2D data
118#         if self.data.__class__.__name__ ==  "Data2D" or \
119#                         self.enable2D:
120#             is_2Ddata = True
121#             
122#         self.sizer5.Clear(True)
123#     
124#         self.qmin  = ModelTextCtrl(self, wx.ID_ANY, size=(_BOX_WIDTH, 20),
125#                                           style=wx.TE_PROCESS_ENTER,
126#                                     text_enter_callback = self._onQrangeEnter)
127#         self.qmin.SetValue(str(self.qmin_x))
128#         self.qmin.SetToolTipString("Minimun value of Q in linear scale.")
129#     
130#         self.qmax  = ModelTextCtrl(self, wx.ID_ANY, size=(_BOX_WIDTH, 20),
131#                                           style=wx.TE_PROCESS_ENTER,
132#                                         text_enter_callback=self._onQrangeEnter)
133#         self.qmax.SetValue(str(self.qmax_x))
134#         self.qmax.SetToolTipString("Maximum value of Q in linear scale.")
135#         
136#         id = self._ids.next()
137#         self.reset_qrange =wx.Button(self, id, 'Reset', size=(77, 20))
138#       
139#         self.reset_qrange.Bind(wx.EVT_BUTTON, self.on_reset_clicked, id=id)
140#         self.reset_qrange.SetToolTipString(\
141#                                     "Reset Q range to the default values")
142#     
143#         sizer_horizontal = wx.BoxSizer(wx.HORIZONTAL)
144#         sizer = wx.GridSizer(2, 4, 2, 6)
145#
146#         self.btEditMask = wx.Button(self, self._ids.next(),'Editor', size=(88, 23))
147#         self.btEditMask.Bind(wx.EVT_BUTTON,
148#                              self._onMask,id=self.btEditMask.GetId())
149#         self.btEditMask.SetToolTipString("Edit Mask.")
150#         self.EditMask_title = wx.StaticText(self, wx.ID_ANY, ' Masking(2D)')
151#
152#         sizer.Add(wx.StaticText(self, wx.ID_ANY, 'Q range'))
153#         sizer.Add(wx.StaticText(self, wx.ID_ANY, ' Min[1/A]'))
154#         sizer.Add(wx.StaticText(self, wx.ID_ANY, ' Max[1/A]'))
155#         sizer.Add(self.EditMask_title)
156
157#         sizer.Add(self.reset_qrange)   
158#         sizer.Add(self.qmin)
159#         sizer.Add(self.qmax)
160#
161#         sizer.Add(self.btEditMask)
162#         boxsizer_range.Add(sizer_chi2)
163#         boxsizer_range.Add((10, 10))
164#         boxsizer_range.Add(sizer)
165#         
166#         boxsizer_range.Add((10, 15))
167#         boxsizer_range.Add(sizer_fit)
168#         if is_2Ddata:
169#             self.btEditMask.Enable() 
170#             self.EditMask_title.Enable()
171#         else:
172#             self.btEditMask.Disable() 
173#             self.EditMask_title.Disable()
174#
175#         ## save state
176#         #self.save_current_state()
177#
178#         self.sizer5.Add(boxsizer_range, 0, wx.EXPAND | wx.ALL, 10)
179#         self.sizer5.Layout()
180#       
181#     def _on_select_model(self, event=None):
182#         """
183#         call back for model selection
184#         """ 
185#         
186#         self.Show(False)   
187#         self._on_select_model_helper()
188#         self.set_model_param_sizer(self.model)                   
189#         if self.model is None:
190#             self._set_bookmark_flag(False)
191#             self._keep.Enable(False)
192#             self._set_save_flag(False)
193#         self.enable_disp.SetValue(False)
194#         self.disable_disp.SetValue(True)
195#         try:
196#             self.set_dispers_sizer()
197#         except:
198#             pass
199#         self.state.structurecombobox = self.structurebox.GetCurrentSelection()
200#         self.state.formfactorcombobox = self.formfactorbox.GetCurrentSelection()
201#       
202#         if self.model != None:
203#             self._set_copy_flag(True)
204#             self._set_paste_flag(True)
205#             if self.data != None:
206#                 self._set_bookmark_flag(False)
207#                 self._keep.Enable(False)
208#                 
209#             temp_smear = None
210#             ## event to post model to fit to fitting plugins
211#             (ModelEventbox, _) = wx.lib.newevent.NewEvent()
212#         
213#             ## set smearing value whether or not
214#             #    the data contain the smearing info
215#             evt = ModelEventbox(model=self.model,
216#                                         smearer=temp_smear,
217#                                         qmin=float(self.qmin_x),
218#                                         uid=self.uid,
219#                                      qmax=float(self.qmax_x))
220#   
221#             self._manager._on_model_panel(evt=evt)
222#             self.mbox_description.SetLabel("Model [%s]" % str(self.model.name))
223#             self.state.model = self.model.clone()
224#             self.state.model.name = self.model.name
225#
226#             
227#         if event != None:
228#             ## post state to fit panel
229#             new_event = PageInfoEvent(page = self)
230#             wx.PostEvent(self.parent, new_event)
231#             #update list of plugins if new plugin is available
232#             if self.plugin_rbutton.GetValue():
233#                 temp = self.parent.update_model_list()
234#                 if temp:
235#                     self.model_list_box = temp
236#                     current_val = self.formfactorbox.GetValue()
237#                     pos = self.formfactorbox.GetSelection()
238#                     self._show_combox_helper()
239#                     self.formfactorbox.SetSelection(pos)
240#                     self.formfactorbox.SetValue(current_val)
241#             self._onDraw(event=None)
242#         else:
243#             self._draw_model()
244#         self.SetupScrolling()
245#         self.Show(True)   
246#         
247#     def _update_paramv_on_fit(self):
248#         """
249#         make sure that update param values just before the fitting
250#         """
251#         #flag for qmin qmax check values
252#         flag = True
253#         self.fitrange = True
254#         is_modified = False
255#
256#         if self.model != None:           
257#             ##Check the values
258#             self._check_value_enter( self.fittable_param)
259#             self._check_value_enter( self.fixed_param)
260#             self._check_value_enter( self.parameters)
261#
262#             # If qmin and qmax have been modified, update qmin and qmax and
263#              # Here we should check whether the boundaries have been modified.
264#             # If qmin and qmax have been modified, update qmin and qmax and
265#             # set the is_modified flag to True
266#             self.fitrange = self._validate_qrange(self.qmin, self.qmax)
267#             if self.fitrange:
268#                 tempmin = float(self.qmin.GetValue())
269#                 if tempmin != self.qmin_x:
270#                     self.qmin_x = tempmin
271#                 tempmax = float(self.qmax.GetValue())
272#                 if tempmax != self.qmax_x:
273#                     self.qmax_x = tempmax
274#                 if tempmax == tempmin:
275#                     flag = False   
276#                 #temp_smearer = None
277#                 if self._is_2D():
278#                     # only 2D case set mask 
279#                     flag = self._validate_Npts()
280#                     if not flag:
281#                         return flag
282#             else: flag = False
283#         else:
284#             flag = False
285#
286#         #For invalid q range, disable the mask editor and fit button, vs.   
287#         if not self.fitrange:
288#             #self.btFit.Disable()
289#             if self._is_2D():
290#                 self.btEditMask.Disable()
291#         else:
292#             #self.btFit.Enable(True)
293#             if self._is_2D() and  self.data != None:
294#                 self.btEditMask.Enable(True)
295#
296#         if not flag:
297#             msg = "Cannot Plot or Fit :Must select a "
298#             msg += " model or Fitting range is not valid!!!  "
299#             wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
300#         
301#         self.save_current_state()
302#   
303#         return flag 
304#     def save_current_state(self):
305#         """
306#         Currently no save option implemented for batch page
307#         """
308#         pass
309#     def save_current_state_fit(self):
310#         """
311#         Currently no save option implemented for batch page
312#         """
313#         pass
314#     def set_data(self, data):
315#         """
316#         reset the current data
317#         """
318#         #id = None
319#         group_id = None
320#         flag = False
321#         if self.data is None and data is not None:
322#             flag = True
323#         if data is not None:
324#             #id = data.id
325#             group_id = data.group_id
326#             if self.data is not None:
327#                 flag = (data.id != self.data.id)
328#         self.data = data
329#         if self.data is None:
330#             data_min = ""
331#             data_max = ""
332#             data_name = ""
333#             self._set_bookmark_flag(False)
334#             self._keep.Enable(False)
335#             self._set_save_flag(False)
336#         else:
337#             if self.model != None:
338#                 self._set_bookmark_flag(False)
339#                 self._keep.Enable(False)
340#             self._set_save_flag(False)
341#             self._set_preview_flag(True)
342#   
343#             self.formfactorbox.Enable()
344#             self.structurebox.Enable()
345#             data_name = self.data.name
346#             #set maximum range for x in linear scale
347#             if not hasattr(self.data,"data"): #Display only for 1D data fit
348#                 # Minimum value of data   
349#                 data_min = min(self.data.x)
350#                 # Maximum value of data 
351#                 data_max = max(self.data.x)
352#                 self.btEditMask.Disable() 
353#                 self.EditMask_title.Disable()
354#             else:
355#                 
356#                 ## Minimum value of data
357#                 data_min = 0
358#                 x = max(math.fabs(self.data.xmin), math.fabs(self.data.xmax))
359#                 y = max(math.fabs(self.data.ymin), math.fabs(self.data.ymax))
360#                 ## Maximum value of data 
361#                 data_max = math.sqrt(x*x + y*y)
362#                 self.btEditMask.Enable() 
363#                 self.EditMask_title.Enable()
364#
365#         self.dataSource.SetValue(data_name)
366#         self.qmin_x = data_min
367#         self.qmax_x = data_max
368#         #self.minimum_q.SetValue(str(data_min))
369#         #self.maximum_q.SetValue(str(data_max))
370#         self.qmin.SetValue(str(data_min))
371#         self.qmax.SetValue(str(data_max))
372#         self.qmin.SetBackgroundColour("white")
373#         self.qmax.SetBackgroundColour("white")
374#         self.state.data = data
375#         self.state.qmin = self.qmin_x
376#         self.state.qmax = self.qmax_x
377#         
378#         #update model plot with new data information
379#         if flag:
380#             #set model view button
381#             if self.data.__class__.__name__ == "Data2D":
382#                 self.enable2D = True
383#                 self.model_view.SetLabel("2D Mode")
384#             else:
385#                 self.enable2D = False
386#                 self.model_view.SetLabel("1D Mode")
387#                 
388#             self.model_view.Disable()
389#             
390#             wx.PostEvent(self._manager.parent,
391#                              NewPlotEvent(group_id=group_id,
392#                                                action="delete"))
393#             #plot the current selected data
394#             wx.PostEvent(self._manager.parent, NewPlotEvent(plot=self.data,
395#                                                     title=str(self.data.title)))
396#             self._manager.store_data(uid=self.uid, data=data,
397#                                      data_list=self.data_list,
398#                                       caption=self.window_name)
399#             self._draw_model()
400
401
402
403class BGTextCtrl(wx.TextCtrl):
404    """
405    Text control used to display outputs.
406    No editing allowed. The background is
407    grayed out. User can't select text.
408    """
409    def __init__(self, *args, **kwds):
410        wx.TextCtrl.__init__(self, *args, **kwds)
411        self.SetEditable(False)
412        self.SetBackgroundColour(self.GetParent().parent.GetBackgroundColour())
413
414        # Bind to mouse event to avoid text highlighting
415        # The event will be skipped once the call-back
416        # is called.
417        self.Bind(wx.EVT_MOUSE_EVENTS, self._click)
418
419    def _click(self, event):
420        """
421        Prevent further handling of the mouse event
422        by not calling Skip().
423        """
424        pass
425
Note: See TracBrowser for help on using the repository browser.