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

Source Code for Module gui.analyses.wizard

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2011-2014 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  # Unique IDs for the wizard buttons. 
 42  BUTTON_ID_NOE = wx.NewId() 
 43  BUTTON_ID_R1 = wx.NewId() 
 44  BUTTON_ID_R2 = wx.NewId() 
 45  BUTTON_ID_MF = wx.NewId() 
 46  BUTTON_ID_RELAX_DISP = wx.NewId() 
 47  BUTTON_ID_CONSIST_TEST = wx.NewId() 
 48  BUTTON_ID_CUSTOM = wx.NewId() 
 49  BUTTON_ID_RESERVED = wx.NewId() 
 50   
 51   
 52   
53 -class Analysis_wizard:
54 """The analysis selection wizard.""" 55
56 - def Destroy(self):
57 """Properly delete the wizard and all its elements.""" 58 59 self.wizard.Destroy()
60 61
62 - def run(self):
63 """Run through the analysis selection wizard, returning the results. 64 65 @return: The analysis type, analysis name, data pipe name, data pipe bundle name, and user function on_execute method list. 66 @rtype: tuple of str 67 """ 68 69 # Change the cursor to busy. 70 wx.Yield() 71 wx.BeginBusyCursor() 72 73 # Set up the wizard. 74 self.wizard = Wiz_window(size_x=1000, size_y=700, title='Analysis selection wizard') 75 76 # Change the finish button. 77 self.wizard.TEXT_FINISH = " Start" 78 79 # Add the new analysis panel. 80 self.new_page = New_analysis_page(self.wizard) 81 self.wizard.add_page(self.new_page, apply_button=False) 82 self.wizard.set_seq_next_fn(0, self.wizard_page_after_analysis) 83 84 # Add the data pipe name panel. 85 self.pipe_page = Data_pipe_page(self.wizard, height_desc=400) 86 self.wizard.add_page(self.pipe_page, apply_button=False) 87 88 # Reset the cursor. 89 if wx.IsBusy(): 90 wx.EndBusyCursor() 91 92 # Execute the wizard. 93 setup = self.wizard.run(modal=True) 94 if setup != wx.ID_OK: 95 return 96 97 # Return the analysis type, analysis name, data pipe name, data pipe bundle name, and user function on_execute method list. 98 return self.get_data()
99 100
101 - def get_data(self):
102 """Assemble and return the analysis type, analysis name, and pipe name. 103 104 @return: The analysis type, analysis name, data pipe name, data pipe bundle name, and list of user function on_execute methods. 105 @rtype: str, str, str, str, list of methods 106 """ 107 108 # Get the data. 109 analysis_type = gui_to_str(self.wizard.analysis_type) 110 analysis_name = gui_to_str(self.new_page.analysis_name.GetValue()) 111 pipe_name = gui_to_str(self.pipe_page.pipe_name.GetValue()) 112 pipe_bundle = gui_to_str(self.pipe_page.pipe_bundle.GetValue()) 113 114 # The user function on_execute methods. 115 uf_exec = [] 116 117 # Return it. 118 return analysis_type, analysis_name, pipe_name, pipe_bundle, uf_exec
119 120
122 """Set the page after the data pipe setup. 123 124 @return: The index of the next page, which is the current page index plus one. 125 @rtype: int 126 """ 127 128 # The selected analysis. 129 analysis_name = gui_to_str(self.new_page.analysis_name.GetValue()) 130 131 # Default to the second page. 132 return 1
133 134 135
136 -class Data_pipe_page(Wiz_page):
137 """The panel for setting the data pipe name.""" 138 139 # Class variables. 140 image_path = WIZARD_IMAGE_PATH + 'pipe.png' 141 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) 142 title = 'Data pipe set up' 143
144 - def add_contents(self, sizer):
145 """Add the specific GUI elements (dummy method). 146 147 @param sizer: A sizer object. 148 @type sizer: wx.Sizer instance 149 """ 150 151 # The pipe name input. 152 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) 153 154 # The pipe bundle input. 155 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) 156 157 # Spacing. 158 sizer.AddStretchSpacer(3)
159 160
161 - def on_display(self):
162 """Update the pipe name.""" 163 164 # Generate a name for the data pipe bundle based on the type and time. 165 name = "%s (%s)" % (self.parent.analysis_type, asctime(localtime())) 166 167 # Update the fields. 168 self.pipe_name.SetValue(str_to_gui("origin - %s" % name)) 169 self.pipe_bundle.SetValue(str_to_gui(name))
170 171 172
173 -class New_analysis_button(buttons.ThemedGenBitmapTextToggleButton):
174 """A special button for the new analysis panel.""" 175
176 - def OnLeftDown(self, event):
177 """Catch left button mouse down events to ignore when the button is toggled. 178 179 @param event: The wx event. 180 @type event: wx event 181 """ 182 183 # Do nothing on a click if already selected. 184 if self.GetValue(): 185 event.Skip() 186 187 # Otherwise, perform the normal operations. 188 else: 189 super(buttons.ThemedGenBitmapTextToggleButton, self).OnLeftDown(event)
190 191
192 - def OnMouse(self, event):
193 """Catch mouse events, specifically entry into the window. 194 195 @param event: The wx event. 196 @type event: wx event 197 """ 198 199 # Do nothing if entering the button when it is selected. 200 if event.GetEventType() == wx.EVT_ENTER_WINDOW.typeId and self.GetValue(): 201 event.Skip() 202 203 # Otherwise, perform the normal operations. 204 else: 205 super(buttons.ThemedGenBitmapTextToggleButton, self).OnMouse(event)
206 207 208
209 -class New_analysis_page(Wiz_page):
210 """The panel for selection of the new analysis.""" 211 212 # Class variables. 213 image_path = IMAGE_PATH + "relax.gif" 214 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) 215 title = "Start a new analysis" 216
217 - def add_artwork(self, sizer):
218 """Add the artwork to the dialog. 219 220 @param sizer: A sizer object. 221 @type sizer: wx.Sizer instance 222 """ 223 224 # Create a vertical box. 225 sizer2 = wx.BoxSizer(wx.VERTICAL) 226 227 # Add a spacer. 228 sizer2.AddSpacer(30) 229 230 # Add the graphics. 231 self.image = wx.StaticBitmap(self, -1, bitmap_setup(self.image_path)) 232 sizer2.Add(self.image, 0, wx.TOP|wx.ALIGN_CENTER_HORIZONTAL, 0) 233 234 # Nest the sizers. 235 sizer.Add(sizer2) 236 237 # A spacer. 238 sizer.AddSpacer(self.art_spacing)
239 240
241 - def add_buttons(self, box):
242 """The widget of analysis buttons. 243 244 @param box: A sizer object. 245 @type box: wx.BoxSizer instance 246 """ 247 248 # The sizes. 249 size = (170, 170) 250 251 # No button is initially selected. 252 self._select_flag = False 253 254 # The horizontal spacers. 255 sizer1 = wx.BoxSizer(wx.HORIZONTAL) 256 sizer2 = wx.BoxSizer(wx.HORIZONTAL) 257 258 # The NOE button. 259 self.button_noe = self.create_button(id=BUTTON_ID_NOE, box=sizer1, size=size, bmp=ANALYSIS_IMAGE_PATH+"noe_150x150.png", tooltip="Steady-state NOE analysis", fn=self.select_noe) 260 261 # The R1 button. 262 self.button_r1 = self.create_button(id=BUTTON_ID_R1, box=sizer1, size=size, bmp=ANALYSIS_IMAGE_PATH+"r1_150x150.png", tooltip="%s relaxation curve-fitting analysis" % r1, fn=self.select_r1) 263 264 # The R2 button. 265 self.button_r2 = self.create_button(id=BUTTON_ID_R2, box=sizer1, size=size, bmp=ANALYSIS_IMAGE_PATH+"r2_150x150.png", tooltip="%s relaxation curve-fitting analysis" % r2, fn=self.select_r2) 266 267 # The model-free button. 268 self.button_mf = self.create_button(id=BUTTON_ID_MF, box=sizer1, size=size, bmp=ANALYSIS_IMAGE_PATH+"model_free"+sep+"model_free_150x150.png", tooltip="Model-free analysis", fn=self.select_mf) 269 270 # The relaxation dispersion button. 271 self.button_disp = self.create_button(id=BUTTON_ID_RELAX_DISP, box=sizer2, size=size, bmp=ANALYSIS_IMAGE_PATH+"relax_disp_150x150.png", tooltip="Relaxation dispersion analysis", fn=self.select_disp) 272 273 # Consistency testing. 274 self.button_consist_test = self.create_button(id=BUTTON_ID_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) 275 276 # The custom analysis button. 277 self.button_custom = self.create_button(id=BUTTON_ID_CUSTOM, box=sizer2, size=size, bmp=ANALYSIS_IMAGE_PATH+"custom_150x150.png", tooltip="Custom analysis (disabled)", fn=self.select_custom, disabled=True) 278 279 # The blank reserved button. 280 self.button_reserved = self.create_button(id=BUTTON_ID_RESERVED, box=sizer2, size=size, bmp=ANALYSIS_IMAGE_PATH+"blank_150x150.png", tooltip=None, fn=None, disabled=True) 281 282 # Add the sizers. 283 box.Add(sizer1, 0, wx.ALIGN_CENTER_HORIZONTAL, 0) 284 box.Add(sizer2, 0, wx.ALIGN_CENTER_HORIZONTAL, 0)
285 286
287 - def add_contents(self, sizer):
288 """Add the specific GUI elements (dummy method). 289 290 @param sizer: A sizer object. 291 @type sizer: wx.Sizer instance 292 """ 293 294 # Add the button widget. 295 self.add_buttons(sizer) 296 297 # Add a spacer. 298 sizer.AddStretchSpacer(2) 299 300 # Add the analysis name field. 301 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)
302 303
304 - def create_button(self, id=-1, box=None, size=None, bmp=None, text='', tooltip='', fn=None, disabled=False):
305 """Create a button for the new analysis selector panel. 306 307 @keyword id: The unique ID number. 308 @type id: int 309 @keyword box: The box sizer to place the button into. 310 @type box: wx.BoxSizer instance 311 @keyword size: The size of the button. 312 @type size: tuple of int 313 @keyword bmp: The full path of the bitmap image to use for the button. 314 @type bmp: str 315 @keyword text: The text for the button. 316 @type text: str 317 @keyword tooltip: The button tooltip text. 318 @type tooltip: str or None 319 @keyword fn: The function to bind the button click to. 320 @type fn: method 321 @return: The button. 322 @rtype: wx.lib.buttons.ThemedGenBitmapTextToggleButton instance 323 """ 324 325 # Generate the button. 326 if bmp: 327 image = wx.Bitmap(bmp, wx.BITMAP_TYPE_ANY) 328 button = New_analysis_button(self, id, image) 329 else: 330 button = New_analysis_button(self, id) 331 332 # Set the tool tip. 333 if tooltip != None: 334 button.SetToolTipString(tooltip) 335 336 # Button properties. 337 button.SetMinSize(size) 338 339 # Add to the given sizer. 340 box.Add(button) 341 342 # Bind the click. 343 if fn != None: 344 self.Bind(wx.EVT_BUTTON, fn, button) 345 346 # The button is disabled. 347 if disabled: 348 button.Disable() 349 350 # Return the button. 351 return button
352 353
354 - def on_display(self):
355 """Disable the next button until an analysis is selected.""" 356 357 # Turn off the next button. 358 self.parent.block_next(not self._select_flag)
359 360
361 - def select_consist_test(self, event):
362 """NOE analysis selection. 363 364 @param event: The wx event. 365 @type event: wx event 366 """ 367 368 # Toggle all buttons off. 369 self.toggle(self.button_consist_test) 370 371 # Set the analysis type. 372 self.parent.analysis_type = 'consistency test'
373 374
375 - def select_custom(self, event):
376 """NOE analysis selection. 377 378 @param event: The wx event. 379 @type event: wx event 380 """ 381 382 # Toggle all buttons off. 383 self.toggle(self.button_custom) 384 385 # Set the analysis type. 386 self.parent.analysis_type = 'custom'
387 388
389 - def select_disp(self, event):
390 """Relaxation dispersion analysis selection. 391 392 @param event: The wx event. 393 @type event: wx event 394 """ 395 396 # Toggle all buttons off. 397 self.toggle(self.button_disp) 398 399 # Update the analysis name. 400 self.analysis_name.SetValue(str_to_gui('Relaxation dispersion')) 401 402 # Set the analysis type. 403 self.parent.analysis_type = 'relax_disp'
404 405
406 - def select_mf(self, event):
407 """NOE analysis selection. 408 409 @param event: The wx event. 410 @type event: wx event 411 """ 412 413 # Toggle all buttons off. 414 self.toggle(self.button_mf) 415 416 # Update the analysis name. 417 self.analysis_name.SetValue(str_to_gui('Model-free')) 418 419 # Set the analysis type. 420 self.parent.analysis_type = 'mf'
421 422
423 - def select_noe(self, event):
424 """NOE analysis selection. 425 426 @param event: The wx event. 427 @type event: wx event 428 """ 429 430 # Toggle all buttons off. 431 self.toggle(self.button_noe) 432 433 # Update the analysis name. 434 self.analysis_name.SetValue(str_to_gui('Steady-state NOE')) 435 436 # Set the analysis type. 437 self.parent.analysis_type = 'noe'
438 439
440 - def select_r1(self, event):
441 """NOE analysis selection. 442 443 @param event: The wx event. 444 @type event: wx event 445 """ 446 447 # Toggle all buttons off. 448 self.toggle(self.button_r1) 449 450 # Update the analysis name. 451 self.analysis_name.SetValue(str_to_gui("R1 relaxation")) 452 453 # Set the analysis type. 454 self.parent.analysis_type = 'r1'
455 456
457 - def select_r2(self, event):
458 """NOE analysis selection. 459 460 @param event: The wx event. 461 @type event: wx event 462 """ 463 464 # Toggle all buttons off. 465 self.toggle(self.button_r2) 466 467 # Update the analysis name. 468 self.analysis_name.SetValue(str_to_gui("R2 relaxation")) 469 470 # Set the analysis type. 471 self.parent.analysis_type = 'r2'
472 473
474 - def toggle(self, button):
475 """Toggle all buttons off except the selected one. 476 477 @param button: The button of the selected analysis. 478 @type button: wx.ToggleButton instance 479 """ 480 481 # First freeze the wizard. 482 self.Freeze() 483 484 # The button is selected. 485 self._select_flag = True 486 487 # Deselect all. 488 self.button_noe.SetValue(False) 489 self.button_r1.SetValue(False) 490 self.button_r2.SetValue(False) 491 self.button_mf.SetValue(False) 492 self.button_disp.SetValue(False) 493 self.button_consist_test.SetValue(False) 494 self.button_custom.SetValue(False) 495 self.button_reserved.SetValue(False) 496 497 # Turn on the selected button. 498 button.SetValue(True) 499 500 # Refresh the GUI element. 501 self.Refresh() 502 503 # Unfreeze. 504 self.Thaw() 505 506 # Unblock forwards movement. 507 self.parent.block_next(not self._select_flag)
508