source: sasview/prview/perspectives/pr/inversion_panel.py @ bd30f4a5

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.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since bd30f4a5 was 35adaf6, checked in by Mathieu Doucet <doucetm@…>, 17 years ago

From Raiza: n_term estimator. GUI.

  • Property mode set to 100644
File size: 41.0 KB
Line 
1#!/usr/bin/env python
2
3# version
4__id__ = "$Id: aboutdialog.py 1193 2007-05-03 17:29:59Z dmitriy $"
5__revision__ = "$Revision: 1193 $"
6
7import wx
8from sans.guicomm.events import StatusEvent   
9
10class InversionDlg(wx.Dialog):
11    def __init__(self, parent, id, title, plots, file=False, pars=True):
12       
13        # Estimate size
14        nplots = len(plots)
15        # y size for data set only
16        ysize  = 110 + nplots*20
17        # y size including parameters
18        if pars:
19            ysize  += 90
20       
21        wx.Dialog.__init__(self, parent, id, title, size=(250, ysize))
22        self.SetTitle(title)
23
24        # Data set
25        self.datasets = InversionPanel(self, -1, plots)
26        vbox = wx.BoxSizer(wx.VERTICAL)
27
28        vbox.Add(self.datasets)
29
30        # Parameters
31        self.pars_flag = False
32        if pars==True:
33            self.pars_flag = True
34            self.pars = ParsDialog(self, -1, file=file)
35            vbox.Add(self.pars)
36
37        static_line = wx.StaticLine(self, -1)
38        vbox.Add(static_line, 0, wx.EXPAND, 0)
39       
40        button_OK = wx.Button(self, wx.ID_OK, "OK")
41        button_Cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
42       
43        sizer_button = wx.BoxSizer(wx.HORIZONTAL)
44        sizer_button.Add((20, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
45        sizer_button.Add(button_OK, 0, wx.LEFT|wx.ADJUST_MINSIZE, 10)
46        sizer_button.Add(button_Cancel, 0, wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)       
47        vbox.Add(sizer_button, 0, wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
48
49        self.SetSizer(vbox)
50        self.SetAutoLayout(True)
51       
52        self.Layout()
53        self.Centre()
54
55    def get_content(self):
56        dataset = self.datasets.get_selected()
57        if self.pars_flag:
58            nfunc, alpha, dmax, file = self.pars.getContent()
59            return dataset, nfunc, alpha, dmax
60        else:
61            return dataset
62   
63    def set_content(self, dataset, nfunc, alpha, dmax):
64        if not dataset==None and dataset in self.datasets.radio_buttons.keys():
65            self.datasets.radio_buttons[dataset].SetValue(True)
66        if self.pars_flag:
67            self.pars.setContent(nfunc, alpha, dmax, None)
68
69class InversionPanel(wx.Panel):
70   
71    def __init__(self, parent, id = -1, plots = None, **kwargs):
72        wx.Panel.__init__(self, parent, id = id, **kwargs)
73       
74        self.plots = plots
75        self.radio_buttons = {}
76       
77        self._do_layout()
78       
79    def _do_layout(self):
80        panel = wx.Panel(self, -1)
81        vbox = wx.BoxSizer(wx.VERTICAL)
82
83        ysize = 30+20*len(self.plots)
84        wx.StaticBox(panel, -1, 'Choose a data set', (5, 5), (230, ysize))
85        ypos = 30
86        self.radio_buttons = {}
87        for item in self.plots.keys():
88            self.radio_buttons[self.plots[item].name] = wx.RadioButton(panel, -1, self.plots[item].name, (15, ypos))
89            ypos += 20
90       
91        vbox.Add(panel)
92
93        self.SetSizer(vbox)
94       
95    def get_selected(self):
96        for item in self.radio_buttons:
97            if self.radio_buttons[item].GetValue():
98                return item
99        return None
100
101class InversionControl(wx.Panel):
102    window_name = 'pr_control'
103    window_caption = "P(r) control panel"
104    CENTER_PANE = True
105   
106    # Figure of merit parameters [default]
107   
108    ## Oscillation parameters (sin function = 1.1)
109    oscillation_max = 1.5
110   
111    ## Fraction of P(r) that is positive
112    positive = 1.0
113   
114    ## Fraction of P(r) that is greater than zero by more than 1 sigma
115    pos_err  = 1.0
116   
117    def __init__(self, parent, id = -1, plots = None, standalone=False, **kwargs):
118        wx.Panel.__init__(self, parent, id = id, **kwargs)
119       
120        self.plots = plots
121        self.radio_buttons = {}
122       
123        ## Data file TextCtrl
124        self.data_file  = None
125        self.plot_data  = None
126        self.nfunc_ctl  = None
127        self.alpha_ctl  = None
128        self.dmax_ctl   = None
129        self.time_ctl   = None
130        self.chi2_ctl   = None
131        self.osc_ctl    = None
132        self.file_radio = None
133        self.plot_radio = None
134        self.label_sugg = None
135        self.qmin_ctl   = None
136        self.qmax_ctl   = None
137       
138        self.rg_ctl     = None
139        self.iq0_ctl    = None
140        self.bck_chk    = None
141        self.bck_ctl    = None
142       
143        # TextCtrl for fraction of positive P(r)
144        self.pos_ctl = None
145       
146        # TextCtrl for fraction of 1 sigma positive P(r)
147        self.pos_err_ctl = None 
148       
149        ## Estimates
150        self.alpha_estimate_ctl = None
151        self.nterms_estimate_ctl = None
152       
153        ## Data manager
154        self.manager   = None
155       
156        ## Standalone flage
157        self.standalone = standalone
158       
159        self._do_layout()
160       
161    def __setattr__(self, name, value):
162        """
163            Allow direct hooks to text boxes
164        """
165        if name=='nfunc':
166            self.nfunc_ctl.SetValue(str(value))
167        elif name=='d_max':
168            self.dmax_ctl.SetValue(str(value))
169        elif name=='alpha':
170            self.alpha_ctl.SetValue(str(value))
171        elif name=='chi2':
172            self.chi2_ctl.SetValue("%-5.2g" % value)
173        elif name=='bck':
174            self.bck_ctl.SetValue("%-5.2g" % value)
175        elif name=='q_min':
176            self.qmin_ctl.SetValue("%-5.2g" % value)
177        elif name=='q_max':
178            self.qmax_ctl.SetValue("%-5.2g" % value)
179        elif name=='elapsed':
180            self.time_ctl.SetValue("%-5.2g" % value)
181        elif name=='rg':
182            self.rg_ctl.SetValue("%-5.2g" % value)
183        elif name=='iq0':
184            self.iq0_ctl.SetValue("%-5.2g" % value)
185        elif name=='oscillation':
186            self.osc_ctl.SetValue("%-5.2g" % value)
187        elif name=='positive':
188            self.pos_ctl.SetValue("%-5.2g" % value)
189        elif name=='pos_err':
190            self.pos_err_ctl.SetValue("%-5.2g" % value)
191        elif name=='alpha_estimate':
192            self.alpha_estimate_ctl.SetToolTipString("Click to accept value.")
193            self.alpha_estimate_ctl.Enable(True)
194            self.alpha_estimate_ctl.SetLabel("%-3.1g" % value)
195            #self.alpha_estimate_ctl.Show()
196            #self.label_sugg.Show()
197        elif name=='nterms_estimate':
198            self.nterms_estimate_ctl.SetToolTipString("Click to accept value.")
199            self.nterms_estimate_ctl.Enable(True)
200            self.nterms_estimate_ctl.SetLabel("%-g" % value)
201        elif name=='plotname':
202            if self.standalone==False:
203                self.plot_data.SetValue(str(value))
204                self.plot_radio.SetValue(True)
205                self._on_pars_changed(None)
206        elif name=='datafile':
207            self.data_file.SetValue(str(value))
208            self.file_radio.SetValue(True)
209            self._on_pars_changed(None)
210        else:
211            wx.Panel.__setattr__(self, name, value)
212       
213    def __getattr__(self, name):
214        """
215            Allow direct hooks to text boxes
216        """
217        if name=='nfunc':
218            try:
219                return int(self.nfunc_ctl.GetValue())
220            except:
221                return -1
222        elif name=='d_max':
223            try:
224                return self.dmax_ctl.GetValue()
225            except:
226                return -1.0
227        elif name=='alpha':
228            try:
229                return self.alpha_ctl.GetValue()
230            except:
231                return -1.0
232        elif name=='chi2':
233            try:
234                return float(self.chi2_ctl.GetValue())
235            except:
236                return -1.0
237        elif name=='bck':
238            try:
239                return float(self.bck_ctl.GetValue())
240            except:
241                return -1.0
242        elif name=='q_min':
243            try:
244                return float(self.qmin_ctl.GetValue())
245            except:
246                return 0.0
247        elif name=='q_max':
248            try:
249                return float(self.qmax_ctl.GetValue())
250            except:
251                return 0.0
252        elif name=='elapsed':
253            try:
254                return float(self.time_ctl.GetValue())
255            except:
256                return -1.0
257        elif name=='rg':
258            try:
259                return float(self.rg_ctl.GetValue())
260            except:
261                return -1.0
262        elif name=='iq0':
263            try:
264                return float(self.iq0_ctl.GetValue())
265            except:
266                return -1.0
267        elif name=='oscillation':
268            try:
269                return float(self.osc_ctl.GetValue())
270            except:
271                return -1.0
272        elif name=='pos':
273            try:
274                return float(self.pos_ctl.GetValue())
275            except:
276                return -1.0
277        elif name=='pos_err':
278            return self.pos_err_ctl.GetValue()
279        elif name=='alpha_estimate':
280            return self.alpha_estimate_ctl.GetLabel()
281        elif name=='nterms_estimate':
282            return self.nterms_estimate_ctl.GetLabel()
283        elif name=='plotname':
284            if self.standalone==False:
285                return self.plot_data.GetValue()
286        elif name=='datafile':
287            return self.data_file.GetValue()
288        else:
289            wx.Panel.__getattr__(self, name)
290       
291    def set_manager(self, manager):
292        self.manager = manager
293        # Get data
294       
295        # Push data to form
296       
297       
298    def _do_layout(self):
299        #panel = wx.Panel(self, -1)
300        vbox = wx.BoxSizer(wx.VERTICAL)
301
302        # ----- I(q) data -----
303        databox = wx.StaticBox(self, -1, "I(q) data source")
304       
305        boxsizer1 = wx.StaticBoxSizer(databox, wx.VERTICAL)
306        boxsizer1.SetMinSize((320,50))
307        pars_sizer = wx.GridBagSizer(5,5)
308
309        iy = 0
310        if self.standalone==False:
311            self.file_radio = wx.RadioButton(self, -1, "File data:")
312        else:
313            self.file_radio = wx.StaticText(self, -1, "Data file:")
314        self.data_file = wx.TextCtrl(self, -1, size=(100,20))
315        self.data_file.SetEditable(False)
316        self.data_file.SetValue("")
317        id = wx.NewId()
318        choose_button = wx.Button(self, id, "Choose file")
319        self.Bind(wx.EVT_BUTTON, self._change_file, id = id)   
320        pars_sizer.Add(self.file_radio, (iy,0), (1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
321        #pars_sizer.Add(self.data_file, (iy,1), (1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 15)
322        pars_sizer.Add(self.data_file, (iy,1), (1,1), wx.ADJUST_MINSIZE, 15)
323        pars_sizer.Add(choose_button, (iy,3), (1,1), wx.RIGHT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
324       
325        if self.standalone==False:
326            iy += 1
327            self.plot_radio = wx.RadioButton(self, -1, "Plot data:")
328            self.plot_data = wx.TextCtrl(self, -1, size=(100,20))
329            self.plot_data.SetEditable(False)
330            pars_sizer.Add(self.plot_radio, (iy,0), (1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
331            pars_sizer.Add(self.plot_data, (iy,1), (1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 15)
332       
333        self.bck_chk = wx.CheckBox(self, -1, "Estimate background level")
334        self.bck_chk.SetToolTipString("Check box to let the fit estimate the constant background level.")
335        self.bck_chk.Bind(wx.EVT_CHECKBOX, self._on_pars_changed)
336        iy += 1
337        pars_sizer.Add(self.bck_chk, (iy,0), (1,2), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
338        boxsizer1.Add(pars_sizer, 0, wx.EXPAND) 
339        vbox.Add(boxsizer1)
340       
341        # ----- Add slit parameters -----
342        if False:
343            sbox = wx.StaticBox(self, -1, "Slit parameters")
344            sboxsizer = wx.StaticBoxSizer(sbox, wx.VERTICAL)
345            sboxsizer.SetMinSize((320,20))
346           
347            sizer_slit = wx.GridBagSizer(5,5)
348   
349            label_sheight = wx.StaticText(self, -1, "Height")
350            label_swidth = wx.StaticText(self, -1, "Width")
351            #label_sunits1 = wx.StaticText(self, -1, "[A^(-1)]")
352            label_sunits2 = wx.StaticText(self, -1, "[A^(-1)]")
353            self.sheight_ctl = wx.TextCtrl(self, -1, size=(60,20))
354            self.swidth_ctl = wx.TextCtrl(self, -1, size=(60,20))
355            self.sheight_ctl.SetToolTipString("Enter slit height in units of Q or leave blank.")
356            self.swidth_ctl.SetToolTipString("Enter slit width in units of Q or leave blank.")
357            self.sheight_ctl.Bind(wx.EVT_TEXT, self._on_pars_changed)
358            self.swidth_ctl.Bind(wx.EVT_TEXT,  self._on_pars_changed)
359           
360            iy = 0
361            sizer_slit.Add(label_sheight,    (iy,0), (1,1), wx.LEFT|wx.EXPAND, 15)
362            sizer_slit.Add(self.sheight_ctl, (iy,1), (1,1), wx.LEFT|wx.EXPAND, 10)
363            #sizer_slit.Add(label_sunits1,    (iy,2), (1,1), wx.LEFT|wx.EXPAND, 10)
364            sizer_slit.Add(label_swidth,     (iy,2), (1,1), wx.LEFT|wx.EXPAND, 15)
365            sizer_slit.Add(self.swidth_ctl,  (iy,3), (1,1), wx.LEFT|wx.EXPAND, 10)
366            sizer_slit.Add(label_sunits2,    (iy,4), (1,1), wx.LEFT|wx.EXPAND, 10)
367           
368            sboxsizer.Add(sizer_slit, wx.TOP, 15)
369            vbox.Add(sboxsizer)
370       
371
372        # ----- Parameters -----
373        parsbox = wx.StaticBox(self, -1, "Parameters")
374        boxsizer2 = wx.StaticBoxSizer(parsbox, wx.VERTICAL)
375        boxsizer2.SetMinSize((320,50))
376       
377        explanation  = "P(r) is found by fitting a set of base functions to I(Q). "
378        explanation += "The minimization involves a regularization term to ensure "
379        explanation += "a smooth P(r). The alpha parameter gives the size of that " 
380        explanation += "term. The suggested value is the value above which the "
381        explanation += "output P(r) will have only one peak."
382        label_explain = wx.StaticText(self, -1, explanation, size=(280,80))
383        boxsizer2.Add(label_explain,  wx.LEFT|wx.BOTTOM, 5)
384       
385       
386       
387        label_nfunc = wx.StaticText(self, -1, "Number of terms")
388        label_nfunc.SetMinSize((120,20))
389        label_alpha = wx.StaticText(self, -1, "Regularization constant")
390        label_dmax  = wx.StaticText(self, -1, "Max distance [A]")
391        self.label_sugg  = wx.StaticText(self, -1, "Suggested value")
392        #self.label_sugg.Hide()
393       
394        self.nfunc_ctl = wx.TextCtrl(self, -1, size=(60,20))
395        self.nfunc_ctl.SetToolTipString("Number of terms in the expansion.")
396        self.alpha_ctl = wx.TextCtrl(self, -1, size=(60,20))
397        self.alpha_ctl.SetToolTipString("Control parameter for the size of the regularization term.")
398        self.dmax_ctl  = wx.TextCtrl(self, -1, size=(60,20))
399        self.dmax_ctl.SetToolTipString("Maximum distance between any two points in the system.")
400        id = wx.NewId()
401        self.alpha_estimate_ctl  = wx.Button(self, id, "")
402        #self.alpha_estimate_ctl.Hide()
403        self.Bind(wx.EVT_BUTTON, self._on_accept_alpha, id = id)   
404        self.alpha_estimate_ctl.Enable(False)
405        #self.alpha_estimate_ctl.SetBackgroundColour('#ffdf85')
406        #self.alpha_estimate_ctl.SetBackgroundColour(self.GetBackgroundColour())
407        self.alpha_estimate_ctl.SetToolTipString("Waiting for estimate...")
408       
409        id = wx.NewId()
410        self.nterms_estimate_ctl  = wx.Button(self, id, "")
411        #self.nterms_estimate_ctl.Hide()
412        self.Bind(wx.EVT_BUTTON, self._on_accept_nterms, id = id)   
413        self.nterms_estimate_ctl.Enable(False)
414        #self.nterms_estimate_ctl.SetBackgroundColour('#ffdf85')
415        #self.nterms_estimate_ctl.SetBackgroundColour(self.GetBackgroundColour())
416        self.nterms_estimate_ctl.SetToolTipString("Waiting for estimate...")
417       
418        # EVT_TEXT would trigger an event for each character entered
419        #self.nfunc_ctl.Bind(wx.EVT_KILL_FOCUS, self._on_pars_changed)
420        #self.alpha_ctl.Bind(wx.EVT_KILL_FOCUS, self._read_pars)
421        #self.dmax_ctl.Bind(wx.EVT_KILL_FOCUS, self._on_pars_changed)
422        #self.dmax_ctl.Bind(wx.EVT_TEXT_ENTER, self._on_pars_changed)
423        #self.Bind(wx.EVT_TEXT_ENTER, self._on_pars_changed)
424       
425        self.nfunc_ctl.Bind(wx.EVT_TEXT, self._on_pars_changed)
426        self.alpha_ctl.Bind(wx.EVT_TEXT, self._read_pars)
427        self.dmax_ctl.Bind(wx.EVT_TEXT, self._on_pars_changed)
428       
429       
430       
431        sizer_params = wx.GridBagSizer(5,5)
432
433        iy = 0
434        sizer_params.Add(self.label_sugg,       (iy,2), (1,1), wx.LEFT, 15)
435        iy += 1
436        sizer_params.Add(label_nfunc,      (iy,0), (1,1), wx.LEFT, 15)
437        sizer_params.Add(self.nfunc_ctl,   (iy,1), (1,1), wx.RIGHT, 0)
438        sizer_params.Add(self.nterms_estimate_ctl, (iy,2), (1,1), wx.LEFT, 15)
439        iy += 1
440        sizer_params.Add(label_alpha,      (iy,0), (1,1), wx.LEFT, 15)
441        sizer_params.Add(self.alpha_ctl,   (iy,1), (1,1), wx.RIGHT, 0)
442        sizer_params.Add(self.alpha_estimate_ctl, (iy,2), (1,1), wx.LEFT, 15)
443        iy += 1
444        sizer_params.Add(label_dmax, (iy,0), (1,1), wx.LEFT, 15)
445        sizer_params.Add(self.dmax_ctl,   (iy,1), (1,1), wx.RIGHT, 0)
446
447        boxsizer2.Add(sizer_params, 0)
448       
449        vbox.Add(boxsizer2)
450
451        # ----- Q range -----
452        qbox = wx.StaticBox(self, -1, "Q range")
453        qboxsizer = wx.StaticBoxSizer(qbox, wx.VERTICAL)
454        qboxsizer.SetMinSize((320,20))
455       
456        sizer_q = wx.GridBagSizer(5,5)
457
458        label_qmin = wx.StaticText(self, -1, "Q min")
459        label_qmax = wx.StaticText(self, -1, "Q max")
460        #label_qunits1 = wx.StaticText(self, -1, "[A^(-1)]")
461        label_qunits2 = wx.StaticText(self, -1, "[A^(-1)]")
462        self.qmin_ctl = wx.TextCtrl(self, -1, size=(60,20))
463        self.qmax_ctl = wx.TextCtrl(self, -1, size=(60,20))
464        self.qmin_ctl.SetToolTipString("Select a lower bound for Q or leave blank.")
465        self.qmax_ctl.SetToolTipString("Select an upper bound for Q or leave blank.")
466        self.qmin_ctl.Bind(wx.EVT_TEXT, self._on_pars_changed)
467        self.qmax_ctl.Bind(wx.EVT_TEXT, self._on_pars_changed)
468       
469        iy = 0
470        sizer_q.Add(label_qmin,    (iy,0), (1,1), wx.LEFT|wx.EXPAND, 15)
471        sizer_q.Add(self.qmin_ctl, (iy,1), (1,1), wx.LEFT|wx.EXPAND, 10)
472        #sizer_q.Add(label_qunits1, (iy,2), (1,1), wx.LEFT|wx.EXPAND, 15)
473        sizer_q.Add(label_qmax,    (iy,2), (1,1), wx.LEFT|wx.EXPAND, 15)
474        sizer_q.Add(self.qmax_ctl, (iy,3), (1,1), wx.LEFT|wx.EXPAND, 10)
475        sizer_q.Add(label_qunits2, (iy,4), (1,1), wx.LEFT|wx.EXPAND, 15)
476        qboxsizer.Add(sizer_q, wx.TOP, 15)
477        vbox.Add(qboxsizer)
478       
479       
480
481        # ----- Results -----
482        resbox = wx.StaticBox(self, -1, "Outputs")
483        ressizer = wx.StaticBoxSizer(resbox, wx.VERTICAL)
484        ressizer.SetMinSize((320,50))
485       
486        label_rg       = wx.StaticText(self, -1, "Rg")
487        label_rg_unit  = wx.StaticText(self, -1, "[A]")
488        label_iq0      = wx.StaticText(self, -1, "I(Q=0)")
489        label_iq0_unit = wx.StaticText(self, -1, "[A^(-1)]")
490        label_bck      = wx.StaticText(self, -1, "Background")
491        label_bck_unit = wx.StaticText(self, -1, "[A^(-1)]")
492        self.rg_ctl    = wx.TextCtrl(self, -1, size=(60,20))
493        self.rg_ctl.SetEditable(False)
494        self.rg_ctl.SetToolTipString("Radius of gyration for the computed P(r).")
495        self.iq0_ctl   = wx.TextCtrl(self, -1, size=(60,20))
496        self.iq0_ctl.SetEditable(False)
497        self.iq0_ctl.SetToolTipString("Scattering intensity at Q=0 for the computed P(r).")
498        self.bck_ctl   = wx.TextCtrl(self, -1, size=(60,20))
499        self.bck_ctl.SetEditable(False)
500        self.bck_ctl.SetToolTipString("Value of estimated constant background.")
501       
502        label_time = wx.StaticText(self, -1, "Computation time")
503        label_time_unit = wx.StaticText(self, -1, "secs")
504        label_time.SetMinSize((120,20))
505        label_chi2 = wx.StaticText(self, -1, "Chi2/dof")
506        label_osc = wx.StaticText(self, -1, "Oscillations")
507        label_pos = wx.StaticText(self, -1, "Positive fraction")
508        label_pos_err = wx.StaticText(self, -1, "1-sigma positive fraction")
509       
510        self.time_ctl = wx.TextCtrl(self, -1, size=(60,20))
511        self.time_ctl.SetEditable(False)
512        self.time_ctl.SetToolTipString("Computation time for the last inversion, in seconds.")
513       
514        self.chi2_ctl = wx.TextCtrl(self, -1, size=(60,20))
515        self.chi2_ctl.SetEditable(False)
516        self.chi2_ctl.SetToolTipString("Chi^2 over degrees of freedom.")
517       
518        # Oscillation parameter
519        self.osc_ctl = wx.TextCtrl(self, -1, size=(60,20))
520        self.osc_ctl.SetEditable(False)
521        self.osc_ctl.SetToolTipString("Oscillation parameter. P(r) for a sphere has an oscillation parameter of 1.1.")
522       
523        # Positive fraction figure of merit
524        self.pos_ctl = wx.TextCtrl(self, -1, size=(60,20))
525        self.pos_ctl.SetEditable(False)
526        self.pos_ctl.SetToolTipString("Fraction of P(r) that is positive. Theoretically, P(r) is defined positive.")
527       
528        # 1-simga positive fraction figure of merit
529        self.pos_err_ctl = wx.TextCtrl(self, -1, size=(60,20))
530        self.pos_err_ctl.SetEditable(False)
531        message  = "Fraction of P(r) that is at least 1 standard deviation greater than zero.\n"
532        message += "This figure of merit tells you about the size of the P(r) errors.\n"
533        message += "If it is close to 1 and the other figures of merit are bad, consider changing "
534        message += "the maximum distance."
535        self.pos_err_ctl.SetToolTipString(message)
536       
537        sizer_res = wx.GridBagSizer(5,5)
538
539        iy = 0
540        sizer_res.Add(label_rg, (iy,0), (1,1), wx.LEFT|wx.EXPAND, 15)
541        sizer_res.Add(self.rg_ctl,   (iy,1), (1,1), wx.RIGHT|wx.EXPAND, 15)
542        sizer_res.Add(label_rg_unit,   (iy,2), (1,1), wx.RIGHT|wx.EXPAND, 15)
543        iy += 1
544        sizer_res.Add(label_iq0, (iy,0), (1,1), wx.LEFT|wx.EXPAND, 15)
545        sizer_res.Add(self.iq0_ctl,   (iy,1), (1,1), wx.RIGHT|wx.EXPAND, 15)
546        sizer_res.Add(label_iq0_unit,   (iy,2), (1,1), wx.RIGHT|wx.EXPAND, 15)
547        iy += 1
548        sizer_res.Add(label_bck, (iy,0), (1,1), wx.LEFT|wx.EXPAND, 15)
549        sizer_res.Add(self.bck_ctl,   (iy,1), (1,1), wx.RIGHT|wx.EXPAND, 15)
550        sizer_res.Add(label_bck_unit,   (iy,2), (1,1), wx.RIGHT|wx.EXPAND, 15)
551        iy += 1
552        sizer_res.Add(label_time, (iy,0), (1,1), wx.LEFT|wx.EXPAND, 15)
553        sizer_res.Add(self.time_ctl,   (iy,1), (1,1), wx.RIGHT|wx.EXPAND, 15)
554        sizer_res.Add(label_time_unit,   (iy,2), (1,1), wx.RIGHT|wx.EXPAND, 15)
555        iy += 1
556        sizer_res.Add(label_chi2, (iy,0), (1,1), wx.LEFT|wx.EXPAND, 15)
557        sizer_res.Add(self.chi2_ctl,   (iy,1), (1,1), wx.RIGHT|wx.EXPAND, 15)
558        iy += 1
559        sizer_res.Add(label_osc, (iy,0), (1,1), wx.LEFT|wx.EXPAND, 15)
560        sizer_res.Add(self.osc_ctl,   (iy,1), (1,1), wx.RIGHT|wx.EXPAND, 15)
561
562        iy += 1
563        sizer_res.Add(label_pos, (iy,0), (1,1), wx.LEFT|wx.EXPAND, 15)
564        sizer_res.Add(self.pos_ctl,   (iy,1), (1,1), wx.RIGHT|wx.EXPAND, 15)
565
566        iy += 1
567        sizer_res.Add(label_pos_err, (iy,0), (1,1), wx.LEFT|wx.EXPAND, 15)
568        sizer_res.Add(self.pos_err_ctl,   (iy,1), (1,1), wx.RIGHT|wx.EXPAND, 15)
569
570        ressizer.Add(sizer_res, 0)
571        vbox.Add(ressizer)
572
573        # ----- Buttons -----
574        static_line = wx.StaticLine(self, -1)
575        vbox.Add(static_line, 0, wx.EXPAND|wx.TOP, 10)
576       
577        id = wx.NewId()
578        button_OK = wx.Button(self, id, "Compute")
579        button_OK.SetToolTipString("Perform P(r) inversion.")
580        self.Bind(wx.EVT_BUTTON, self._on_invert, id = id)   
581       
582        id = wx.NewId()
583        button_Reset = wx.Button(self, id, "Reset")
584        button_Reset.SetToolTipString("Reset inversion parameters to default.")
585        self.Bind(wx.EVT_BUTTON, self._on_reset, id = id)   
586        #button_Cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
587       
588        sizer_button = wx.BoxSizer(wx.HORIZONTAL)
589        sizer_button.Add((20, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
590        sizer_button.Add(button_Reset, 0, wx.LEFT|wx.ADJUST_MINSIZE, 10)
591        sizer_button.Add(button_OK, 0, wx.LEFT|wx.ADJUST_MINSIZE, 10)
592        #sizer_button.Add(button_Cancel, 0, wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)       
593        vbox.Add(sizer_button, 0, wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
594
595
596        self.SetSizer(vbox)
597       
598    def _on_accept_alpha(self, evt):
599        """
600            User has accepted the estimated alpha,
601            set it as part of the input parameters
602        """
603        try:
604            alpha = self.alpha_estimate_ctl.GetLabel()
605            tmp = float(alpha)
606            self.alpha_ctl.SetValue(alpha)
607        except:
608            # No estimate or bad estimate, either do nothing
609            import sys
610            print "InversionControl._on_accept_alpha: %s" % sys.exc_value
611            pass
612   
613    def _on_accept_nterms(self, evt):
614        """
615            User has accepted the estimated number of terms,
616            set it as part of the input parameters
617        """
618        try:
619            nterms = self.nterms_estimate_ctl.GetLabel()
620            tmp = float(nterms)
621            self.nfunc_ctl.SetValue(nterms)
622        except:
623            # No estimate or bad estimate, either do nothing
624            import sys
625            print "InversionControl._on_accept_nterms: %s" % sys.exc_value
626            pass
627       
628    def _on_reset(self, evt):
629        """
630            Resets inversion parameters
631        """
632        self.nfunc = self.manager.DEFAULT_NFUNC
633        self.d_max = self.manager.DEFAULT_DMAX
634        self.alpha = self.manager.DEFAULT_ALPHA
635        self.qmin_ctl.SetValue("")
636        self.qmax_ctl.SetValue("")
637        self.time_ctl.SetValue("")
638        self.rg_ctl.SetValue("")
639        self.iq0_ctl.SetValue("")
640        self.bck_ctl.SetValue("")
641        self.chi2_ctl.SetValue("")
642        self.osc_ctl.SetValue("")
643        self.pos_ctl.SetValue("")
644        self.pos_err_ctl.SetValue("")
645        self.alpha_estimate_ctl.Enable(False)
646        self.alpha_estimate_ctl.SetLabel("")
647        self.nterms_estimate_ctl.Enable(False)
648        self.nterms_estimate_ctl.SetLabel("")
649        self._on_pars_changed()
650       
651    def _on_pars_changed(self, evt=None):
652        """
653            Called when an input parameter has changed
654            We will estimate the alpha parameter behind the
655            scenes.
656        """
657        flag, alpha, dmax, nfunc, qmin, qmax = self._read_pars()
658        has_bck = self.bck_chk.IsChecked()
659       
660        # If the pars are valid, estimate alpha
661        if flag:
662            if self.standalone==False and self.plot_radio.GetValue():
663                dataset = self.plot_data.GetValue()
664                self.manager.estimate_plot_inversion(alpha=alpha, nfunc=nfunc, 
665                                                     d_max=dmax,
666                                                     q_min=qmin, q_max=qmax,
667                                                     bck=has_bck)
668            else:
669                path = self.data_file.GetValue()
670                self.manager.estimate_file_inversion(alpha=alpha, nfunc=nfunc, 
671                                                     d_max=dmax, path=path,
672                                                     q_min=qmin, q_max=qmax,
673                                                     bck=has_bck)
674       
675       
676    def _read_pars(self, evt=None):   
677        alpha = 0
678        nfunc = 5
679        dmax  = 120
680        qmin  = 0
681        qmax  = 0
682       
683        flag = True
684       
685        # Read alpha
686        try:
687            alpha = float(self.alpha_ctl.GetValue())
688            self.alpha_ctl.SetBackgroundColour(wx.WHITE)
689            self.alpha_ctl.Refresh()
690        except:
691            flag = False
692            self.alpha_ctl.SetBackgroundColour("pink")
693            self.alpha_ctl.Refresh()
694       
695        # Read d_max   
696        try:
697            dmax = float(self.dmax_ctl.GetValue())
698            self.dmax_ctl.SetBackgroundColour(wx.WHITE)
699            self.dmax_ctl.Refresh()
700        except:
701            flag = False
702            self.dmax_ctl.SetBackgroundColour("pink")
703            self.dmax_ctl.Refresh()
704           
705        # Read nfunc
706        try:
707            nfunc = int(self.nfunc_ctl.GetValue())
708            npts = self.manager.get_npts()
709            if npts>0 and nfunc>npts:
710                message = "Number of function terms should be smaller than the number of points"
711                wx.PostEvent(self.manager.parent, StatusEvent(status=message))
712                raise ValueError, message
713            self.nfunc_ctl.SetBackgroundColour(wx.WHITE)
714            self.nfunc_ctl.Refresh()
715        except:
716            flag = False
717            self.nfunc_ctl.SetBackgroundColour("pink")
718            self.nfunc_ctl.Refresh()
719       
720        # Read qmin
721        try:
722            qmin_str = self.qmin_ctl.GetValue()
723            if len(qmin_str.lstrip().rstrip())==0:
724                qmin = None
725            else:
726                qmin = float(qmin_str)
727                self.qmin_ctl.SetBackgroundColour(wx.WHITE)
728                self.qmin_ctl.Refresh()
729        except:
730            flag = False
731            self.qmin_ctl.SetBackgroundColour("pink")
732            self.qmin_ctl.Refresh()
733       
734        # Read qmax
735        try:
736            qmax_str = self.qmax_ctl.GetValue()
737            if len(qmax_str.lstrip().rstrip())==0:
738                qmax = None
739            else:
740                qmax = float(qmax_str)
741                self.qmax_ctl.SetBackgroundColour(wx.WHITE)
742                self.qmax_ctl.Refresh()
743        except:
744            flag = False
745            self.qmax_ctl.SetBackgroundColour("pink")
746            self.qmax_ctl.Refresh()
747       
748        return flag, alpha, dmax, nfunc, qmin, qmax
749   
750    def _on_invert(self, evt):
751        """
752            Perform inversion
753            @param silent: when True, there will be no output for the user
754        """
755        # Get the data from the form
756        # Push it to the manager
757       
758        flag, alpha, dmax, nfunc, qmin, qmax = self._read_pars()
759        has_bck = self.bck_chk.IsChecked()
760       
761        if flag:
762            if self.standalone==False and self.plot_radio.GetValue():
763                dataset = self.plot_data.GetValue()
764                if len(dataset.strip())==0:
765                    message = "No data to invert. Select a data set before proceeding with P(r) inversion."
766                    wx.PostEvent(self.manager.parent, StatusEvent(status=message))
767                else:
768                    self.manager.setup_plot_inversion(alpha=alpha, nfunc=nfunc, 
769                                                      d_max=dmax,
770                                                      q_min=qmin, q_max=qmax,
771                                                      bck=has_bck)
772            else:
773                path = self.data_file.GetValue()
774                if len(path.strip())==0:
775                    message = "No data to invert. Select a data set before proceeding with P(r) inversion."
776                    wx.PostEvent(self.manager.parent, StatusEvent(status=message))
777                else:
778                    self.manager.setup_file_inversion(alpha=alpha, nfunc=nfunc, 
779                                                      d_max=dmax, path=path,
780                                                      q_min=qmin, q_max=qmax,
781                                                      bck=has_bck)
782               
783        else:
784            message = "The P(r) form contains invalid values: please submit it again."
785            wx.PostEvent(self.parent, StatusEvent(status=message))
786       
787    def _change_file(self, evt):
788        """
789            Choose a new input file for I(q)
790        """
791        import os
792        if not self.manager==None:
793            path = self.manager.choose_file()
794           
795            if path and os.path.isfile(path):
796                self.data_file.SetValue(str(path))
797                if self.standalone==False:
798                    self.file_radio.SetValue(True)
799                self._on_pars_changed(None)
800                self.manager.show_data(path)
801       
802
803
804
805class HelpDialog(wx.Dialog):
806    def __init__(self, parent, id):
807        from sans.pr.invertor import help
808        wx.Dialog.__init__(self, parent, id, size=(400, 420))
809        self.SetTitle("P(r) help") 
810       
811
812        vbox = wx.BoxSizer(wx.VERTICAL)
813
814        explanation = help()
815           
816        label_explain = wx.StaticText(self, -1, explanation, size=(350,320))
817           
818        vbox.Add(label_explain, 0, wx.ALL|wx.EXPAND, 15)
819
820
821        static_line = wx.StaticLine(self, -1)
822        vbox.Add(static_line, 0, wx.EXPAND, 0)
823       
824        button_OK = wx.Button(self, wx.ID_OK, "OK")
825        #button_Cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
826       
827        sizer_button = wx.BoxSizer(wx.HORIZONTAL)
828        sizer_button.Add((20, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
829        sizer_button.Add(button_OK, 0, wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)
830        #sizer_button.Add(button_Cancel, 0, wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)       
831        vbox.Add(sizer_button, 0, wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
832
833        self.SetSizer(vbox)
834        self.SetAutoLayout(True)
835       
836        self.Layout()
837        self.Centre()
838
839class PrDistDialog(wx.Dialog):
840    """
841        Property dialog to let the user change the number
842        of points on the P(r) plot.
843    """
844    def __init__(self, parent, id):
845        from sans.pr.invertor import help
846        wx.Dialog.__init__(self, parent, id, size=(250, 120))
847        self.SetTitle("P(r) distribution") 
848       
849
850        vbox = wx.BoxSizer(wx.VERTICAL)
851       
852        label_npts = wx.StaticText(self, -1, "Number of points")
853        self.npts_ctl = wx.TextCtrl(self, -1, size=(100,20))
854                 
855        pars_sizer = wx.GridBagSizer(5,5)
856        iy = 0
857        pars_sizer.Add(label_npts,      (iy,0), (1,1), wx.LEFT, 15)
858        pars_sizer.Add(self.npts_ctl,   (iy,1), (1,1), wx.RIGHT, 0)
859       
860        vbox.Add(pars_sizer, 0, wx.ALL|wx.EXPAND, 15)
861
862
863        static_line = wx.StaticLine(self, -1)
864        vbox.Add(static_line, 0, wx.EXPAND, 0)
865       
866        button_OK = wx.Button(self, wx.ID_OK, "OK")
867        self.Bind(wx.EVT_BUTTON, self._checkValues, button_OK)
868        button_Cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
869       
870        sizer_button = wx.BoxSizer(wx.HORIZONTAL)
871        sizer_button.Add((20, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
872        sizer_button.Add(button_OK, 0, wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)
873        sizer_button.Add(button_Cancel, 0, wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)       
874        vbox.Add(sizer_button, 0, wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
875
876        self.SetSizer(vbox)
877        self.SetAutoLayout(True)
878       
879        self.Layout()
880        self.Centre()
881
882    def _checkValues(self, event):
883        """
884            Check the dialog content.
885        """
886        flag = True
887        try:
888            int(self.npts_ctl.GetValue())
889            self.npts_ctl.SetBackgroundColour(wx.WHITE)
890            self.npts_ctl.Refresh()
891        except:
892            flag = False
893            self.npts_ctl.SetBackgroundColour("pink")
894            self.npts_ctl.Refresh()
895        if flag:
896            event.Skip(True)
897
898    def get_content(self):
899        """
900            Return the content of the dialog.
901            At this point the values have already been
902            checked.
903        """
904        value = int(self.npts_ctl.GetValue())
905        return value
906   
907    def set_content(self, npts):
908        """
909            Initialize the content of the dialog.
910        """
911        self.npts_ctl.SetValue("%i" % npts)
912
913
914class ParsDialog(wx.Panel):
915    """
916        Dialog box to let the user edit detector settings
917    """
918   
919    def __init__(self, parent, id = id, file=True, **kwargs):
920
921        wx.Panel.__init__(self, parent, id = id, **kwargs)
922        self.file = file
923       
924        self.label_nfunc = wx.StaticText(self, -1, "Number of terms")
925        self.label_alpha = wx.StaticText(self, -1, "Regularization constant")
926        self.label_dmax  = wx.StaticText(self, -1, "Max distance [A]")
927       
928        # Npts, q max
929        self.nfunc_ctl = wx.TextCtrl(self, -1, size=(60,20))
930        self.alpha_ctl = wx.TextCtrl(self, -1, size=(60,20))
931        self.dmax_ctl  = wx.TextCtrl(self, -1, size=(60,20))
932
933        self.label_file = None
934        self.file_ctl   = None
935
936        self.static_line_3 = wx.StaticLine(self, -1)
937       
938       
939
940        self.__do_layout()
941
942        self.Fit()
943       
944    def _load_file(self, evt):
945        import os
946        path = None
947        dlg = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.txt", wx.OPEN)
948        if dlg.ShowModal() == wx.ID_OK:
949            path = dlg.GetPath()
950            mypath = os.path.basename(path)
951        dlg.Destroy()
952       
953        if path and os.path.isfile(path):
954            self.file_ctl.SetValue(str(path))
955
956       
957    def checkValues(self, event):
958        flag = True
959        try:
960            float(self.alpha_ctl.GetValue())
961            self.alpha_ctl.SetBackgroundColour(wx.WHITE)
962            self.alpha_ctl.Refresh()
963        except:
964            flag = False
965            self.alpha_ctl.SetBackgroundColour("pink")
966            self.alpha_ctl.Refresh()
967           
968        try:
969            float(self.dmax_ctl.GetValue())
970            self.dmax_ctl.SetBackgroundColour(wx.WHITE)
971            self.dmax_ctl.Refresh()
972        except:
973            flag = False
974            self.dmax_ctl.SetBackgroundColour("pink")
975            self.dmax_ctl.Refresh()
976           
977        try:
978            int(self.nfunc_ctl.GetValue())
979            self.nfunc_ctl.SetBackgroundColour(wx.WHITE)
980            self.nfunc_ctl.Refresh()
981        except:
982            flag = False
983            self.nfunc_ctl.SetBackgroundColour("pink")
984            self.nfunc_ctl.Refresh()
985       
986        if flag:
987            event.Skip(True)
988   
989    def setContent(self, nfunc, alpha, dmax, file):
990        self.nfunc_ctl.SetValue(str(nfunc))
991        self.alpha_ctl.SetValue(str(alpha))
992        self.dmax_ctl.SetValue(str(dmax))
993        if self.file:
994            self.file_ctl.SetValue(str(file))
995
996    def getContent(self):
997        nfunc = int(self.nfunc_ctl.GetValue())
998        alpha = float(self.alpha_ctl.GetValue())
999        dmax = float(self.dmax_ctl.GetValue())
1000        file = None
1001        if self.file:
1002            file = self.file_ctl.GetValue()
1003        return nfunc, alpha, dmax, file
1004
1005
1006    def __do_layout(self):
1007        sizer_main = wx.BoxSizer(wx.VERTICAL)
1008        sizer_params = wx.GridBagSizer(5,5)
1009
1010        iy = 0
1011        sizer_params.Add(self.label_nfunc, (iy,0), (1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
1012        sizer_params.Add(self.nfunc_ctl,   (iy,1), (1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1013        iy += 1
1014        sizer_params.Add(self.label_alpha, (iy,0), (1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
1015        sizer_params.Add(self.alpha_ctl,   (iy,1), (1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1016        iy += 1
1017        sizer_params.Add(self.label_dmax, (iy,0), (1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
1018        sizer_params.Add(self.dmax_ctl,   (iy,1), (1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1019        iy += 1
1020        if self.file:
1021            self.label_file  = wx.StaticText(self, -1, "Input file")
1022            self.file_ctl  = wx.TextCtrl(self, -1, size=(120,20))
1023            sizer_params.Add(self.label_file, (iy,0), (1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
1024            sizer_params.Add(self.file_ctl,   (iy,1), (1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1025
1026        sizer_main.Add(sizer_params, 0, wx.EXPAND|wx.ALL, 10)
1027       
1028       
1029        if self.file:
1030            sizer_button = wx.BoxSizer(wx.HORIZONTAL)
1031            self.button_load = wx.Button(self, 1, "Choose file")
1032            self.Bind(wx.EVT_BUTTON, self._load_file, id = 1)       
1033            sizer_button.Add(self.button_load, 0, wx.LEFT|wx.ADJUST_MINSIZE, 10)
1034       
1035       
1036            sizer_main.Add(sizer_button, 0, wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
1037        self.SetAutoLayout(True)
1038        self.SetSizer(sizer_main)
1039        self.Layout()
1040        self.Centre()
1041        # end wxGlade
1042
1043
1044# end of class DialogAbout
1045
1046##### testing code ############################################################
1047class TestPlot:
1048    def __init__(self, text):
1049        self.name = text
1050   
1051class MyApp(wx.App):
1052    def OnInit(self):
1053        wx.InitAllImageHandlers()
1054        dialog = PrDistDialog(None, -1)
1055        if dialog.ShowModal() == wx.ID_OK:
1056            pass
1057        dialog.Destroy()
1058       
1059        return 1
1060
1061# end of class MyApp
1062
1063if __name__ == "__main__":
1064    app = MyApp(0)
1065    app.MainLoop()
1066   
1067##### end of testing code #####################################################   
Note: See TracBrowser for help on using the repository browser.