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

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 aa4b8379 was aa4b8379, checked in by Mathieu Doucet <doucetm@…>, 16 years ago

Updated for interactive graphs. Improved for standalone use.

  • Property mode set to 100644
File size: 32.7 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        # TextCtrl for fraction of positive P(r)
139        self.pos_ctl = None
140       
141        # TextCtrl for fraction of 1 sigma positive P(r)
142        self.pos_err_ctl = None 
143       
144        ## Estimates
145        self.alpha_estimate_ctl = None
146       
147        ## Data manager
148        self.manager   = None
149       
150        ## Standalone flage
151        self.standalone = standalone
152       
153        self._do_layout()
154       
155    def __setattr__(self, name, value):
156        """
157            Allow direct hooks to text boxes
158        """
159        if name=='nfunc':
160            self.nfunc_ctl.SetValue(str(value))
161        elif name=='d_max':
162            self.dmax_ctl.SetValue(str(value))
163        elif name=='alpha':
164            self.alpha_ctl.SetValue(str(value))
165        elif name=='chi2':
166            self.chi2_ctl.SetValue("%-5.3g" % value)
167        elif name=='q_min':
168            self.qmin_ctl.SetValue("%-5.3g" % value)
169        elif name=='q_max':
170            self.qmax_ctl.SetValue("%-5.3g" % value)
171        elif name=='elapsed':
172            self.time_ctl.SetValue("%-5.2g" % value)
173        elif name=='oscillation':
174            self.osc_ctl.SetValue("%-5.2g" % value)
175        elif name=='positive':
176            self.pos_ctl.SetValue("%-5.2g" % value)
177        elif name=='pos_err':
178            self.pos_err_ctl.SetValue("%-5.2g" % value)
179        elif name=='alpha_estimate':
180            self.alpha_estimate_ctl.SetToolTipString("Click to accept value.")
181            self.alpha_estimate_ctl.Enable(True)
182            self.alpha_estimate_ctl.SetLabel("%-3.1g" % value)
183            #self.alpha_estimate_ctl.Show()
184            #self.label_sugg.Show()
185        elif name=='plotname':
186            if self.standalone==False:
187                self.plot_data.SetValue(str(value))
188                self.plot_radio.SetValue(True)
189                self._on_pars_changed(None)
190        elif name=='datafile':
191            self.data_file.SetValue(str(value))
192            self.file_radio.SetValue(True)
193            self._on_pars_changed(None)
194        else:
195            wx.Panel.__setattr__(self, name, value)
196       
197    def __getattr__(self, name):
198        """
199            Allow direct hooks to text boxes
200        """
201        if name=='nfunc':
202            int(self.nfunc_ctl.GetValue())
203        elif name=='d_max':
204            self.dmax_ctl.GetValue()
205        elif name=='alpha':
206            self.alpha_ctl.GetValue()
207        elif name=='chi2':
208            self.chi2_ctl.GetValue()
209        elif name=='q_min':
210            self.qmin_ctl.GetValue()
211        elif name=='q_max':
212            self.qmax_ctl.GetValue()
213        elif name=='elapsed':
214            self.time_ctl.GetValue()
215        elif name=='oscillation':
216            self.osc_ctl.GetValue()
217        elif name=='pos':
218            self.pos_ctl.GetValue()
219        elif name=='pos_err':
220            self.pos_err_ctl.GetValue()
221        elif name=='alpha_estimate':
222            self.alpha_estimate_ctl.GetValue()
223        elif name=='plotname':
224            if self.standalone==False:
225                self.plot_data.GetValue()
226        elif name=='datafile':
227            self.data_file.GetValue()
228        else:
229            wx.Panel.__getattr__(self, name)
230       
231    def set_manager(self, manager):
232        self.manager = manager
233        # Get data
234       
235        # Push data to form
236       
237       
238    def _do_layout(self):
239        #panel = wx.Panel(self, -1)
240        vbox = wx.BoxSizer(wx.VERTICAL)
241
242        # ----- I(q) data -----
243        databox = wx.StaticBox(self, -1, "I(q) data source")
244       
245        boxsizer1 = wx.StaticBoxSizer(databox, wx.VERTICAL)
246        boxsizer1.SetMinSize((320,50))
247        pars_sizer = wx.GridBagSizer(5,5)
248
249        iy = 0
250        self.file_radio = wx.RadioButton(self, -1, "File data:")
251        self.data_file = wx.TextCtrl(self, -1, size=(100,20))
252        self.data_file.SetEditable(False)
253        self.data_file.SetValue("")
254        id = wx.NewId()
255        choose_button = wx.Button(self, id, "Choose file")
256        self.Bind(wx.EVT_BUTTON, self._change_file, id = id)   
257        pars_sizer.Add(self.file_radio, (iy,0), (1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
258        pars_sizer.Add(self.data_file, (iy,1), (1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 15)
259        pars_sizer.Add(choose_button, (iy,3), (1,1), wx.RIGHT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
260       
261        if self.standalone==False:
262            iy += 1
263            self.plot_radio = wx.RadioButton(self, -1, "Plot data:")
264            self.plot_data = wx.TextCtrl(self, -1, size=(100,20))
265            self.plot_data.SetEditable(False)
266            pars_sizer.Add(self.plot_radio, (iy,0), (1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
267            pars_sizer.Add(self.plot_data, (iy,1), (1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 15)
268       
269        boxsizer1.Add(pars_sizer, 0, wx.EXPAND)
270        vbox.Add(boxsizer1)
271
272        # ----- Parameters -----
273        parsbox = wx.StaticBox(self, -1, "Parameters")
274        boxsizer2 = wx.StaticBoxSizer(parsbox, wx.VERTICAL)
275        boxsizer2.SetMinSize((320,50))
276       
277        explanation  = "P(r) is found by fitting a set of base functions to I(Q). "
278        explanation += "The minimization involves a regularization term to ensure "
279        explanation += "a smooth P(r). The alpha parameter gives the size of that " 
280        explanation += "term. The suggested value is the value above which the "
281        explanation += "output P(r) will have only one peak."
282        label_explain = wx.StaticText(self, -1, explanation, size=(280,80))
283        boxsizer2.Add(label_explain,  wx.LEFT|wx.BOTTOM, 5)
284       
285       
286       
287        label_nfunc = wx.StaticText(self, -1, "Number of terms")
288        label_nfunc.SetMinSize((120,20))
289        label_alpha = wx.StaticText(self, -1, "Regularization constant")
290        label_dmax  = wx.StaticText(self, -1, "Max distance [A]")
291        self.label_sugg  = wx.StaticText(self, -1, "Suggested value")
292        #self.label_sugg.Hide()
293       
294        self.nfunc_ctl = wx.TextCtrl(self, -1, size=(60,20))
295        self.nfunc_ctl.SetToolTipString("Number of terms in the expansion.")
296        self.alpha_ctl = wx.TextCtrl(self, -1, size=(60,20))
297        self.alpha_ctl.SetToolTipString("Control parameter for the size of the regularization term.")
298        self.dmax_ctl  = wx.TextCtrl(self, -1, size=(60,20))
299        self.dmax_ctl.SetToolTipString("Maximum distance between any two points in the system.")
300        id = wx.NewId()
301        self.alpha_estimate_ctl  = wx.Button(self, id, "")
302        #self.alpha_estimate_ctl.Hide()
303        self.Bind(wx.EVT_BUTTON, self._on_accept_alpha, id = id)   
304        self.alpha_estimate_ctl.Enable(False)
305        #self.alpha_estimate_ctl.SetBackgroundColour('#ffdf85')
306        #self.alpha_estimate_ctl.SetBackgroundColour(self.GetBackgroundColour())
307        self.alpha_estimate_ctl.SetToolTipString("Waiting for estimate...")
308       
309        # EVT_TEXT would trigger an event for each character entered
310        self.nfunc_ctl.Bind(wx.EVT_KILL_FOCUS, self._on_pars_changed)
311        self.alpha_ctl.Bind(wx.EVT_KILL_FOCUS, self._read_pars)
312        self.dmax_ctl.Bind(wx.EVT_KILL_FOCUS, self._on_pars_changed)
313        self.Bind(wx.EVT_TEXT_ENTER, self._on_pars_changed)
314       
315        sizer_params = wx.GridBagSizer(5,5)
316
317        iy = 0
318        sizer_params.Add(self.label_sugg,       (iy,2), (1,1), wx.LEFT, 15)
319        iy += 1
320        sizer_params.Add(label_nfunc,      (iy,0), (1,1), wx.LEFT, 15)
321        sizer_params.Add(self.nfunc_ctl,   (iy,1), (1,1), wx.RIGHT, 0)
322        iy += 1
323        sizer_params.Add(label_alpha,      (iy,0), (1,1), wx.LEFT, 15)
324        sizer_params.Add(self.alpha_ctl,   (iy,1), (1,1), wx.RIGHT, 0)
325        sizer_params.Add(self.alpha_estimate_ctl, (iy,2), (1,1), wx.LEFT, 15)
326        iy += 1
327        sizer_params.Add(label_dmax, (iy,0), (1,1), wx.LEFT, 15)
328        sizer_params.Add(self.dmax_ctl,   (iy,1), (1,1), wx.RIGHT, 0)
329
330        boxsizer2.Add(sizer_params, 0)
331       
332        vbox.Add(boxsizer2)
333
334        # ----- Q range -----
335        qbox = wx.StaticBox(self, -1, "Q range")
336        qboxsizer = wx.StaticBoxSizer(qbox, wx.VERTICAL)
337        qboxsizer.SetMinSize((320,20))
338       
339        sizer_q = wx.GridBagSizer(5,5)
340
341        label_qmin = wx.StaticText(self, -1, "Q min")
342        label_qmax = wx.StaticText(self, -1, "Q max")
343        self.qmin_ctl = wx.TextCtrl(self, -1, size=(60,20))
344        self.qmax_ctl = wx.TextCtrl(self, -1, size=(60,20))
345       
346        iy = 0
347        sizer_q.Add(label_qmin, (iy,0), (1,1), wx.LEFT|wx.EXPAND, 15)
348        sizer_q.Add(self.qmin_ctl, (iy,1), (1,1), wx.LEFT|wx.EXPAND, 10)
349        sizer_q.Add(label_qmax, (iy,2), (1,1), wx.LEFT|wx.EXPAND, 15)
350        sizer_q.Add(self.qmax_ctl, (iy,3), (1,1), wx.LEFT|wx.EXPAND, 10)
351        qboxsizer.Add(sizer_q, wx.TOP, 15)
352        vbox.Add(qboxsizer)
353       
354       
355
356        # ----- Results -----
357        resbox = wx.StaticBox(self, -1, "Outputs")
358        ressizer = wx.StaticBoxSizer(resbox, wx.VERTICAL)
359        ressizer.SetMinSize((320,50))
360       
361        label_time = wx.StaticText(self, -1, "Computation time")
362        label_time_unit = wx.StaticText(self, -1, "secs")
363        label_time.SetMinSize((120,20))
364        label_chi2 = wx.StaticText(self, -1, "Chi2/dof")
365        label_osc = wx.StaticText(self, -1, "Oscillations")
366        label_pos = wx.StaticText(self, -1, "Positive fraction")
367        label_pos_err = wx.StaticText(self, -1, "1-sigma positive fraction")
368       
369        self.time_ctl = wx.TextCtrl(self, -1, size=(60,20))
370        self.time_ctl.SetEditable(False)
371        self.time_ctl.SetToolTipString("Computation time for the last inversion, in seconds.")
372       
373        self.chi2_ctl = wx.TextCtrl(self, -1, size=(60,20))
374        self.chi2_ctl.SetEditable(False)
375        self.chi2_ctl.SetToolTipString("Chi^2 over degrees of freedom.")
376       
377        # Oscillation parameter
378        self.osc_ctl = wx.TextCtrl(self, -1, size=(60,20))
379        self.osc_ctl.SetEditable(False)
380        self.osc_ctl.SetToolTipString("Oscillation parameter. P(r) for a sphere has an oscillation parameter of 1.1.")
381       
382        # Positive fraction figure of merit
383        self.pos_ctl = wx.TextCtrl(self, -1, size=(60,20))
384        self.pos_ctl.SetEditable(False)
385        self.pos_ctl.SetToolTipString("Fraction of P(r) that is positive. Theoretically, P(r) is defined positive.")
386       
387        # 1-simga positive fraction figure of merit
388        self.pos_err_ctl = wx.TextCtrl(self, -1, size=(60,20))
389        self.pos_err_ctl.SetEditable(False)
390        message  = "Fraction of P(r) that is at least 1 standard deviation greater than zero.\n"
391        message += "This figure of merit tells you about the size of the P(r) errors.\n"
392        message += "If it is close to 1 and the other figures of merit are bad, consider changing "
393        message += "the maximum distance."
394        self.pos_err_ctl.SetToolTipString(message)
395       
396        sizer_res = wx.GridBagSizer(5,5)
397
398        iy = 0
399        sizer_res.Add(label_time, (iy,0), (1,1), wx.LEFT|wx.EXPAND, 15)
400        sizer_res.Add(self.time_ctl,   (iy,1), (1,1), wx.RIGHT|wx.EXPAND, 15)
401        sizer_res.Add(label_time_unit,   (iy,2), (1,1), wx.RIGHT|wx.EXPAND, 15)
402        iy += 1
403        sizer_res.Add(label_chi2, (iy,0), (1,1), wx.LEFT|wx.EXPAND, 15)
404        sizer_res.Add(self.chi2_ctl,   (iy,1), (1,1), wx.RIGHT|wx.EXPAND, 15)
405        iy += 1
406        sizer_res.Add(label_osc, (iy,0), (1,1), wx.LEFT|wx.EXPAND, 15)
407        sizer_res.Add(self.osc_ctl,   (iy,1), (1,1), wx.RIGHT|wx.EXPAND, 15)
408
409        iy += 1
410        sizer_res.Add(label_pos, (iy,0), (1,1), wx.LEFT|wx.EXPAND, 15)
411        sizer_res.Add(self.pos_ctl,   (iy,1), (1,1), wx.RIGHT|wx.EXPAND, 15)
412
413        iy += 1
414        sizer_res.Add(label_pos_err, (iy,0), (1,1), wx.LEFT|wx.EXPAND, 15)
415        sizer_res.Add(self.pos_err_ctl,   (iy,1), (1,1), wx.RIGHT|wx.EXPAND, 15)
416
417        ressizer.Add(sizer_res, 0)
418        vbox.Add(ressizer)
419
420        # ----- Buttons -----
421        static_line = wx.StaticLine(self, -1)
422        vbox.Add(static_line, 0, wx.EXPAND|wx.TOP, 10)
423       
424        id = wx.NewId()
425        button_OK = wx.Button(self, id, "Compute")
426        button_OK.SetToolTipString("Perform P(r) inversion.")
427        self.Bind(wx.EVT_BUTTON, self._on_invert, id = id)   
428       
429        id = wx.NewId()
430        button_Reset = wx.Button(self, id, "Reset")
431        button_Reset.SetToolTipString("Reset inversion parameters to default.")
432        self.Bind(wx.EVT_BUTTON, self._on_reset, id = id)   
433        #button_Cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
434       
435        sizer_button = wx.BoxSizer(wx.HORIZONTAL)
436        sizer_button.Add((20, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
437        sizer_button.Add(button_Reset, 0, wx.LEFT|wx.ADJUST_MINSIZE, 10)
438        sizer_button.Add(button_OK, 0, wx.LEFT|wx.ADJUST_MINSIZE, 10)
439        #sizer_button.Add(button_Cancel, 0, wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)       
440        vbox.Add(sizer_button, 0, wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
441
442
443        self.SetSizer(vbox)
444       
445
446       
447    def _on_accept_alpha(self, evt):
448        """
449            User has accepted the estimated alpha,
450            set it as part of the input parameters
451        """
452        try:
453            alpha = self.alpha_estimate_ctl.GetLabel()
454            tmp = float(alpha)
455            self.alpha_ctl.SetValue(alpha)
456        except:
457            # No estimate or bad estimate, either do nothing
458            import sys
459            print "InversionControl._on_accept_alpha: %s" % sys.exc_value
460            pass
461       
462    def _on_reset(self, evt):
463        """
464            Resets inversion parameters
465        """
466        self.nfunc = self.manager.DEFAULT_NFUNC
467        self.d_max = self.manager.DEFAULT_DMAX
468        self.alpha = self.manager.DEFAULT_ALPHA
469        self.qmin_ctl.SetValue("")
470        self.qmax_ctl.SetValue("")
471        self.time_ctl.SetValue("")
472        self.chi2_ctl.SetValue("")
473        self.osc_ctl.SetValue("")
474        self.pos_ctl.SetValue("")
475        self.pos_err_ctl.SetValue("")
476        self.alpha_estimate_ctl.Enable(False)
477        self.alpha_estimate_ctl.SetLabel("")
478        self._on_pars_changed()
479       
480    def _on_pars_changed(self, evt=None):
481        """
482            Called when an input parameter has changed
483            We will estimate the alpha parameter behind the
484            scenes.
485        """
486        flag, alpha, dmax, nfunc, qmin, qmax = self._read_pars()
487       
488        # If the pars are valid, estimate alpha
489        if flag:
490            if self.standalone==False and self.plot_radio.GetValue():
491                dataset = self.plot_data.GetValue()
492                self.manager.estimate_plot_inversion(alpha=alpha, nfunc=nfunc, 
493                                                     d_max=dmax,
494                                                     q_min=qmin, q_max=qmax)
495            else:
496                path = self.data_file.GetValue()
497                self.manager.estimate_file_inversion(alpha=alpha, nfunc=nfunc, 
498                                                     d_max=dmax, path=path,
499                                                     q_min=qmin, q_max=qmax)
500       
501       
502    def _read_pars(self, evt=None):   
503        alpha = 0
504        nfunc = 5
505        dmax  = 120
506       
507        flag = True
508       
509        # Read alpha
510        try:
511            alpha = float(self.alpha_ctl.GetValue())
512            self.alpha_ctl.SetBackgroundColour(wx.WHITE)
513            self.alpha_ctl.Refresh()
514        except:
515            flag = False
516            self.alpha_ctl.SetBackgroundColour("pink")
517            self.alpha_ctl.Refresh()
518       
519        # Read d_max   
520        try:
521            dmax = float(self.dmax_ctl.GetValue())
522            self.dmax_ctl.SetBackgroundColour(wx.WHITE)
523            self.dmax_ctl.Refresh()
524        except:
525            flag = False
526            self.dmax_ctl.SetBackgroundColour("pink")
527            self.dmax_ctl.Refresh()
528           
529        # Read nfunc
530        try:
531            nfunc = int(self.nfunc_ctl.GetValue())
532            npts = self.manager.get_npts()
533            if npts>0 and nfunc>npts:
534                message = "Number of function terms should be smaller than the number of points"
535                wx.PostEvent(self.manager.parent, StatusEvent(status=message))
536                raise ValueError, message
537            self.nfunc_ctl.SetBackgroundColour(wx.WHITE)
538            self.nfunc_ctl.Refresh()
539        except:
540            flag = False
541            self.nfunc_ctl.SetBackgroundColour("pink")
542            self.nfunc_ctl.Refresh()
543       
544        # Read qmin
545        try:
546            qmin_str = self.qmin_ctl.GetValue()
547            if len(qmin_str.lstrip().rstrip())==0:
548                qmin = None
549            else:
550                qmin = float(qmin_str)
551                self.qmin_ctl.SetBackgroundColour(wx.WHITE)
552                self.qmin_ctl.Refresh()
553        except:
554            flag = False
555            self.qmin_ctl.SetBackgroundColour("pink")
556            self.qmin_ctl.Refresh()
557       
558        # Read qmax
559        try:
560            qmax_str = self.qmax_ctl.GetValue()
561            if len(qmax_str.lstrip().rstrip())==0:
562                qmax = None
563            else:
564                qmax = float(qmax_str)
565                self.qmax_ctl.SetBackgroundColour(wx.WHITE)
566                self.qmax_ctl.Refresh()
567        except:
568            flag = False
569            self.qmax_ctl.SetBackgroundColour("pink")
570            self.qmax_ctl.Refresh()
571       
572        return flag, alpha, dmax, nfunc, qmin, qmax
573   
574    def _on_invert(self, evt):
575        """
576            Perform inversion
577            @param silent: when True, there will be no output for the user
578        """
579        # Get the data from the form
580        # Push it to the manager
581       
582        flag, alpha, dmax, nfunc, qmin, qmax = self._read_pars()
583       
584        if flag:
585            if self.standalone==False and self.plot_radio.GetValue():
586                dataset = self.plot_data.GetValue()
587                if len(dataset.strip())==0:
588                    message = "No data to invert. Select a data set before proceeding with P(r) inversion."
589                    wx.PostEvent(self.manager.parent, StatusEvent(status=message))
590                else:
591                    self.manager.setup_plot_inversion(alpha=alpha, nfunc=nfunc, 
592                                                      d_max=dmax,
593                                                      q_min=qmin, q_max=qmax)
594            else:
595                path = self.data_file.GetValue()
596                if len(path.strip())==0:
597                    message = "No data to invert. Select a data set before proceeding with P(r) inversion."
598                    wx.PostEvent(self.manager.parent, StatusEvent(status=message))
599                else:
600                    self.manager.setup_file_inversion(alpha=alpha, nfunc=nfunc, 
601                                                      d_max=dmax, path=path,
602                                                      q_min=qmin, q_max=qmax
603                                                      )
604               
605        else:
606            message = "The P(r) form contains invalid values: please submit it again."
607            wx.PostEvent(self.parent, StatusEvent(status=message))
608       
609    def _change_file(self, evt):
610        """
611            Choose a new input file for I(q)
612        """
613        import os
614        if not self.manager==None:
615            path = self.manager.choose_file()
616           
617            if path and os.path.isfile(path):
618                self.data_file.SetValue(str(path))
619                self.file_radio.SetValue(True)
620                self._on_pars_changed(None)
621                self.manager.show_data(path)
622       
623
624
625
626class HelpDialog(wx.Dialog):
627    def __init__(self, parent, id):
628        from sans.pr.invertor import help
629        wx.Dialog.__init__(self, parent, id, size=(400, 420))
630        self.SetTitle("P(r) help") 
631       
632
633        vbox = wx.BoxSizer(wx.VERTICAL)
634
635        explanation = help()
636           
637        label_explain = wx.StaticText(self, -1, explanation, size=(350,320))
638           
639        vbox.Add(label_explain, 0, wx.ALL|wx.EXPAND, 15)
640
641
642        static_line = wx.StaticLine(self, -1)
643        vbox.Add(static_line, 0, wx.EXPAND, 0)
644       
645        button_OK = wx.Button(self, wx.ID_OK, "OK")
646        #button_Cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
647       
648        sizer_button = wx.BoxSizer(wx.HORIZONTAL)
649        sizer_button.Add((20, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
650        sizer_button.Add(button_OK, 0, wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)
651        #sizer_button.Add(button_Cancel, 0, wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)       
652        vbox.Add(sizer_button, 0, wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
653
654        self.SetSizer(vbox)
655        self.SetAutoLayout(True)
656       
657        self.Layout()
658        self.Centre()
659
660class PrDistDialog(wx.Dialog):
661    """
662        Property dialog to let the user change the number
663        of points on the P(r) plot.
664    """
665    def __init__(self, parent, id):
666        from sans.pr.invertor import help
667        wx.Dialog.__init__(self, parent, id, size=(250, 120))
668        self.SetTitle("P(r) distribution") 
669       
670
671        vbox = wx.BoxSizer(wx.VERTICAL)
672       
673        label_npts = wx.StaticText(self, -1, "Number of points")
674        self.npts_ctl = wx.TextCtrl(self, -1, size=(100,20))
675                 
676        pars_sizer = wx.GridBagSizer(5,5)
677        iy = 0
678        pars_sizer.Add(label_npts,      (iy,0), (1,1), wx.LEFT, 15)
679        pars_sizer.Add(self.npts_ctl,   (iy,1), (1,1), wx.RIGHT, 0)
680       
681        vbox.Add(pars_sizer, 0, wx.ALL|wx.EXPAND, 15)
682
683
684        static_line = wx.StaticLine(self, -1)
685        vbox.Add(static_line, 0, wx.EXPAND, 0)
686       
687        button_OK = wx.Button(self, wx.ID_OK, "OK")
688        self.Bind(wx.EVT_BUTTON, self._checkValues, button_OK)
689        button_Cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
690       
691        sizer_button = wx.BoxSizer(wx.HORIZONTAL)
692        sizer_button.Add((20, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
693        sizer_button.Add(button_OK, 0, wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)
694        sizer_button.Add(button_Cancel, 0, wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)       
695        vbox.Add(sizer_button, 0, wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
696
697        self.SetSizer(vbox)
698        self.SetAutoLayout(True)
699       
700        self.Layout()
701        self.Centre()
702
703    def _checkValues(self, event):
704        """
705            Check the dialog content.
706        """
707        flag = True
708        try:
709            int(self.npts_ctl.GetValue())
710            self.npts_ctl.SetBackgroundColour(wx.WHITE)
711            self.npts_ctl.Refresh()
712        except:
713            flag = False
714            self.npts_ctl.SetBackgroundColour("pink")
715            self.npts_ctl.Refresh()
716        if flag:
717            event.Skip(True)
718
719    def get_content(self):
720        """
721            Return the content of the dialog.
722            At this point the values have already been
723            checked.
724        """
725        value = int(self.npts_ctl.GetValue())
726        return value
727   
728    def set_content(self, npts):
729        """
730            Initialize the content of the dialog.
731        """
732        self.npts_ctl.SetValue("%i" % npts)
733
734
735class ParsDialog(wx.Panel):
736    """
737        Dialog box to let the user edit detector settings
738    """
739   
740    def __init__(self, parent, id = id, file=True, **kwargs):
741
742        wx.Panel.__init__(self, parent, id = id, **kwargs)
743        self.file = file
744       
745        self.label_nfunc = wx.StaticText(self, -1, "Number of terms")
746        self.label_alpha = wx.StaticText(self, -1, "Regularization constant")
747        self.label_dmax  = wx.StaticText(self, -1, "Max distance [A]")
748       
749        # Npts, q max
750        self.nfunc_ctl = wx.TextCtrl(self, -1, size=(60,20))
751        self.alpha_ctl = wx.TextCtrl(self, -1, size=(60,20))
752        self.dmax_ctl  = wx.TextCtrl(self, -1, size=(60,20))
753
754        self.label_file = None
755        self.file_ctl   = None
756
757        self.static_line_3 = wx.StaticLine(self, -1)
758       
759       
760
761        self.__do_layout()
762
763        self.Fit()
764       
765    def _load_file(self, evt):
766        import os
767        path = None
768        dlg = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.txt", wx.OPEN)
769        if dlg.ShowModal() == wx.ID_OK:
770            path = dlg.GetPath()
771            mypath = os.path.basename(path)
772        dlg.Destroy()
773       
774        if path and os.path.isfile(path):
775            self.file_ctl.SetValue(str(path))
776
777       
778    def checkValues(self, event):
779        flag = True
780        try:
781            float(self.alpha_ctl.GetValue())
782            self.alpha_ctl.SetBackgroundColour(wx.WHITE)
783            self.alpha_ctl.Refresh()
784        except:
785            flag = False
786            self.alpha_ctl.SetBackgroundColour("pink")
787            self.alpha_ctl.Refresh()
788           
789        try:
790            float(self.dmax_ctl.GetValue())
791            self.dmax_ctl.SetBackgroundColour(wx.WHITE)
792            self.dmax_ctl.Refresh()
793        except:
794            flag = False
795            self.dmax_ctl.SetBackgroundColour("pink")
796            self.dmax_ctl.Refresh()
797           
798        try:
799            int(self.nfunc_ctl.GetValue())
800            self.nfunc_ctl.SetBackgroundColour(wx.WHITE)
801            self.nfunc_ctl.Refresh()
802        except:
803            flag = False
804            self.nfunc_ctl.SetBackgroundColour("pink")
805            self.nfunc_ctl.Refresh()
806       
807        if flag:
808            event.Skip(True)
809   
810    def setContent(self, nfunc, alpha, dmax, file):
811        self.nfunc_ctl.SetValue(str(nfunc))
812        self.alpha_ctl.SetValue(str(alpha))
813        self.dmax_ctl.SetValue(str(dmax))
814        if self.file:
815            self.file_ctl.SetValue(str(file))
816
817    def getContent(self):
818        nfunc = int(self.nfunc_ctl.GetValue())
819        alpha = float(self.alpha_ctl.GetValue())
820        dmax = float(self.dmax_ctl.GetValue())
821        file = None
822        if self.file:
823            file = self.file_ctl.GetValue()
824        return nfunc, alpha, dmax, file
825
826
827    def __do_layout(self):
828        sizer_main = wx.BoxSizer(wx.VERTICAL)
829        sizer_params = wx.GridBagSizer(5,5)
830
831        iy = 0
832        sizer_params.Add(self.label_nfunc, (iy,0), (1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
833        sizer_params.Add(self.nfunc_ctl,   (iy,1), (1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
834        iy += 1
835        sizer_params.Add(self.label_alpha, (iy,0), (1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
836        sizer_params.Add(self.alpha_ctl,   (iy,1), (1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
837        iy += 1
838        sizer_params.Add(self.label_dmax, (iy,0), (1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
839        sizer_params.Add(self.dmax_ctl,   (iy,1), (1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
840        iy += 1
841        if self.file:
842            self.label_file  = wx.StaticText(self, -1, "Input file")
843            self.file_ctl  = wx.TextCtrl(self, -1, size=(120,20))
844            sizer_params.Add(self.label_file, (iy,0), (1,1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
845            sizer_params.Add(self.file_ctl,   (iy,1), (1,1), wx.EXPAND|wx.ADJUST_MINSIZE, 0)
846
847        sizer_main.Add(sizer_params, 0, wx.EXPAND|wx.ALL, 10)
848       
849       
850        if self.file:
851            sizer_button = wx.BoxSizer(wx.HORIZONTAL)
852            self.button_load = wx.Button(self, 1, "Choose file")
853            self.Bind(wx.EVT_BUTTON, self._load_file, id = 1)       
854            sizer_button.Add(self.button_load, 0, wx.LEFT|wx.ADJUST_MINSIZE, 10)
855       
856       
857            sizer_main.Add(sizer_button, 0, wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
858        self.SetAutoLayout(True)
859        self.SetSizer(sizer_main)
860        self.Layout()
861        self.Centre()
862        # end wxGlade
863
864
865# end of class DialogAbout
866
867##### testing code ############################################################
868class TestPlot:
869    def __init__(self, text):
870        self.name = text
871   
872class MyApp(wx.App):
873    def OnInit(self):
874        wx.InitAllImageHandlers()
875        dialog = PrDistDialog(None, -1)
876        if dialog.ShowModal() == wx.ID_OK:
877            pass
878        dialog.Destroy()
879       
880        return 1
881
882# end of class MyApp
883
884if __name__ == "__main__":
885    app = MyApp(0)
886    app.MainLoop()
887   
888##### end of testing code #####################################################   
Note: See TracBrowser for help on using the repository browser.