Package gui :: Package analyses :: Module wizard
[hide private]
[frames] | no frames]

Source Code for Module gui.analyses.wizard

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2011-2013 Edward d'Auvergne                                   # 
  4  #                                                                             # 
  5  # This file is part of the program relax (http://www.nmr-relax.com).          # 
  6  #                                                                             # 
  7  # This program is free software: you can redistribute it and/or modify        # 
  8  # it under the terms of the GNU General Public License as published by        # 
  9  # the Free Software Foundation, either version 3 of the License, or           # 
 10  # (at your option) any later version.                                         # 
 11  #                                                                             # 
 12  # This program is distributed in the hope that it will be useful,             # 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 15  # GNU General Public License for more details.                                # 
 16  #                                                                             # 
 17  # You should have received a copy of the GNU General Public License           # 
 18  # along with this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 19  #                                                                             # 
 20  ############################################################################### 
 21   
 22  # Module docstring. 
 23  """Module for the analysis selection wizard.""" 
 24   
 25  # Python module imports. 
 26  from os import sep 
 27  from time import asctime, localtime 
 28  import wx 
 29  from wx.lib import buttons 
 30   
 31  # relax module imports. 
 32  from graphics import ANALYSIS_IMAGE_PATH, IMAGE_PATH, WIZARD_IMAGE_PATH 
 33  from gui.input_elements.value import Value 
 34  from gui.misc import bitmap_setup 
 35  from gui.string_conv import gui_to_str, str_to_gui 
 36  from gui.uf_objects import Uf_storage; uf_store = Uf_storage() 
 37  from gui.wizards.wiz_objects import Wiz_page, Wiz_window 
 38  from lib.text.gui import r1, r2 
 39   
 40   
