Changeset 8b21fa7 in sasview
- Timestamp:
- Mar 6, 2015 12:05:50 PM (10 years ago)
- Branches:
- master, ESS_GUI, ESS_GUI_Docs, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_iss959, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc, costrafo411, magnetic_scatt, release-4.1.1, release-4.1.2, release-4.2.2, release_4.0.1, ticket-1009, ticket-1094-headless, ticket-1242-2d-resolution, ticket-1243, ticket-1249, ticket885, unittest-saveload
- Children:
- b1e609c
- Parents:
- c1c14ba
- Location:
- src/sas/perspectives/pr
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/perspectives/pr/explore_dialog.py
r79492222 r8b21fa7 3 3 #This software was developed by the University of Tennessee as part of the 4 4 #Distributed Data Analysis of Neutron Scattering Experiments (DANSE) 5 #project funded by the US National Science Foundation. 5 #project funded by the US National Science Foundation. 6 6 # 7 7 #See the license text in license.txt … … 16 16 their distribution as a function of D_max. 17 17 """ 18 18 19 19 20 20 import wx 21 21 import numpy 22 import math23 22 import logging 24 23 import sys 25 24 26 # Avoid Matplotlib complaining about the lack of legend on the plot 25 # Avoid Matplotlib complaining about the lack of legend on the plot 27 26 import warnings 28 27 warnings.simplefilter("ignore") … … 46 45 of D_max 47 46 """ 48 def __init__(self, d_min, d_max, parent, id = -1, color = None,\49 dpi = None, style =wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):47 def __init__(self, d_min, d_max, parent, id= -1, color=None, \ 48 dpi=None, style=wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs): 50 49 """ 51 50 Initialization. The parameters added to PlotPanel are: 52 51 53 52 :param d_min: Minimum value of D_max to explore 54 53 :param d_max: Maximum value of D_max to explore 55 56 """ 57 PlotPanel.__init__(self, parent, id = id, style =style, **kwargs)54 55 """ 56 PlotPanel.__init__(self, parent, id=id, style=style, **kwargs) 58 57 59 58 self.parent = parent … … 62 61 self.npts = DEFAULT_NPTS 63 62 64 step = (self.max -self.min)/(self.npts-1)65 self.x = numpy.arange(self.min, self.max +step*0.01, step)63 step = (self.max - self.min) / (self.npts - 1) 64 self.x = numpy.arange(self.min, self.max + step * 0.01, step) 66 65 dx = numpy.zeros(len(self.x)) 67 66 y = numpy.ones(len(self.x)) 68 67 dy = numpy.zeros(len(self.x)) 69 68 70 69 # Plot area 71 70 self.plot = Model1D(self.x, y=y, dy=dy) … … 76 75 self.graph = Graph() 77 76 self.graph.xaxis("\\rm{D_{max}}", 'A') 78 self.graph.yaxis("\\rm{%s}" % DEFAULT_OUTPUT, "")77 self.graph.yaxis("\\rm{%s}" % DEFAULT_OUTPUT, "") 79 78 self.graph.add(self.plot) 80 79 self.graph.render(self) 81 80 82 81 self.toolbar.DeleteToolByPos(0) 83 82 self.toolbar.DeleteToolByPos(8) … … 87 86 """ 88 87 Default context menu for the plot panel 89 88 90 89 :TODO: Would be nice to add printing and log/linear scales. 91 The current verison of plottools no longer plays well with 92 plots outside of guiframe. Guiframe team needs to fix this. 90 The current verison of plottools no longer plays well with 91 plots outside of guiframe. Guiframe team needs to fix this. 93 92 """ 94 93 # Slicer plot popup menu 95 id = wx.NewId()94 wx_id = wx.NewId() 96 95 slicerpop = wx.Menu() 97 slicerpop.Append( id, '&Save image', 'Save image as PNG')98 wx.EVT_MENU(self, id, self.onSaveImage)99 100 id = wx.NewId()96 slicerpop.Append(wx_id, '&Save image', 'Save image as PNG') 97 wx.EVT_MENU(self, wx_id, self.onSaveImage) 98 99 wx_id = wx.NewId() 101 100 slicerpop.AppendSeparator() 102 slicerpop.Append( id, '&Reset Graph')103 wx.EVT_MENU(self, id, self.onResetGraph)104 101 slicerpop.Append(wx_id, '&Reset Graph') 102 wx.EVT_MENU(self, wx_id, self.onResetGraph) 103 105 104 pos = event.GetPosition() 106 105 pos = self.ScreenToClient(pos) 107 106 self.PopupMenu(slicerpop, pos) 108 107 109 class Results :108 class Results(object): 110 109 """ 111 110 Class to hold the inversion output parameters … … 126 125 self.bck = [] 127 126 self.d_max = [] 128 127 129 128 # Dictionary of outputs 130 129 self.outputs = {} 131 self.outputs['Chi2/dof'] = ["\chi^2/dof", "a.u.", self.chi2] 132 self.outputs['Oscillation parameter'] = ["Osc", "a.u.", self.osc] 133 self.outputs['Positive fraction'] = ["P^+", "a.u.", self.pos] 134 self.outputs['1-sigma positive fraction'] = ["P^+_{1\ \sigma}", 135 "a.u.", self.pos_err] 136 self.outputs['Rg'] = ["R_g", "A", self.rg] 137 self.outputs['I(q=0)'] = ["I(q=0)", "1/A", self.iq0] 138 self.outputs['Background'] = ["Bck", "1/A", self.bck] 139 130 self.outputs['Chi2/dof'] = ["\chi^2/dof", "a.u.", self.chi2] 131 self.outputs['Oscillation parameter'] = ["Osc", "a.u.", self.osc] 132 self.outputs['Positive fraction'] = ["P^+", "a.u.", self.pos] 133 self.outputs['1-sigma positive fraction'] = ["P^+_{1\ \sigma}", 134 "a.u.", self.pos_err] 135 self.outputs['Rg'] = ["R_g", "A", self.rg] 136 self.outputs['I(q=0)'] = ["I(q=0)", "1/A", self.iq0] 137 self.outputs['Background'] = ["Bck", "1/A", self.bck] 138 140 139 class ExploreDialog(wx.Dialog): 141 140 """ … … 143 142 invoked by the InversionControl class. 144 143 """ 145 144 146 145 def __init__(self, pr_state, nfunc, *args, **kwds): 147 146 """ 148 147 Initialization. The parameters added to Dialog are: 149 148 150 149 :param pr_state: sas.pr.invertor.Invertor object 151 150 :param nfunc: Number of terms in the expansion 152 153 """ 154 kwds["style"] = wx.RESIZE_BORDER |wx.DEFAULT_DIALOG_STYLE151 152 """ 153 kwds["style"] = wx.RESIZE_BORDER | wx.DEFAULT_DIALOG_STYLE 155 154 wx.Dialog.__init__(self, *args, **kwds) 156 155 157 156 # Initialize Results object 158 157 self.results = Results() 159 160 self.pr_state 161 self._default_min = 0.9 *self.pr_state.d_max162 self._default_max = 1.1 *self.pr_state.d_max163 self.nfunc 164 158 159 self.pr_state = pr_state 160 self._default_min = 0.9 * self.pr_state.d_max 161 self._default_max = 1.1 * self.pr_state.d_max 162 self.nfunc = nfunc 163 165 164 # Control for number of points 166 165 self.npts_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, 167 size=(60, 20))166 size=(60, 20)) 168 167 # Control for the minimum value of D_max 169 168 self.dmin_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, 170 size=(60, 20))169 size=(60, 20)) 171 170 # Control for the maximum value of D_max 172 171 self.dmax_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, 173 size=(60, 20))172 size=(60, 20)) 174 173 175 174 # Output selection box for the y axis … … 179 178 self.plotpanel = OutputPlot(self._default_min, self._default_max, 180 179 self, -1, style=wx.RAISED_BORDER) 181 180 182 181 # Create the layout of the dialog 183 182 self.__do_layout() 184 183 self.Fit() 185 184 186 185 # Calculate exploration results 187 186 self._recalc() 188 187 # Graph the default output curve 189 188 self._plot_output() 190 191 class Event :189 190 class Event(object): 192 191 """ 193 192 Class that holds the content of the form 194 193 """ 195 194 ## Number of points to be plotted 196 npts 195 npts = 0 197 196 ## Minimum value of D_max 198 dmin 197 dmin = 0 199 198 ## Maximum value of D_max 200 dmax 201 199 dmax = 0 200 202 201 def _get_values(self, event=None): 203 202 """ 204 203 Invoked when the user changes a value of the form. 205 204 Check that the values are of the right type. 206 207 :return: ExploreDialog.Event object if the content is good, 205 206 :return: ExploreDialog.Event object if the content is good, 208 207 None otherwise 209 208 """ 210 209 # Flag to make sure that all values are good 211 210 flag = True 212 211 213 212 # Empty ExploreDialog.Event content 214 213 content_event = self.Event() 215 214 216 215 # Read each text control and make sure the type is valid 217 216 # Let the user know if a type is invalid by changing the … … 225 224 self.npts_ctl.SetBackgroundColour("pink") 226 225 self.npts_ctl.Refresh() 227 226 228 227 try: 229 228 content_event.dmin = float(self.dmin_ctl.GetValue()) … … 234 233 self.dmin_ctl.SetBackgroundColour("pink") 235 234 self.dmin_ctl.Refresh() 236 235 237 236 try: 238 237 content_event.dmax = float(self.dmax_ctl.GetValue()) … … 243 242 self.dmax_ctl.SetBackgroundColour("pink") 244 243 self.dmax_ctl.Refresh() 245 244 246 245 # If the content of the form is valid, return the content, 247 246 # otherwise return None … … 252 251 else: 253 252 return None 254 253 255 254 def _plot_output(self, event=None): 256 255 """ 257 Invoked when a new output type is selected for plotting, 256 Invoked when a new output type is selected for plotting, 258 257 or when a new computation is finished. 259 258 """ 260 259 # Get the output type selection 261 260 output_type = self.output_box.GetString(self.output_box.GetSelection()) 262 261 263 262 # If the selected output type is part of the results ojbect, 264 # display the results. 263 # display the results. 265 264 # Note: by design, the output type should always be part of the 266 265 # results object. 267 if self.results.outputs.has_key(output_type): 266 if self.results.outputs.has_key(output_type): 268 267 self.plotpanel.plot.x = self.results.d_max 269 268 self.plotpanel.plot.y = self.results.outputs[output_type][2] … … 272 271 self.plotpanel.graph.yaxis(y_label, 273 272 self.results.outputs[output_type][1]) 274 273 275 274 # Redraw 276 275 self.plotpanel.graph.render(self.plotpanel) 277 276 self.plotpanel.subplot.figure.canvas.draw_idle() 278 277 else: 279 msg = 278 msg = "ExploreDialog: the Results object's dictionary " 280 279 msg += "does not contain " 281 280 msg += "the [%s] output type. This must be indicative of " … … 283 282 msg += "ExploreDialog code." 284 283 logging.error(msg) 285 284 286 285 def __do_layout(self): 287 286 """ … … 291 290 self.SetTitle("D_max Explorer") 292 291 self.SetSize((600, 595)) 293 292 294 293 sizer_main = wx.BoxSizer(wx.VERTICAL) 295 294 sizer_button = wx.BoxSizer(wx.HORIZONTAL) … … 298 297 iy = 0 299 298 ix = 0 300 label_npts 301 sizer_params.Add(label_npts, (iy, ix), (1, 1), 302 wx.LEFT |wx.EXPAND|wx.ADJUST_MINSIZE, 15)299 label_npts = wx.StaticText(self, -1, "Npts") 300 sizer_params.Add(label_npts, (iy, ix), (1, 1), 301 wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15) 303 302 ix += 1 304 sizer_params.Add(self.npts_ctl, (iy, ix), (1, 1),305 wx.EXPAND |wx.ADJUST_MINSIZE, 0)303 sizer_params.Add(self.npts_ctl, (iy, ix), (1, 1), 304 wx.EXPAND | wx.ADJUST_MINSIZE, 0) 306 305 self.npts_ctl.SetValue("%g" % DEFAULT_NPTS) 307 306 self.npts_ctl.Bind(wx.EVT_KILL_FOCUS, self._recalc) 308 307 309 308 ix += 1 310 label_dmin 309 label_dmin = wx.StaticText(self, -1, "Min Distance [A]") 311 310 sizer_params.Add(label_dmin, (iy, ix), (1, 1), 312 wx.LEFT |wx.EXPAND|wx.ADJUST_MINSIZE, 15)311 wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15) 313 312 ix += 1 314 313 sizer_params.Add(self.dmin_ctl, (iy, ix), (1, 1), 315 wx.EXPAND |wx.ADJUST_MINSIZE, 0)314 wx.EXPAND | wx.ADJUST_MINSIZE, 0) 316 315 self.dmin_ctl.SetValue(str(self._default_min)) 317 316 self.dmin_ctl.Bind(wx.EVT_KILL_FOCUS, self._recalc) 318 317 319 318 ix += 1 320 319 label_dmax = wx.StaticText(self, -1, "Max Distance [A]") 321 320 sizer_params.Add(label_dmax, (iy, ix), (1, 1), 322 wx.LEFT |wx.EXPAND|wx.ADJUST_MINSIZE, 15)321 wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15) 323 322 ix += 1 324 sizer_params.Add(self.dmax_ctl, 325 wx.EXPAND |wx.ADJUST_MINSIZE, 0)323 sizer_params.Add(self.dmax_ctl, (iy, ix), (1, 1), 324 wx.EXPAND | wx.ADJUST_MINSIZE, 0) 326 325 self.dmax_ctl.SetValue(str(self._default_max)) 327 326 self.dmax_ctl.Bind(wx.EVT_KILL_FOCUS, self._recalc) … … 334 333 self.output_box.Append(item, "") 335 334 self.output_box.SetStringSelection(DEFAULT_OUTPUT) 336 335 337 336 output_sizer = wx.GridBagSizer(5, 5) 338 337 output_sizer.Add(selection_msg, (0, 0), (1, 1), 339 wx.LEFT |wx.EXPAND|wx.ADJUST_MINSIZE, 10)338 wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 10) 340 339 output_sizer.Add(self.output_box, (0, 1), (1, 2), 341 wx.LEFT |wx.EXPAND|wx.ADJUST_MINSIZE, 10)342 343 wx.EVT_COMBOBOX(self.output_box, -1, self._plot_output) 340 wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 10) 341 342 wx.EVT_COMBOBOX(self.output_box, -1, self._plot_output) 344 343 sizer_main.Add(output_sizer, 0, wx.EXPAND | wx.ALL, 10) 345 344 346 345 sizer_main.Add(self.plotpanel, 0, wx.EXPAND | wx.ALL, 10) 347 346 sizer_main.SetItemMinSize(self.plotpanel, 400, 400) 348 349 sizer_main.Add(sizer_params, 0, wx.EXPAND |wx.ALL, 10)347 348 sizer_main.Add(sizer_params, 0, wx.EXPAND | wx.ALL, 10) 350 349 static_line_3 = wx.StaticLine(self, -1) 351 350 sizer_main.Add(static_line_3, 0, wx.EXPAND, 0) 352 351 353 352 # Bottom area with the close button 354 sizer_button.Add((20, 20), 1, wx.EXPAND |wx.ADJUST_MINSIZE, 0)353 sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0) 355 354 button_OK = wx.Button(self, wx.ID_OK, "Close") 356 sizer_button.Add(button_OK, 0, wx.LEFT |wx.RIGHT|wx.ADJUST_MINSIZE, 10)357 358 sizer_main.Add(sizer_button, 0, wx.EXPAND |wx.BOTTOM|wx.TOP, 10)355 sizer_button.Add(button_OK, 0, wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10) 356 357 sizer_main.Add(sizer_button, 0, wx.EXPAND | wx.BOTTOM | wx.TOP, 10) 359 358 self.SetAutoLayout(True) 360 359 self.SetSizer(sizer_main) 361 360 self.Layout() 362 361 self.Centre() 363 362 364 363 # Bind the Enter key to recalculation 365 364 self.Bind(wx.EVT_TEXT_ENTER, self._recalc) … … 370 369 """ 371 370 pass 372 371 373 372 def _recalc(self, event=None): 374 373 """ … … 381 380 if content is None: 382 381 return 383 382 384 383 # Results object to store the computation outputs. 385 384 results = Results() 386 385 387 386 # Loop over d_max values 388 for i in range(content.npts): 389 temp = (content.dmax - content.dmin) /(content.npts - 1.0)387 for i in range(content.npts): 388 temp = (content.dmax - content.dmin) / (content.npts - 1.0) 390 389 d = content.dmin + i * temp 391 390 392 391 self.pr_state.d_max = d 393 392 try: 394 out, cov = self.pr_state.invert(self.nfunc) 395 393 out, cov = self.pr_state.invert(self.nfunc) 394 396 395 # Store results 397 396 iq0 = self.pr_state.iq0(out) … … 400 399 pos_err = self.pr_state.get_pos_err(out, cov) 401 400 osc = self.pr_state.oscillations(out) 402 401 403 402 results.d_max.append(self.pr_state.d_max) 404 403 results.bck.append(self.pr_state.background) … … 408 407 results.pos.append(pos) 409 408 results.pos_err.append(pos_err) 410 results.osc.append(osc) 409 results.osc.append(osc) 411 410 except: 412 411 # This inversion failed, skip this D_max value … … 414 413 msg += "for D_max=%s\n%s" % (str(d), sys.exc_value) 415 414 logging.error(msg) 416 417 self.results = results 418 415 416 self.results = results 417 419 418 # Plot the selected output 420 self._plot_output() 421 422 ##### testing code ############################################################ 423 """ 424 Example: :: 425 426 class MyApp(wx.App): 427 428 #Test application used to invoke the ExploreDialog for testing 429 430 def OnInit(self): 431 from inversion_state import Reader 432 from sas.pr.invertor import Invertor 433 wx.InitAllImageHandlers() 434 435 def call_back(state, datainfo=None): 436 437 #Dummy call-back method used by the P(r) 438 #file reader. 439 440 print state 441 442 # Load test data 443 # This would normally be loaded by the application 444 # of the P(r) plug-in. 445 r = Reader(call_back) 446 data = r.read("test_pr_data.prv") 447 pr_state = data.meta_data['prstate'] 448 449 # Create Invertor object for the data 450 # This would normally be assembled by the P(r) plug-in 451 pr = Invertor() 452 pr.d_max = pr_state.d_max 453 pr.alpha = pr_state.alpha 454 pr.q_min = pr_state.qmin 455 pr.q_max = pr_state.qmax 456 pr.x = data.x 457 pr.y = data.y 458 pr.err = data.y*0.1 459 pr.has_bck = False 460 pr.slit_height = pr_state.height 461 pr.slit_width = pr_state.width 462 463 # Create the dialog 464 dialog = ExploreDialog(pr, 10, None, -1, "") 465 self.SetTopWindow(dialog) 466 dialog.ShowModal() 467 dialog.Destroy() 468 469 return 1 470 471 if __name__ == "__main__": 472 app = MyApp(0) 473 app.MainLoop() 474 475 """ 419 self._plot_output() -
src/sas/perspectives/pr/inversion_panel.py
r79492222 r8b21fa7 10 10 import logging 11 11 from wx.lib.scrolledpanel import ScrolledPanel 12 from sas.guiframe.events import StatusEvent 13 from sas.guiframe.panel_base import PanelBase 12 from sas.guiframe.events import StatusEvent 13 from sas.guiframe.panel_base import PanelBase 14 14 from inversion_state import InversionState 15 15 from pr_widgets import PrTextCtrl … … 28 28 window_caption = "P(r) control panel" 29 29 CENTER_PANE = True 30 30 31 31 # Figure of merit parameters [default] 32 32 33 33 ## Oscillation parameters (sin function = 1.1) 34 34 oscillation_max = 1.5 35 36 def __init__(self, parent, id=-1, plots=None, 37 standalone=False, **kwargs): 35 36 def __init__(self, parent, id=-1, plots=None, standalone=False, **kwargs): 38 37 """ 39 38 """ … … 41 40 PanelBase.__init__(self, parent) 42 41 self.SetupScrolling() 43 #Set window's font size 42 #Set window's font size 44 43 self.SetWindowVariant(variant=FONT_VARIANT) 45 44 46 45 self.plots = plots 47 46 self.radio_buttons = {} 48 47 self.parent = parent.parent 49 48 50 49 ## Data file TextCtrl 51 self.data_file 52 self.plot_data 53 self.nfunc_ctl 54 self.alpha_ctl 55 self.dmax_ctl 56 self.time_ctl 57 self.chi2_ctl 58 self.osc_ctl 50 self.data_file = None 51 self.plot_data = None 52 self.nfunc_ctl = None 53 self.alpha_ctl = None 54 self.dmax_ctl = None 55 self.time_ctl = None 56 self.chi2_ctl = None 57 self.osc_ctl = None 59 58 self.file_radio = None 60 59 self.plot_radio = None 61 60 self.label_sugg = None 62 self.qmin_ctl 63 self.qmax_ctl 61 self.qmin_ctl = None 62 self.qmax_ctl = None 64 63 self.swidth_ctl = None 65 64 self.sheight_ctl = None 66 67 self.rg_ctl 68 self.iq0_ctl 69 self.bck_chk 70 self.bck_ctl 71 65 66 self.rg_ctl = None 67 self.iq0_ctl = None 68 self.bck_chk = None 69 self.bck_ctl = None 70 72 71 # TextCtrl for fraction of positive P(r) 73 72 self.pos_ctl = None 74 73 75 74 # TextCtrl for fraction of 1 sigma positive P(r) 76 self.pos_err_ctl = None 77 75 self.pos_err_ctl = None 76 78 77 ## Estimates 79 78 self.alpha_estimate_ctl = None … … 82 81 self.distance_explorator_ctl = None 83 82 ## Data manager 84 self._manager 83 self._manager = None 85 84 ## Standalone flage 86 85 self.standalone = standalone … … 88 87 self._default_save_location = os.getcwd() 89 88 if self.parent is not None: 90 self._default_save_location = \89 self._default_save_location = \ 91 90 self.parent._default_save_location 92 91 93 92 # Default width 94 93 self._default_width = 350 95 94 self._do_layout() 96 95 97 96 def __setattr__(self, name, value): 98 97 """ … … 115 114 elif name == 'elapsed': 116 115 self.time_ctl.SetValue("%-5.2g" % value) 117 elif name == 'rg':116 elif name == 'rg': 118 117 self.rg_ctl.SetValue("%-5.2g" % value) 119 118 elif name == 'iq0': … … 147 146 else: 148 147 wx.Panel.__setattr__(self, name, value) 149 148 150 149 def __getattr__(self, name): 151 150 """ … … 182 181 except: 183 182 return 0.0 184 elif name =='q_max':183 elif name == 'q_max': 185 184 try: 186 185 return float(self.qmax_ctl.GetValue()) … … 197 196 except: 198 197 return None 199 elif name =='iq0':198 elif name == 'iq0': 200 199 try: 201 200 return float(self.iq0_ctl.GetValue()) … … 212 211 except: 213 212 return None 214 elif name =='slit_height':213 elif name == 'slit_height': 215 214 try: 216 215 return float(self.sheight_ctl.GetValue()) … … 243 242 else: 244 243 return wx.Panel.__getattribute__(self, name) 245 244 246 245 def save_project(self, doc=None): 247 246 """ … … 260 259 else: 261 260 doc = new_doc 262 return doc 263 261 return doc 262 264 263 def on_save(self, evt=None): 265 264 """ 266 265 Method used to create a memento of the current state 267 268 :return: state object 266 267 :return: state object 269 268 """ 270 269 # Ask the user the location of the file to write to. 271 270 path = None 272 271 if self.parent != None: 273 self._default_save_location =\ 274 self.parent._default_save_location 272 self._default_save_location = self.parent._default_save_location 275 273 dlg = wx.FileDialog(self, "Choose a file", 276 self._default_save_location, \274 self._default_save_location, 277 275 self.window_caption, "*.prv", wx.SAVE) 278 276 if dlg.ShowModal() == wx.ID_OK: … … 280 278 self._default_save_location = os.path.dirname(path) 281 279 if self.parent != None: 282 self.parent._default_save_location =\ 283 self._default_save_location 280 self.parent._default_save_location = self._default_save_location 284 281 else: 285 282 return None 286 283 287 284 dlg.Destroy() 288 285 289 286 state = self.get_state() 290 287 291 288 # MAC always needs the extension for saving 292 289 extens = ".prv" … … 294 291 fName = os.path.splitext(path)[0] + extens 295 292 self._manager.save_data(filepath=fName, prstate=state) 296 293 297 294 return state 298 295 299 296 def get_data(self): 300 297 """ 301 298 """ 302 299 return self._manager.get_data() 303 300 304 301 def get_state(self): 305 302 """ 306 303 Get the current state 307 304 308 305 : return: state object 309 306 """ 310 # Construct the state object 307 # Construct the state object 311 308 state = InversionState() 312 309 313 310 # Read the panel's parameters 314 311 flag, alpha, dmax, nfunc, qmin, \ 315 312 qmax, height, width = self._read_pars() 316 313 317 314 state.nfunc = nfunc 318 315 state.d_max = dmax 319 316 state.alpha = alpha 320 state.qmin 321 state.qmax 317 state.qmin = qmin 318 state.qmax = qmax 322 319 state.width = width 323 320 state.height = height 324 321 325 322 # Data file 326 323 state.file = self.plot_data.GetValue() 327 324 328 325 # Background evaluation checkbox 329 326 state.estimate_bck = self.bck_chk.IsChecked() 330 327 331 328 # Estimates 332 329 state.nterms_estimate = self.nterms_estimate 333 330 state.alpha_estimate = self.alpha_estimate 334 331 335 332 # Read the output values 336 state.chi2 333 state.chi2 = self.chi2 337 334 state.elapsed = self.elapsed 338 state.osc 339 state.pos 335 state.osc = self.oscillation 336 state.pos = self.pos 340 337 state.pos_err = self.pos_err 341 state.rg 342 state.iq0 343 state.bck 344 338 state.rg = self.rg 339 state.iq0 = self.iq0 340 state.bck = self.bck 341 345 342 return state 346 343 347 344 def set_state(self, state): 348 345 """ 349 346 Set the state of the panel and inversion problem to 350 347 the state passed as a parameter. 351 Execute the inversion immediately after filling the 348 Execute the inversion immediately after filling the 352 349 controls. 353 350 354 351 :param state: InversionState object 355 352 """ … … 361 358 self.alpha = state.alpha 362 359 if state.qmin is not None: 363 self.q_min 360 self.q_min = state.qmin 364 361 if state.qmax is not None: 365 self.q_max 362 self.q_max = state.qmax 366 363 if state.width is not None: 367 364 self.slit_width = state.width 368 365 if state.height is not None: 369 366 self.slit_height = state.height 370 367 371 368 # Data file 372 369 self.plot_data.SetValue(str(state.file)) 373 370 374 371 # Background evaluation checkbox 375 372 self.bck_chk.SetValue(state.estimate_bck) 376 373 377 374 # Estimates 378 375 if state.nterms_estimate is not None: 379 376 self.nterms_estimate = state.nterms_estimate 380 if state.alpha_estimate is not None: 381 self.alpha_estimate = state.alpha_estimate 382 383 377 if state.alpha_estimate is not None: 378 self.alpha_estimate = state.alpha_estimate 379 380 384 381 # Read the output values 385 382 if state.chi2 is not None: 386 self.chi2 383 self.chi2 = state.chi2 387 384 if state.elapsed is not None: 388 385 self.elapsed = state.elapsed … … 394 391 self.pos_err = state.pos_err 395 392 if state.rg is not None: 396 self.rg 393 self.rg = state.rg 397 394 if state.iq0 is not None: 398 self.iq0 395 self.iq0 = state.iq0 399 396 if state.bck is not None: 400 self.bck 397 self.bck = state.bck 401 398 402 399 # Perform inversion 403 self._on_invert(None) 404 400 self._on_invert(None) 401 405 402 def set_manager(self, manager): 406 403 self._manager = manager 407 404 408 405 def _do_layout(self): 409 vbox = wx.GridBagSizer(0, 0)406 vbox = wx.GridBagSizer(0, 0) 410 407 iy_vb = 0 411 408 412 409 # ----- I(q) data ----- 413 410 databox = wx.StaticBox(self, -1, "I(q) data source") 414 411 415 412 boxsizer1 = wx.StaticBoxSizer(databox, wx.VERTICAL) 416 413 boxsizer1.SetMinSize((self._default_width, 50)) … … 420 417 self.file_radio = wx.StaticText(self, -1, "Name:") 421 418 pars_sizer.Add(self.file_radio, (iy, 0), (1, 1), 422 wx.LEFT |wx.EXPAND|wx.ADJUST_MINSIZE, 15)423 424 self.plot_data = DataFileTextCtrl(self, -1, size=(260, 20))425 419 wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15) 420 421 self.plot_data = DataFileTextCtrl(self, -1, size=(260, 20)) 422 426 423 pars_sizer.Add(self.plot_data, (iy, 1), (1, 1), 427 wx.EXPAND |wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 15)428 424 wx.EXPAND | wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 15) 425 429 426 self.bck_chk = wx.CheckBox(self, -1, "Estimate background level") 430 427 hint_msg = "Check box to let the fit estimate " … … 434 431 iy += 1 435 432 pars_sizer.Add(self.bck_chk, (iy, 0), (1, 2), 436 wx.LEFT |wx.EXPAND|wx.ADJUST_MINSIZE, 15)437 boxsizer1.Add(pars_sizer, 0, wx.EXPAND) 433 wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15) 434 boxsizer1.Add(pars_sizer, 0, wx.EXPAND) 438 435 vbox.Add(boxsizer1, (iy_vb, 0), (1, 1), 439 wx.LEFT |wx.RIGHT|wx.EXPAND|wx.ADJUST_MINSIZE|wx.TOP, 5)440 436 wx.LEFT | wx.RIGHT | wx.EXPAND | wx.ADJUST_MINSIZE | wx.TOP, 5) 437 441 438 # ----- Add slit parameters ----- 442 439 if True: … … 444 441 sboxsizer = wx.StaticBoxSizer(sbox, wx.VERTICAL) 445 442 sboxsizer.SetMinSize((self._default_width, 20)) 446 443 447 444 sizer_slit = wx.GridBagSizer(5, 5) 448 445 449 446 label_sheight = wx.StaticText(self, -1, "Height", size=(40, 20)) 450 447 label_swidth = wx.StaticText(self, -1, "Width", size=(40, 20)) 451 #label_sunits1 = wx.StaticText(self, -1, "[A^(-1)]") 452 label_sunits2 = wx.StaticText(self, -1, "[A^(-1)]", size=(55,20)) 453 self.sheight_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, 454 size=(60,20)) 455 self.swidth_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, 456 size=(60,20)) 448 label_sunits2 = wx.StaticText(self, -1, "[A^(-1)]", size=(55, 20)) 449 self.sheight_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, size=(60, 20)) 450 self.swidth_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, size=(60, 20)) 457 451 hint_msg = "Enter slit height in units of Q or leave blank." 458 452 self.sheight_ctl.SetToolTipString(hint_msg) 459 453 hint_msg = "Enter slit width in units of Q or leave blank." 460 454 self.swidth_ctl.SetToolTipString(hint_msg) 461 #self.sheight_ctl.Bind(wx.EVT_TEXT, self._on_pars_changed) 462 #self.swidth_ctl.Bind(wx.EVT_TEXT, self._on_pars_changed) 463 455 464 456 iy = 0 465 sizer_slit.Add(label_sheight, (iy, 0), (1, 1), 466 wx.LEFT|wx.EXPAND, 5) 467 sizer_slit.Add(self.sheight_ctl, (iy, 1), (1, 1), 468 wx.LEFT|wx.EXPAND, 5) 469 470 sizer_slit.Add(label_swidth, (iy, 2), (1, 1), 471 wx.LEFT|wx.EXPAND, 5) 472 sizer_slit.Add(self.swidth_ctl, (iy, 3), (1, 1), 473 wx.LEFT|wx.EXPAND, 5) 474 sizer_slit.Add(label_sunits2, (iy, 4), (1, 1), 475 wx.LEFT|wx.EXPAND, 5) 476 457 sizer_slit.Add(label_sheight, (iy, 0), (1, 1), wx.LEFT | wx.EXPAND, 5) 458 sizer_slit.Add(self.sheight_ctl, (iy, 1), (1, 1), wx.LEFT | wx.EXPAND, 5) 459 sizer_slit.Add(label_swidth, (iy, 2), (1, 1), wx.LEFT | wx.EXPAND, 5) 460 sizer_slit.Add(self.swidth_ctl, (iy, 3), (1, 1), wx.LEFT | wx.EXPAND, 5) 461 sizer_slit.Add(label_sunits2, (iy, 4), (1, 1), wx.LEFT | wx.EXPAND, 5) 462 477 463 sboxsizer.Add(sizer_slit, wx.TOP, 15) 478 464 iy_vb += 1 479 465 vbox.Add(sboxsizer, (iy_vb, 0), (1, 1), 480 wx.LEFT|wx.RIGHT|wx.EXPAND|wx.ADJUST_MINSIZE, 5) 481 482 466 wx.LEFT | wx.RIGHT | wx.EXPAND | wx.ADJUST_MINSIZE, 5) 467 483 468 # ----- Q range ----- 484 469 qbox = wx.StaticBox(self, -1, "Q range") 485 470 qboxsizer = wx.StaticBoxSizer(qbox, wx.VERTICAL) 486 471 qboxsizer.SetMinSize((self._default_width, 20)) 487 472 488 473 sizer_q = wx.GridBagSizer(5, 5) 489 474 490 475 label_qmin = wx.StaticText(self, -1, "Q min", size=(40, 20)) 491 476 label_qmax = wx.StaticText(self, -1, "Q max", size=(40, 20)) 492 #label_qunits1 = wx.StaticText(self, -1, "[A^(-1)]")493 477 label_qunits2 = wx.StaticText(self, -1, "[A^(-1)]", size=(55, 20)) 494 self.qmin_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, 495 size=(60,20)) 496 self.qmax_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, 497 size=(60,20)) 478 self.qmin_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, size=(60, 20)) 479 self.qmax_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, size=(60, 20)) 498 480 hint_msg = "Select a lower bound for Q or leave blank." 499 481 self.qmin_ctl.SetToolTipString(hint_msg) … … 502 484 self.qmin_ctl.Bind(wx.EVT_TEXT, self._on_pars_changed) 503 485 self.qmax_ctl.Bind(wx.EVT_TEXT, self._on_pars_changed) 504 486 505 487 iy = 0 506 sizer_q.Add(label_qmin, (iy, 0), (1, 1), wx.LEFT|wx.EXPAND, 5) 507 sizer_q.Add(self.qmin_ctl, (iy, 1), (1, 1), wx.LEFT|wx.EXPAND, 5) 508 #sizer_q.Add(label_qunits1, (iy,2), (1,1), wx.LEFT|wx.EXPAND, 15) 509 sizer_q.Add(label_qmax, (iy, 2), (1, 1), wx.LEFT|wx.EXPAND, 5) 510 sizer_q.Add(self.qmax_ctl, (iy, 3), (1, 1), wx.LEFT|wx.EXPAND, 5) 511 sizer_q.Add(label_qunits2, (iy, 4), (1, 1), wx.LEFT|wx.EXPAND, 5) 488 sizer_q.Add(label_qmin, (iy, 0), (1, 1), wx.LEFT | wx.EXPAND, 5) 489 sizer_q.Add(self.qmin_ctl, (iy, 1), (1, 1), wx.LEFT | wx.EXPAND, 5) 490 sizer_q.Add(label_qmax, (iy, 2), (1, 1), wx.LEFT | wx.EXPAND, 5) 491 sizer_q.Add(self.qmax_ctl, (iy, 3), (1, 1), wx.LEFT | wx.EXPAND, 5) 492 sizer_q.Add(label_qunits2, (iy, 4), (1, 1), wx.LEFT | wx.EXPAND, 5) 512 493 qboxsizer.Add(sizer_q, wx.TOP, 15) 513 494 514 495 iy_vb += 1 515 vbox.Add(qboxsizer, (iy_vb, 0), (1,1),516 wx.LEFT |wx.RIGHT|wx.EXPAND|wx.ADJUST_MINSIZE, 5)517 496 vbox.Add(qboxsizer, (iy_vb, 0), (1, 1), 497 wx.LEFT | wx.RIGHT | wx.EXPAND | wx.ADJUST_MINSIZE, 5) 498 518 499 # ----- Parameters ----- 519 500 parsbox = wx.StaticBox(self, -1, "Parameters") 520 501 boxsizer2 = wx.StaticBoxSizer(parsbox, wx.VERTICAL) 521 boxsizer2.SetMinSize((self._default_width, 50))522 523 explanation 502 boxsizer2.SetMinSize((self._default_width, 50)) 503 504 explanation = "P(r) is found by fitting a set of base functions" 524 505 explanation += " to I(Q). The minimization involves" 525 506 explanation += " a regularization term to ensure a smooth P(r)." 526 explanation += " The regularization constant gives the size of that " 507 explanation += " The regularization constant gives the size of that " 527 508 explanation += "term. The suggested value is the value above which the" 528 509 explanation += " output P(r) will have only one peak." 529 label_explain = wx.StaticText(self, -1, explanation, size=(280,90)) 530 boxsizer2.Add(label_explain, wx.LEFT|wx.BOTTOM, 5) 531 532 533 510 label_explain = wx.StaticText(self, -1, explanation, size=(280, 90)) 511 boxsizer2.Add(label_explain, wx.LEFT | wx.BOTTOM, 5) 512 534 513 label_nfunc = wx.StaticText(self, -1, "Number of terms") 535 514 label_nfunc.SetMinSize((120, 20)) 536 515 label_alpha = wx.StaticText(self, -1, "Regularization constant") 537 label_dmax = wx.StaticText(self, -1, "Max distance [A]") 538 self.label_sugg = wx.StaticText(self, -1, "Suggested value") 539 #self.label_sugg.Hide() 540 541 self.nfunc_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, 542 size=(60,20)) 516 label_dmax = wx.StaticText(self, -1, "Max distance [A]") 517 self.label_sugg = wx.StaticText(self, -1, "Suggested value") 518 519 self.nfunc_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, size=(60, 20)) 543 520 self.nfunc_ctl.SetToolTipString("Number of terms in the expansion.") 544 self.alpha_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, 545 size=(60,20)) 521 self.alpha_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, size=(60, 20)) 546 522 hint_msg = "Control parameter for the size of the regularization term." 547 523 self.alpha_ctl.SetToolTipString(hint_msg) 548 self.dmax_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, 549 size=(60,20)) 524 self.dmax_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, size=(60, 20)) 550 525 hint_msg = "Maximum distance between any two points in the system." 551 526 self.dmax_ctl.SetToolTipString(hint_msg) 552 id = wx.NewId() 553 self.alpha_estimate_ctl = wx.Button(self, id, "") 554 #self.alpha_estimate_ctl.Hide() 555 self.Bind(wx.EVT_BUTTON, self._on_accept_alpha, id = id) 527 wx_id = wx.NewId() 528 self.alpha_estimate_ctl = wx.Button(self, wx_id, "") 529 self.Bind(wx.EVT_BUTTON, self._on_accept_alpha, id=wx_id) 556 530 self.alpha_estimate_ctl.Enable(False) 557 #self.alpha_estimate_ctl.SetBackgroundColour('#ffdf85')558 #self.alpha_estimate_ctl.SetBackgroundColour(self.GetBackgroundColour())559 531 self.alpha_estimate_ctl.SetToolTipString("Waiting for estimate...") 560 561 id = wx.NewId()562 self.nterms_estimate_ctl = wx.Button(self,id, "")532 533 wx_id = wx.NewId() 534 self.nterms_estimate_ctl = wx.Button(self, wx_id, "") 563 535 #self.nterms_estimate_ctl.Hide() 564 self.Bind(wx.EVT_BUTTON, self._on_accept_nterms, id = id)536 self.Bind(wx.EVT_BUTTON, self._on_accept_nterms, id=wx_id) 565 537 self.nterms_estimate_ctl.Enable(False) 566 538 567 539 self.nterms_estimate_ctl.SetToolTipString("Waiting for estimate...") 568 540 569 541 self.nfunc_ctl.Bind(wx.EVT_TEXT, self._read_pars) 570 542 self.alpha_ctl.Bind(wx.EVT_TEXT, self._read_pars) 571 543 self.dmax_ctl.Bind(wx.EVT_TEXT, self._on_pars_changed) 572 544 573 545 # Distance explorator 574 id = wx.NewId()575 self.distance_explorator_ctl = wx.Button(self, id, "Explore")576 self.Bind(wx.EVT_BUTTON, self._on_explore, id = id)577 578 579 sizer_params = wx.GridBagSizer(5, 5)546 wx_id = wx.NewId() 547 self.distance_explorator_ctl = wx.Button(self, wx_id, "Explore") 548 self.Bind(wx.EVT_BUTTON, self._on_explore, id=wx_id) 549 550 551 sizer_params = wx.GridBagSizer(5, 5) 580 552 581 553 iy = 0 582 554 sizer_params.Add(self.label_sugg, (iy, 2), (1, 1), wx.LEFT, 15) 583 555 iy += 1 584 sizer_params.Add(label_nfunc, 585 sizer_params.Add(self.nfunc_ctl, 556 sizer_params.Add(label_nfunc, (iy, 0), (1, 1), wx.LEFT, 15) 557 sizer_params.Add(self.nfunc_ctl, (iy, 1), (1, 1), wx.RIGHT, 0) 586 558 sizer_params.Add(self.nterms_estimate_ctl, (iy, 2), (1, 1), wx.LEFT, 15) 587 559 iy += 1 588 sizer_params.Add(label_alpha, 589 sizer_params.Add(self.alpha_ctl, 560 sizer_params.Add(label_alpha, (iy, 0), (1, 1), wx.LEFT, 15) 561 sizer_params.Add(self.alpha_ctl, (iy, 1), (1, 1), wx.RIGHT, 0) 590 562 sizer_params.Add(self.alpha_estimate_ctl, (iy, 2), (1, 1), wx.LEFT, 15) 591 563 iy += 1 592 564 sizer_params.Add(label_dmax, (iy, 0), (1, 1), wx.LEFT, 15) 593 sizer_params.Add(self.dmax_ctl, 565 sizer_params.Add(self.dmax_ctl, (iy, 1), (1, 1), wx.RIGHT, 0) 594 566 sizer_params.Add(self.distance_explorator_ctl, (iy, 2), 595 567 (1, 1), wx.LEFT, 15) 596 568 597 569 boxsizer2.Add(sizer_params, 0) 598 570 599 571 iy_vb += 1 600 572 vbox.Add(boxsizer2, (iy_vb, 0), (1, 1), 601 wx.LEFT |wx.RIGHT|wx.EXPAND|wx.ADJUST_MINSIZE, 5)573 wx.LEFT | wx.RIGHT | wx.EXPAND | wx.ADJUST_MINSIZE, 5) 602 574 603 575 … … 606 578 ressizer = wx.StaticBoxSizer(resbox, wx.VERTICAL) 607 579 ressizer.SetMinSize((self._default_width, 50)) 608 609 label_rg 610 label_rg_unit 611 label_iq0 580 581 label_rg = wx.StaticText(self, -1, "Rg") 582 label_rg_unit = wx.StaticText(self, -1, "[A]") 583 label_iq0 = wx.StaticText(self, -1, "I(Q=0)") 612 584 label_iq0_unit = wx.StaticText(self, -1, "[A^(-1)]") 613 label_bck 585 label_bck = wx.StaticText(self, -1, "Background") 614 586 label_bck_unit = wx.StaticText(self, -1, "[A^(-1)]") 615 self.rg_ctl = OutputTextCtrl(self, -1, size=(60,20))587 self.rg_ctl = OutputTextCtrl(self, -1, size=(60, 20)) 616 588 hint_msg = "Radius of gyration for the computed P(r)." 617 589 self.rg_ctl.SetToolTipString(hint_msg) 618 self.iq0_ctl 590 self.iq0_ctl = OutputTextCtrl(self, -1, size=(60, 20)) 619 591 hint_msg = "Scattering intensity at Q=0 for the computed P(r)." 620 592 self.iq0_ctl.SetToolTipString(hint_msg) 621 self.bck_ctl 593 self.bck_ctl = OutputTextCtrl(self, -1, size=(60, 20)) 622 594 self.bck_ctl.SetToolTipString("Value of estimated constant background.") 623 595 624 596 label_time = wx.StaticText(self, -1, "Computation time") 625 597 label_time_unit = wx.StaticText(self, -1, "secs") 626 label_time.SetMinSize((120, 20))598 label_time.SetMinSize((120, 20)) 627 599 label_chi2 = wx.StaticText(self, -1, "Chi2/dof") 628 600 label_osc = wx.StaticText(self, -1, "Oscillations") 629 601 label_pos = wx.StaticText(self, -1, "Positive fraction") 630 602 label_pos_err = wx.StaticText(self, -1, "1-sigma positive fraction") 631 603 632 604 self.time_ctl = OutputTextCtrl(self, -1, size=(60, 20)) 633 605 hint_msg = "Computation time for the last inversion, in seconds." 634 606 self.time_ctl.SetToolTipString(hint_msg) 635 607 636 608 self.chi2_ctl = OutputTextCtrl(self, -1, size=(60, 20)) 637 609 self.chi2_ctl.SetToolTipString("Chi^2 over degrees of freedom.") 638 610 639 611 # Oscillation parameter 640 612 self.osc_ctl = OutputTextCtrl(self, -1, size=(60, 20)) … … 642 614 hint_msg += " oscillation parameter of 1.1." 643 615 self.osc_ctl.SetToolTipString(hint_msg) 644 616 645 617 # Positive fraction figure of merit 646 618 self.pos_ctl = OutputTextCtrl(self, -1, size=(60, 20)) … … 648 620 hint_msg += "Theoretically, P(r) is defined positive." 649 621 self.pos_ctl.SetToolTipString(hint_msg) 650 622 651 623 # 1-simga positive fraction figure of merit 652 624 self.pos_err_ctl = OutputTextCtrl(self, -1, size=(60, 20)) 653 message 625 message = "Fraction of P(r) that is at least 1 standard deviation" 654 626 message += " greater than zero.\n" 655 627 message += "This figure of merit tells you about the size of the " … … 658 630 message += " consider changing the maximum distance." 659 631 self.pos_err_ctl.SetToolTipString(message) 660 632 661 633 sizer_res = wx.GridBagSizer(5, 5) 662 634 663 635 iy = 0 664 sizer_res.Add(label_rg, (iy, 0), (1, 1), wx.LEFT |wx.EXPAND, 15)665 sizer_res.Add(self.rg_ctl, (iy, 1), (1, 1), wx.RIGHT|wx.EXPAND, 15)666 sizer_res.Add(label_rg_unit, (iy, 2), (1, 1), wx.RIGHT|wx.EXPAND, 15)636 sizer_res.Add(label_rg, (iy, 0), (1, 1), wx.LEFT | wx.EXPAND, 15) 637 sizer_res.Add(self.rg_ctl, (iy, 1), (1, 1), wx.RIGHT | wx.EXPAND, 15) 638 sizer_res.Add(label_rg_unit, (iy, 2), (1, 1), wx.RIGHT | wx.EXPAND, 15) 667 639 iy += 1 668 sizer_res.Add(label_iq0, (iy, 0), (1, 1), wx.LEFT |wx.EXPAND, 15)669 sizer_res.Add(self.iq0_ctl, (iy, 1), (1, 1), wx.RIGHT|wx.EXPAND, 15)670 sizer_res.Add(label_iq0_unit, (iy, 2), (1, 1), wx.RIGHT |wx.EXPAND, 15)640 sizer_res.Add(label_iq0, (iy, 0), (1, 1), wx.LEFT | wx.EXPAND, 15) 641 sizer_res.Add(self.iq0_ctl, (iy, 1), (1, 1), wx.RIGHT | wx.EXPAND, 15) 642 sizer_res.Add(label_iq0_unit, (iy, 2), (1, 1), wx.RIGHT | wx.EXPAND, 15) 671 643 iy += 1 672 sizer_res.Add(label_bck, (iy, 0), (1, 1), wx.LEFT |wx.EXPAND, 15)673 sizer_res.Add(self.bck_ctl, (iy, 1), (1, 1), wx.RIGHT |wx.EXPAND, 15)674 sizer_res.Add(label_bck_unit, (iy, 2), (1, 1), wx.RIGHT |wx.EXPAND, 15)644 sizer_res.Add(label_bck, (iy, 0), (1, 1), wx.LEFT | wx.EXPAND, 15) 645 sizer_res.Add(self.bck_ctl, (iy, 1), (1, 1), wx.RIGHT | wx.EXPAND, 15) 646 sizer_res.Add(label_bck_unit, (iy, 2), (1, 1), wx.RIGHT | wx.EXPAND, 15) 675 647 iy += 1 676 sizer_res.Add(label_time, (iy, 0), (1, 1), wx.LEFT |wx.EXPAND, 15)677 sizer_res.Add(self.time_ctl, (iy, 1), (1, 1), wx.RIGHT|wx.EXPAND, 15)678 sizer_res.Add(label_time_unit, (iy, 2), (1, 1), wx.RIGHT |wx.EXPAND, 15)648 sizer_res.Add(label_time, (iy, 0), (1, 1), wx.LEFT | wx.EXPAND, 15) 649 sizer_res.Add(self.time_ctl, (iy, 1), (1, 1), wx.RIGHT | wx.EXPAND, 15) 650 sizer_res.Add(label_time_unit, (iy, 2), (1, 1), wx.RIGHT | wx.EXPAND, 15) 679 651 iy += 1 680 sizer_res.Add(label_chi2, (iy, 0), (1, 1), wx.LEFT |wx.EXPAND, 15)681 sizer_res.Add(self.chi2_ctl, (iy, 1), (1, 1), wx.RIGHT|wx.EXPAND, 15)652 sizer_res.Add(label_chi2, (iy, 0), (1, 1), wx.LEFT | wx.EXPAND, 15) 653 sizer_res.Add(self.chi2_ctl, (iy, 1), (1, 1), wx.RIGHT | wx.EXPAND, 15) 682 654 iy += 1 683 sizer_res.Add(label_osc, (iy, 0), (1, 1), wx.LEFT |wx.EXPAND, 15)684 sizer_res.Add(self.osc_ctl, (iy, 1), (1, 1), wx.RIGHT|wx.EXPAND, 15)655 sizer_res.Add(label_osc, (iy, 0), (1, 1), wx.LEFT | wx.EXPAND, 15) 656 sizer_res.Add(self.osc_ctl, (iy, 1), (1, 1), wx.RIGHT | wx.EXPAND, 15) 685 657 686 658 iy += 1 687 sizer_res.Add(label_pos, (iy, 0), (1, 1), wx.LEFT |wx.EXPAND, 15)688 sizer_res.Add(self.pos_ctl, (iy, 1), (1, 1), wx.RIGHT |wx.EXPAND, 15)659 sizer_res.Add(label_pos, (iy, 0), (1, 1), wx.LEFT | wx.EXPAND, 15) 660 sizer_res.Add(self.pos_ctl, (iy, 1), (1, 1), wx.RIGHT | wx.EXPAND, 15) 689 661 690 662 iy += 1 691 sizer_res.Add(label_pos_err, (iy, 0), (1, 1), wx.LEFT |wx.EXPAND, 15)692 sizer_res.Add(self.pos_err_ctl, (iy,1), (1, 1), wx.RIGHT|wx.EXPAND, 15)663 sizer_res.Add(label_pos_err, (iy, 0), (1, 1), wx.LEFT | wx.EXPAND, 15) 664 sizer_res.Add(self.pos_err_ctl, (iy, 1), (1, 1), wx.RIGHT | wx.EXPAND, 15) 693 665 694 666 ressizer.Add(sizer_res, 0) 695 667 iy_vb += 1 696 668 vbox.Add(ressizer, (iy_vb, 0), (1, 1), 697 wx.LEFT |wx.RIGHT|wx.EXPAND|wx.ADJUST_MINSIZE, 5)669 wx.LEFT | wx.RIGHT | wx.EXPAND | wx.ADJUST_MINSIZE, 5) 698 670 699 671 # ----- Buttons ----- 700 id = wx.NewId()701 button_ OK = wx.Button(self,id, "Compute")702 button_ OK.SetToolTipString("Perform P(r) inversion.")703 self.Bind(wx.EVT_BUTTON, self._on_invert, id = id)704 672 wx_id = wx.NewId() 673 button_ok = wx.Button(self, wx_id, "Compute") 674 button_ok.SetToolTipString("Perform P(r) inversion.") 675 self.Bind(wx.EVT_BUTTON, self._on_invert, id=wx_id) 676 705 677 self._set_reset_flag(True) 706 678 self._set_save_flag(True) 707 679 sizer_button = wx.BoxSizer(wx.HORIZONTAL) 708 sizer_button.Add((20, 20), 1, wx.EXPAND |wx.ADJUST_MINSIZE, 0)709 sizer_button.Add(button_ OK, 0, wx.LEFT|wx.ADJUST_MINSIZE, 10)710 680 sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0) 681 sizer_button.Add(button_ok, 0, wx.LEFT | wx.ADJUST_MINSIZE, 10) 682 711 683 iy_vb += 1 712 684 vbox.Add(sizer_button, (iy_vb, 0), (1, 1), 713 wx.EXPAND |wx.BOTTOM|wx.TOP|wx.RIGHT, 10)685 wx.EXPAND | wx.BOTTOM | wx.TOP | wx.RIGHT, 10) 714 686 715 687 self.Bind(wx.EVT_TEXT_ENTER, self._on_invert) 716 688 717 689 self.SetSizer(vbox) 718 690 719 691 def _on_accept_alpha(self, evt): 720 692 """ 721 User has accepted the estimated alpha, 693 User has accepted the estimated alpha, 722 694 set it as part of the input parameters 723 695 """ 724 696 try: 725 697 alpha = self.alpha_estimate_ctl.GetLabel() 726 tmp = float(alpha) 727 self.alpha_ctl.SetValue(alpha) 698 self.alpha_ctl.SetValue(float(alpha)) 728 699 except: 729 700 # No estimate or bad estimate, either do nothing 730 #import sys 731 print "InversionControl._on_accept_alpha: %s" % sys.exc_value 732 pass 733 701 logging.error("InversionControl._on_accept_alpha: %s" % sys.exc_value) 702 734 703 def _on_accept_nterms(self, evt): 735 704 """ 736 User has accepted the estimated number of terms, 705 User has accepted the estimated number of terms, 737 706 set it as part of the input parameters 738 707 """ 739 708 try: 740 709 nterms = self.nterms_estimate_ctl.GetLabel() 741 tmp = float(nterms) 742 self.nfunc_ctl.SetValue(nterms) 710 self.nfunc_ctl.SetValue(float(nterms)) 743 711 except: 744 712 # No estimate or bad estimate, either do nothing 745 import sys 746 print "InversionControl._on_accept_nterms: %s" % sys.exc_value 747 pass 748 713 logging.error("InversionControl._on_accept_nterms: %s" % sys.exc_value) 714 749 715 def clear_panel(self): 750 716 """ … … 752 718 self.plot_data.SetValue("") 753 719 self.on_reset(event=None) 754 720 755 721 def on_reset(self, event=None): 756 722 """ … … 775 741 self.nterms_estimate_ctl.SetLabel("") 776 742 self._on_pars_changed() 777 743 778 744 def _on_pars_changed(self, evt=None): 779 745 """ 780 746 Called when an input parameter has changed 781 747 We will estimate the alpha parameter behind the 782 scenes. 748 scenes. 783 749 """ 784 750 flag, alpha, dmax, nfunc, qmin, qmax, height, width = self._read_pars() 785 751 has_bck = self.bck_chk.IsChecked() 786 752 787 753 # If the pars are valid, estimate alpha 788 754 if flag: 789 755 self.nterms_estimate_ctl.Enable(False) 790 756 self.alpha_estimate_ctl.Enable(False) 791 757 792 758 dataset = self.plot_data.GetValue() 793 759 if dataset is not None and dataset.strip() != "": 794 self._manager.estimate_plot_inversion(alpha=alpha, nfunc=nfunc, 795 d_max=dmax,796 q_min=qmin, q_max=qmax,797 bck=has_bck,798 height=height,799 width=width)800 760 self._manager.estimate_plot_inversion(alpha=alpha, nfunc=nfunc, 761 d_max=dmax, 762 q_min=qmin, q_max=qmax, 763 bck=has_bck, 764 height=height, 765 width=width) 766 801 767 def _read_pars(self, evt=None): 802 768 """ 803 """ 769 """ 804 770 alpha = 0 805 771 nfunc = 5 806 dmax 807 qmin 808 qmax 772 dmax = 120 773 qmin = 0 774 qmax = 0 809 775 height = 0 810 width 776 width = 0 811 777 flag = True 812 778 # Read slit height … … 823 789 self.sheight_ctl.SetBackgroundColour("pink") 824 790 self.sheight_ctl.Refresh() 825 791 826 792 # Read slit width 827 793 try: 828 794 width_str = self.swidth_ctl.GetValue() 829 if len(width_str.lstrip().rstrip()) ==0:795 if len(width_str.lstrip().rstrip()) == 0: 830 796 width = 0 831 797 else: … … 837 803 self.swidth_ctl.SetBackgroundColour("pink") 838 804 self.swidth_ctl.Refresh() 839 805 840 806 # Read alpha 841 807 try: … … 847 813 self.alpha_ctl.SetBackgroundColour("pink") 848 814 self.alpha_ctl.Refresh() 849 850 # Read d_max 815 816 # Read d_max 851 817 try: 852 818 dmax = float(self.dmax_ctl.GetValue()) … … 857 823 self.dmax_ctl.SetBackgroundColour("pink") 858 824 self.dmax_ctl.Refresh() 859 825 860 826 # Read nfunc 861 827 try: … … 873 839 self.nfunc_ctl.SetBackgroundColour("pink") 874 840 self.nfunc_ctl.Refresh() 875 841 876 842 # Read qmin 877 843 try: … … 887 853 self.qmin_ctl.SetBackgroundColour("pink") 888 854 self.qmin_ctl.Refresh() 889 855 890 856 # Read qmax 891 857 try: … … 901 867 self.qmax_ctl.SetBackgroundColour("pink") 902 868 self.qmax_ctl.Refresh() 903 869 904 870 return flag, alpha, dmax, nfunc, qmin, qmax, height, width 905 871 906 872 def _on_explore(self, evt): 907 873 """ … … 916 882 message = "No data to analyze. Please load a data set to proceed." 917 883 wx.PostEvent(self._manager.parent, StatusEvent(status=message)) 918 884 919 885 def _on_invert(self, evt): 920 886 """ 921 887 Perform inversion 922 923 :param silent: when True, there will be no output for the user 924 888 889 :param silent: when True, there will be no output for the user 890 925 891 """ 926 892 # Get the data from the form 927 893 # Push it to the manager 928 894 929 895 flag, alpha, dmax, nfunc, qmin, qmax, height, width = self._read_pars() 930 896 has_bck = self.bck_chk.IsChecked() 931 897 932 898 if flag: 933 899 dataset = self.plot_data.GetValue() 934 if dataset ==None or len(dataset.strip())==0:900 if dataset == None or len(dataset.strip()) == 0: 935 901 message = "No data to invert. Select a data set before" 936 902 message += " proceeding with P(r) inversion." 937 903 wx.PostEvent(self._manager.parent, StatusEvent(status=message)) 938 904 else: 939 self._manager.setup_plot_inversion(alpha=alpha, nfunc=nfunc, 940 d_max=dmax,941 q_min=qmin, q_max=qmax,942 bck=has_bck,943 height=height,944 width=width)905 self._manager.setup_plot_inversion(alpha=alpha, nfunc=nfunc, 906 d_max=dmax, 907 q_min=qmin, q_max=qmax, 908 bck=has_bck, 909 height=height, 910 width=width) 945 911 else: 946 912 message = "The P(r) form contains invalid values: " 947 913 message += "please submit it again." 948 914 wx.PostEvent(self.parent, StatusEvent(status=message)) 949 915 950 916 def _change_file(self, evt=None, filepath=None, data=None): 951 917 """ … … 960 926 except: 961 927 msg = "InversionControl._change_file: %s" % sys.exc_value 962 logging.error(msg) 928 logging.error(msg) 963 929 964 930 class HelpDialog(wx.Dialog): … … 970 936 from sas.pr.invertor import help 971 937 wx.Dialog.__init__(self, parent, id, size=(400, 450)) 972 self.SetTitle("P(r) help") 938 self.SetTitle("P(r) help") 973 939 self.SetWindowVariant(variant=FONT_VARIANT) 974 940 … … 976 942 977 943 explanation = help() 978 944 979 945 label_explain = wx.StaticText(self, -1, explanation, size=(360, 350)) 980 981 vbox.Add(label_explain, 0, wx.ALL |wx.EXPAND, 15)946 947 vbox.Add(label_explain, 0, wx.ALL | wx.EXPAND, 15) 982 948 983 949 984 950 static_line = wx.StaticLine(self, -1) 985 951 vbox.Add(static_line, 0, wx.EXPAND, 0) 986 987 button_OK = wx.Button(self, wx.ID_OK, "OK") 988 #button_Cancel = wx.Button(self, wx.ID_CANCEL, "Cancel") 989 952 953 button_ok = wx.Button(self, wx.ID_OK, "OK") 954 990 955 sizer_button = wx.BoxSizer(wx.HORIZONTAL) 991 sizer_button.Add((20, 20), 1, wx.EXPAND |wx.ADJUST_MINSIZE, 0)992 sizer_button.Add(button_ OK, 0, wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)993 994 vbox.Add(sizer_button, 0, wx.EXPAND |wx.BOTTOM|wx.TOP, 10)956 sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0) 957 sizer_button.Add(button_ok, 0, wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10) 958 959 vbox.Add(sizer_button, 0, wx.EXPAND | wx.BOTTOM | wx.TOP, 10) 995 960 996 961 self.SetSizer(vbox) 997 962 self.SetAutoLayout(True) 998 963 999 964 self.Layout() 1000 965 self.Centre() … … 1008 973 from sas.pr.invertor import help 1009 974 wx.Dialog.__init__(self, parent, id, size=(250, 120)) 1010 self.SetTitle("P(r) distribution") 1011 975 self.SetTitle("P(r) distribution") 976 1012 977 1013 978 vbox = wx.BoxSizer(wx.VERTICAL) 1014 979 1015 980 label_npts = wx.StaticText(self, -1, "Number of points") 1016 981 self.npts_ctl = PrTextCtrl(self, -1, size=(100, 20)) 1017 982 1018 983 pars_sizer = wx.GridBagSizer(5, 5) 1019 984 iy = 0 1020 985 pars_sizer.Add(label_npts, (iy, 0), (1, 1), wx.LEFT, 15) 1021 986 pars_sizer.Add(self.npts_ctl, (iy, 1), (1, 1), wx.RIGHT, 0) 1022 1023 vbox.Add(pars_sizer, 0, wx.ALL |wx.EXPAND, 15)987 988 vbox.Add(pars_sizer, 0, wx.ALL | wx.EXPAND, 15) 1024 989 1025 990 static_line = wx.StaticLine(self, -1) 1026 991 vbox.Add(static_line, 0, wx.EXPAND, 0) 1027 1028 button_ OK= wx.Button(self, wx.ID_OK, "OK")1029 self.Bind(wx.EVT_BUTTON, self._checkValues, button_ OK)1030 button_ Cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")1031 992 993 button_ok = wx.Button(self, wx.ID_OK, "OK") 994 self.Bind(wx.EVT_BUTTON, self._checkValues, button_ok) 995 button_cancel = wx.Button(self, wx.ID_CANCEL, "Cancel") 996 1032 997 sizer_button = wx.BoxSizer(wx.HORIZONTAL) 1033 sizer_button.Add((20, 20), 1, wx.EXPAND |wx.ADJUST_MINSIZE, 0)1034 sizer_button.Add(button_ OK, 0, wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)1035 sizer_button.Add(button_ Cancel, 0,1036 wx.LEFT |wx.RIGHT|wx.ADJUST_MINSIZE, 10)1037 vbox.Add(sizer_button, 0, wx.EXPAND |wx.BOTTOM|wx.TOP, 10)998 sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0) 999 sizer_button.Add(button_ok, 0, wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10) 1000 sizer_button.Add(button_cancel, 0, 1001 wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10) 1002 vbox.Add(sizer_button, 0, wx.EXPAND | wx.BOTTOM | wx.TOP, 10) 1038 1003 1039 1004 self.SetSizer(vbox) 1040 1005 self.SetAutoLayout(True) 1041 1006 1042 1007 self.Layout() 1043 1008 self.Centre() … … 1067 1032 value = int(self.npts_ctl.GetValue()) 1068 1033 return value 1069 1034 1070 1035 def set_content(self, npts): 1071 1036 """ … … 1073 1038 """ 1074 1039 self.npts_ctl.SetValue("%i" % npts) 1075 1076 ##### testing code ############################################################1077 """1078 Example: ::1079 1080 class TestPlot:1081 def __init__(self, text):1082 self.name = text1083 1084 class MyApp(wx.App):1085 def OnInit(self):1086 wx.InitAllImageHandlers()1087 dialog = PrDistDialog(None, -1)1088 if dialog.ShowModal() == wx.ID_OK:1089 pass1090 dialog.Destroy()1091 1092 return 11093 1094 # end of class MyApp1095 1096 if __name__ == "__main__":1097 app = MyApp(0)1098 app.MainLoop()1099 1100 """1101 ##### end of testing code ##################################################### -
src/sas/perspectives/pr/inversion_state.py
rc4f6851 r8b21fa7 5 5 #This software was developed by the University of Tennessee as part of the 6 6 #Distributed Data Analysis of Neutron Scattering Experiments (DANSE) 7 #project funded by the US National Science Foundation. 7 #project funded by the US National Science Foundation. 8 8 # 9 9 #See the license text in license.txt … … 26 26 27 27 # Translation of names between stored and object data 28 ## List of P(r) inversion inputs 29 in_list = [["nterms","nfunc"],30 ["d_max", 31 ["alpha", 32 ["slit_width", 33 ["slit_height", 34 ["qmin", 35 ["qmax", 36 ["estimate_bck", "estimate_bck"]] 28 ## List of P(r) inversion inputs 29 in_list = [["nterms", "nfunc"], 30 ["d_max", "d_max"], 31 ["alpha", "alpha"], 32 ["slit_width", "width"], 33 ["slit_height", "height"], 34 ["qmin", "qmin"], 35 ["qmax", "qmax"], 36 ["estimate_bck", "estimate_bck"]] 37 37 38 38 ## List of P(r) inversion outputs 39 39 out_list = [["elapsed", "elapsed"], 40 ["rg","rg"],41 ["iq0","iq0"],42 ["bck","bck"],43 ["chi2","chi2"],44 ["osc","osc"],45 ["pos","pos"],46 ["pos_err", "pos_err"],47 ["alpha_estimate", "alpha_estimate"],48 ["nterms_estimate", "nterms_estimate"]]40 ["rg", "rg"], 41 ["iq0", "iq0"], 42 ["bck", "bck"], 43 ["chi2", "chi2"], 44 ["osc", "osc"], 45 ["pos", "pos"], 46 ["pos_err", "pos_err"], 47 ["alpha_estimate", "alpha_estimate"], 48 ["nterms_estimate", "nterms_estimate"]] 49 49 50 50 class InversionState(object): … … 56 56 Default values 57 57 """ 58 # Input 59 self.file 58 # Input 59 self.file = None 60 60 self.estimate_bck = False 61 61 self.timestamp = time.time() 62 62 63 63 # Inversion parameters 64 64 self.nfunc = None 65 65 self.d_max = None 66 66 self.alpha = None 67 67 68 68 # Slit parameters 69 69 self.height = None 70 self.width 71 70 self.width = None 71 72 72 # Q range 73 self.qmin 74 self.qmax 75 73 self.qmin = None 74 self.qmax = None 75 76 76 # Outputs 77 77 self.elapsed = None 78 self.rg 79 self.iq0 80 self.bck 81 self.chi2 82 self.osc 83 self.pos 78 self.rg = None 79 self.iq0 = None 80 self.bck = None 81 self.chi2 = None 82 self.osc = None 83 self.pos = None 84 84 self.pos_err = None 85 85 86 86 # Estimates 87 87 self.alpha_estimate = None 88 88 self.nterms_estimate = None 89 89 90 90 # Data 91 self.q 92 self.iq_obs 91 self.q = None 92 self.iq_obs = None 93 93 self.iq_calc = None 94 94 95 95 # Coefficients 96 96 self.coefficients = None 97 97 self.covariance = None 98 98 99 99 def __str__(self): 100 100 """ 101 101 Pretty print 102 102 103 103 :return: string representing the state 104 105 """ 106 state 104 105 """ 106 state = "File: %s\n" % self.file 107 107 state += "Timestamp: %s\n" % self.timestamp 108 108 state += "Estimate bck: %s\n" % str(self.estimate_bck) … … 110 110 state += "D_max: %s\n" % str(self.d_max) 111 111 state += "Alpha: %s\n" % str(self.alpha) 112 112 113 113 state += "Slit height: %s\n" % str(self.height) 114 114 state += "Slit width: %s\n" % str(self.width) 115 115 116 116 state += "Qmin: %s\n" % str(self.qmin) 117 117 state += "Qmax: %s\n" % str(self.qmax) 118 118 119 119 state += "\nEstimates:\n" 120 120 state += " Alpha: %s\n" % str(self.alpha_estimate) 121 121 state += " Nterms: %s\n" % str(self.nterms_estimate) 122 122 123 123 state += "\nOutputs:\n" 124 124 state += " Elapsed: %s\n" % str(self.elapsed) … … 130 130 state += " Positive: %s\n" % str(self.pos) 131 131 state += " 1-sigma pos:%s\n" % str(self.pos_err) 132 132 133 133 return state 134 134 135 135 def toXML(self, file="pr_state.prv", doc=None, entry_node=None): 136 136 """ 137 137 Writes the state of the InversionControl panel to file, as XML. 138 138 139 139 Compatible with standalone writing, or appending to an 140 140 already existing XML document. In that case, the XML document 141 is required. An optional entry node in the XML document 141 is required. An optional entry node in the XML document 142 142 may also be given. 143 143 144 144 :param file: file to write to 145 145 :param doc: XML document object [optional] 146 :param entry_node: XML node within the XML document at which 146 :param entry_node: XML node within the XML document at which 147 147 we will append the data [optional] 148 148 149 149 """ 150 150 #TODO: Get this to work … … 154 154 if doc is None: 155 155 impl = getDOMImplementation() 156 157 doc_type = impl.createDocumentType(PRNODE_NAME, "1.0", "1.0") 158 156 157 doc_type = impl.createDocumentType(PRNODE_NAME, "1.0", "1.0") 158 159 159 newdoc = impl.createDocument(None, PRNODE_NAME, doc_type) 160 160 top_element = newdoc.documentElement … … 167 167 else: 168 168 entry_node.appendChild(top_element) 169 169 170 170 attr = newdoc.createAttribute("version") 171 171 attr.nodeValue = '1.0' 172 172 top_element.setAttributeNode(attr) 173 173 174 174 # File name 175 175 element = newdoc.createElement("filename") … … 179 179 element.appendChild(newdoc.createTextNode(str(file))) 180 180 top_element.appendChild(element) 181 181 182 182 element = newdoc.createElement("timestamp") 183 183 element.appendChild(newdoc.createTextNode(time.ctime(self.timestamp))) … … 186 186 element.setAttributeNode(attr) 187 187 top_element.appendChild(element) 188 188 189 189 # Inputs 190 190 inputs = newdoc.createElement("inputs") 191 191 top_element.appendChild(inputs) 192 192 193 193 for item in in_list: 194 194 element = newdoc.createElement(item[0]) 195 195 element.appendChild(newdoc.createTextNode(str(getattr(self, item[1])))) 196 196 inputs.appendChild(element) 197 197 198 198 # Outputs 199 199 outputs = newdoc.createElement("outputs") 200 200 top_element.appendChild(outputs) 201 201 202 202 for item in out_list: 203 203 element = newdoc.createElement(item[0]) 204 204 element.appendChild(newdoc.createTextNode(str(getattr(self, item[1])))) 205 205 outputs.appendChild(element) 206 206 207 207 # Save output coefficients and its covariance matrix 208 208 element = newdoc.createElement("coefficients") … … 212 212 element.appendChild(newdoc.createTextNode(str(self.covariance))) 213 213 outputs.appendChild(element) 214 214 215 215 # Save the file 216 216 if doc is None: … … 225 225 """ 226 226 Load a P(r) inversion state from a file 227 227 228 228 :param file: .prv file 229 229 :param node: node of a XML document to read from 230 230 231 231 """ 232 232 if file is not None: … … 234 234 msg += " format for P(r) files" 235 235 raise RuntimeError, msg 236 236 237 237 if node.get('version') and node.get('version') == '1.0': 238 238 239 239 # Get file name 240 240 entry = get_content('ns:filename', node) 241 241 if entry is not None: 242 242 self.file = entry.text.strip() 243 243 244 244 # Get time stamp 245 245 entry = get_content('ns:timestamp', node) … … 251 251 msg += "timestamp\n %s" % sys.exc_value 252 252 logging.error(msg) 253 253 254 254 # Parse inversion inputs 255 255 entry = get_content('ns:inputs', node) … … 265 265 if input_field is not None: 266 266 try: 267 self.estimate_bck = input_field.text.strip() =='True'267 self.estimate_bck = input_field.text.strip() == 'True' 268 268 except: 269 269 self.estimate_bck = False 270 270 271 271 # Parse inversion outputs 272 272 entry = get_content('ns:outputs', node) … … 280 280 except: 281 281 setattr(self, item[1], None) 282 282 283 283 # Look for coefficients 284 284 # Format is [value, value, value, value] … … 286 286 if coeff is not None: 287 287 # Remove brackets 288 c_values = coeff.text.strip().replace('[', '')289 c_values = c_values.replace(']', '')288 c_values = coeff.text.strip().replace('[', '') 289 c_values = c_values.replace(']', '') 290 290 toks = c_values.split() 291 291 self.coefficients = [] … … 308 308 logging.error(err_msg) 309 309 self.coefficients = None 310 310 311 311 # Look for covariance matrix 312 312 # Format is [ [value, value], [value, value] ] … … 320 320 if len(row) == 0: continue 321 321 # Remove end bracket 322 row = row.replace(']', '')322 row = row.replace(']', '') 323 323 c_values = row.split() 324 324 cov_row = [] … … 345 345 logging.error(err_msg) 346 346 self.covariance = None 347 347 348 348 class Reader(CansasReader): 349 349 """ … … 352 352 ## File type 353 353 type_name = "P(r)" 354 354 355 355 ## Wildcards 356 356 type = ["P(r) files (*.prv)|*.prv", 357 357 "SASView files (*.svs)|*.svs"] 358 358 ## List of allowed extensions 359 ext = ['.prv', '.PRV', '.svs', '.SVS'] 360 359 ext = ['.prv', '.PRV', '.svs', '.SVS'] 360 361 361 def __init__(self, call_back, cansas=True): 362 362 """ 363 363 Initialize the call-back method to be called 364 364 after we load a file 365 365 366 366 :param call_back: call-back method 367 367 :param cansas: True = files will be written/read in CanSAS format 368 368 False = write CanSAS format 369 369 370 370 """ 371 371 ## Call back method to be executed after a file is read … … 374 374 self.cansas = cansas 375 375 self.state = None 376 376 377 377 def read(self, path): 378 """ 378 """ 379 379 Load a new P(r) inversion state from file 380 380 381 381 :param path: file path 382 382 383 383 :return: None 384 385 """ 386 if self.cansas ==True:384 385 """ 386 if self.cansas == True: 387 387 return self._read_cansas(path) 388 388 else: 389 389 return self._read_standalone(path) 390 390 391 391 def _read_standalone(self, path): 392 """ 392 """ 393 393 Load a new P(r) inversion state from file. 394 394 The P(r) node is assumed to be the top element. 395 395 396 396 :param path: file path 397 397 398 398 :return: None 399 399 400 400 """ 401 401 # Read the new state from file 402 402 state = InversionState() 403 403 state.fromXML(file=path) 404 404 405 405 # Call back to post the new state 406 406 self.state = state 407 407 #self.call_back(state) 408 408 return None 409 409 410 410 def _parse_prstate(self, entry): 411 411 """ 412 412 Read a p(r) inversion result from an XML node 413 414 :param entry: XML node to read from 415 413 414 :param entry: XML node to read from 415 416 416 :return: InversionState object 417 417 418 418 """ 419 419 state = None 420 420 421 421 # Locate the P(r) node 422 422 try: 423 423 nodes = entry.xpath('ns:%s' % PRNODE_NAME, 424 424 namespaces={'ns': CANSAS_NS}) 425 if nodes != []:425 if nodes != []: 426 426 # Create an empty state 427 state = 427 state = InversionState() 428 428 state.fromXML(node=nodes[0]) 429 429 except: … … 431 431 msg += "information.\n %s" % sys.exc_value 432 432 logging.info(msg) 433 433 434 434 return state 435 435 436 436 def _read_cansas(self, path): 437 """ 437 """ 438 438 Load data and P(r) information from a CanSAS XML file. 439 439 440 440 :param path: file path 441 442 :return: Data1D object if a single SASentry was found, 441 442 :return: Data1D object if a single SASentry was found, 443 443 or a list of Data1D objects if multiple entries were found, 444 444 or None of nothing was found 445 445 446 446 :raise RuntimeError: when the file can't be opened 447 447 :raise ValueError: when the length of the data vectors are inconsistent 448 448 449 449 """ 450 450 output = [] 451 451 452 452 if os.path.isfile(path): 453 basename 453 basename = os.path.basename(path) 454 454 root, extension = os.path.splitext(basename) 455 455 #TODO: eventually remove the check for .xml once 456 456 # the P(r) writer/reader is truly complete. 457 457 if extension.lower() in self.ext or extension.lower() == '.xml': 458 458 459 459 tree = etree.parse(path, parser=etree.ETCompatXMLParser()) 460 460 # Check the format version number … … 462 462 #format version 463 463 root = tree.getroot() 464 464 465 465 entry_list = root.xpath('/ns:SASroot/ns:SASentry', 466 466 namespaces={'ns': CANSAS_NS}) … … 477 477 else: 478 478 raise RuntimeError, "%s is not a file" % path 479 479 480 480 # Return output consistent with the loader's api 481 481 if len(output) == 0: … … 483 483 elif len(output) == 1: 484 484 # Call back to post the new state 485 self.call_back(output[0].meta_data['prstate'], datainfo =output[0])485 self.call_back(output[0].meta_data['prstate'], datainfo=output[0]) 486 486 #self.state = output[0].meta_data['prstate'] 487 487 return output[0] 488 488 else: 489 return output 490 491 489 return output 490 491 492 492 def write(self, filename, datainfo=None, prstate=None): 493 493 """ 494 494 Write the content of a Data1D as a CanSAS XML file 495 495 496 496 :param filename: name of the file to write 497 497 :param datainfo: Data1D object 498 498 :param prstate: InversionState object 499 499 500 500 """ 501 501 # Sanity check 502 502 if self.cansas == True: 503 doc = self.write_toXML(datainfo, prstate) 503 doc = self.write_toXML(datainfo, prstate) 504 504 # Write the XML document 505 505 fd = open(filename, 'w') … … 508 508 else: 509 509 prstate.toXML(file=filename) 510 510 511 511 def write_toXML(self, datainfo=None, state=None): 512 512 """ 513 513 Write toXML, a helper for write() 514 514 515 515 : return: xml doc 516 516 """ 517 517 if datainfo is None: 518 datainfo = Data1D(x=[], y=[]) 518 datainfo = Data1D(x=[], y=[]) 519 519 elif not issubclass(datainfo.__class__, Data1D): 520 520 msg = "The cansas writer expects a Data1D " 521 521 msg += "instance: %s" % str(datainfo.__class__.__name__) 522 522 raise RuntimeError, msg 523 523 524 524 # Create basic XML document 525 525 doc, sasentry = self._to_xml_doc(datainfo) 526 526 527 527 # Add the invariant information to the XML document 528 528 if state is not None: 529 529 doc = state.toXML(doc=doc, entry_node=sasentry) 530 531 return doc 532 530 531 return doc -
src/sas/perspectives/pr/pr_thread.py
r79492222 r8b21fa7 3 3 #This software was developed by the University of Tennessee as part of the 4 4 #Distributed Data Analysis of Neutron Scattering Experiments (DANSE) 5 #project funded by the US National Science Foundation. 5 #project funded by the US National Science Foundation. 6 6 # 7 7 #See the license text in license.txt … … 18 18 Compute P(r) 19 19 """ 20 21 def __init__(self, pr, nfunc=5, error_func=None, 22 completefn = None, 23 updatefn = None, 24 yieldtime = 0.01, 25 worktime = 0.01 26 ): 20 21 def __init__(self, pr, nfunc=5, error_func=None, completefn=None, 22 updatefn=None, yieldtime=0.01, worktime=0.01): 27 23 """ 28 24 """ 29 CalcThread.__init__(self,completefn, 30 updatefn, 31 yieldtime, 32 worktime) 25 CalcThread.__init__(self, completefn, updatefn, yieldtime, worktime) 33 26 self.pr = pr 34 27 self.nfunc = nfunc 35 28 self.error_func = error_func 36 29 self.starttime = 0 37 30 38 31 def compute(self): 39 32 """ … … 43 36 self.starttime = time.time() 44 37 out, cov = self.pr.invert(self.nfunc) 45 #out, cov = self.pr.lstsq(self.nfunc) 46 #out, cov = self.pr.invert_optimize(self.nfunc) 47 elapsed = time.time()-self.starttime 38 elapsed = time.time() - self.starttime 48 39 self.complete(out=out, cov=cov, pr=self.pr, elapsed=elapsed) 49 40 except KeyboardInterrupt: … … 51 42 pass 52 43 except: 53 if not self.error_func ==None:44 if not self.error_func == None: 54 45 self.error_func("CalcPr.compute: %s" % sys.exc_value) 55 46 … … 58 49 Estimate P(r) 59 50 """ 60 61 def __init__(self, pr, nfunc=5, error_func=None, 62 completefn = None, 63 updatefn = None, 64 yieldtime = 0.01, 65 worktime = 0.01 66 ): 67 CalcThread.__init__(self,completefn, 68 updatefn, 69 yieldtime, 70 worktime) 51 52 def __init__(self, pr, nfunc=5, error_func=None, completefn=None, 53 updatefn=None, yieldtime=0.01, worktime=0.01): 54 CalcThread.__init__(self, completefn, updatefn, yieldtime, worktime) 71 55 self.pr = pr 72 56 self.nfunc = nfunc 73 57 self.error_func = error_func 74 58 self.starttime = 0 75 59 76 60 def compute(self): 77 61 """ 78 62 Calculates the estimate 79 63 """ 80 try: 64 try: 81 65 alpha, message, elapsed = self.pr.estimate_alpha(self.nfunc) 82 66 self.isquit() … … 86 70 pass 87 71 except: 88 if not self.error_func ==None:72 if not self.error_func == None: 89 73 self.error_func("EstimatePr.compute: %s" % sys.exc_value) 90 74 … … 92 76 """ 93 77 """ 94 def __init__(self, pr, nfunc=5, error_func=None, 95 completefn = None, 96 updatefn = None, 97 yieldtime = 0.01, 98 worktime = 0.01 99 ): 100 CalcThread.__init__(self,completefn, 101 updatefn, 102 yieldtime, 103 worktime) 78 def __init__(self, pr, nfunc=5, error_func=None, completefn=None, 79 updatefn=None, yieldtime=0.01, worktime=0.01): 80 CalcThread.__init__(self, completefn, updatefn, yieldtime, worktime) 104 81 self.pr = pr 105 82 self.nfunc = nfunc … … 114 91 """ 115 92 CalcThread.isquit(self) 116 if time.time() >self._time_for_sleep+self._sleep_delay:93 if time.time() > self._time_for_sleep + self._sleep_delay: 117 94 time.sleep(.2) 118 95 self._time_for_sleep = time.time() … … 122 99 Calculates the estimate 123 100 """ 124 try: 101 try: 125 102 t_0 = time.time() 126 103 self._time_for_sleep = t_0 127 104 nterms, alpha, message = self.pr.estimate_numterms(self.isquit) 128 t_1 = time.time() -t_0105 t_1 = time.time() - t_0 129 106 self.isquit() 130 107 self.complete(nterms=nterms, alpha=alpha, message=message, elapsed=t_1) … … 133 110 pass 134 111 except: 135 if not self.error_func ==None:112 if not self.error_func == None: 136 113 self.error_func("EstimatePr2.compute: %s" % sys.exc_value) -
src/sas/perspectives/pr/pr_widgets.py
r79492222 r8b21fa7 3 3 #This software was developed by the University of Tennessee as part of the 4 4 #Distributed Data Analysis of Neutron Scattering Experiments (DANSE) 5 #project funded by the US National Science Foundation. 5 #project funded by the US National Science Foundation. 6 6 # 7 7 #See the license text in license.txt … … 26 26 ScrolledPanel.__init__(self, *args, **kwds) 27 27 self.SetupScrolling() 28 29 28 29 30 30 class PrTextCtrl(wx.TextCtrl): 31 31 """ … … 34 34 """ 35 35 def __init__(self, *args, **kwds): 36 36 37 37 wx.TextCtrl.__init__(self, *args, **kwds) 38 38 39 39 ## Set to True when the mouse is clicked while the whole string is selected 40 40 self.full_selection = False … … 49 49 Catch when the text control is set in focus to highlight the whole 50 50 text if necessary 51 51 52 52 :param event: mouse event 53 53 54 54 """ 55 55 event.Skip() 56 56 self.full_selection = True 57 57 58 58 def _highlight_text(self, event): 59 59 """ 60 60 Highlight text of a TextCtrl only of no text has be selected 61 61 62 62 :param event: mouse event 63 63 64 64 """ 65 65 # Make sure the mouse event is available to other listeners 66 66 event.Skip() 67 control 67 control = event.GetEventObject() 68 68 if self.full_selection: 69 69 self.full_selection = False 70 70 # Check that we have a TextCtrl 71 71 if issubclass(control.__class__, wx.TextCtrl): 72 # Check whether text has been selected, 72 # Check whether text has been selected, 73 73 # if not, select the whole string 74 74 (start, end) = control.GetSelection() 75 if start ==end:76 control.SetSelection(-1, -1)75 if start == end: 76 control.SetSelection(-1, -1) 77 77 78 78 class OutputTextCtrl(wx.TextCtrl): 79 79 """ 80 80 Text control used to display outputs. 81 No editing allowed. The background is 81 No editing allowed. The background is 82 82 grayed out. User can't select text. 83 83 """ … … 88 88 self.SetEditable(False) 89 89 self.SetBackgroundColour(self.GetParent().GetBackgroundColour()) 90 90 91 91 # Bind to mouse event to avoid text highlighting 92 92 # The event will be skipped once the call-back 93 93 # is called. 94 94 self.Bind(wx.EVT_MOUSE_EVENTS, self._click) 95 95 96 96 def _click(self, event): 97 97 """ 98 98 Prevent further handling of the mouse event 99 99 by not calling Skip(). 100 """ 100 """ 101 101 pass 102 102 103 103 104 104 class DataFileTextCtrl(OutputTextCtrl): … … 106 106 Text control used to display only the file name 107 107 given a full path. 108 108 109 109 :TODO: now that we no longer choose the data file from the panel, 110 110 it's no longer necessary to pass around the file path. That code 111 should be refactored away and simplified. 111 should be refactored away and simplified. 112 112 """ 113 113 def __init__(self, *args, **kwds): … … 116 116 OutputTextCtrl.__init__(self, *args, **kwds) 117 117 self._complete_path = None 118 118 119 119 def SetValue(self, value): 120 120 """ … … 122 122 """ 123 123 self._complete_path = str(value) 124 file = os.path.basename(self._complete_path)125 OutputTextCtrl.SetValue(self, file )126 124 file_path = os.path.basename(self._complete_path) 125 OutputTextCtrl.SetValue(self, file_path) 126 127 127 def GetValue(self): 128 128 """ … … 130 130 """ 131 131 return self._complete_path 132 133 134 135 132 133 136 134 def load_error(error=None): 137 135 """ 138 136 Pop up an error message. 139 137 140 138 :param error: details error message to be displayed 141 139 """ 142 140 message = "The data file you selected could not be loaded.\n" 143 141 message += "Make sure the content of your file is properly formatted.\n\n" 144 142 145 143 if error is not None: 146 144 message += "When contacting the DANSE team, mention the" 147 145 message += " following:\n%s" % str(error) 148 146 149 147 dial = wx.MessageDialog(None, message, 'Error Loading File', 150 148 wx.OK | wx.ICON_EXCLAMATION) 151 dial.ShowModal() 152 153 149 dial.ShowModal() 150 151 154 152 class DataDialog(wx.Dialog): 155 153 """ … … 166 164 self._choice_sizer = wx.GridBagSizer(5, 5) 167 165 self._panel = DialogPanel(self, style=wx.RAISED_BORDER, 168 size=(WIDTH-20, HEIGHT/3))169 166 size=(WIDTH - 20, HEIGHT / 3)) 167 170 168 self.__do_layout(data_list, text=text) 171 172 169 173 170 def __do_layout(self, data_list, text=''): 174 171 """ 175 172 layout the dialog 176 173 """ 177 #if not data_list or len(data_list) <= 1:178 # return179 174 #add text 180 175 if text.strip() == "": … … 182 177 text += "Please select only one Data.\n" 183 178 text_ctrl = wx.TextCtrl(self, -1, str(text), style=wx.TE_MULTILINE, 184 size=(-1, HEIGHT /3))179 size=(-1, HEIGHT / 3)) 185 180 text_ctrl.SetEditable(False) 186 self._sizer_txt.Add(text_ctrl , 1, wx.EXPAND|wx.ALL, 10)181 self._sizer_txt.Add(text_ctrl, 1, wx.EXPAND | wx.ALL, 10) 187 182 iy = 0 188 183 ix = 0 189 rbox = wx.RadioButton(self._panel, -1, str(data_list[0].name), 190 (10, 10), style=wx.RB_GROUP)184 rbox = wx.RadioButton(self._panel, -1, str(data_list[0].name), 185 (10, 10), style=wx.RB_GROUP) 191 186 rbox.SetValue(True) 192 187 self.list_of_ctrl.append((rbox, data_list[0])) 193 188 self._choice_sizer.Add(rbox, (iy, ix), (1, 1), 194 wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)189 wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15) 195 190 for i in range(1, len(data_list)): 196 191 iy += 1 197 rbox = wx.RadioButton(self._panel, -1, 192 rbox = wx.RadioButton(self._panel, -1, 198 193 str(data_list[i].name), (10, 10)) 199 194 rbox.SetValue(False) 200 195 self.list_of_ctrl.append((rbox, data_list[i])) 201 196 self._choice_sizer.Add(rbox, (iy, ix), 202 (1, 1), wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)197 (1, 1), wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15) 203 198 self._panel.SetSizer(self._choice_sizer) 204 199 #add sizer 205 self._sizer_button.Add((20, 20), 1, wx.EXPAND |wx.ADJUST_MINSIZE, 0)200 self._sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0) 206 201 button_cancel = wx.Button(self, wx.ID_CANCEL, "Cancel") 207 202 self._sizer_button.Add(button_cancel, 0, 208 wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)209 button_ OK= wx.Button(self, wx.ID_OK, "Ok")210 button_ OK.SetFocus()211 self._sizer_button.Add(button_ OK, 0,212 wx.LEFT|wx.RIGHT|wx.ADJUST_MINSIZE, 10)203 wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10) 204 button_ok = wx.Button(self, wx.ID_OK, "Ok") 205 button_ok.SetFocus() 206 self._sizer_button.Add(button_ok, 0, 207 wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10) 213 208 static_line = wx.StaticLine(self, -1) 214 215 self._sizer_txt.Add(self._panel, 0, wx.EXPAND |wx.ALL, 5)216 self._sizer_main.Add(self._sizer_txt, 0, wx.EXPAND |wx.ALL, 5)209 210 self._sizer_txt.Add(self._panel, 0, wx.EXPAND | wx.ALL, 5) 211 self._sizer_main.Add(self._sizer_txt, 0, wx.EXPAND | wx.ALL, 5) 217 212 self._sizer_main.Add(static_line, 0, wx.EXPAND, 0) 218 self._sizer_main.Add(self._sizer_button, 0, wx.EXPAND |wx.ALL, 10)213 self._sizer_main.Add(self._sizer_button, 0, wx.EXPAND | wx.ALL, 10) 219 214 self.SetSizer(self._sizer_main) 220 215 221 216 def get_data(self): 222 217 """ … … 226 221 rbox, data = item 227 222 if rbox.GetValue(): 228 return data 229 230 231 232 223 return data
Note: See TracChangeset
for help on using the changeset viewer.