Source code for samsifter.gui.dialogs

# -*- coding: utf-8 -*-
"""Dialogs to configure options for Bash script export and SAM2RMA.

This module also includes container objects for the specified options.

.. moduleauthor:: Florian Aldehoff <samsifter@biohazardous.de>
"""

# Qt4 imports
from PyQt4.QtGui import (
    QVBoxLayout, QCheckBox, QDialog, QDialogButtonBox, QLabel, QFormLayout,
    QRadioButton, QWidget, QButtonGroup
)
from PyQt4.QtCore import Qt

# custom libraries
from samsifter.gui.composites import SliderSpinboxCombo, FileChooser


[docs]class RmaOptionsDialog(QDialog): """Modal dialog to set SAM2RMA conversion settings.""" def __init__(self, saved_options=None, parent=None): """Initialize a new modal RMA options dialog using current settings. Parameters ---------- saved_options : RmaOptions, optional Currently saved SAM2RMA options, defaults to standard options if no previous settings exist. parent : QWidget, optional Parent Qt4 widget this widget belongs to, defaults to None. """ super(RmaOptionsDialog, self).__init__(parent) self.setSizeGripEnabled(False) self.setVisible(False) self.setModal(True) self.setWindowTitle("SAM2RMA Settings") self.options = saved_options self.setMinimumWidth(500) self.defaults = RmaOptions() self.top_percent = SliderSpinboxCombo( minimum=0.5, maximum=20.0, default=self.defaults.get_top_percent(), precision=1 ) self.min_score = SliderSpinboxCombo( minimum=1, default=self.defaults.get_min_score(), precision=0 ) self.max_expected = SliderSpinboxCombo( maximum=1.00, default=self.defaults.get_max_expected(), precision=2) self.min_support_percent = SliderSpinboxCombo( maximum=10.000, default=self.defaults.get_min_support_percent(), precision=3 ) self.sam2rma_path = FileChooser( suffix_string="sam2rma binary (sam2rma)" ) self.sam2rma_path.set_filename(self.defaults.get_sam2rma_path()) # override defaults with previous settings if self.options is not None: self.top_percent.set_value(self.options.get_top_percent()) self.min_score.set_value(self.options.get_min_score()) self.max_expected.set_value(self.options.get_max_expected()) self.min_support_percent.set_value( self.options.get_min_support_percent() ) self.sam2rma_path.set_filename(self.options.get_sam2rma_path()) form = QFormLayout(self) form.addRow("top [%]:", self.top_percent) form.addRow("max. expected:", self.max_expected) form.addRow("min. score:", self.min_score) form.addRow("min. support [%]", self.min_support_percent) form.addRow("SAM2RMA binary:", self.sam2rma_path) form_box = QWidget() form_box.setLayout(form) button_box = QDialogButtonBox( QDialogButtonBox.Save | QDialogButtonBox.Cancel | QDialogButtonBox.Reset, Qt.Horizontal, self ) button_box.button(QDialogButtonBox.Reset).clicked.connect( self.reset_form ) button_box.rejected.connect(self.close) button_box.accepted.connect(self.save_options) layout = QVBoxLayout(self) layout.addWidget(form_box) layout.addWidget(button_box) self.setLayout(layout)
[docs] def reset_form(self): """Resets all form elements to defaults.""" self.top_percent.set_value(self.defaults.get_top_percent()) self.min_score.set_value(self.defaults.get_min_score()) self.max_expected.set_value(self.defaults.get_max_expected()) self.min_support_percent.set_value( self.defaults.get_min_support_percent() ) self.sam2rma_path.set_filename(self.defaults.get_sam2rma_path())
[docs] def get_options(self): """Shows dialog and returns options unless user decides to cancel. Returns ------- RmaOptions New SAM2RMA settings. """ self.exec_() return self.options
[docs] def save_options(self): """Stores current settings in BashOptions object to be returned. Closes the dialog when done. """ self.options = RmaOptions() self.options.set_top_percent(self.top_percent.get_value()) self.options.set_min_score(self.min_score.get_value()) self.options.set_max_expected(self.max_expected.get_value()) self.options.set_min_support_percent( self.min_support_percent.get_value() ) self.options.set_sam2rma_path(self.sam2rma_path.get_filename()) self.close()
[docs]class RmaOptions(): """Options for the conversion of SAM to RMA files. Based on the command line arguments of SAM2RMA released with MEGAN 5.8.3. Sets default options as used by the Krause Lab in February 2015. """ def __init__( self, sam2rma_path='/usr/local/megan/tools/sam2rma', top_percent=1, max_expected=0.01, min_score=50, min_support_percent=0.05, min_support=1 ): """Initialize a new instance of SAM2RMA options. Parameters ---------- sam2rma_path : str, optional Path to sam2rma executable, defaults to the standard path for system-wide installations of MEGAN on Linux in ``/usr/local``. top_percent : int, optional Threshold for the maximum percentage by which the score of a hit may fall below the best score achieved for a given read. Any hit that falls below this threshold is discarded. Defaults to 1% instead of 10%. max_expected : float, optional Maximum threshold for the expected value of hits. Any hit in the input data whose E-value exceeds this value is ignored. Defaults to 0.01. min_score : int, optional Minimum threshold for the bit score of hits. Any hit in the input data that scores less than the given threshold is ignored. Defaults to 50. min_support_percent : float, optional Threshold for the minimum support that a taxon requires, as a percentage of assigned reads. This feature is turned off by setting the value to 0. Overrides the use of absolute thresholds with ``min_support``. min_support : int, optional Threshold for the minimum support that a taxon requires, that is, the number of reads that must be assigned to it so that it appears in the result. Any read that is assigned to a taxon that does not have the required support is pushed up the taxonomy until a node is found that has sufficient support. This value will be overridden by the relative ``min_support_percent`` if specified and not 0. """ self.sam2rma_path = sam2rma_path self.top_percent = top_percent self.max_expected = max_expected self.min_score = min_score self.min_support_percent = min_support_percent self.min_support = min_support # Getters & Setters
[docs] def set_sam2rma_path(self, sam2rma_path): self.sam2rma_path = sam2rma_path
[docs] def get_sam2rma_path(self): return self.sam2rma_path
[docs] def set_top_percent(self, top_percent): self.top_percent = top_percent
[docs] def get_top_percent(self): return self.top_percent
[docs] def set_max_expected(self, max_expected): self.max_expected = max_expected
[docs] def get_max_expected(self): return self.max_expected
[docs] def set_min_score(self, min_score): self.min_score = min_score
[docs] def get_min_score(self): return self.min_score
[docs] def set_min_support_percent(self, min_support_percent): self.min_support_percent = min_support_percent
[docs] def get_min_support_percent(self): return self.min_support_percent
[docs] def set_min_support(self, min_support): self.min_support = min_support
[docs] def get_min_support(self): return self.min_support
[docs]class BashOptionsDialog(QDialog): """Modal dialog to set Bash script export options. Switches between three types of processing modes and sets the Bash options to print executed commands and/or stop on errors. The available processing modes are: 1. **Single Mode** processes only the specified input file and produces the specified output file similar to running the workflow in the GUI. This mode should be used with unmodified filenames unless all input files are located in the same directory as the exported bash script. 2. **Sequential Mode** processes a list of arbitrary input files one file after another and saves the output to files renamed with the filename extension ``sifted``. This mode should be used with shortened filenames unless all of the required list files (CSV) are available at identical paths from all machines that this script is deployed to. 3. **Parallel Mode** speeds up the process by distributing jobs across all available CPU cores and running them in parallel. This requires the installation of GNU ``parallel``. Similar to sequential mode above it should be used with shortened filenames unless all of the required list files (CSV) are available at identical paths from all machines that this script is deployed to. """ def __init__(self, parent=None): """Initialize a new dialog to set Bash options. Parameters ---------- parent : QWidget, optional Parent Qt4 widget this widget belongs to, defaults to None. """ super(BashOptionsDialog, self).__init__(parent) self.setSizeGripEnabled(False) self.setVisible(False) self.setModal(True) self.setWindowTitle("Bash Export Options") self.options = None single_help = ("Enable this to limit processing to the specified " "input file") single_label = QLabel("process only the specified file") single_label.setToolTip(single_help) single_label.setWhatsThis(single_help) single_rb = QRadioButton(self) single_rb.setToolTip(single_help) single_rb.setWhatsThis(single_help) single_rb.setChecked(False) seq_help = ("Enable this to process an arbitrary number of files " "one after another on a single CPU core") seq_label = QLabel("process a batch of files sequentially") seq_label.setToolTip(seq_help) seq_label.setWhatsThis(seq_help) seq_rb = QRadioButton(self) seq_rb.setToolTip(seq_help) seq_rb.setWhatsThis(seq_help) seq_rb.setChecked(False) par_help = ("Enable this to process an arbitrary number of files " "as fast as possible using multiple CPU cores; requires " "'GNU parallel'") par_label = QLabel("process a batch of files parallelly") par_label.setToolTip(par_help) par_label.setWhatsThis(par_help) par_rb = QRadioButton(self) par_rb.setToolTip(par_help) par_rb.setWhatsThis(par_help) par_rb.setChecked(True) self.mode = QButtonGroup(self) self.mode.addButton(single_rb) self.mode.setId(single_rb, BashOptions.SINGLE_MODE) self.mode.addButton(seq_rb) self.mode.setId(seq_rb, BashOptions.SEQUENTIAL_MODE) self.mode.addButton(par_rb) self.mode.addButton(par_rb, BashOptions.PARALLEL_MODE) self.mode.setExclusive(True) basename_help = ("Enable this if the input files (including CSVs) are " "always located in the current working directory") basename_label = QLabel("shorten filepaths to filenames only") basename_label.setToolTip(basename_help) basename_label.setWhatsThis(basename_help) self.basename_cb = QCheckBox(self) self.basename_cb.setToolTip(basename_help) self.basename_cb.setWhatsThis(basename_help) self.basename_cb.setChecked(True) print_help = ("Enable this to print all executed commands to STDERR " "(sets bash option '-x')") print_label = QLabel("print executed commands") print_label.setToolTip(print_help) print_label.setWhatsThis(print_help) self.print_cb = QCheckBox(self) self.print_cb.setToolTip(print_help) self.print_cb.setWhatsThis(print_help) self.print_cb.setChecked(False) stop_help = ("Enable this to stop execution if an error occurs (sets " "bash option '-e')") stop_label = QLabel("stop on error") stop_label.setToolTip(stop_help) stop_label.setWhatsThis(stop_help) self.stop_cb = QCheckBox(self) self.stop_cb.setToolTip(stop_help) self.stop_cb.setWhatsThis(stop_help) self.stop_cb.setChecked(True) button_box = QDialogButtonBox(QDialogButtonBox.Save | QDialogButtonBox.Cancel, Qt.Horizontal, self) button_box.rejected.connect(self.close) button_box.accepted.connect(self.save_options) form = QFormLayout() form.addRow(single_rb, single_label) form.addRow(seq_rb, seq_label) form.addRow(par_rb, par_label) form.addRow(self.basename_cb, basename_label) form.addRow(self.print_cb, print_label) form.addRow(self.stop_cb, stop_label) form_box = QWidget() form_box.setLayout(form) layout = QVBoxLayout(self) layout.addWidget(form_box) layout.addWidget(button_box) self.setLayout(layout)
[docs] def get_options(self): """Shows dialog and returns options unless user decides to cancel. Returns ------- BashOptions New Bash export settings. """ self.exec_() return self.options
[docs] def save_options(self): """Stores current settings in BashOptions object to be returned. Closes the dialog when done. """ self.options = BashOptions() self.options.set_processing_mode(self.mode.checkedId()) self.options.set_use_basenames(self.basename_cb.isChecked()) self.options.set_print_commands(self.print_cb.isChecked()) self.options.set_stop_on_error(self.stop_cb.isChecked()) self.close()
[docs]class BashOptions(): """Options for the export of a workflow to a bash script.""" SINGLE_MODE = 1 # one file only SEQUENTIAL_MODE = 2 # arbitrary files, uses Bash for-loop PARALLEL_MODE = 3 # arbitrary files, uses GNU parallel def __init__(self, use_basenames=True, processing_mode=PARALLEL_MODE, print_commands=False, stop_on_error=True): """Initialize a new instance of Bash export options. Parameters ---------- use_basename : bool, optional Shorten all paths to their filenames only, forcing the exported script to be located in the same directory as all of the required input files (eg. CSV filter lists). Defaults to True. processing_mode : int, optional Chooses one of three processing modes. 1. Single Mode (one file only), 2. Sequential Mode (arbitrary files, using Bash ``for``-loop), or 3. Parallel Mode (arbitrary files, using GNU *parallel*) Defaults to 3. print_commands : bool, optional Enable the Bash option ``-x`` to print all executed commands. Defaults to False. stop_on_error : bool, optional Enable the Bash option ``-e`` to stop on errors. Defaults to True. """ self.use_basenames = use_basenames self.processing_mode = processing_mode self.print_commands = print_commands self.stop_on_error = stop_on_error # Getters & Setters
[docs] def set_processing_mode(self, mode=PARALLEL_MODE): self.processing_mode = mode
[docs] def get_processing_mode(self): return self.processing_mode
[docs] def set_use_basenames(self, boolean=False): self.use_basenames = boolean
[docs] def get_use_basenames(self): return self.use_basenames
[docs] def set_print_commands(self, boolean=True): self.print_commands = boolean
[docs] def get_print_commands(self): return self.print_commands
[docs] def set_stop_on_error(self, boolean=True): self.stop_on_error = boolean
[docs] def get_stop_on_error(self): return self.stop_on_error