41 -class Analysis_wizard:
42 """The analysis selection wizard.""" 43
44 - def run(self):
45 """Run through the analysis selection wizard, returning the results. 46 47 @return: The analysis type, analysis name, data pipe name, data pipe bundle name, and user function on_execute method list. 48 @rtype: tuple of str 49 """ 50 51 # Change the cursor to busy. 52 wx.Yield() 53 wx.BeginBusyCursor() 54 55 # Set up the wizard. 56 self.wizard = Wiz_window(size_x=1000, size_y=700, title='Analysis selection wizard') 57 58 # Change the finish button. 59 self.wizard.TEXT_FINISH = " Start" 60 61 # Add the new analysis panel. 62 self.new_page = New_analysis_page(self.wizard) 63 self.wizard.add_page(self.new_page, apply_button=False) 64 self.wizard.set_seq_next_fn(0, self.wizard_page_after_analysis) 65 66 # Add the data pipe name panel. 67 self.pipe_page = Data_pipe_page(self.wizard, height_desc=400) 68 self.wizard.add_page(self.pipe_page, apply_button=False) 69 70 # Reset the cursor. 71 if wx.IsBusy(): 72 wx.EndBusyCursor() 73 74 # Execute the wizard. 75 setup = self.wizard.run(modal=True) 76 if setup != wx.ID_OK: 77 return 78 79 # Return the analysis type, analysis name, data pipe name, data pipe bundle name, and user function on_execute method list. 80 return self.get_data()
81 82
83 - def get_data(self):
84 """Assemble and return the analysis type, analysis name, and pipe name. 85 86 @return: The analysis type, analysis name, data pipe name, data pipe bundle name, and list of user function on_execute methods. 87 @rtype: str, str, str, str, list of methods 88 """ 89 90 # Get the data. 91 analysis_type = gui_to_str(self.wizard.analysis_type) 92 analysis_name = gui_to_str(self.new_page.analysis_name.GetValue()) 93 pipe_name = gui_to_str(self.pipe_page.pipe_name.GetValue()) 94 pipe_bundle = gui_to_str(self.pipe_page.pipe_bundle.GetValue()) 95 96 # The user function on_execute methods. 97 uf_exec = [] 98 99 # Return it. 100 return analysis_type, analysis_name, pipe_name, pipe_bundle, uf_exec
101 102
104 """Set the page after the data pipe setup. 105 106 @return: The index of the next page, which is the current page index plus one. 107 @rtype: int 108 """ 109 110 # The selected analysis. 111 analysis_name = gui_to_str(self.new_page.analysis_name.GetValue()) 112 113 # Default to the second page. 114 return 1
115 116 117
118 -class Data_pipe_page(Wiz_page):
119 """The panel for setting the data pipe name.""" 120 121 # Class variables. 122 image_path = WIZARD_IMAGE_PATH + 'pipe.png' 123 main_text = "Select the name of the data pipe used at the start of the analysis and the name of the data pipe bundle to be associated with this analysis. All data in relax is kept within a special structure known as the relax data store. This store is composed of multiple data pipes, each being associated with a specific analysis type. Data pipe bundles are simple groupings of the pipes within the data store and each analysis tab is coupled to a specific bundle.\n\nSimple analyses such as the steady-state NOE and the %s and %s curve-fitting will be located within a single data pipe. More complex analyses such as the automated model-free analysis will be spread across multiple data pipes, internally created by forking the original data pipe which holds the input data, all grouped together within a single bundle.\n\nThe initialisation of a new analysis will call the pipe.create user function with the pipe name and pipe bundle as given below." % (r1, r2) 124 title = 'Data pipe set up' 125
126 - def add_contents(self, sizer):
127 """Add the specific GUI elements (dummy method). 128 129 @param sizer: A sizer object. 130 @type sizer: wx.Sizer instance 131 """ 132 133 # The pipe name input. 134 self.pipe_name = Value(name='pipe_name', parent=self, value_type='str', sizer=sizer, desc="The starting data pipe for the analysis:", divider=self._div_left, height_element=self.height_element) 135 136 # The pipe bundle input. 137 self.pipe_bundle = Value(name='pipe_bundle', parent=self, value_type='str', sizer=sizer, desc="The data pipe bundle:", divider=self._div_left, height_element=self.height_element) 138 139 # Spacing. 140 sizer.AddStretchSpacer(3)
141 142
143 - def on_display(self):
144 """Update the pipe name.""" 145 146 # Generate a name for the data pipe bundle based on the type and time. 147 name = "%s (%s)" % (self.parent.analysis_type, asctime(localtime())) 148 149 # Update the fields. 150 self.pipe_name.SetValue(str_to_gui("origin - %s" % name)) 151 self.pipe_bundle.SetValue(str_to_gui(name))
152 153 154
155 -class New_analysis_button(buttons.ThemedGenBitmapTextToggleButton):
156 """A special button for the new analysis panel.""" 157
158 - def OnLeftDown(self, event):
159 """Catch left button mouse down events to ignore when the button is toggled. 160 161 @param event: The wx event. 162 @type event: wx event 163 """ 164 165 # Do nothing on a click if already selected. 166 if self.GetValue(): 167 event.Skip() 168 169 # Otherwise, perform the normal operations. 170 else: 171 super(buttons.ThemedGenBitmapTextToggleButton, self).OnLeftDown(event)
172 173
174 - def OnMouse(self, event):
175 """Catch mouse events, specifically entry into the window. 176 177 @param event: The wx event. 178 @type event: wx event 179 """ 180 181 # Do nothing if entering the button when it is selected. 182 if event.GetEventType() == wx.EVT_ENTER_WINDOW.typeId and self.GetValue(): 183 event.Skip() 184 185 # Otherwise, perform the normal operations. 186 else: 187 super(buttons.ThemedGenBitmapTextToggleButton, self).OnMouse(event)
188 189 190
191 -class New_analysis_page(Wiz_page):
192 """The panel for selection of the new analysis.""" 193 194 # Class variables. 195 image_path = IMAGE_PATH + "relax.gif" 196 main_text = "A number of automatic analyses to be preformed using relax in GUI mode. Although not as flexible or powerful as the prompt/scripting modes, this provides a quick and easy setup and execution for a number of analysis types. These currently include the calculation of the steady-state NOE, the exponential curve-fitting for the %s and %s relaxation rates, and for a full and automatic model-free analysis using the d'Auvergne and Gooley, 2008b protocol. All analyses perform error propagation using the gold standard Monte Calro simulations. Please select from one of the following analysis types:" % (r1, r2) 197 title = "Start a new analysis" 198
199 - def add_artwork(self, sizer):
200 """Add the artwork to the dialog. 201 202 @param sizer: A sizer object. 203 @type sizer: wx.Sizer instance 204 """ 205 206 # Create a vertical box. 207 sizer2 = wx.BoxSizer(wx.VERTICAL) 208 209 # Add a spacer. 210 sizer2.AddSpacer(30) 211 212 # Add the graphics. 213 self.image = wx.StaticBitmap(self, -1, bitmap_setup(self.image_path)) 214 sizer2.Add(self.image, 0, wx.TOP|wx.ALIGN_CENTER_HORIZONTAL, 0) 215 216 # Nest the sizers. 217 sizer.Add(sizer2) 218 219 # A spacer. 220 sizer.AddSpacer(self.art_spacing)
221 222
223 - def add_buttons(self, box):
224 """The widget of analysis buttons. 225 226 @param box: A sizer object. 227 @type box: wx.BoxSizer instance 228 """ 229 230 # The sizes. 231 size = (170, 170) 232 233 # No button is initially selected. 234 self._select_flag = False 235 236 # The horizontal spacers. 237 sizer1 = wx.BoxSizer(wx.HORIZONTAL) 238 sizer2 = wx.BoxSizer(wx.HORIZONTAL) 239 240 # A set of unique IDs for the buttons. 241 self.button_ids = {'noe': wx.NewId(), 242 'r1': wx.NewId(), 243 'r2': wx.NewId(), 244 'mf': wx.NewId(), 245 'relax_disp': wx.NewId(), 246 'consist_test': wx.NewId(), 247 'custom': wx.NewId(), 248 'reserved': wx.NewId()} 249 250 # The NOE button. 251 self.button_noe = self.create_button(id=self.button_ids['noe'], box=sizer1, size=size, bmp=ANALYSIS_IMAGE_PATH+"noe_150x150.png", tooltip="Steady-state NOE analysis", fn=self.select_noe) 252 253 # The R1 button. 254 self.button_r1 = self.create_button(id=self.button_ids['r1'], box=sizer1, size=size, bmp=ANALYSIS_IMAGE_PATH+"r1_150x150.png", tooltip="%s relaxation curve-fitting analysis" % r1, fn=self.select_r1) 255 256 # The R2 button. 257 self.button_r2 = self.create_button(id=self.button_ids['r2'], box=sizer1, size=size, bmp=ANALYSIS_IMAGE_PATH+"r2_150x150.png", tooltip="%s relaxation curve-fitting analysis" % r2, fn=self.select_r2) 258 259 # The model-free button. 260 self.button_mf = self.create_button(id=self.button_ids['mf'], box=sizer1, size=size, bmp=ANALYSIS_IMAGE_PATH+"model_free"+sep+"model_free_150x150.png", tooltip="Model-free analysis", fn=self.select_mf) 261 262 # The relaxation dispersion button. 263 self.button_disp = self.create_button(id=self.button_ids['relax_disp'], box=sizer2, size=size, bmp=ANALYSIS_IMAGE_PATH+"relax_disp_150x150.png", tooltip="Relaxation dispersion analysis", fn=self.select_disp) 264 265 # Consistency testing. 266 self.button_consist_test = self.create_button(id=self.button_ids['consist_test'], box=sizer2, size=size, bmp=ANALYSIS_IMAGE_PATH+"consistency_testing_150x70.png", tooltip="Relaxation data consistency testing (disabled)", fn=self.select_consist_test, disabled=True) 267 268 # The custom analysis button. 269 self.button_custom = self.create_button(id=self.button_ids['custom'], box=sizer2, size=size, bmp=ANALYSIS_IMAGE_PATH+"custom_150x150.png", tooltip="Custom analysis (disabled)", fn=self.select_custom, disabled=True) 270 271 # The blank reserved button. 272 self.button_reserved = self.create_button(id=self.button_ids['reserved'], box=sizer2, size=size, bmp=ANALYSIS_IMAGE_PATH+"blank_150x150.png", tooltip=None, fn=None, disabled=True) 273 274 # Add the sizers. 275 box.Add(sizer1, 0, wx.ALIGN_CENTER_HORIZONTAL, 0) 276 box.Add(sizer2, 0, wx.ALIGN_CENTER_HORIZONTAL, 0)
277 278
279 - def add_contents(self, sizer):
280 """Add the specific GUI elements (dummy method). 281 282 @param sizer: A sizer object. 283 @type sizer: wx.Sizer instance 284 """ 285 286 # Add the button widget. 287 self.add_buttons(sizer) 288 289 # Add a spacer. 290 sizer.AddStretchSpacer(2) 291 292 # Add the analysis name field. 293 self.analysis_name = Value(name='analysis_name', parent=self, value_type='str', sizer=sizer, desc="The name of the new analysis:", tooltip='The name of the analysis can be changed to any text.', divider=self._div_left, height_element=self.height_element)
294 295
296 - def create_button(self, id=-1, box=None, size=None, bmp=None, text='', tooltip='', fn=None, disabled=False):
297 """Create a button for the new analysis selector panel. 298 299 @keyword id: The unique ID number. 300 @type id: int 301 @keyword box: The box sizer to place the button into. 302 @type box: wx.BoxSizer instance 303 @keyword size: The size of the button. 304 @type size: tuple of int 305 @keyword bmp: The full path of the bitmap image to use for the button. 306 @type bmp: str 307 @keyword text: The text for the button. 308 @type text: str 309 @keyword tooltip: The button tooltip text. 310 @type tooltip: str or None 311 @keyword fn: The function to bind the button click to. 312 @type fn: method 313 @return: The button. 314 @rtype: wx.lib.buttons.ThemedGenBitmapTextToggleButton instance 315 """ 316 317 # Generate the button. 318 if bmp: 319 image = wx.Bitmap(bmp, wx.BITMAP_TYPE_ANY) 320 button = New_analysis_button(self, id, image) 321 else: 322 button = New_analysis_button(self, id) 323 324 # Set the tool tip. 325 if tooltip != None: 326 button.SetToolTipString(tooltip) 327 328 # Button properties. 329 button.SetMinSize(size) 330 331 # Add to the given sizer. 332 box.Add(button) 333 334 # Bind the click. 335 if fn != None: 336 self.Bind(wx.EVT_BUTTON, fn, button) 337 338 # The button is disabled. 339 if disabled: 340 button.Disable() 341 342 # Return the button. 343 return button
344 345
346 - def on_display(self):
347 """Disable the next button until an analysis is selected.""" 348 349 # Turn off the next button. 350 self.parent.block_next(not self._select_flag)
351 352
353 - def select_consist_test(self, event):
354 """NOE analysis selection. 355 356 @param event: The wx event. 357 @type event: wx event 358 """ 359 360 # Toggle all buttons off. 361 self.toggle(self.button_consist_test) 362 363 # Set the analysis type. 364 self.parent.analysis_type = 'consistency test'
365 366
367 - def select_custom(self, event):
368 """NOE analysis selection. 369 370 @param event: The wx event. 371 @type event: wx event 372 """ 373 374 # Toggle all buttons off. 375 self.toggle(self.button_custom) 376 377 # Set the analysis type. 378 self.parent.analysis_type = 'custom'
379 380
381 - def select_disp(self, event):
382 """Relaxation dispersion analysis selection. 383 384 @param event: The wx event. 385 @type event: wx event 386 """ 387 388 # Toggle all buttons off. 389 self.toggle(self.button_disp) 390 391 # Update the analysis name. 392 self.analysis_name.SetValue(str_to_gui('Relaxation dispersion')) 393 394 # Set the analysis type. 395 self.parent.analysis_type = 'relax_disp'
396 397
398 - def select_mf(self, event):
399 """NOE analysis selection. 400 401 @param event: The wx event. 402 @type event: wx event 403 """ 404 405 # Toggle all buttons off. 406 self.toggle(self.button_mf) 407 408 # Update the analysis name. 409 self.analysis_name.SetValue(str_to_gui('Model-free')) 410 411 # Set the analysis type. 412 self.parent.analysis_type = 'mf'
413 414
415 - def select_noe(self, event):
416 """NOE analysis selection. 417 418 @param event: The wx event. 419 @type event: wx event 420 """ 421 422 # Toggle all buttons off. 423 self.toggle(self.button_noe) 424 425 # Update the analysis name. 426 self.analysis_name.SetValue(str_to_gui('Steady-state NOE')) 427 428 # Set the analysis type. 429 self.parent.analysis_type = 'noe'
430 431
432 - def select_r1(self, event):
433 """NOE analysis selection. 434 435 @param event: The wx event. 436 @type event: wx event 437 """ 438 439 # Toggle all buttons off. 440 self.toggle(self.button_r1) 441 442 # Update the analysis name. 443 self.analysis_name.SetValue(str_to_gui("R1 relaxation")) 444 445 # Set the analysis type. 446 self.parent.analysis_type = 'r1'
447 448
449 - def select_r2(self, event):
450 """NOE analysis selection. 451 452 @param event: The wx event. 453 @type event: wx event 454 """ 455 456 # Toggle all buttons off. 457 self.toggle(self.button_r2) 458 459 # Update the analysis name. 460 self.analysis_name.SetValue(str_to_gui("R2 relaxation")) 461 462 # Set the analysis type. 463 self.parent.analysis_type = 'r2'
464 465
466 - def toggle(self, button):
467 """Toggle all buttons off except the selected one. 468 469 @param button: The button of the selected analysis. 470 @type button: wx.ToggleButton instance 471 """ 472 473 # First freeze the wizard. 474 self.Freeze() 475 476 # The button is selected. 477 self._select_flag = True 478 479 # Deselect all. 480 self.button_noe.SetValue(False) 481 self.button_r1.SetValue(False) 482 self.button_r2.SetValue(False) 483 self.button_mf.SetValue(False) 484 self.button_disp.SetValue(False) 485 self.button_consist_test.SetValue(False) 486 self.button_custom.SetValue(False) 487 self.button_reserved.SetValue(False) 488 489 # Turn on the selected button. 490 button.SetValue(True) 491 492 # Refresh the GUI element. 493 self.Refresh() 494 495 # Unfreeze. 496 self.Thaw() 497 498 # Unblock forwards movement. 499 self.parent.block_next(not self._select_flag)
500