def test_calctype_not_impemented(qtbot, caplog): view = MainWindow(controller=None) qtbot.addWidget(view) testbutton = QRadioButton() testbutton.setObjectName('custom') buttongroup = view._ui.calctype.buttongroup buttongroup.addButton(testbutton) assert testbutton in buttongroup.buttons() testbutton.animateClick(msec=0) qtbot.wait(100) assert caplog.records[-1].levelname == 'ERROR' assert 'button name mismatch' in caplog.text
def configFilterTypeButtons(self, name=u"default", checked=False, xPos=0, yPos=0, idButton=0): button = QRadioButton(self) button.setObjectName(name) button.setEnabled(True) button.setGeometry(QRect(xPos, yPos, 82, 17)) button.setCursor(QCursor(Qt.PointingHandCursor)) button.setChecked(checked) lam = lambda id=idButton: self.buttonChecked(id) self.connect(button, SIGNAL("clicked()"), lam) self.filterTypeButtons.addButton(button, idButton)
class SCOUTS(QMainWindow): """Main Window Widget for SCOUTS.""" style = { 'title': 'QLabel {font-size: 18pt; font-weight: 600}', 'header': 'QLabel {font-size: 12pt; font-weight: 520}', 'label': 'QLabel {font-size: 10pt}', 'button': 'QPushButton {font-size: 10pt}', 'md button': 'QPushButton {font-size: 12pt}', 'run button': 'QPushButton {font-size: 18pt; font-weight: 600}', 'line edit': 'QLineEdit {font-size: 10pt}', 'checkbox': 'QCheckBox {font-size: 10pt}', 'radio button': 'QRadioButton {font-size: 10pt}' } def __init__(self) -> None: """SCOUTS Constructor. Defines all aspects of the GUI.""" # ### # ### Main Window setup # ### # Inherits from QMainWindow super().__init__() self.rootdir = get_project_root() self.threadpool = QThreadPool() # Sets values for QMainWindow self.setWindowTitle("SCOUTS") self.setWindowIcon( QIcon( os.path.abspath(os.path.join(self.rootdir, 'src', 'scouts.ico')))) # Creates StackedWidget as QMainWindow's central widget self.stacked_pages = QStackedWidget(self) self.setCentralWidget(self.stacked_pages) # Creates Widgets for individual "pages" and adds them to the StackedWidget self.main_page = QWidget() self.samples_page = QWidget() self.gating_page = QWidget() self.pages = (self.main_page, self.samples_page, self.gating_page) for page in self.pages: self.stacked_pages.addWidget(page) # ## Sets widget at program startup self.stacked_pages.setCurrentWidget(self.main_page) # ### # ### MAIN PAGE # ### # Main page layout self.main_layout = QVBoxLayout(self.main_page) # Title section # Title self.title = QLabel(self.main_page) self.title.setText('SCOUTS - Single Cell Outlier Selector') self.title.setStyleSheet(self.style['title']) self.title.adjustSize() self.main_layout.addWidget(self.title) # ## Input section # Input header self.input_header = QLabel(self.main_page) self.input_header.setText('Input settings') self.input_header.setStyleSheet(self.style['header']) self.main_layout.addChildWidget(self.input_header) self.input_header.adjustSize() self.main_layout.addWidget(self.input_header) # Input frame self.input_frame = QFrame(self.main_page) self.input_frame.setFrameShape(QFrame.StyledPanel) self.input_frame.setLayout(QFormLayout()) self.main_layout.addWidget(self.input_frame) # Input button self.input_button = QPushButton(self.main_page) self.input_button.setStyleSheet(self.style['button']) self.set_icon(self.input_button, 'x-office-spreadsheet') self.input_button.setObjectName('input') self.input_button.setText(' Select input file (.xlsx or .csv)') self.input_button.clicked.connect(self.get_path) # Input path box self.input_path = QLineEdit(self.main_page) self.input_path.setObjectName('input_path') self.input_path.setStyleSheet(self.style['line edit']) # Go to sample naming page self.samples_button = QPushButton(self.main_page) self.samples_button.setStyleSheet(self.style['button']) self.set_icon(self.samples_button, 'preferences-other') self.samples_button.setText(' Name samples...') self.samples_button.clicked.connect(self.goto_samples_page) # Go to gating page self.gates_button = QPushButton(self.main_page) self.gates_button.setStyleSheet(self.style['button']) self.set_icon(self.gates_button, 'preferences-other') self.gates_button.setText(' Gating && outlier options...') self.gates_button.clicked.connect(self.goto_gates_page) # Add widgets above to input frame Layout self.input_frame.layout().addRow(self.input_button, self.input_path) self.input_frame.layout().addRow(self.samples_button) self.input_frame.layout().addRow(self.gates_button) # ## Analysis section # Analysis header self.analysis_header = QLabel(self.main_page) self.analysis_header.setText('Analysis settings') self.analysis_header.setStyleSheet(self.style['header']) self.analysis_header.adjustSize() self.main_layout.addWidget(self.analysis_header) # Analysis frame self.analysis_frame = QFrame(self.main_page) self.analysis_frame.setFrameShape(QFrame.StyledPanel) self.analysis_frame.setLayout(QVBoxLayout()) self.main_layout.addWidget(self.analysis_frame) # Cutoff text self.cutoff_text = QLabel(self.main_page) self.cutoff_text.setText('Type of outlier to select:') self.cutoff_text.setToolTip( 'Choose whether to select outliers using the cutoff value from a reference\n' 'sample (OutR) or by using the cutoff value calculated for each sample\n' 'individually (OutS)') self.cutoff_text.setStyleSheet(self.style['label']) # Cutoff button group self.cutoff_group = QButtonGroup(self) # Cutoff by sample self.cutoff_sample = QRadioButton(self.main_page) self.cutoff_sample.setText('OutS') self.cutoff_sample.setObjectName('sample') self.cutoff_sample.setStyleSheet(self.style['radio button']) self.cutoff_sample.setChecked(True) self.cutoff_group.addButton(self.cutoff_sample) # Cutoff by reference self.cutoff_reference = QRadioButton(self.main_page) self.cutoff_reference.setText('OutR') self.cutoff_reference.setObjectName('ref') self.cutoff_reference.setStyleSheet(self.style['radio button']) self.cutoff_group.addButton(self.cutoff_reference) # Both cutoffs self.cutoff_both = QRadioButton(self.main_page) self.cutoff_both.setText('both') self.cutoff_both.setObjectName('sample ref') self.cutoff_both.setStyleSheet(self.style['radio button']) self.cutoff_group.addButton(self.cutoff_both) # Markers text self.markers_text = QLabel(self.main_page) self.markers_text.setStyleSheet(self.style['label']) self.markers_text.setText('Show results for:') self.markers_text.setToolTip( 'Individual markers: for each marker, select outliers\n' 'Any marker: select cells that are outliers for AT LEAST one marker' ) # Markers button group self.markers_group = QButtonGroup(self) # Single marker self.single_marker = QRadioButton(self.main_page) self.single_marker.setText('individual markers') self.single_marker.setObjectName('single') self.single_marker.setStyleSheet(self.style['radio button']) self.single_marker.setChecked(True) self.markers_group.addButton(self.single_marker) # Any marker self.any_marker = QRadioButton(self.main_page) self.any_marker.setText('any marker') self.any_marker.setObjectName('any') self.any_marker.setStyleSheet(self.style['radio button']) self.markers_group.addButton(self.any_marker) # Both methods self.both_methods = QRadioButton(self.main_page) self.both_methods.setText('both') self.both_methods.setObjectName('single any') self.both_methods.setStyleSheet(self.style['radio button']) self.markers_group.addButton(self.both_methods) # Tukey text self.tukey_text = QLabel(self.main_page) self.tukey_text.setStyleSheet(self.style['label']) # Tukey button group self.tukey_text.setText('Tukey factor:') self.tukey_group = QButtonGroup(self) # Low Tukey value self.tukey_low = QRadioButton(self.main_page) self.tukey_low.setText('1.5') self.tukey_low.setStyleSheet(self.style['radio button']) self.tukey_low.setChecked(True) self.tukey_group.addButton(self.tukey_low) # High Tukey value self.tukey_high = QRadioButton(self.main_page) self.tukey_high.setText('3.0') self.tukey_high.setStyleSheet(self.style['radio button']) self.tukey_group.addButton(self.tukey_high) # Add widgets above to analysis frame layout self.analysis_frame.layout().addWidget(self.cutoff_text) self.cutoff_buttons = QHBoxLayout() for button in self.cutoff_group.buttons(): self.cutoff_buttons.addWidget(button) self.analysis_frame.layout().addLayout(self.cutoff_buttons) self.analysis_frame.layout().addWidget(self.markers_text) self.markers_buttons = QHBoxLayout() for button in self.markers_group.buttons(): self.markers_buttons.addWidget(button) self.analysis_frame.layout().addLayout(self.markers_buttons) self.analysis_frame.layout().addWidget(self.tukey_text) self.tukey_buttons = QHBoxLayout() for button in self.tukey_group.buttons(): self.tukey_buttons.addWidget(button) self.tukey_buttons.addWidget(QLabel()) # aligns row with 2 buttons self.analysis_frame.layout().addLayout(self.tukey_buttons) # ## Output section # Output header self.output_header = QLabel(self.main_page) self.output_header.setText('Output settings') self.output_header.setStyleSheet(self.style['header']) self.output_header.adjustSize() self.main_layout.addWidget(self.output_header) # Output frame self.output_frame = QFrame(self.main_page) self.output_frame.setFrameShape(QFrame.StyledPanel) self.output_frame.setLayout(QFormLayout()) self.main_layout.addWidget(self.output_frame) # Output button self.output_button = QPushButton(self.main_page) self.output_button.setStyleSheet(self.style['button']) self.set_icon(self.output_button, 'folder') self.output_button.setObjectName('output') self.output_button.setText(' Select output folder') self.output_button.clicked.connect(self.get_path) # Output path box self.output_path = QLineEdit(self.main_page) self.output_path.setStyleSheet(self.style['line edit']) # Generate CSV checkbox self.output_csv = QCheckBox(self.main_page) self.output_csv.setText('Export multiple text files (.csv)') self.output_csv.setStyleSheet(self.style['checkbox']) self.output_csv.setChecked(True) # Generate XLSX checkbox self.output_excel = QCheckBox(self.main_page) self.output_excel.setText('Export multiple Excel spreadsheets (.xlsx)') self.output_excel.setStyleSheet(self.style['checkbox']) self.output_excel.clicked.connect(self.enable_single_excel) # Generate single, large XLSX checkbox self.single_excel = QCheckBox(self.main_page) self.single_excel.setText( 'Also save one multi-sheet Excel spreadsheet') self.single_excel.setToolTip( 'After generating all Excel spreadsheets, SCOUTS combines them into ' 'a single\nExcel spreadsheet where each sheet corresponds to an output' 'file from SCOUTS') self.single_excel.setStyleSheet(self.style['checkbox']) self.single_excel.setEnabled(False) self.single_excel.clicked.connect(self.memory_warning) # Add widgets above to output frame layout self.output_frame.layout().addRow(self.output_button, self.output_path) self.output_frame.layout().addRow(self.output_csv) self.output_frame.layout().addRow(self.output_excel) self.output_frame.layout().addRow(self.single_excel) # ## Run & help-quit section # Run button (stand-alone) self.run_button = QPushButton(self.main_page) self.set_icon(self.run_button, 'system-run') self.run_button.setText(' Run!') self.run_button.setStyleSheet(self.style['run button']) self.main_layout.addWidget(self.run_button) self.run_button.clicked.connect(self.run) # Help-quit frame (invisible) self.helpquit_frame = QFrame(self.main_page) self.helpquit_frame.setLayout(QHBoxLayout()) self.helpquit_frame.layout().setMargin(0) self.main_layout.addWidget(self.helpquit_frame) # Help button self.help_button = QPushButton(self.main_page) self.set_icon(self.help_button, 'help-about') self.help_button.setText(' Help') self.help_button.setStyleSheet(self.style['md button']) self.help_button.clicked.connect(self.get_help) # Quit button self.quit_button = QPushButton(self.main_page) self.set_icon(self.quit_button, 'process-stop') self.quit_button.setText(' Quit') self.quit_button.setStyleSheet(self.style['md button']) self.quit_button.clicked.connect(self.close) # Add widgets above to help-quit layout self.helpquit_frame.layout().addWidget(self.help_button) self.helpquit_frame.layout().addWidget(self.quit_button) # ### # ### SAMPLES PAGE # ### # Samples page layout self.samples_layout = QVBoxLayout(self.samples_page) # ## Title section # Title self.samples_title = QLabel(self.samples_page) self.samples_title.setText('Name your samples') self.samples_title.setStyleSheet(self.style['title']) self.samples_title.adjustSize() self.samples_layout.addWidget(self.samples_title) # Subtitle self.samples_subtitle = QLabel(self.samples_page) string = ( 'Please name the samples to be analysed by SCOUTS.\n\nSCOUTS searches the first ' 'column of your data\nand locates the exact string as part of the sample name.' ) self.samples_subtitle.setText(string) self.samples_subtitle.setStyleSheet(self.style['label']) self.samples_subtitle.adjustSize() self.samples_layout.addWidget(self.samples_subtitle) # ## Sample addition section # Sample addition frame self.samples_frame = QFrame(self.samples_page) self.samples_frame.setFrameShape(QFrame.StyledPanel) self.samples_frame.setLayout(QGridLayout()) self.samples_layout.addWidget(self.samples_frame) # Sample name box self.sample_name = QLineEdit(self.samples_page) self.sample_name.setStyleSheet(self.style['line edit']) self.sample_name.setPlaceholderText('Sample name ...') # Reference check self.is_reference = QCheckBox(self.samples_page) self.is_reference.setText('Reference?') self.is_reference.setStyleSheet(self.style['checkbox']) # Add sample to table self.add_sample_button = QPushButton(self.samples_page) QShortcut(QKeySequence("Return"), self.add_sample_button, self.write_to_sample_table) self.set_icon(self.add_sample_button, 'list-add') self.add_sample_button.setText(' Add sample (Enter)') self.add_sample_button.setStyleSheet(self.style['button']) self.add_sample_button.clicked.connect(self.write_to_sample_table) # Remove sample from table self.remove_sample_button = QPushButton(self.samples_page) QShortcut(QKeySequence("Delete"), self.remove_sample_button, self.remove_from_sample_table) self.set_icon(self.remove_sample_button, 'list-remove') self.remove_sample_button.setText(' Remove sample (Del)') self.remove_sample_button.setStyleSheet(self.style['button']) self.remove_sample_button.clicked.connect( self.remove_from_sample_table) # Add widgets above to sample addition layout self.samples_frame.layout().addWidget(self.sample_name, 0, 0) self.samples_frame.layout().addWidget(self.is_reference, 1, 0) self.samples_frame.layout().addWidget(self.add_sample_button, 0, 1) self.samples_frame.layout().addWidget(self.remove_sample_button, 1, 1) # ## Sample table self.sample_table = QTableWidget(self.samples_page) self.sample_table.setColumnCount(2) self.sample_table.setHorizontalHeaderItem(0, QTableWidgetItem('Sample')) self.sample_table.setHorizontalHeaderItem( 1, QTableWidgetItem('Reference?')) self.sample_table.horizontalHeader().setSectionResizeMode( 0, QHeaderView.Stretch) self.sample_table.horizontalHeader().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self.samples_layout.addWidget(self.sample_table) # ## Save & clear buttons # Save & clear frame (invisible) self.saveclear_frame = QFrame(self.samples_page) self.saveclear_frame.setLayout(QHBoxLayout()) self.saveclear_frame.layout().setMargin(0) self.samples_layout.addWidget(self.saveclear_frame) # Clear samples button self.clear_samples = QPushButton(self.samples_page) self.set_icon(self.clear_samples, 'edit-delete') self.clear_samples.setText(' Clear table') self.clear_samples.setStyleSheet(self.style['md button']) self.clear_samples.clicked.connect(self.prompt_clear_data) # Save samples button self.save_samples = QPushButton(self.samples_page) self.set_icon(self.save_samples, 'document-save') self.save_samples.setText(' Save samples') self.save_samples.setStyleSheet(self.style['md button']) self.save_samples.clicked.connect(self.goto_main_page) # Add widgets above to save & clear layout self.saveclear_frame.layout().addWidget(self.clear_samples) self.saveclear_frame.layout().addWidget(self.save_samples) # ### # ### GATING PAGE # ### # Gating page layout self.gating_layout = QVBoxLayout(self.gating_page) # ## Title section # Title self.gates_title = QLabel(self.gating_page) self.gates_title.setText('Gating & outlier options') self.gates_title.setStyleSheet(self.style['title']) self.gates_title.adjustSize() self.gating_layout.addWidget(self.gates_title) # ## Gating options section # Gating header self.gate_header = QLabel(self.gating_page) self.gate_header.setText('Gating') self.gate_header.setStyleSheet(self.style['header']) self.gate_header.adjustSize() self.gating_layout.addWidget(self.gate_header) # Gating frame self.gate_frame = QFrame(self.gating_page) self.gate_frame.setFrameShape(QFrame.StyledPanel) self.gate_frame.setLayout(QFormLayout()) self.gating_layout.addWidget(self.gate_frame) # Gating button group self.gating_group = QButtonGroup(self) # Do not gate samples self.no_gates = QRadioButton(self.gating_page) self.no_gates.setObjectName('no_gate') self.no_gates.setText("Don't gate samples") self.no_gates.setStyleSheet(self.style['radio button']) self.no_gates.setChecked(True) self.gating_group.addButton(self.no_gates) self.no_gates.clicked.connect(self.activate_gate) # CyToF gating self.cytof_gates = QRadioButton(self.gating_page) self.cytof_gates.setObjectName('cytof') self.cytof_gates.setText('Mass Cytometry gating') self.cytof_gates.setStyleSheet(self.style['radio button']) self.cytof_gates.setToolTip( 'Exclude cells for which the average expression of all\n' 'markers is below the selected value') self.gating_group.addButton(self.cytof_gates) self.cytof_gates.clicked.connect(self.activate_gate) # CyToF gating spinbox self.cytof_gates_value = QDoubleSpinBox(self.gating_page) self.cytof_gates_value.setMinimum(0) self.cytof_gates_value.setMaximum(1) self.cytof_gates_value.setValue(0.1) self.cytof_gates_value.setSingleStep(0.05) self.cytof_gates_value.setEnabled(False) # scRNA-Seq gating self.rnaseq_gates = QRadioButton(self.gating_page) self.rnaseq_gates.setText('scRNA-Seq gating') self.rnaseq_gates.setStyleSheet(self.style['radio button']) self.rnaseq_gates.setToolTip( 'When calculating cutoff, ignore reads below the selected value') self.rnaseq_gates.setObjectName('rnaseq') self.gating_group.addButton(self.rnaseq_gates) self.rnaseq_gates.clicked.connect(self.activate_gate) # scRNA-Seq gating spinbox self.rnaseq_gates_value = QDoubleSpinBox(self.gating_page) self.rnaseq_gates_value.setMinimum(0) self.rnaseq_gates_value.setMaximum(10) self.rnaseq_gates_value.setValue(0) self.rnaseq_gates_value.setSingleStep(1) self.rnaseq_gates_value.setEnabled(False) # export gated population checkbox self.export_gated = QCheckBox(self.gating_page) self.export_gated.setText('Export gated cells as an output file') self.export_gated.setStyleSheet(self.style['checkbox']) self.export_gated.setEnabled(False) # Add widgets above to Gate frame layout self.gate_frame.layout().addRow(self.no_gates, QLabel()) self.gate_frame.layout().addRow(self.cytof_gates, self.cytof_gates_value) self.gate_frame.layout().addRow(self.rnaseq_gates, self.rnaseq_gates_value) self.gate_frame.layout().addRow(self.export_gated, QLabel()) # ## Outlier options section # Outlier header self.outlier_header = QLabel(self.gating_page) self.outlier_header.setText('Outliers') self.outlier_header.setStyleSheet(self.style['header']) self.outlier_header.adjustSize() self.gating_layout.addWidget(self.outlier_header) # Outlier frame self.outlier_frame = QFrame(self.gating_page) self.outlier_frame.setFrameShape(QFrame.StyledPanel) self.outlier_frame.setLayout(QVBoxLayout()) self.gating_layout.addWidget(self.outlier_frame) # Top outliers information self.top_outliers = QLabel(self.gating_page) self.top_outliers.setStyleSheet(self.style['label']) self.top_outliers.setText( 'By default, SCOUTS selects the top outliers from the population') self.top_outliers.setStyleSheet(self.style['label']) # Bottom outliers data self.bottom_outliers = QCheckBox(self.gating_page) self.bottom_outliers.setText('Include results for low outliers') self.bottom_outliers.setStyleSheet(self.style['checkbox']) # Non-outliers data self.not_outliers = QCheckBox(self.gating_page) self.not_outliers.setText('Include results for non-outliers') self.not_outliers.setStyleSheet(self.style['checkbox']) # Add widgets above to Gate frame layout self.outlier_frame.layout().addWidget(self.top_outliers) self.outlier_frame.layout().addWidget(self.bottom_outliers) self.outlier_frame.layout().addWidget(self.not_outliers) # ## Save/back button self.save_gates = QPushButton(self.gating_page) self.set_icon(self.save_gates, 'go-next') self.save_gates.setText(' Back to main menu') self.save_gates.setStyleSheet(self.style['md button']) self.gating_layout.addWidget(self.save_gates) self.save_gates.clicked.connect(self.goto_main_page) # ## Add empty label to take vertical space self.empty_label = QLabel(self.gating_page) self.empty_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.gating_layout.addWidget(self.empty_label) # ### # ### ICON SETTING # ### def set_icon(self, widget: QWidget, icon: str) -> None: """Associates an icon to a widget.""" i = QIcon() i.addPixmap( QPixmap( os.path.abspath( os.path.join(self.rootdir, 'src', 'default_icons', f'{icon}.svg')))) widget.setIcon(QIcon.fromTheme(icon, i)) # ### # ### STACKED WIDGET PAGE SWITCHING # ### def goto_main_page(self) -> None: """Switches stacked widget pages to the main page.""" self.stacked_pages.setCurrentWidget(self.main_page) def goto_samples_page(self) -> None: """Switches stacked widget pages to the samples table page.""" self.stacked_pages.setCurrentWidget(self.samples_page) def goto_gates_page(self) -> None: """Switches stacked widget pages to the gating & other options page.""" self.stacked_pages.setCurrentWidget(self.gating_page) # ### # ### MAIN PAGE GUI LOGIC # ### def get_path(self) -> None: """Opens a dialog box and sets the chosen file/folder path, depending on the caller widget.""" options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog sender_name = self.sender().objectName() if sender_name == 'input': query, _ = QFileDialog.getOpenFileName(self, "Select file", "", "All Files (*)", options=options) elif sender_name == 'output': query = QFileDialog.getExistingDirectory(self, "Select Directory", options=options) else: return if query: getattr(self, f'{sender_name}_path').setText(query) def enable_single_excel(self) -> None: """Enables checkbox for generating a single Excel output.""" if self.output_excel.isChecked(): self.single_excel.setEnabled(True) else: self.single_excel.setEnabled(False) self.single_excel.setChecked(False) # ### # ### SAMPLE NAME/SAMPLE TABLE GUI LOGIC # ### def write_to_sample_table(self) -> None: """Writes data to sample table.""" table = self.sample_table ref = 'no' sample = self.sample_name.text() if sample: for cell in range(table.rowCount()): item = table.item(cell, 0) if item.text() == sample: self.same_sample() return if self.is_reference.isChecked(): for cell in range(table.rowCount()): item = table.item(cell, 1) if item.text() == 'yes': self.more_than_one_reference() return ref = 'yes' sample = QTableWidgetItem(sample) is_reference = QTableWidgetItem(ref) is_reference.setFlags(Qt.ItemIsEnabled) row_position = table.rowCount() table.insertRow(row_position) table.setItem(row_position, 0, sample) table.setItem(row_position, 1, is_reference) self.is_reference.setChecked(False) self.sample_name.setText('') def remove_from_sample_table(self) -> None: """Removes data from sample table.""" table = self.sample_table rows = set(index.row() for index in table.selectedIndexes()) for index in sorted(rows, reverse=True): self.sample_table.removeRow(index) def prompt_clear_data(self) -> None: """Prompts option to clear all data in the sample table.""" if self.confirm_clear_data(): table = self.sample_table while table.rowCount(): self.sample_table.removeRow(0) # ### # ### GATING GUI LOGIC # ### def activate_gate(self) -> None: """Activates/deactivates buttons related to gating.""" if self.sender().objectName() == 'no_gate': self.cytof_gates_value.setEnabled(False) self.rnaseq_gates_value.setEnabled(False) self.export_gated.setEnabled(False) self.export_gated.setChecked(False) elif self.sender().objectName() == 'cytof': self.cytof_gates_value.setEnabled(True) self.rnaseq_gates_value.setEnabled(False) self.export_gated.setEnabled(True) elif self.sender().objectName() == 'rnaseq': self.cytof_gates_value.setEnabled(False) self.rnaseq_gates_value.setEnabled(True) self.export_gated.setEnabled(True) # ### # ### CONNECT SCOUTS TO ANALYTICAL MODULES # ### def run(self) -> None: """Runs SCOUTS as a Worker, based on user input in the GUI.""" try: data = self.parse_input() except Exception as error: trace = traceback.format_exc() self.propagate_error((error, trace)) else: data['widget'] = self worker = Worker(func=start_scouts, **data) worker.signals.started.connect(self.analysis_has_started) worker.signals.finished.connect(self.analysis_has_finished) worker.signals.success.connect(self.success_message) worker.signals.error.connect(self.propagate_error) self.threadpool.start(worker) def parse_input(self) -> Dict: """Returns user input on the GUI as a dictionary.""" # Input and output input_dict = { 'input_file': str(self.input_path.text()), 'output_folder': str(self.output_path.text()) } if not input_dict['input_file'] or not input_dict['output_folder']: raise NoIOPathError # Set cutoff by reference or by sample rule input_dict['cutoff_rule'] = self.cutoff_group.checkedButton( ).objectName() # 'sample', 'ref', 'sample ref' # Outliers for each individual marker or any marker in row input_dict['marker_rule'] = self.markers_group.checkedButton( ).objectName() # 'single', 'any', 'single any' # Tukey factor used for calculating cutoff input_dict['tukey_factor'] = float( self.tukey_group.checkedButton().text()) # '1.5', '3.0' # Output settings input_dict['export_csv'] = True if self.output_csv.isChecked( ) else False input_dict['export_excel'] = True if self.output_excel.isChecked( ) else False input_dict['single_excel'] = True if self.single_excel.isChecked( ) else False # Retrieve samples from sample table input_dict['sample_list'] = [] for tuples in self.yield_samples_from_table(): input_dict['sample_list'].append(tuples) if not input_dict['sample_list']: raise NoSampleError # Set gate cutoff (if any) input_dict['gating'] = self.gating_group.checkedButton().objectName( ) # 'no_gate', 'cytof', 'rnaseq' input_dict['gate_cutoff_value'] = None if input_dict['gating'] != 'no_gate': input_dict['gate_cutoff_value'] = getattr( self, f'{input_dict["gating"]}_gates_value').value() input_dict['export_gated'] = True if self.export_gated.isChecked( ) else False # Generate results for non-outliers input_dict['non_outliers'] = False if self.not_outliers.isChecked(): input_dict['non_outliers'] = True # Generate results for bottom outliers input_dict['bottom_outliers'] = False if self.bottom_outliers.isChecked(): input_dict['bottom_outliers'] = True # return dictionary with all gathered inputs return input_dict def yield_samples_from_table( self) -> Generator[Tuple[str, str], None, None]: """Yields sample names from the sample table.""" table = self.sample_table for cell in range(table.rowCount()): sample_name = table.item(cell, 0).text() sample_type = table.item(cell, 1).text() yield sample_name, sample_type # ### # ### MESSAGE BOXES # ### def analysis_has_started(self) -> None: """Disables run button while SCOUTS analysis is underway.""" self.run_button.setText(' Working...') self.run_button.setEnabled(False) def analysis_has_finished(self) -> None: """Enables run button after SCOUTS analysis has finished.""" self.run_button.setEnabled(True) self.run_button.setText(' Run!') def success_message(self) -> None: """Info message box used when SCOUTS finished without errors.""" title = "Analysis finished!" mes = "Your analysis has finished. No errors were reported." if self.stacked_pages.isEnabled() is True: QMessageBox.information(self, title, mes) def memory_warning(self) -> None: """Warning message box used when user wants to generate a single excel file.""" if self.sender().isChecked(): title = 'Memory warning!' mes = ( "Depending on your dataset, this option can consume a LOT of memory and take" " a long time to process. Please make sure that your computer can handle it!" ) QMessageBox.information(self, title, mes) def same_sample(self) -> None: """Error message box used when the user tries to input the same sample twice in the sample table.""" title = 'Error: sample name already in table' mes = ( "Sorry, you can't do this because this sample name is already in the table. " "Please select a different name.") QMessageBox.critical(self, title, mes) def more_than_one_reference(self) -> None: """Error message box used when the user tries to input two reference samples in the sample table.""" title = "Error: more than one reference selected" mes = ( "Sorry, you can't do this because there is already a reference column in the table. " "Please remove it before adding a reference.") QMessageBox.critical(self, title, mes) def confirm_clear_data(self) -> bool: """Question message box used to confirm user action of clearing sample table.""" title = 'Confirm Action' mes = "Table will be cleared. Are you sure?" reply = QMessageBox.question(self, title, mes, QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: return True return False # ### # ### EXCEPTIONS & ERRORS # ### def propagate_error(self, error: Tuple[Exception, str]) -> None: """Calls the appropriate error message box based on type of Exception raised.""" if isinstance(error[0], NoIOPathError): self.no_io_path_error_message() elif isinstance(error[0], NoReferenceError): self.no_reference_error_message() elif isinstance(error[0], NoSampleError): self.no_sample_error_message() elif isinstance(error[0], PandasInputError): self.pandas_input_error_message() elif isinstance(error[0], SampleNamingError): self.sample_naming_error_message() else: self.generic_error_message(error) def no_io_path_error_message(self) -> None: """Message displayed when the user did not include an input file path, or an output folder path.""" title = 'Error: no file/folder' message = ("Sorry, no input file and/or output folder was provided. " "Please add the path to the necessary file/folder.") QMessageBox.critical(self, title, message) def no_reference_error_message(self) -> None: """Message displayed when the user wants to analyse cutoff based on a reference, but did not specify what sample corresponds to the reference.""" title = "Error: No reference selected" message = ( "Sorry, no reference sample was found on the sample list, but analysis was set to " "reference. Please add a reference sample, or change the rule for cutoff calculation." ) QMessageBox.critical(self, title, message) def no_sample_error_message(self) -> None: """Message displayed when the user did not add any samples to the sample table.""" title = "Error: No samples selected" message = ( "Sorry, the analysis cannot be performed because no sample names were input. " "Please add your sample names.") QMessageBox.critical(self, title, message) def pandas_input_error_message(self) -> None: """Message displayed when the input file cannot be read (likely because it is not a Excel or csv file).""" title = 'Error: unexpected input file' message = ( "Sorry, the input file could not be read. Please make sure that " "the data is save in a valid format (supported formats are: " ".csv, .xlsx).") QMessageBox.critical(self, title, message) def sample_naming_error_message(self) -> None: """Message displayed when none of the sample names passed by the user are found in the input DataFrame.""" title = 'Error: sample names not in input file' message = ( "Sorry, your sample names were not found in the input file. Please " "make sure that the names were typed correctly (case-sensitive).") QMessageBox.critical(self, title, message) def generic_error_message(self, error: Tuple[Exception, str]) -> None: """Error message box used to display any error message (including traceback) for any uncaught errors.""" title = 'An error occurred!' name, trace = error QMessageBox.critical(self, title, f"{str(name)}\n\nfull traceback:\n{trace}") def not_implemented_error_message(self) -> None: """Error message box used when the user accesses a functionality that hasn't been implemented yet.""" title = "Not yet implemented" mes = "Sorry, this functionality has not been implemented yet." QMessageBox.critical(self, title, mes) # ### # ### HELP & QUIT # ### @staticmethod def get_help() -> None: """Opens SCOUTS documentation on the browser. Called when the user clicks the "help" button""" webbrowser.open('https://scouts.readthedocs.io/en/master/') def closeEvent(self, event: QEvent) -> None: """Defines the message box for when the user wants to quit SCOUTS.""" title = 'Quit SCOUTS' mes = "Are you sure you want to quit?" reply = QMessageBox.question(self, title, mes, QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: self.stacked_pages.setEnabled(False) message = self.quit_message() waiter = Waiter(waiter_func=self.threadpool.activeThreadCount) waiter.signals.started.connect(message.show) waiter.signals.finished.connect(message.destroy) waiter.signals.finished.connect(sys.exit) self.threadpool.start(waiter) event.ignore() def quit_message(self) -> QDialog: """Displays a window while SCOUTS is exiting""" message = QDialog(self) message.setWindowTitle('Exiting SCOUTS') message.resize(300, 50) label = QLabel('SCOUTS is exiting, please wait...', message) label.setStyleSheet(self.style['label']) label.adjustSize() label.setAlignment(Qt.AlignCenter) label.move(int((message.width() - label.width()) / 2), int((message.height() - label.height()) / 2)) return message
class Ui_GroupBox(object): def setupUi(self, GroupBox): if not GroupBox.objectName(): GroupBox.setObjectName(u"GroupBox") GroupBox.resize(535, 520) sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(GroupBox.sizePolicy().hasHeightForWidth()) GroupBox.setSizePolicy(sizePolicy) self.verticalLayout_2 = QVBoxLayout(GroupBox) self.verticalLayout_2.setObjectName(u"verticalLayout_2") self.groupBox_occupancy_histogram = QGroupBox(GroupBox) self.groupBox_occupancy_histogram.setObjectName( u"groupBox_occupancy_histogram") self.verticalLayout = QVBoxLayout(self.groupBox_occupancy_histogram) self.verticalLayout.setObjectName(u"verticalLayout") self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setObjectName(u"horizontalLayout") self.label_56 = QLabel(self.groupBox_occupancy_histogram) self.label_56.setObjectName(u"label_56") self.label_56.setMaximumSize(QSize(16777215, 16777215)) self.label_56.setAlignment(Qt.AlignRight | Qt.AlignTrailing | Qt.AlignVCenter) self.horizontalLayout.addWidget(self.label_56) self.lineEdit_bins = QLineEdit(self.groupBox_occupancy_histogram) self.lineEdit_bins.setObjectName(u"lineEdit_bins") self.lineEdit_bins.setMinimumSize(QSize(50, 0)) self.lineEdit_bins.setMaximumSize(QSize(50, 16777215)) self.horizontalLayout.addWidget(self.lineEdit_bins) self.horizontalSpacer_3 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout.addItem(self.horizontalSpacer_3) self.label_55 = QLabel(self.groupBox_occupancy_histogram) self.label_55.setObjectName(u"label_55") self.label_55.setMaximumSize(QSize(16777215, 16777215)) self.label_55.setAlignment(Qt.AlignRight | Qt.AlignTrailing | Qt.AlignVCenter) self.horizontalLayout.addWidget(self.label_55) self.lineEdit_minimum = QLineEdit(self.groupBox_occupancy_histogram) self.lineEdit_minimum.setObjectName(u"lineEdit_minimum") self.lineEdit_minimum.setMinimumSize(QSize(50, 0)) self.lineEdit_minimum.setMaximumSize(QSize(50, 16777215)) self.horizontalLayout.addWidget(self.lineEdit_minimum) self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout.addItem(self.horizontalSpacer_2) self.label_17 = QLabel(self.groupBox_occupancy_histogram) self.label_17.setObjectName(u"label_17") self.label_17.setAlignment(Qt.AlignRight | Qt.AlignTrailing | Qt.AlignVCenter) self.horizontalLayout.addWidget(self.label_17) self.lineEdit_maximum = QLineEdit(self.groupBox_occupancy_histogram) self.lineEdit_maximum.setObjectName(u"lineEdit_maximum") self.lineEdit_maximum.setMinimumSize(QSize(50, 0)) self.lineEdit_maximum.setMaximumSize(QSize(50, 16777215)) self.horizontalLayout.addWidget(self.lineEdit_maximum) self.verticalLayout.addLayout(self.horizontalLayout) self.horizontalLayout_7 = QHBoxLayout() self.horizontalLayout_7.setObjectName(u"horizontalLayout_7") self.checkBox_cumulative_histogram = QCheckBox( self.groupBox_occupancy_histogram) self.checkBox_cumulative_histogram.setObjectName( u"checkBox_cumulative_histogram") self.horizontalLayout_7.addWidget(self.checkBox_cumulative_histogram) self.horizontalSpacer_12 = QSpacerItem(40, 20, QSizePolicy.Fixed, QSizePolicy.Minimum) self.horizontalLayout_7.addItem(self.horizontalSpacer_12) self.checkBox_stacked_histogram = QCheckBox( self.groupBox_occupancy_histogram) self.checkBox_stacked_histogram.setObjectName( u"checkBox_stacked_histogram") self.horizontalLayout_7.addWidget(self.checkBox_stacked_histogram) self.horizontalSpacer_11 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_7.addItem(self.horizontalSpacer_11) self.verticalLayout.addLayout(self.horizontalLayout_7) self.horizontalLayout_6 = QHBoxLayout() self.horizontalLayout_6.setObjectName(u"horizontalLayout_6") self.checkBox_color_segments_occupancy = QCheckBox( self.groupBox_occupancy_histogram) self.checkBox_color_segments_occupancy.setObjectName( u"checkBox_color_segments_occupancy") self.checkBox_color_segments_occupancy.setChecked(True) self.horizontalLayout_6.addWidget( self.checkBox_color_segments_occupancy) self.horizontalSpacer_9 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_6.addItem(self.horizontalSpacer_9) self.verticalLayout.addLayout(self.horizontalLayout_6) self.horizontalLayout_2 = QHBoxLayout() self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_2.addItem(self.horizontalSpacer) self.pushButton_save_occupancy = QPushButton( self.groupBox_occupancy_histogram) self.pushButton_save_occupancy.setObjectName( u"pushButton_save_occupancy") self.horizontalLayout_2.addWidget(self.pushButton_save_occupancy) self.pushButton_plot_occupancy = QPushButton( self.groupBox_occupancy_histogram) self.pushButton_plot_occupancy.setObjectName( u"pushButton_plot_occupancy") self.pushButton_plot_occupancy.setAutoDefault(False) self.horizontalLayout_2.addWidget(self.pushButton_plot_occupancy) self.verticalLayout.addLayout(self.horizontalLayout_2) self.verticalLayout_2.addWidget(self.groupBox_occupancy_histogram) self.verticalSpacer_2 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) self.verticalLayout_2.addItem(self.verticalSpacer_2) self.groupBox_nb_connections = QGroupBox(GroupBox) self.groupBox_nb_connections.setObjectName(u"groupBox_nb_connections") self.verticalLayout_3 = QVBoxLayout(self.groupBox_nb_connections) self.verticalLayout_3.setObjectName(u"verticalLayout_3") self.horizontalLayout_5 = QHBoxLayout() self.horizontalLayout_5.setObjectName(u"horizontalLayout_5") self.checkBox_color_segments_timeseries = QCheckBox( self.groupBox_nb_connections) self.checkBox_color_segments_timeseries.setObjectName( u"checkBox_color_segments_timeseries") self.checkBox_color_segments_timeseries.setChecked(True) self.horizontalLayout_5.addWidget( self.checkBox_color_segments_timeseries) self.horizontalSpacer_7 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_5.addItem(self.horizontalSpacer_7) self.verticalLayout_3.addLayout(self.horizontalLayout_5) self.horizontalLayout_4 = QHBoxLayout() self.horizontalLayout_4.setObjectName(u"horizontalLayout_4") self.horizontalSpacer_5 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_4.addItem(self.horizontalSpacer_5) self.pushButton_save_timeseries = QPushButton( self.groupBox_nb_connections) self.pushButton_save_timeseries.setObjectName( u"pushButton_save_timeseries") self.horizontalLayout_4.addWidget(self.pushButton_save_timeseries) self.pushButton_plot_timeseries = QPushButton( self.groupBox_nb_connections) self.pushButton_plot_timeseries.setObjectName( u"pushButton_plot_timeseries") self.pushButton_plot_timeseries.setAutoDefault(False) self.horizontalLayout_4.addWidget(self.pushButton_plot_timeseries) self.verticalLayout_3.addLayout(self.horizontalLayout_4) self.verticalLayout_2.addWidget(self.groupBox_nb_connections) self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) self.verticalLayout_2.addItem(self.verticalSpacer) self.groupBox_joint_occupancy = QGroupBox(GroupBox) self.groupBox_joint_occupancy.setObjectName( u"groupBox_joint_occupancy") self.verticalLayout_4 = QVBoxLayout(self.groupBox_joint_occupancy) self.verticalLayout_4.setObjectName(u"verticalLayout_4") self.horizontalLayout_10 = QHBoxLayout() self.horizontalLayout_10.setObjectName(u"horizontalLayout_10") self.radioButton_scatter = QRadioButton(self.groupBox_joint_occupancy) self.radioButton_scatter.setObjectName(u"radioButton_scatter") self.radioButton_scatter.setChecked(True) self.horizontalLayout_10.addWidget(self.radioButton_scatter) self.label_3 = QLabel(self.groupBox_joint_occupancy) self.label_3.setObjectName(u"label_3") self.horizontalLayout_10.addWidget(self.label_3) self.lineEdit_scatter_size = QLineEdit(self.groupBox_joint_occupancy) self.lineEdit_scatter_size.setObjectName(u"lineEdit_scatter_size") self.lineEdit_scatter_size.setMaximumSize(QSize(50, 16777215)) self.horizontalLayout_10.addWidget(self.lineEdit_scatter_size) self.horizontalSpacer_10 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_10.addItem(self.horizontalSpacer_10) self.verticalLayout_4.addLayout(self.horizontalLayout_10) self.horizontalLayout_3 = QHBoxLayout() self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") self.radioButton_heatmap = QRadioButton(self.groupBox_joint_occupancy) self.radioButton_heatmap.setObjectName(u"radioButton_heatmap") self.horizontalLayout_3.addWidget(self.radioButton_heatmap) self.horizontalSpacer_4 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_3.addItem(self.horizontalSpacer_4) self.pushButton_save_jo = QPushButton(self.groupBox_joint_occupancy) self.pushButton_save_jo.setObjectName(u"pushButton_save_jo") self.horizontalLayout_3.addWidget(self.pushButton_save_jo) self.pushButton_plot_jo = QPushButton(self.groupBox_joint_occupancy) self.pushButton_plot_jo.setObjectName(u"pushButton_plot_jo") self.pushButton_plot_jo.setAutoDefault(False) self.horizontalLayout_3.addWidget(self.pushButton_plot_jo) self.verticalLayout_4.addLayout(self.horizontalLayout_3) self.verticalLayout_2.addWidget(self.groupBox_joint_occupancy) self.retranslateUi(GroupBox) QMetaObject.connectSlotsByName(GroupBox) # setupUi def retranslateUi(self, GroupBox): GroupBox.setWindowTitle( QCoreApplication.translate("GroupBox", u"GroupBox", None)) self.groupBox_occupancy_histogram.setTitle( QCoreApplication.translate("GroupBox", u"Occupancy histogram", None)) self.label_56.setText( QCoreApplication.translate("GroupBox", u"# of bins", None)) self.lineEdit_bins.setText( QCoreApplication.translate("GroupBox", u"10", None)) self.label_55.setText( QCoreApplication.translate("GroupBox", u"min. occupancy", None)) self.lineEdit_minimum.setText( QCoreApplication.translate("GroupBox", u"0.0", None)) self.label_17.setText( QCoreApplication.translate("GroupBox", u"max. occupancy", None)) self.lineEdit_maximum.setText( QCoreApplication.translate("GroupBox", u"1.0", None)) self.checkBox_cumulative_histogram.setText( QCoreApplication.translate("GroupBox", u"cumulative", None)) self.checkBox_stacked_histogram.setText( QCoreApplication.translate("GroupBox", u"stacked", None)) #if QT_CONFIG(tooltip) self.checkBox_color_segments_occupancy.setToolTip( QCoreApplication.translate( "GroupBox", u"<html><head/><body><p align=\"justify\">Toggle if histogram bars are colored by segment or molecule. With colors turned on, comparing to other analyses is not possible.</p></body></html>", None)) #endif // QT_CONFIG(tooltip) self.checkBox_color_segments_occupancy.setText( QCoreApplication.translate("GroupBox", u"color by segment", None)) self.pushButton_save_occupancy.setText( QCoreApplication.translate("GroupBox", u"Data", None)) #if QT_CONFIG(tooltip) self.pushButton_plot_occupancy.setToolTip( QCoreApplication.translate( "GroupBox", u"<html><head/><body><p>Compute histogram of H bond occupancies. Counts the number of H bonds with an occupancy equal or greater than the respective value.</p></body></html>", None)) #endif // QT_CONFIG(tooltip) self.pushButton_plot_occupancy.setText( QCoreApplication.translate("GroupBox", u"Plot", None)) self.groupBox_nb_connections.setTitle( QCoreApplication.translate("GroupBox", u"Number of connections time series", None)) #if QT_CONFIG(tooltip) self.checkBox_color_segments_timeseries.setToolTip( QCoreApplication.translate( "GroupBox", u"<html><head/><body><p align=\"justify\">Toggle if histogram bars are colored by segment or molecule. With colors turned on, comparing to other analyses is not possible.</p></body></html>", None)) #endif // QT_CONFIG(tooltip) self.checkBox_color_segments_timeseries.setText( QCoreApplication.translate("GroupBox", u"color by segment", None)) self.pushButton_save_timeseries.setText( QCoreApplication.translate("GroupBox", u"Data", None)) #if QT_CONFIG(tooltip) self.pushButton_plot_timeseries.setToolTip( QCoreApplication.translate( "GroupBox", u"<html><head/><body><p align=\"justify\">Compute the number of H bonds per frame.</p></body></html>", None)) #endif // QT_CONFIG(tooltip) self.pushButton_plot_timeseries.setText( QCoreApplication.translate("GroupBox", u"Plot", None)) self.groupBox_joint_occupancy.setTitle( QCoreApplication.translate("GroupBox", u"Joint Occupancy", None)) self.radioButton_scatter.setText( QCoreApplication.translate("GroupBox", u"scatter plot", None)) self.label_3.setText( QCoreApplication.translate("GroupBox", u"with dot size", None)) self.lineEdit_scatter_size.setText( QCoreApplication.translate("GroupBox", u"1", None)) self.lineEdit_scatter_size.setPlaceholderText( QCoreApplication.translate("GroupBox", u"0 - 100", None)) self.radioButton_heatmap.setText( QCoreApplication.translate("GroupBox", u"heatmap", None)) self.pushButton_save_jo.setText( QCoreApplication.translate("GroupBox", u"Data", None)) #if QT_CONFIG(tooltip) self.pushButton_plot_jo.setToolTip( QCoreApplication.translate( "GroupBox", u"<html><head/><body><p align=\"justify\">Compute the joint occupancy of the H bond network. The joint occupancy is true, if all H bonds of the network are present in a frame and false otherwise.</p></body></html>", None)) #endif // QT_CONFIG(tooltip) self.pushButton_plot_jo.setText( QCoreApplication.translate("GroupBox", u"Plot", None))
class MainWindow(QMainWindow): def __init__(self, ui_file, devMode, parent=None): super(MainWindow, self).__init__() self.uiFileName = ui_file # use this if there are multiple UI files if devMode == "development": # use ui file directly made by QDesigner uiFile = QFile(ui_file) uiFile.open(QFile.ReadOnly) # read in UI for the form loader = QUiLoader() self.window = loader.load(uiFile) uiFile.close() else: #deployment - use .py version of ui file, with slightly different setup self.ui = Ui_MainWindow() self.ui.setupUi(self) self.getParts() # identify form objects self.connectParts() # connect buttons to operations self.convs = Converters( ) # load converters for main conversion categories self.yc = YearConverters( ) # load converters for japanese years, zodiac years self.mess = Mess() # instructions and messages in local language self.validFloat = QDoubleValidator() self.validYear = QIntValidator() self.validYear.setRange(1, 9999) # used for years self.btnConvert.hide() self.widgetSetup("start") # initial conditions for form if devMode == "development": self.window.show() else: self.show() def widgetSetup(self, themode): # based on which main button is pressed self.themode = themode # this is set when a main button is pressed, or on initial load self.emptyConvLayout( ) # get rid of old radio buttons if they exist, hide input/output, etc. thetext, thestyle = makeHeader1( themode, self.uiFileName) # make heading for convType = themode self.header1.setStyleSheet( thestyle) # can have different background colors self.header1.setText(thetext) self.header1.show() self.hideBigInstructions() if themode in self.convs.getValidConvTypes( ): # set up radio buttons for conversions oneConvTypeInfo = self.convs.convTypeToConvInfo( themode) # get convCodes, displays for this convType for ix, (convCode, convDisplay) in enumerate( oneConvTypeInfo ): # iterate through enumerated list of tuples self.oneRadio = QRadioButton( "{}".format(convDisplay)) # text for button self.oneRadio.setObjectName("object_{}".format( convCode)) # to be used later by sender() self.oneRadio.setStyleSheet( makeStyleSheet("radiobutton", self.uiFileName)) self.layoutConv.addWidget(self.oneRadio) self.oneRadio.clicked.connect( self.convSetup ) # convSetup will call sender() to find convCode if ix == 0: self.oneRadio.setFocus( ) # set focus on first button in list if themode == "fromjpyear": # set up radio buttons for modern eras self.fromjpyearmode = "modern" # start with modern eras only self.showJpEras() if themode == "fromjpyearhistoric": # set up radio buttons for all eras self.fromjpyearmode = "all" # start with modern eras only self.showJpEras() if themode == "tojpyear": # no choices, go straight to input box self.showInstructions(self.mess.getToJpYear(self.yc.getMinYear()), "") self.input1.setText(str( self.yc.getNowYear())) # start with current year self.setUpValidator() self.convertUnits() if themode == "zodiac": # no choices, go straight to input box self.showInstructions(self.mess.getEnterYearZodiac(), "") self.input1.setText(str( self.yc.getNowYear())) # start with current year self.setUpValidator() self.convertUnits() if themode == "start": self.btnFromMetric.setFocus() self.showBigInstructions(self.mess.getStartMsg2()) def showBigInstructions(self, themsg): self.instructions2.setText(themsg) self.scrollArea.hide() self.instructions2.show() def hideBigInstructions(self): self.scrollArea.show() self.instructions2.hide() def showJpEras(self): # display radio buttons for Japanese eras jpEraList = self.yc.getEraNamesPlusCodes( self.fromjpyearmode) # modern or all for ix, (eraText, eraCode) in enumerate(jpEraList): self.oneRadio = QRadioButton( "{}".format(eraText)) # text for button self.oneRadio.setObjectName( "object_{}".format(eraCode)) # to be used later by sender() self.oneRadio.setStyleSheet( makeStyleSheet("radiobutton", self.uiFileName)) self.layoutConv.addWidget(self.oneRadio) self.oneRadio.clicked.connect( self.eraSetup) # eraSetup will call sender() to find eraCode if ix == 0: self.oneRadio.setFocus() # set focus on first button if self.fromjpyearmode == "modern": self.oneRadio = QRadioButton( "{}".format("Show more eras")) # now add option for more eras self.oneRadio.setObjectName( "object_{}".format("all")) # to be used later by sender() else: self.oneRadio = QRadioButton("{}".format( "Show fewer eras")) # now add option to return to modern eras self.oneRadio.setObjectName( "object_{}".format("modern")) # to be used later by sender() self.oneRadio.setStyleSheet( makeStyleSheet("radiobutton", self.uiFileName)) self.layoutConv.addWidget(self.oneRadio) self.oneRadio.clicked.connect( self.eraSetup) # eraSetup will call sender() to find eraCode def eraSetup(self): # this is called when radio button is chosen theEra = self.getCodeFromSenderName( ) # era or mode is determined by object name of sending radio button if theEra in ["all", "modern"]: # switch between modern and all self.fromjpyearmode = theEra # set the mode here self.emptyConvLayout() # clear former list if theEra == "all": self.widgetSetup("fromjpyearhistoric") else: self.widgetSetup("fromjpyear") else: # theEra will be eraCode for chosen era self.chosenEra = theEra # set this property if self.yc.getNowEra() == theEra: theHint = "(1- )" # no final year if it's the current era else: theHint = "(1-{})".format( self.yc.getNumYears(theEra)) # final year in that era self.showInstructions( self.mess.getFromJpYear(self.yc.getENameUnparsed(theEra)), theHint) self.output2.hide() self.setUpValidator() def setUpValidator(self): if self.themode in self.convs.getValidConvTypes(): # measures if self.convs.isTempConv(self.theConvCode): self.validFloat.setBottom( -999999) # temperatures can be negative else: self.validFloat.setBottom( 0.0) # other measures can't be negative self.input1.setValidator(self.validFloat) if self.themode in [ "fromjpyear", "fromjpyearhistoric", "tojpyear", "zodiac" ]: self.input1.setValidator( self.validYear) # range already set to 1-9999 def convSetup(self): # set up based on which radio button was set self.theConvCode = self.getCodeFromSenderName( ) # get the code based on the sending button, and set it self.showInstructions(self.mess.getEnterAmt()) self.setUpValidator() self.input1.setText("1") # show units=1 to start self.convertUnits() def getCodeFromSenderName(self): # based on objectName of sender button sending_button = self.sender() return str(sending_button.objectName()).replace("object_", "") def convertUnits(self): # main conversion routine pstart = self.mess.getPstart( ) # get paragraph HTML from Message object pstopstart = self.mess.getPstopstart() pstop = self.mess.getPstop() jcol = self.mess.getJColor() # special color for Japanese text if len(self.input1.text()) < 1: # test for blank input self.output2.setText( self.mess.getBlankConvertMsg()) # show error message self.output2.show() return if self.themode in self.convs.getValidConvTypes( ): # standard conversions: fromjpmeasure, tometric, etc amt1Text = self.input1.text() amt1 = strToNum(amt1Text) if self.convs.isTooCold(self.theConvCode, amt1): eqString = self.mess.getTooCold( ) #check for temp below abs zero else: eqString = self.convs.getEquation(self.theConvCode, amt1, " =" + pstopstart, jcol) self.output2.setText( pstart + eqString + pstop) # use paragraphs for better control of appearance elif self.themode == "tojpyear": # int'l year to Japanese year try: iYear = int(self.input1.text()) yearDisplay = self.mess.makeJYearDisplay( self.yc.iYearToJYear(iYear, jcol), iYear) except ValueError as errorMsg: yearDisplay = pstart + str( errorMsg) + pstop # display the error message self.output2.setText(yearDisplay) #print (yearDisplay) elif self.themode in ["fromjpyear", "fromjpyearhistoric" ]: # Japanese year to int'l year jYear = int(self.input1.text() ) # validator at work, so this should be an integer try: # raise exception if not in range iYear = self.yc.jYearToIYear(self.chosenEra, jYear) yearDisplay = pstart + "{} ({}) {}".format(self.yc.getENameUnparsed(self.chosenEra), \ self.yc.getJName(self.chosenEra, jcol), jYear) + \ pstopstart + self.mess.getIs() + " " + str(iYear) + pstop except ValueError as errorMsg: yearDisplay = pstart + str( errorMsg) + pstop # display the error message self.output2.setText(yearDisplay) elif self.themode == "zodiac": # international year to zodiac sign iYear = int(self.input1.text()) # display is HTML with paragraph, line height, and Japanese characters in color (specified in Mess class) yearDisplay = pstart + str(iYear) + " " + self.mess.getIs() + ":" + pstopstart + \ self.mess.getYearOfThe().capitalize() + " " + self.yc.getZodEName(iYear) + pstop self.output2.setText(yearDisplay) zBig = self.mess.makeZodiacBigDisplay( self.yc.getZodEName(iYear), self.yc.getZodJName(iYear, jcol), self.yc.getZodJZName(iYear, jcol)) self.showBigInstructions(zBig) self.output2.show() # common to all conversion types def emptyConvLayout( self): # clear the radio buttons in the converter/jpYear layout for i in reversed(range( self.layoutConv.count())): # delete them in reverse order self.layoutConv.itemAt(i).widget().deleteLater() self.instructions1.hide() self.input1.setPlaceholderText("") # clear previous hints self.input1.hide() # conversion not chosen yet, so hide this self.btnConvert.hide() # conversion not chosen yet, so hide this self.output2.hide() # conversion not chosen yet, so hide this def showInstructions( self, instructionsText, inputHint=""): # position UI elements, set label, show input box self.instructions1.setText(instructionsText) self.instructions1.show() self.input1.setText("") self.input1.setPlaceholderText(inputHint) self.input1.show() self.btnConvert.show() self.input1.setFocus() def convertQuickly(self): # testing if not self.input1.text(): amt = 0 else: amt = float(self.input1.text()) * 2.0 amtString = '{} kilograms'.format(amt) self.output2.setText(amtString) def getParts(self): # map form elements to object properties self.centralw = self.findWidget(QWidget, 'central_widget') self.input1 = self.findWidget(QLineEdit, 'input1') self.output2 = self.findWidget(QTextEdit, 'label_output2') self.header1 = self.findWidget(QLabel, 'label_header1') self.btnConvert = self.findWidget(QPushButton, 'button_convert') self.btnExit = self.findWidget(QPushButton, 'button_exit') self.btnFromMetric = self.findWidget(QPushButton, 'button_from_metric') self.btnToMetric = self.findWidget(QPushButton, 'button_to_metric') self.btnFromJpMeasure = self.findWidget(QPushButton, 'button_from_jpmeasure') self.btnToJpMeasure = self.findWidget(QPushButton, 'button_to_jpmeasure') self.btnFromJpYear = self.findWidget(QPushButton, 'button_from_jpyear') self.btnToJpYear = self.findWidget(QPushButton, 'button_to_jpyear') self.btnZodiac = self.findWidget(QPushButton, 'button_zodiac') self.scrollArea = self.findWidget(QScrollArea, 'conv_layout') content_widget = QWidget( ) # now add the QVBoxLayout widget programmatically, for scrolling self.scrollArea.setWidget(content_widget) self.scrollArea.setWidgetResizable(True) self.layoutConv = QVBoxLayout(content_widget) self.layoutConv.setAlignment( Qt.AlignTop ) # don't evenly space the radio buttons, but start at the top self.instructions1 = self.findWidget(QLabel, 'label_instructions1') self.instructions2 = self.findWidget(QLabel, 'label_instructions2') self.menuExit = self.findWidget(QAction, 'action_exit') self.menuFromMetric = self.findWidget(QAction, 'action_from_metric') self.menuToMetric = self.findWidget(QAction, 'action_to_metric') self.menuFromJpMeasure = self.findWidget(QAction, 'action_from_jpmeasure') self.menuToJpMeasure = self.findWidget(QAction, 'action_to_jpmeasure') self.menuFromJpYear = self.findWidget(QAction, 'action_from_jpyear') self.menuFromJpYearHistoric = self.findWidget( QAction, 'action_from_jpyear_historic') self.menuToJpYear = self.findWidget(QAction, 'action_to_jpyear') self.menuZodiac = self.findWidget(QAction, 'action_zodiac') self.menubar = self.findWidget(QMenuBar, 'menubar') if self.uiFileName == "main3.ui": self.menubar.setStyleSheet( getMenuStyle("main3.ui")) # in jpconvhelper.py def findWidget(self, widgetType, widgetName): if devMode == "development": return self.window.findChild(widgetType, widgetName) else: return self.findChild(widgetType, widgetName) def connectParts(self): # connect buttons and menu actions to operations self.input1.returnPressed.connect(self.convertUnits) self.btnConvert.clicked.connect(self.convertUnits) self.btnExit.clicked.connect(self.exitHandler) self.menuExit.triggered.connect(self.exitHandler) self.btnFromMetric.clicked.connect( lambda: self.widgetSetup("frommetric")) self.menuFromMetric.triggered.connect( lambda: self.widgetSetup("frommetric")) self.btnToMetric.clicked.connect(lambda: self.widgetSetup("tometric")) self.menuToMetric.triggered.connect( lambda: self.widgetSetup("tometric")) self.btnFromJpMeasure.clicked.connect( lambda: self.widgetSetup("fromjpmeasure")) self.menuFromJpMeasure.triggered.connect( lambda: self.widgetSetup("fromjpmeasure")) self.btnToJpMeasure.clicked.connect( lambda: self.widgetSetup("tojpmeasure")) self.menuToJpMeasure.triggered.connect( lambda: self.widgetSetup("tojpmeasure")) self.btnFromJpYear.clicked.connect( lambda: self.widgetSetup("fromjpyear")) self.menuFromJpYear.triggered.connect( lambda: self.widgetSetup("fromjpyear")) self.menuFromJpYearHistoric.triggered.connect( lambda: self.widgetSetup("fromjpyearhistoric")) self.btnToJpYear.clicked.connect(lambda: self.widgetSetup("tojpyear")) self.menuToJpYear.triggered.connect( lambda: self.widgetSetup("tojpyear")) self.btnZodiac.clicked.connect(lambda: self.widgetSetup("zodiac")) self.menuZodiac.triggered.connect(lambda: self.widgetSetup("zodiac")) def exitHandler(self): app.exit()
class Ui_GroupBox(object): def setupUi(self, GroupBox): if not GroupBox.objectName(): GroupBox.setObjectName(u"GroupBox") GroupBox.resize(528, 576) sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(GroupBox.sizePolicy().hasHeightForWidth()) GroupBox.setSizePolicy(sizePolicy) self.verticalLayout_2 = QVBoxLayout(GroupBox) self.verticalLayout_2.setObjectName(u"verticalLayout_2") self.groupBox = QGroupBox(GroupBox) self.groupBox.setObjectName(u"groupBox") self.verticalLayout_4 = QVBoxLayout(self.groupBox) self.verticalLayout_4.setObjectName(u"verticalLayout_4") self.horizontalLayout_7 = QHBoxLayout() self.horizontalLayout_7.setObjectName(u"horizontalLayout_7") self.horizontalSpacer_7 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_7.addItem(self.horizontalSpacer_7) self.pushButton_degree_save = QPushButton(self.groupBox) self.pushButton_degree_save.setObjectName(u"pushButton_degree_save") self.horizontalLayout_7.addWidget(self.pushButton_degree_save) self.verticalLayout_4.addLayout(self.horizontalLayout_7) self.verticalLayout_2.addWidget(self.groupBox) self.verticalSpacer_2 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) self.verticalLayout_2.addItem(self.verticalSpacer_2) self.groupBox_degree = QGroupBox(GroupBox) self.groupBox_degree.setObjectName(u"groupBox_degree") self.verticalLayout_3 = QVBoxLayout(self.groupBox_degree) self.verticalLayout_3.setObjectName(u"verticalLayout_3") self.horizontalLayout_2 = QHBoxLayout() self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") self.radioButton_betweenness = QRadioButton(self.groupBox_degree) self.radioButton_betweenness.setObjectName(u"radioButton_betweenness") self.horizontalLayout_2.addWidget(self.radioButton_betweenness) self.radioButton_degree = QRadioButton(self.groupBox_degree) self.radioButton_degree.setObjectName(u"radioButton_degree") self.radioButton_degree.setChecked(True) self.horizontalLayout_2.addWidget(self.radioButton_degree) self.horizontalSpacer_5 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_2.addItem(self.horizontalSpacer_5) self.verticalLayout_3.addLayout(self.horizontalLayout_2) self.checkBox_averaged_frames = QCheckBox(self.groupBox_degree) self.checkBox_averaged_frames.setObjectName( u"checkBox_averaged_frames") self.checkBox_averaged_frames.setChecked(True) self.verticalLayout_3.addWidget(self.checkBox_averaged_frames) self.checkBox_normalized = QCheckBox(self.groupBox_degree) self.checkBox_normalized.setObjectName(u"checkBox_normalized") self.verticalLayout_3.addWidget(self.checkBox_normalized) self.groupBox_per_residue = QGroupBox(self.groupBox_degree) self.groupBox_per_residue.setObjectName(u"groupBox_per_residue") self.groupBox_per_residue.setCheckable(True) self.verticalLayout = QVBoxLayout(self.groupBox_per_residue) self.verticalLayout.setObjectName(u"verticalLayout") self.horizontalLayout_6 = QHBoxLayout() self.horizontalLayout_6.setObjectName(u"horizontalLayout_6") self.label_2 = QLabel(self.groupBox_per_residue) self.label_2.setObjectName(u"label_2") self.horizontalLayout_6.addWidget(self.label_2) self.comboBox = QComboBox(self.groupBox_per_residue) self.comboBox.setObjectName(u"comboBox") self.horizontalLayout_6.addWidget(self.comboBox) self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_6.addItem(self.horizontalSpacer_2) self.verticalLayout.addLayout(self.horizontalLayout_6) self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setObjectName(u"horizontalLayout") self.label_10 = QLabel(self.groupBox_per_residue) self.label_10.setObjectName(u"label_10") self.label_10.setAlignment(Qt.AlignRight | Qt.AlignTrailing | Qt.AlignVCenter) self.horizontalLayout.addWidget(self.label_10) self.lineEdit_degree_residue_ids = QLineEdit(self.groupBox_per_residue) self.lineEdit_degree_residue_ids.setObjectName( u"lineEdit_degree_residue_ids") self.horizontalLayout.addWidget(self.lineEdit_degree_residue_ids) self.horizontalSpacer_6 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout.addItem(self.horizontalSpacer_6) self.verticalLayout.addLayout(self.horizontalLayout) self.verticalLayout_3.addWidget(self.groupBox_per_residue) self.groupBox_histogram = QGroupBox(self.groupBox_degree) self.groupBox_histogram.setObjectName(u"groupBox_histogram") self.groupBox_histogram.setCheckable(True) self.groupBox_histogram.setChecked(False) self.verticalLayout_5 = QVBoxLayout(self.groupBox_histogram) self.verticalLayout_5.setObjectName(u"verticalLayout_5") self.horizontalLayout_3 = QHBoxLayout() self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") self.label_56 = QLabel(self.groupBox_histogram) self.label_56.setObjectName(u"label_56") self.label_56.setMaximumSize(QSize(16777215, 16777215)) self.label_56.setAlignment(Qt.AlignRight | Qt.AlignTrailing | Qt.AlignVCenter) self.horizontalLayout_3.addWidget(self.label_56) self.lineEdit_bins = QLineEdit(self.groupBox_histogram) self.lineEdit_bins.setObjectName(u"lineEdit_bins") self.lineEdit_bins.setMinimumSize(QSize(50, 0)) self.lineEdit_bins.setMaximumSize(QSize(50, 16777215)) self.horizontalLayout_3.addWidget(self.lineEdit_bins) self.label_55 = QLabel(self.groupBox_histogram) self.label_55.setObjectName(u"label_55") self.label_55.setMaximumSize(QSize(16777215, 16777215)) self.label_55.setAlignment(Qt.AlignRight | Qt.AlignTrailing | Qt.AlignVCenter) self.horizontalLayout_3.addWidget(self.label_55) self.lineEdit_minimum = QLineEdit(self.groupBox_histogram) self.lineEdit_minimum.setObjectName(u"lineEdit_minimum") self.lineEdit_minimum.setMinimumSize(QSize(50, 0)) self.lineEdit_minimum.setMaximumSize(QSize(50, 16777215)) self.horizontalLayout_3.addWidget(self.lineEdit_minimum) self.label_17 = QLabel(self.groupBox_histogram) self.label_17.setObjectName(u"label_17") self.label_17.setAlignment(Qt.AlignRight | Qt.AlignTrailing | Qt.AlignVCenter) self.horizontalLayout_3.addWidget(self.label_17) self.lineEdit_maximum = QLineEdit(self.groupBox_histogram) self.lineEdit_maximum.setObjectName(u"lineEdit_maximum") self.lineEdit_maximum.setMinimumSize(QSize(50, 0)) self.lineEdit_maximum.setMaximumSize(QSize(50, 16777215)) self.horizontalLayout_3.addWidget(self.lineEdit_maximum) self.horizontalSpacer_3 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_3.addItem(self.horizontalSpacer_3) self.verticalLayout_5.addLayout(self.horizontalLayout_3) self.horizontalLayout_8 = QHBoxLayout() self.horizontalLayout_8.setObjectName(u"horizontalLayout_8") self.checkBox_cumulative_histogram = QCheckBox(self.groupBox_histogram) self.checkBox_cumulative_histogram.setObjectName( u"checkBox_cumulative_histogram") self.horizontalLayout_8.addWidget(self.checkBox_cumulative_histogram) self.horizontalSpacer_12 = QSpacerItem(40, 20, QSizePolicy.Fixed, QSizePolicy.Minimum) self.horizontalLayout_8.addItem(self.horizontalSpacer_12) self.checkBox_stacked_histogram = QCheckBox(self.groupBox_histogram) self.checkBox_stacked_histogram.setObjectName( u"checkBox_stacked_histogram") self.horizontalLayout_8.addWidget(self.checkBox_stacked_histogram) self.horizontalSpacer_11 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_8.addItem(self.horizontalSpacer_11) self.verticalLayout_5.addLayout(self.horizontalLayout_8) self.horizontalLayout_9 = QHBoxLayout() self.horizontalLayout_9.setObjectName(u"horizontalLayout_9") self.checkBox_color_segments_occupancy = QCheckBox( self.groupBox_histogram) self.checkBox_color_segments_occupancy.setObjectName( u"checkBox_color_segments_occupancy") self.checkBox_color_segments_occupancy.setChecked(True) self.horizontalLayout_9.addWidget( self.checkBox_color_segments_occupancy) self.horizontalSpacer_9 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_9.addItem(self.horizontalSpacer_9) self.verticalLayout_5.addLayout(self.horizontalLayout_9) self.verticalLayout_3.addWidget(self.groupBox_histogram) self.horizontalLayout_5 = QHBoxLayout() self.horizontalLayout_5.setObjectName(u"horizontalLayout_5") self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_5.addItem(self.horizontalSpacer) self.pushButton_degree_plot = QPushButton(self.groupBox_degree) self.pushButton_degree_plot.setObjectName(u"pushButton_degree_plot") self.pushButton_degree_plot.setAutoDefault(False) self.horizontalLayout_5.addWidget(self.pushButton_degree_plot) self.verticalLayout_3.addLayout(self.horizontalLayout_5) self.verticalLayout_2.addWidget(self.groupBox_degree) self.retranslateUi(GroupBox) QMetaObject.connectSlotsByName(GroupBox) # setupUi def retranslateUi(self, GroupBox): GroupBox.setWindowTitle( QCoreApplication.translate("GroupBox", u"GroupBox", None)) self.groupBox.setTitle( QCoreApplication.translate("GroupBox", u"All centrality measures", None)) self.pushButton_degree_save.setText( QCoreApplication.translate("GroupBox", u"Data", None)) self.groupBox_degree.setTitle( QCoreApplication.translate("GroupBox", u"Plots", None)) self.radioButton_betweenness.setText( QCoreApplication.translate("GroupBox", u"betweenness centrality", None)) self.radioButton_degree.setText( QCoreApplication.translate("GroupBox", u"degree centrality", None)) #if QT_CONFIG(tooltip) self.checkBox_averaged_frames.setToolTip( QCoreApplication.translate( "GroupBox", u"<html><head/><body><p align=\"justify\">Toggle, if absolute number of connections or time averaged number of connections are used.</p></body></html>", None)) #endif // QT_CONFIG(tooltip) self.checkBox_averaged_frames.setText( QCoreApplication.translate("GroupBox", u"average across frames", None)) self.checkBox_normalized.setText( QCoreApplication.translate("GroupBox", u"normalized", None)) self.groupBox_per_residue.setTitle( QCoreApplication.translate("GroupBox", u"Per Residue", None)) self.label_2.setText( QCoreApplication.translate("GroupBox", u"segment: ", None)) self.label_10.setText( QCoreApplication.translate("GroupBox", u"residue ids: ", None)) self.lineEdit_degree_residue_ids.setPlaceholderText( QCoreApplication.translate("GroupBox", u"e.g. 0-12, 20, 70-90", None)) self.groupBox_histogram.setTitle( QCoreApplication.translate("GroupBox", u"Histogram", None)) self.label_56.setText( QCoreApplication.translate("GroupBox", u"# of bins", None)) self.lineEdit_bins.setText( QCoreApplication.translate("GroupBox", u"10", None)) self.label_55.setText( QCoreApplication.translate("GroupBox", u"min. value", None)) self.lineEdit_minimum.setText( QCoreApplication.translate("GroupBox", u"0.0", None)) self.label_17.setText( QCoreApplication.translate("GroupBox", u"max. value", None)) self.lineEdit_maximum.setText( QCoreApplication.translate("GroupBox", u"1.0", None)) self.checkBox_cumulative_histogram.setText( QCoreApplication.translate("GroupBox", u"cumulative", None)) self.checkBox_stacked_histogram.setText( QCoreApplication.translate("GroupBox", u"stacked", None)) #if QT_CONFIG(tooltip) self.checkBox_color_segments_occupancy.setToolTip( QCoreApplication.translate( "GroupBox", u"<html><head/><body><p align=\"justify\">Toggle if histogram bars are colored by segment or molecule. With colors turned on, comparing to other analyses is not possible.</p></body></html>", None)) #endif // QT_CONFIG(tooltip) self.checkBox_color_segments_occupancy.setText( QCoreApplication.translate("GroupBox", u"color by segment", None)) #if QT_CONFIG(tooltip) self.pushButton_degree_plot.setToolTip( QCoreApplication.translate( "GroupBox", u"<html><head/><body><p align=\"justify\">Compute the number of H bonds per residue. Results are colored by segment.</p></body></html>", None)) #endif // QT_CONFIG(tooltip) self.pushButton_degree_plot.setText( QCoreApplication.translate("GroupBox", u"Plot", None))
class Ui_dlg_new_tool(object): def setupUi(self, dlg_new_tool): if not dlg_new_tool.objectName(): dlg_new_tool.setObjectName(u"dlg_new_tool") dlg_new_tool.resize(570, 463) dlg_new_tool.setModal(True) self.gridLayout_2 = QGridLayout(dlg_new_tool) self.gridLayout_2.setObjectName(u"gridLayout_2") self.gridLayout = QGridLayout() self.gridLayout.setObjectName(u"gridLayout") self.te_description = QTextEdit(dlg_new_tool) self.te_description.setObjectName(u"te_description") self.gridLayout.addWidget(self.te_description, 3, 0, 1, 6) self.label = QLabel(dlg_new_tool) self.label.setObjectName(u"label") self.gridLayout.addWidget(self.label, 0, 0, 1, 1) self.lbl_file_exists = QLabel(dlg_new_tool) self.lbl_file_exists.setObjectName(u"lbl_file_exists") self.lbl_file_exists.setPixmap(QPixmap(u"../resources/OK.png")) self.gridLayout.addWidget(self.lbl_file_exists, 0, 5, 1, 1) self.label_5 = QLabel(dlg_new_tool) self.label_5.setObjectName(u"label_5") self.gridLayout.addWidget(self.label_5, 0, 3, 1, 1) self.chk_mask_required = QCheckBox(dlg_new_tool) self.chk_mask_required.setObjectName(u"chk_mask_required") self.gridLayout.addWidget(self.chk_mask_required, 5, 0, 1, 6) self.label_4 = QLabel(dlg_new_tool) self.label_4.setObjectName(u"label_4") self.gridLayout.addWidget(self.label_4, 0, 2, 1, 1) self.le_tool_name = QLineEdit(dlg_new_tool) self.le_tool_name.setObjectName(u"le_tool_name") self.gridLayout.addWidget(self.le_tool_name, 0, 1, 1, 1) self.label_3 = QLabel(dlg_new_tool) self.label_3.setObjectName(u"label_3") self.gridLayout.addWidget(self.label_3, 1, 3, 1, 1) self.le_file_name = QLineEdit(dlg_new_tool) self.le_file_name.setObjectName(u"le_file_name") self.le_file_name.setReadOnly(True) self.gridLayout.addWidget(self.le_file_name, 0, 4, 1, 1) self.label_6 = QLabel(dlg_new_tool) self.label_6.setObjectName(u"label_6") font = QFont() font.setPointSize(8) self.label_6.setFont(font) self.gridLayout.addWidget(self.label_6, 1, 2, 1, 1) self.le_class_name = QLineEdit(dlg_new_tool) self.le_class_name.setObjectName(u"le_class_name") self.le_class_name.setReadOnly(True) self.gridLayout.addWidget(self.le_class_name, 1, 4, 1, 1) self.label_2 = QLabel(dlg_new_tool) self.label_2.setObjectName(u"label_2") self.gridLayout.addWidget(self.label_2, 2, 0, 1, 6) self.label_7 = QLabel(dlg_new_tool) self.label_7.setObjectName(u"label_7") self.gridLayout.addWidget(self.label_7, 4, 0, 1, 1) self.le_package_name = QLineEdit(dlg_new_tool) self.le_package_name.setObjectName(u"le_package_name") self.gridLayout.addWidget(self.le_package_name, 4, 1, 1, 5) self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 2) self.verticalLayout_4 = QVBoxLayout() self.verticalLayout_4.setObjectName(u"verticalLayout_4") self.groupBox = QGroupBox(dlg_new_tool) self.groupBox.setObjectName(u"groupBox") self.groupBox.setCheckable(False) self.verticalLayout = QVBoxLayout(self.groupBox) self.verticalLayout.setObjectName(u"verticalLayout") self.rb_output_image = QRadioButton(self.groupBox) self.rb_output_image.setObjectName(u"rb_output_image") self.rb_output_image.setChecked(True) self.verticalLayout.addWidget(self.rb_output_image) self.rb_output_mask = QRadioButton(self.groupBox) self.rb_output_mask.setObjectName(u"rb_output_mask") self.verticalLayout.addWidget(self.rb_output_mask) self.rb_output_data = QRadioButton(self.groupBox) self.rb_output_data.setObjectName(u"rb_output_data") self.verticalLayout.addWidget(self.rb_output_data) self.rb_output_none = QRadioButton(self.groupBox) self.rb_output_none.setObjectName(u"rb_output_none") self.verticalLayout.addWidget(self.rb_output_none) self.verticalLayout_4.addWidget(self.groupBox) self.gb_pipeline_tool_groups = QGroupBox(dlg_new_tool) self.gb_pipeline_tool_groups.setObjectName(u"gb_pipeline_tool_groups") self.verticalLayout_4.addWidget(self.gb_pipeline_tool_groups) self.verticalSpacer = QSpacerItem( 20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding ) self.verticalLayout_4.addItem(self.verticalSpacer) self.gridLayout_2.addLayout(self.verticalLayout_4, 1, 0, 1, 1) self.verticalLayout_3 = QVBoxLayout() self.verticalLayout_3.setObjectName(u"verticalLayout_3") self.groupBox_2 = QGroupBox(dlg_new_tool) self.groupBox_2.setObjectName(u"groupBox_2") self.verticalLayout_2 = QVBoxLayout(self.groupBox_2) self.verticalLayout_2.setObjectName(u"verticalLayout_2") self.rb_rt_yes = QRadioButton(self.groupBox_2) self.rb_rt_yes.setObjectName(u"rb_rt_yes") self.verticalLayout_2.addWidget(self.rb_rt_yes) self.rb_rt_no = QRadioButton(self.groupBox_2) self.rb_rt_no.setObjectName(u"rb_rt_no") self.rb_rt_no.setChecked(True) self.verticalLayout_2.addWidget(self.rb_rt_no) self.rb_rt_widget = QRadioButton(self.groupBox_2) self.rb_rt_widget.setObjectName(u"rb_rt_widget") self.verticalLayout_2.addWidget(self.rb_rt_widget) self.rb_rt_property = QRadioButton(self.groupBox_2) self.rb_rt_property.setObjectName(u"rb_rt_property") self.verticalLayout_2.addWidget(self.rb_rt_property) self.verticalLayout_3.addWidget(self.groupBox_2) self.gb_no_pipeline_tool_groups = QGroupBox(dlg_new_tool) self.gb_no_pipeline_tool_groups.setObjectName(u"gb_no_pipeline_tool_groups") self.verticalLayout_3.addWidget(self.gb_no_pipeline_tool_groups) self.verticalSpacer_2 = QSpacerItem( 20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding ) self.verticalLayout_3.addItem(self.verticalSpacer_2) self.gridLayout_2.addLayout(self.verticalLayout_3, 1, 1, 1, 1) self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setObjectName(u"horizontalLayout") self.horizontalSpacer = QSpacerItem( 40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum ) self.horizontalLayout.addItem(self.horizontalSpacer) self.bt_save = QPushButton(dlg_new_tool) self.bt_save.setObjectName(u"bt_save") self.horizontalLayout.addWidget(self.bt_save) self.bt_cancel = QPushButton(dlg_new_tool) self.bt_cancel.setObjectName(u"bt_cancel") self.horizontalLayout.addWidget(self.bt_cancel) self.gridLayout_2.addLayout(self.horizontalLayout, 2, 1, 1, 1) self.gridLayout_2.setColumnStretch(0, 1) self.gridLayout_2.setColumnStretch(1, 1) self.retranslateUi(dlg_new_tool) QMetaObject.connectSlotsByName(dlg_new_tool) # setupUi def retranslateUi(self, dlg_new_tool): dlg_new_tool.setWindowTitle( QCoreApplication.translate("dlg_new_tool", u"New tool wizard", None) ) self.te_description.setPlaceholderText( QCoreApplication.translate( "dlg_new_tool", u"Write your tool's description here.\\nYou can use HTML tags", None, ) ) self.label.setText( QCoreApplication.translate("dlg_new_tool", u"Tool name:", None) ) self.lbl_file_exists.setText("") self.label_5.setText( QCoreApplication.translate("dlg_new_tool", u"File name:", None) ) self.chk_mask_required.setText( QCoreApplication.translate("dlg_new_tool", u"Requires mask in input", None) ) self.label_4.setText(u"\ud83e\udc62") self.label_6.setText(u"\ud83e\udc62") self.label_3.setText( QCoreApplication.translate("dlg_new_tool", u"Class name", None) ) self.label_2.setText( QCoreApplication.translate("dlg_new_tool", u"Description:", None) ) self.label_7.setText( QCoreApplication.translate("dlg_new_tool", u"Package:", None) ) self.groupBox.setTitle( QCoreApplication.translate("dlg_new_tool", u"Output:", None) ) self.rb_output_image.setText( QCoreApplication.translate("dlg_new_tool", u"Image", None) ) self.rb_output_mask.setText( QCoreApplication.translate("dlg_new_tool", u"Mask", None) ) self.rb_output_data.setText( QCoreApplication.translate("dlg_new_tool", u"Data", None) ) self.rb_output_none.setText( QCoreApplication.translate("dlg_new_tool", u"None", None) ) self.gb_pipeline_tool_groups.setTitle( QCoreApplication.translate( "dlg_new_tool", u"Groups that can be added to pipelines", None ) ) self.groupBox_2.setTitle( QCoreApplication.translate("dlg_new_tool", u"Real time:", None) ) self.rb_rt_yes.setText(QCoreApplication.translate("dlg_new_tool", u"Yes", None)) self.rb_rt_no.setText(QCoreApplication.translate("dlg_new_tool", u"No", None)) self.rb_rt_widget.setText( QCoreApplication.translate("dlg_new_tool", u"Widget", None) ) self.rb_rt_property.setText( QCoreApplication.translate("dlg_new_tool", u"Property", None) ) self.gb_no_pipeline_tool_groups.setTitle( QCoreApplication.translate( "dlg_new_tool", u"Groups forbiden in pipelines", None ) ) self.bt_save.setText(QCoreApplication.translate("dlg_new_tool", u"Save", None)) self.bt_cancel.setText( QCoreApplication.translate("dlg_new_tool", u"Close", None) )
class AddPlayer(QWidget): def __init__(self, playerList, parent=None): super(AddPlayer, self).__init__(parent) self.playerList = playerList mainLayout = QHBoxLayout() mainLayout.setContentsMargins(0, 0, 0, 0) # self.setMaximumSize(600, 270) # self.setMinimumSize(600, 100) # self.resize(600, 270) self.setLayout(mainLayout) baseLayout = QGridLayout() mainLayout.addLayout(baseLayout) # Labels lblPlayerName = QLabel("Player name:") lblPlayerName.setObjectName("addPlayerLabels") baseLayout.addWidget(lblPlayerName, 0, 0) lblGender = QLabel("Gender:") lblGender.setObjectName("addPlayerLabels") baseLayout.addWidget(lblGender, 1, 0) lblPlayerGames = QLabel("Games played:") lblPlayerGames.setObjectName("addPlayerLabels") baseLayout.addWidget(lblPlayerGames, 2, 0) lblGamesWon = QLabel("Games won:") lblGamesWon.setObjectName("addPlayerLabels") baseLayout.addWidget(lblGamesWon, 3, 0) lblPlayedRounds = QLabel("Rounds played:") lblPlayedRounds.setObjectName("addPlayerLabels") baseLayout.addWidget(lblPlayedRounds, 4, 0) # Text fields self.txtPlayerName = QTextEdit() self.txtPlayerName.setObjectName("addPlayer_txtField") baseLayout.addWidget(self.txtPlayerName, 0, 1, 1, 2) self.txtPlayerName.setFixedHeight(35) self.rbtnMale = QRadioButton("Male") self.rbtnMale.setObjectName("addPlayerRadioBtn") baseLayout.addWidget(self.rbtnMale, 1, 1, alignment=Qt.AlignCenter) self.rbtnMale.setChecked(True) self.rbtnFemale = QRadioButton("Female") self.rbtnFemale.setObjectName("addPlayerRadioBtn") baseLayout.addWidget(self.rbtnFemale, 1, 2) self.txtPlayerGames = QTextEdit("0") self.txtPlayerGames.setObjectName("addPlayer_txtField") baseLayout.addWidget(self.txtPlayerGames, 2, 1, 1, 2) self.txtPlayerGames.setFixedHeight(35) self.txtPlayerWins = QTextEdit("0") self.txtPlayerWins.setObjectName("addPlayer_txtField") baseLayout.addWidget(self.txtPlayerWins, 3, 1, 1, 2) self.txtPlayerWins.setFixedHeight(35) self.txtPlayedRounds = QTextEdit("0") self.txtPlayedRounds.setObjectName("addPlayer_txtField") baseLayout.addWidget(self.txtPlayedRounds, 4, 1, 1, 2) self.txtPlayedRounds.setFixedHeight(35) self.txtPlayedRounds.setEnabled(False) # Buttons btnSavePlayer = QPushButton("Save") btnSavePlayer.setFixedHeight(50) baseLayout.addWidget(btnSavePlayer, 5, 0) btnSavePlayer.clicked.connect(self.savePlayer) btnCancel = QPushButton("Cancel") btnCancel.setFixedHeight(50) baseLayout.addWidget(btnCancel, 5, 1) btnCancel.clicked.connect(self.cancel) def clearAll(self): self.txtPlayerName.clear() self.txtPlayerWins.clear() self.txtPlayerGames.clear() def cancel(self): self.hide() self.playerList.btnAddPlayer.show() self.playerList.btnEditPlayer.show() self.playerList.browser.show() self.playerList.btnRemovePlayer.show() self.playerList.mainWindow.btnBack.show() self.playerList.mainWindow.btnStartGame.show() self.playerList.setMaximumSize(600, 800) self.playerList.browser.refreshView() def savePlayer(self): name = self.txtPlayerName.toPlainText() # check name if name: if len(name) < 1: raise TypeError else: msg1 = QMessageBox() msg1.setText("Player name is not given.") msg1.exec_() return # Check radiobuttons value if self.rbtnMale.isChecked(): gender = "male" elif self.rbtnFemale.isChecked(): gender = "female" else: msg1 = QMessageBox() msg1.setText("Select gender.") msg1.exec_() gamesPlayed = self.txtPlayerGames.toPlainText() # Check games played if gamesPlayed: try: gamesPlayed = int(gamesPlayed) if gamesPlayed < 0: raise TypeError else: gamesPlayed = str(gamesPlayed) except: msg2 = QMessageBox() msg2.setText( "Invalid number in Games played.\n\nValid: 0-9999") msg2.exec_() return else: msg2 = QMessageBox() msg2.setText("Number of played games is not given.") msg2.exec_() return wins = self.txtPlayerWins.toPlainText() # Check number of wins if wins: try: wins = int(wins) if wins < 0: raise TypeError else: wins = str(wins) except: msg3 = QMessageBox() msg3.setText("Invalid number in Wins field.\n\nValid: 0-9999") msg3.exec_() return else: msg3 = QMessageBox() msg3.setText("Number of won games is not given.") msg3.exec_() return dbu.Database().addPlayer(name, gender, gamesPlayed, wins, 0) self.hide() self.playerList.btnAddPlayer.show() self.playerList.btnEditPlayer.show() self.playerList.browser.show() self.playerList.btnRemovePlayer.show() self.playerList.mainWindow.btnBack.show() self.playerList.mainWindow.btnStartGame.show() self.playerList.setMaximumSize(600, 850) self.playerList.browser.refreshView()