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

Source Code for Module gui.analyses.wizard

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