"Fossies" - the Fresh Open Source Software Archive

Member "relax-5.0.0/gui/analyses/wizard.py" (2 Dec 2019, 18522 Bytes) of package /linux/privat/relax-5.0.0.src.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "wizard.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.1.3_vs_5.0.0.

    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 
  121     def wizard_page_after_analysis(self):
  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.SetToolTip(wx.ToolTip(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)