def pyvol_window(): """ """ from pymol.Qt.utils import loadUi dialog = QtWidgets.QDialog() uifile = os.path.join(os.path.dirname(__file__), 'pyvol_gui.ui') form = loadUi(uifile, dialog) refresh_installation_status(form) form.close_button.clicked.connect(dialog.close) form.run_button.clicked.connect(lambda: run_gui_pyvol(form)) form.browse_button.clicked.connect(lambda: browse_pocket_file(form)) form.load_button.clicked.connect(lambda: run_gui_load(form)) form.install_remote_button.clicked.connect( lambda: install_remote_pyvol(form)) form.install_cache_button.clicked.connect( lambda: install_local_pyvol(form)) form.check_updates_button.clicked.connect( lambda: refresh_installation_status(form, check_for_updates=True)) form.update_button.clicked.connect(lambda: update_pyvol(form)) form.msms_included_cbox.stateChanged.connect( lambda: toggle_included_msms(form)) dialog.show()
def load_form(self, name, dialog=None): '''Load a form from pmg_qt/forms/{name}.py''' import importlib if dialog is None: dialog = QtWidgets.QDialog(self) widget = dialog elif dialog == 'floating': widget = QtWidgets.QWidget(self) else: widget = dialog try: m = importlib.import_module('.forms.' + name, 'pmg_qt') except ImportError as e: if pymol.Qt.DEBUG: print('load_form import failed (%s)' % (e, )) uifile = os.path.join(os.path.dirname(__file__), 'forms', '%s.ui' % name) form = pymol.Qt.utils.loadUi(uifile, widget) else: if hasattr(m, 'Ui_Form'): form = m.Ui_Form() else: form = m.Ui_Dialog() form.setupUi(widget) if dialog == 'floating': dialog = QtWidgets.QDockWidget(widget.windowTitle(), self) dialog.setFloating(True) dialog.setWidget(widget) dialog.resize(widget.size()) form._dialog = dialog return form
def __init__(self): from pymol.Qt import QtWidgets dialog = QtWidgets.QDialog() self.setupUi(dialog) self.populate_ligand_select_list() dialog.accepted.connect(self.accept) dialog.exec_()
def make_dialog(): # entry point to PyMOL's API from pymol import cmd # pymol.Qt provides the PyQt5 interface, but may support PyQt4 # and/or PySide as well from pymol.Qt import QtWidgets from pymol.Qt.utils import loadUi from pymol.Qt.utils import getSaveFileNameWithExt # create a new Window dialog = QtWidgets.QDialog() # populate the Window from our *.ui file which was created with the Qt Designer uifile = os.path.join(os.path.dirname(__file__), 'demowidget.ui') form = loadUi(uifile, dialog) # callback for the "Ray" button def run(): # get form data height = form.input_height.value() width = form.input_width.value() dpi = form.input_dpi.value() filename = form.input_filename.text() units = form.input_units.currentText() # calculate dots per centimeter or inch if units == 'cm': dots_per_unit = dpi * 2.54 else: dots_per_unit = dpi # convert image size to pixels width *= dots_per_unit height *= dots_per_unit # render the image if filename: cmd.png(filename, width, height, dpi=dpi, ray=1, quiet=0) else: cmd.ray(width, height, quiet=0) print('No filename selected, only rendering on display') # callback for the "Browse" button def browse_filename(): filename = getSaveFileNameWithExt(dialog, 'Save As...', filter='PNG File (*.png)') if filename: form.input_filename.setText(filename) # hook up button callbacks form.button_ray.clicked.connect(run) form.button_browse.clicked.connect(browse_filename) form.button_close.clicked.connect(dialog.close) return dialog
def run_plugin_gui(): ''' Open our custom dialog ''' global dialog if dialog is None: dialog = QtWidgets.QDialog() uifile = os.path.join(os.path.dirname(__file__), 'gui.ui') form = loadUi(uifile, dialog) Isosurface(form) dialog.show()
def create_dialog(): dialog = QtWidgets.QDialog() dialog.setWindowTitle('AlignIt Pymol plugin') layout = QtWidgets.QVBoxLayout(dialog) alignit = AlignItPlugin() actions = { 'Read pharmacophore...': lambda: alignit.readAlignIt(dialog), } for name, action in actions.items(): btn = QtWidgets.QPushButton(name, dialog) btn.pressed.connect(action) layout.addWidget(btn) return dialog
def __init__(self): # create a new Window self.dialog = QtWidgets.QDialog() # populate the Window from our *.ui file which was created with the Qt Designer uifile = os.path.join(os.path.dirname(__file__), 'widgetMPbuilder.ui') self.form = loadUi(uifile, self.dialog) # open always on detergents self.changeForm("detergent") self.protName = None self.membName = None self.scafName = None self.dataName = None self.runNumber = 0 # name of the model self.modelName = "" # prefix self.prefixName = "" # crysol int prediction self.prediction = "" # crysol fit self.fit = "" # result of the fit self.fitResult = {'chi2': -9999, 'Rg': -9999, 'eDens': -9999} # whether to build a membrane or use prebuilt one self.buildMemb = False # hook up button callbacks self.form.button_build.clicked.connect(self.run_build) self.form.button_refinement.clicked.connect(self.run_refinement) self.form.button_crysol_fit.clicked.connect(self.run_crysol_fit) # single fit of assembly to data self.form.button_crysol_predict.clicked.connect(self.run_crysol_predict) # predict theory # self.form.button_crysol_predict.clicked.connect(lambda: self.run_crysol_predict(modelName)) self.form.btn_browse_prot.clicked.connect(self.browse_filename_prot) self.form.btn_browse_lip.clicked.connect(self.browse_filename_lip) self.form.btn_browse_scaffold.clicked.connect(self.browse_filename_scaffold) self.form.btn_browse_data.clicked.connect(self.browse_filename_data) self.form.button_close.clicked.connect(self.dialog.close) # change GUI depending upon the choice of assembly type self.form.input_type.currentIndexChanged.connect(self.change_assembly) # emptyAssembly = assemble complex without transmembrane protein component self.form.checkBox_emptyAssembly.toggled.connect(self.emptyAssembly) # preOriProt = pre-oriented protein self.form.checkBox_3.toggled.connect(self.preOriProt) self.form.checkBox_prebuild_bilayer.toggled.connect(self.preBuildBilayer)
def show_plugin_info_dialog(self, info): dialog = QtWidgets.QDialog(None) dialog.setWindowTitle('Plugin Information') layout = QtWidgets.QVBoxLayout() table = QtWidgets.QTableWidget(0, 2) table.verticalHeader().hide() table.horizontalHeader().hide() table.horizontalHeader().setStretchLastSection(True) layout.addWidget(table) dialog.setLayout(layout) def add_line(label, text): row = table.rowCount() table.insertRow(table.rowCount()) table_item = QtWidgets.QTableWidgetItem(label) table_item.setFlags(table_item.flags() & ~(Qt.ItemIsEditable)) table.setItem(row, 0, table_item) table_item = QtWidgets.QTableWidgetItem(text) table_item.setFlags(table_item.flags() & ~(Qt.ItemIsEditable)) table.setItem(row, 1, table_item) add_line('Name', info.name) if not info.is_temporary: add_line('Python Module Name', info.mod_name) add_line('Filename', info.filename) metadata = info.get_metadata() for label, value in metadata.items(): add_line(label, value) if not info.is_temporary: if info.loaded: add_line('commands', ', '.join(info.commands)) docstring = info.get_docstring() or 'No documentation available.' browser = QtWidgets.QTextBrowser() browser.setPlainText(docstring) layout.addWidget(browser) table.resizeColumnsToContents() dialog.resize(600, dialog.height()) dialog.exec_()
def pyvol_window(): """ """ from pymol.Qt.utils import loadUi dialog = QtWidgets.QDialog() uifile = os.path.join(os.path.dirname(__file__), 'pyvol_gui.ui') form = loadUi(uifile, dialog) refresh_installation_status(form) form.close_button.clicked.connect(dialog.close) form.run_button.clicked.connect(lambda: run_gui_pyvol(form)) form.browse_button.clicked.connect(lambda: browse_pocket_file(form)) form.load_button.clicked.connect(lambda: run_gui_load(form)) dialog.show()
def displayTextDialog(self, text): """ Opens a generic text dialog and displays provided text. """ if not self.text_dialog: self.text_dialog = QtWidgets.QDialog() layout = QtWidgets.QVBoxLayout() self.text_dialog.setLayout(layout) self.text_dialog.text_display = QtWidgets.QPlainTextEdit() self.text_dialog.text_display.setReadOnly(True) self.text_dialog.text_display.setStyleSheet( "font-family: monospace, courier") size = self.text_dialog.size() size.setWidth(DEFAULT_TEXT_DIALOG_WIDTH) self.text_dialog.resize(size) layout.addWidget(self.text_dialog.text_display) self.text_dialog.text_display.setPlainText(text) self.text_dialog.show() self.text_dialog.raise_()
def run_gui_qt(): from pymol.Qt import QtWidgets from pymol.Qt.utils import loadUi # create new Window dialog = QtWidgets.QDialog() uifile = os.path.join(os.path.dirname(__file__), 'form.ui') form = loadUi(uifile, dialog) def browse_file(): form.filenames, extension_filter = QtWidgets.QFileDialog.getOpenFileNames( dialog, 'Open', filter='JSON file (*.json)') if form.filenames: form.input_filename.setText(str(form.filenames)) form.input_state.setText('0') obj_name = os.path.basename(form.filenames[0]).rsplit('.', 1)[0] form.input_object.setText(obj_name) form.browse_button.clicked.connect(browse_file) form.close_button.clicked.connect(dialog.close) form.input_filename.setReadOnly(True) @form.load_button.clicked.connect def load_from_gui_qt(): state = int(form.input_state.text()) obj_name = form.input_object.text() for fn in form.filenames: load_json(fn, obj_name, state) if state: state += 1 dialog.close() dialog.show()
def __init__(self, _pymol_running=False, *args, **kwargs): super().__init__(*args, **kwargs) self.uiIcon = os.path.join(package_directory, 'UI', 'icon.png') self.exampleDataPath = os.path.join(package_directory, 'examples') fretrajUI = os.path.join(package_directory, 'UI', 'fretraj.ui') self.settingsUI = os.path.join(package_directory, 'UI', 'settings.ui') self.textUI = os.path.join(package_directory, 'UI', 'textpad.ui') utils.loadUi(fretrajUI, self) self.setWindowTitle("FRETraj") self.setWindowIcon(utils.QtGui.QIcon(self.uiIcon)) self._pymol_running = _pymol_running self.statusBar().showMessage("Ready", 2000) self.readTheDocsURL = None self.settingsWindow = QtWidgets.QDialog(self) utils.loadUi(self.settingsUI, self.settingsWindow) self.settingsWindow.setWindowTitle("FRETraj - Settings") self.textWindow = QtWidgets.QDialog(self) utils.loadUi(self.textUI, self.textWindow) # initialize labels dictionary with defaults from GUI self.struct = None self.av = {} self.traj = {} self.labels = {'Position': {}, 'Distance': {}} self.labelName = self.comboBox_labelName.currentText() self.labelName_default = self.comboBox_labelName.currentText() self.distanceName = self.comboBox_distanceName.currentText() self.distanceName_default = self.comboBox_distanceName.currentText() self.update_labelDict() self.labels_default = copy.deepcopy(self.labels) # set root path root_err = 'No root directory specified. FRETraj is not initialized.' self.settings = { 'root_path': None, 'browser': None, 'local_docs': None } if os.path.isfile( '{}/.fretraj_settings.conf'.format(package_directory)): with open('{}/.fretraj_settings.conf'.format(package_directory), 'r') as f: self.settings = json.load(f) if os.path.isdir(self.settings['root_path']): self.lineEdit_rootDirectory.setText( self.settings['root_path']) self.settingsWindow.lineEdit_rootDirectory.setText( self.settings['root_path']) else: self.settings['root_path'] = None self.setRootDirectory() if not self.settings['root_path']: raise ValueError(root_err) else: self.setRootDirectory() if not self.settings['root_path']: raise ValueError(root_err) # examples n_examples = 0 fileformat = '.pdb' self.exampleQAction = {} files = [ f for f in os.listdir(self.exampleDataPath) if f.endswith(fileformat) ] for example in files: self.exampleQAction[example] = self.menuLoad_Example.addAction( example.replace(fileformat, '')) self.exampleQAction[example].triggered.connect( functools.partial(self.openExample, self.exampleQAction[example].text(), fileformat)) n_examples += 1 if n_examples > 0: self.menuLoad_Example.removeAction(self.example_placeholder) # activate / deactivate GUI elements self.dyeRadius_spinBox_OnOff() self.push_computeACV.setEnabled(False) self.doubleSpinBox_contourValue.setEnabled(False) self.doubleSpinBox_contourValue_CV.setEnabled(False) self.spinBox_bfactor.setEnabled(False) self.spinBox_gaussRes.setEnabled(False) self.checkBox_transparentAV.setEnabled(False) self.doubleSpinBox_gridBuffer.setEnabled(False) self.push_calculateFRET.setEnabled(False) self.spinBox_statePDB.setEnabled(False) self.spinBox_atomID.setEnabled(False) self.push_transfer.setEnabled(False) self.push_loadParameterFile.setEnabled(False) self.push_showText.setEnabled(False) self.push_clear.setEnabled(False) if not _LabelLib_found: self.checkBox_useLabelLib.setEnabled(False) self.checkBox_useLabelLib.setChecked(False) # signals self.push_computeACV.clicked.connect(self.computeACV) self.push_loadPDB.clicked.connect(self.loadPDB) self.comboBox_simType.activated.connect(self.dyeRadius_spinBox_OnOff) self.push_calculateFRET.clicked.connect(self.calculateFRET) self.push_deleteLabel.clicked.connect(self.deleteLabel) self.push_deleteFRETparam.clicked.connect(self.deleteFRETparam) self.push_loadParameterFile.clicked.connect(self.loadParameterFile) self.doubleSpinBox_contourValue.valueChanged.connect( self.pymol_update_isosurface) self.doubleSpinBox_contourValue_CV.valueChanged.connect( self.pymol_update_isosurface) self.spinBox_bfactor.valueChanged.connect(self.pymol_update_isosurface) self.spinBox_gaussRes.valueChanged.connect( self.pymol_update_isosurface) self.doubleSpinBox_gridBuffer.valueChanged.connect( self.pymol_update_isosurface) self.checkBox_transparentAV.toggled.connect( self.pymol_update_isosurface) self.lineEdit_labelName.returnPressed.connect(self.makeLabel) self.lineEdit_distanceName.returnPressed.connect(self.makeFRETparam) self.comboBox_labelName.currentIndexChanged.connect( self.update_comboBox) self.actionAbout_FRETraj.triggered.connect(self.openAbout) self.comboBox_donorName.currentIndexChanged.connect(self.define_DA) self.comboBox_acceptorName.currentIndexChanged.connect(self.define_DA) self.comboBox_distanceName.currentIndexChanged.connect( self.update_comboBox) self.spinBox_statePDB.valueChanged.connect(self.update_PDBstate) self.push_setRootDirectory.clicked.connect(self.setRootDirectory) self.push_clear.clicked.connect(self.clear_pymol) self.actionDocumentation.triggered.connect(self.openDocumentation) self.spinBox_atomID.valueChanged.connect(self.update_atom) self.push_transfer.clicked.connect(self.transferToLabel) self.push_deleteFRET.clicked.connect(self.deleteFRET) self.actionSettings.triggered.connect(self.openSettings) self.push_showText.clicked.connect(self.openPDBFile) self.settingsWindow.push_root.clicked.connect(self.setRootDirectory) self.settingsWindow.push_browser.clicked.connect(self.set_browser) self.settingsWindow.push_localdocs.clicked.connect( self.set_localdocsDir)
def VolumePanelDialog(parent, *args, **kwargs): window = QtWidgets.QDialog(parent) _VolumePanel(window, window, *args, **kwargs) return window
def dialog(_self=None): if _self is None: from pymol import cmd as _self from pymol.Qt import QtWidgets from pymol.Qt.utils import loadUi names = _self.get_object_list() if len(names) < 2: msg = "Need at least 2 molecular objects" QtWidgets.QMessageBox.warning(None, "Warning", msg) return dialog = QtWidgets.QDialog() uifile = os.path.join(os.path.dirname(__file__), 'align.ui') form = loadUi(uifile, dialog) form.input_mobile.addItems(names) form.input_target.addItems(names) def get_command(*args): method = form.input_method.currentText() mobile = form.input_mobile.currentText() target = form.input_target.currentText() if form.check_many.isChecked(): command = 'extra_fit %s, %s, \\\n method=%s' % (mobile, target, method) elif method == 'cealign': command = 'cealign %s, %s' % (target, mobile) else: command = '%s %s, %s' % (method, mobile, target) if method != 'cealign': if not form.group_outlier.isChecked(): command += (', \\\n cycles=0') else: command += (', \\\n' ' cycles=%d, \\\n' ' cutoff=%.1f' % ( form.input_cycles.value(), form.input_cutoff.value(), )) if method == 'fit': command += ', \\\n matchmaker=1' command += ( ', \\\n' ' mobile_state=%d, \\\n' ' target_state=%d' % (form.input_mobile_state.value(), form.input_target_state.value())) aln_obj = form.input_object.text() if aln_obj: command += ', \\\n object=' + aln_obj return command def update_output_command(*args): form.group_outlier.setEnabled( form.input_method.currentText() != 'cealign') form.output_command.setText(get_command()) def update_output_command_many(*args): mobile = form.input_mobile.currentText() if form.check_many.isChecked(): if mobile == names[1] and form.input_target.currentText( ) == names[0]: form.input_mobile.setEditText('*') elif mobile == '*': if form.input_target.currentText() != names[1]: form.input_mobile.setEditText(names[1]) else: form.input_mobile.setEditText(names[0]) form.output_command.setText(get_command()) def run(): _self.do(get_command()) # hook up events form.group_outlier.toggled.connect(update_output_command) form.check_many.toggled.connect(update_output_command_many) form.input_method.currentIndexChanged.connect(update_output_command) form.input_mobile.editTextChanged.connect(update_output_command) form.input_target.editTextChanged.connect(update_output_command) form.input_mobile_state.valueChanged.connect(update_output_command) form.input_target_state.valueChanged.connect(update_output_command) form.input_cycles.valueChanged.connect(update_output_command) form.input_cutoff.valueChanged.connect(update_output_command) form.input_object.textChanged.connect(update_output_command) form.button_ok.clicked.connect(run) update_output_command() dialog.show()
def create_dialog(): dialog = QtWidgets.QDialog() dialog.setWindowTitle('Lighting Settings') sliders = [ "Diffuse Reflection", ('ambient', 0, 1, None), ('reflect', -1, 1, None), "Direct Light from Front", ('direct (+reflect)', -1, 1, None), # diffuse, coupled with "reflect" ('spec_direct', 0, 1, None), ('spec_direct_power', 0, 100, 1), "Free placeable directed Lights", ('light_count', 1, 8, 1), ('edit_light', 1, 7, 1), "Specular Reflection", ('spec_count', -1, 8, 1), # ('spec_power', -1, 200, 1), # deprecated since v1.5 ('shininess', 0, 100, None), # same as spec_power ('spec_reflect', -0.01, 1, None), ('specular', 0, 1, None), ('specular_intensity (=specular)', 0, 1, None), # same as specular "Ambient Occlusion (Surface only)", ('ambient_occlusion_mode', 0, 2, 1), ('ambient_occlusion_scale', 1.0, 50., None), ('ambient_occlusion_smooth', 1, 20, 1), "Ray trace only", ('power', 1, 10, None), ('reflect_power', 1, 10, None), ] layout = QtWidgets.QVBoxLayout(dialog) button_layout = QtWidgets.QHBoxLayout() layout.addLayout(button_layout) layout.setContentsMargins(5, 0, 5, 0) button_layout.addWidget( QtWidgets.QLabel("<font color=red>Presets:</font>")) presets = [ ("Default", preset_default), ("Metal", preset_metal), ("Plastic", preset_plastic), ("Rubber", preset_rubber), ("X-Ray", preset_xray), ] for name, fun in presets: btn = QtWidgets.QPushButton(name, dialog) btn.pressed.connect(fun) btn.setAutoDefault(False) button_layout.addWidget(btn) form_layout = QtWidgets.QFormLayout() form_layout.setContentsMargins(0, 0, 0, 0) form_layout.setVerticalSpacing(0) form_layout.setLabelAlignment(Qt.AlignLeft) layout.addLayout(form_layout) for i, item in enumerate(sliders, 1): if isinstance(item, str): label = QtWidgets.QLabel("<font color=blue>" + item + "</font>") form_layout.addRow(label) continue name, min, max, res = item if res is None: res = 0.01 if (max - min < 100) else 0.1 line_edit = QtWidgets.QLineEdit(dialog) slider = SettingSlider(dialog, name.split()[0], min, max, res, line_edit) h_layout = QtWidgets.QHBoxLayout() h_layout.addWidget(slider, 3) h_layout.addWidget(line_edit, 1) form_layout.addRow(name, h_layout) return dialog
def run_gui(): """Main PyViewDock dialog window""" docked = get_docked() # create a new Window dialog = QtWidgets.QDialog() # populate the Window from our *.ui file which was created with the Qt Designer uifile = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'gui.ui') widget = loadUi(uifile, dialog) # hide question mark and add minimize button widget.setWindowFlags(widget.windowFlags() ^ QtCore.Qt.WindowContextHelpButtonHint | QtCore.Qt.WindowMinimizeButtonHint) ## ERROR MESSAGE ------------------------------------------------ def error_msg(text, informative_text=None): msg = QtWidgets.QMessageBox() msg.setIcon(QtWidgets.QMessageBox.Critical) msg.setWindowTitle("PyViewDock") msg.setText(text) if informative_text: msg.setInformativeText(informative_text) msg.exec_() ## MENUBAR ------------------------------------------------------ show_column = widget.menuColumns.addMenu('Show') hide_column = widget.menuColumns.addMenu('Hide') hide_all = widget.menuColumns.addAction('buttonHideAll') hide_all.setText("Hide All") ## I/O FILES ---------------------------------------------------- def clear_all(): """Clear all the docked entries""" docked.clear() draw_table() def browse_open(): """Callback for the 'Open' button""" supported_formats = { 'PDB Dock >4 (*.pdb)': load_dock4, 'ChimeraX (*.chimerax)': load_chimerax, 'pyDock (*.ene; *.eneRST)': load_pydock, 'XYZ (*.xyz)': load_xyz, 'All Files(*)': None } default_suffix_format = { 'pdb': 'PDB Dock >4 (*.pdb)', 'chimerax': 'ChimeraX (*.chimerax)', 'ene': 'pyDock (*.ene; *.eneRST)', 'enerst': 'pyDock (*.ene; *.eneRST)', 'xyz': 'XYZ (*.xyz)' } # launch open file dialog from system filename, format_selected = QtWidgets.QFileDialog.getOpenFileName( parent=dialog, caption='Open file containing docked structures', directory=os.getcwd(), filter=";;".join(supported_formats.keys())) if not filename: return # guess format from suffix if format_selected == 'All Files(*)': suffix = os.path.basename(filename).rpartition('.')[-1].lower() if suffix in default_suffix_format: format_selected = default_suffix_format[suffix] else: # error message error_msg(f"Unsupported format file: .{suffix}") return # load file with corresponding format' function supported_formats[format_selected](filename) draw_table() def browse_export_data(): """Callback for the 'Export Data' button""" supported_formats = { 'CSV (*.csv)': 'csv', 'Text (*.txt)': 'txt', 'All Files(*)': None } default_suffix_format = {'csv': 'CSV (*.csv)', 'txt': 'Text (*.txt)'} # launch open file dialog from system filename, format_selected = QtWidgets.QFileDialog.getSaveFileName( parent=dialog, caption='Save file containing docked data', directory=os.getcwd(), filter=";;".join(supported_formats.keys())) if not filename: return # guess format from suffix if format_selected == 'All Files(*)': suffix = os.path.basename(filename).rpartition('.')[-1].lower() # if not in supported_formats, fallback to csv format_selected = default_suffix_format.get( suffix, default_suffix_format['csv']) # save file with corresponding format' arguments export_docked_data(filename, supported_formats[format_selected]) ## TABLE -------------------------------------------------------- headers = docked.headers def draw_table(headers=headers): """Fill the whole table with data from docked entries""" widget.tableDocked.clear() widget.tableDocked.setSortingEnabled(False) n_internal_columns = 3 # check if requested headers in remarks headers = [i for i in headers if i in docked.remarks] # number of rows and columns widget.tableDocked.setColumnCount(len(headers) + n_internal_columns) widget.tableDocked.setRowCount(docked.n_entries) # fill table widget.tableDocked.setHorizontalHeaderLabels([""] * n_internal_columns + headers) for row, entry in enumerate(docked.entries): # hidden internal columns [n_entry, 'object', 'state'] widget.tableDocked.setItem(row, 0, QtWidgets.QTableWidgetItem(str(row))) widget.tableDocked.setItem( row, 1, QtWidgets.QTableWidgetItem(str(entry['internal']['object']))) widget.tableDocked.setItem( row, 2, QtWidgets.QTableWidgetItem(str(entry['internal']['state']))) # assign to table cell for column, remark in enumerate(headers): value = entry['remarks'][remark] item = QtWidgets.QTableWidgetItem() item.setData(QtCore.Qt.EditRole, value) widget.tableDocked.setItem(row, column + n_internal_columns, item) widget.tableDocked.item(row, column + n_internal_columns).setTextAlignment( QtCore.Qt.AlignCenter) widget.tableDocked.resizeColumnsToContents() widget.tableDocked.resizeRowsToContents() for i in range(n_internal_columns): widget.tableDocked.hideColumn(i) # update columns menubar show_column.clear() hide_column.clear() for i in sorted(docked.remarks - set(headers)): action = show_column.addAction(i) action.triggered.connect(lambda chk, i=i: show_header(i)) for i in headers: action = hide_column.addAction(i) action.triggered.connect(lambda chk, i=i: hide_header(i)) # show table widget.tableDocked.setSortingEnabled(True) widget.tableDocked.show() def show_header(header): """Add a column to headers""" headers.append(header) draw_table() def hide_header(header): """Remove a column from headers""" headers.remove(header) draw_table() def hide_header_all(): """Remove all column headers""" headers.clear() draw_table() def display_selected(): """Display entries corresponding to selected rows""" #TODO: multiple selection selected_row = widget.tableDocked.selectedItems() if selected_row: row_n = selected_row[0].row() object = widget.tableDocked.item(row_n, 1).text() state = widget.tableDocked.item(row_n, 2).text() cmd.set('state', state) cmd.disable(" ".join(docked.objects)) cmd.enable(object) draw_table() ## CALLBACKS ---------------------------------------------------- widget.buttonOpen.triggered.connect(browse_open) widget.buttonExportData.triggered.connect(browse_export_data) widget.buttonClearAll.triggered.connect(clear_all) hide_all.triggered.connect(hide_header_all) widget.tableDocked.itemSelectionChanged.connect(display_selected) dialog.show()
def make_dialog(): ''' Function which initiates the dialog ''' from pymol import cmd from pymol.Qt import QtWidgets, QtGui, QtCore # note this gives the PyQt5 rather than PyQt4 interface from pymol.Qt.utils import loadUi from pymol.Qt.utils import getSaveFileNameWithExt import pymol.Qt Qt = QtCore.Qt #make a viewer object accessible by all functions viewer = BXlink_viewer() QFileDialog = QtWidgets.QFileDialog getOpenFileNames = QFileDialog.getOpenFileNames # create a new Window dialog = QtWidgets.QDialog() # populate the Window from our *.ui file which was created with the Qt Designer uifile = os.path.join(os.path.dirname(__file__), 'PyXlinkViewer.ui') form = loadUi(uifile, dialog) #------------------------------------------------------------------- def open_file(): ''' Callback for the open_xlink_file button ''' # get a filename using open file diagog - not the filename can have any extension startdir = os.getcwd() open_fname = getOpenFileNames(dialog, 'Open file', startdir)[0] if open_fname: #need to convert list object returned by open file dialog to a string xlink_file = "".join(open_fname) # only deal with files in jwalk format for now xlink_file_type = 'jwalk' viewer.set_xlink_file(xlink_file) viewer.set_xlink_file_type(xlink_file_type) viewer.parse_xlink_file() viewer.calculate_distances() viewer.test_monos_in_obj() populate_xlink_table() change_num_sat_viol() viewer.display() #------------------------------------------------------------------- def populate_xlink_table(): ''' Populates the table with xlinks and mono-links according to which are currently set to be displayed ''' obs_xlinks = viewer.obs_xlinks obs_monos = viewer.obs_monos w = form.table_xlinks #remove data if already w.setRowCount(0) entries = [] for xl in obs_xlinks: str_dist = '{0:3.1f}'.format(xl.distance) entry = [xl.chain1, xl.resid1, xl.chain2, xl.resid2, str_dist] bAdded_entry = False if xl.distance <= viewer.threshold and viewer.show_satisied == True: entries.append(entry) bAdded_entry = True if xl.distance > viewer.threshold and viewer.show_violated == True: entries.append(entry) bAdded_entry = True # check that inters should be shown if bAdded_entry and xl.chain1 != xl.chain2 and viewer.show_inter == False: entries.pop() if bAdded_entry and xl.chain1 == xl.chain2 and viewer.show_intra == False: entries.pop() #now add the monolinks to end of table for m in obs_monos: if viewer.show_mono == True: entry = [m.chain, m.resid, '-', '-', '-'] entries.append(entry) if entries: w.setColumnCount(len(entries[0])) w.setRowCount(len(entries)) for i, row in enumerate(entries): for j, col in enumerate(row): item = QtWidgets.QTableWidgetItem(col) w.setItem(i, j, item) #align text in centre of cell item.setTextAlignment(Qt.AlignCenter) # set the columns to be equal width and fit in the table header = w.horizontalHeader() for i in range(0, len(entries[0])): header.setSectionResizeMode(i, QtWidgets.QHeaderView.Stretch) #------------------------------------------------------------------- def export(): ''' Callback function for 'Export' button. Opens save file dialog and saves current table in csv format. For each entry in the table two additional columns are outputted. One containing the current threshold value, and one 'Sat/Viol' for which 'S' or 'V' is outputted depending on whether the xlink is satisfied or violated, given the currently set threshold value ''' filename = getSaveFileNameWithExt(dialog, 'Save As...', filter='csv file (*.csv)') if filename: table = form.table_xlinks num_cols = table.columnCount() num_rows = table.rowCount() with open(filename, 'w') as f: for i in range(0, num_cols): item = table.horizontalHeaderItem(i) f.write(item.text() + ',') f.write('Threshold,Sat-Viol\n') for i in range(0, num_rows): for j in range(0, num_cols): item = table.item(i, j) text = item.text() f.write(text + ',') #last item retrieved was the distance for this xlink or a dash if a mono-link entry so use this to test if satisfied if text == '-': f.write('-,-\n') else: f.write(str(viewer.threshold) + ',') if float(text) <= viewer.threshold: f.write('S\n') else: f.write('V\n') #---------------------------------------------------------------------------------------------------- # callback functions for checkboxes def check_satisfied_click(): viewer.set_show_satisfied(form.check_satisfied.isChecked()) populate_xlink_table() viewer.update() def check_violated_click(): viewer.set_show_violated(form.check_violated.isChecked()) populate_xlink_table() viewer.update() def check_inter_click(): viewer.set_show_inter(form.check_inter.isChecked()) populate_xlink_table() viewer.update() change_num_sat_viol() def check_intra_click(): viewer.set_show_intra(form.check_intra.isChecked()) populate_xlink_table() viewer.update() change_num_sat_viol() def check_mono_click(): viewer.set_show_mono(form.check_mono.isChecked()) populate_xlink_table() viewer.update() #--------------------------------------------------------------------------- # Call back functions for colour change buttons def change_satisfied_colour(): color = QtWidgets.QColorDialog.getColor() form.frame_satisfied_colour.setStyleSheet( "QWidget { background-color: %s}" % color.name()) rgb_list = [color.redF(), color.greenF(), color.blueF()] viewer.set_satisfied_colour(rgb_list) viewer.update() def change_violated_colour(): color = QtWidgets.QColorDialog.getColor() form.frame_violated_colour.setStyleSheet( "QWidget { background-color: %s}" % color.name()) rgb_list = [color.redF(), color.greenF(), color.blueF()] viewer.set_violated_colour(rgb_list) viewer.update() def change_mono_colour(): color = QtWidgets.QColorDialog.getColor() form.frame_mono_colour.setStyleSheet( "QWidget { background-color: %s}" % color.name()) rgb_list = [color.redF(), color.greenF(), color.blueF()] viewer.set_mono_colour(rgb_list) viewer.update() #--------------------------------------------------------------------------- # call back functions for doublespin boxes def change_threshold(): viewer.set_threshold(form.doublespin_threshold.value()) change_num_sat_viol() populate_xlink_table() viewer.update() def change_width(): viewer.set_radius(form.doublespin_width.value()) viewer.update() def change_mono_size(): viewer.set_mono_size(form.doublespin_mono_size.value()) viewer.update() #--------------------------------------------------------------------------- def change_num_sat_viol(): ''' Changes the numbers of satisfied and violated xlinks in line-edit boxes. Called when either a change to threshold value is made, or the intra or inter checkboxes are clicked on ''' num_sat = 0 num_viol = 0 for xl in viewer.obs_xlinks: # NB. check that both residues are in structure, if one is not, don't class as either sat or viol as not known if xl.distance <= viewer.threshold and xl.bRes1_in_obj == True and xl.bRes2_in_obj == True: #check that inter/intra are selected if viewer.show_inter == True and xl.chain1 != xl.chain2: num_sat += 1 if viewer.show_intra == True and xl.chain1 == xl.chain2: num_sat += 1 if xl.distance > viewer.threshold and xl.bRes1_in_obj == True and xl.bRes2_in_obj == True: #check that inter/intra are selected if viewer.show_inter == True and xl.chain1 != xl.chain2: num_viol += 1 if viewer.show_intra == True and xl.chain1 == xl.chain2: num_viol += 1 form.line_edit_satisfied.setText(str(num_sat)) form.line_edit_violated.setText(str(num_viol)) form.line_edit_satisfied.setAlignment(Qt.AlignCenter) form.line_edit_violated.setAlignment(Qt.AlignCenter) #------------------------------------------------------------------------- def change_selected_object(item): ''' This function is called when the user clicks on an object name in the objects listbox. It updates the BXlink_viewer object with the currently selected PyMOL object ''' viewer.set_obj(item.text()) #------------------------------------------------------------------------- # initialise the viewer threshold and mono-size values in doublespin boxes - these are set in QtDesigner viewer.set_threshold(form.doublespin_threshold.value()) viewer.set_mono_size(form.doublespin_mono_size.value()) # initialise the widgets form.check_satisfied.setChecked(True) form.check_violated.setChecked(True) form.check_inter.setChecked(True) form.check_intra.setChecked(True) # stop object list box from resizing when objects are added w = form.list_select_object w.setFixedSize(149, 50) # fill the listbox with the current objects objects = cmd.get_names() for i, obj in enumerate(objects): item = QtWidgets.QListWidgetItem(obj) form.list_select_object.addItem(item) if i == 0: #select the first item in the QListWidget item.setSelected(True) viewer.set_obj(item.text()) form.list_select_object.setFocus() #call a function of clicking listbox item to update selected PyMOL object stored by viewer class form.list_select_object.itemClicked.connect(change_selected_object) # initialise colours in for satisfied, violated, and mono-links form.frame_satisfied_colour.setStyleSheet( "QWidget { background-color: %s}" % '#0000FF') # initialise to blue form.frame_violated_colour.setStyleSheet( "QWidget { background-color: %s}" % '#FF0000') # initialise to red form.frame_mono_colour.setStyleSheet("QWidget { background-color: %s}" % '#FFFF00') # initialise to yellow # hook up the button callbacks form.button_open_xlink_file.clicked.connect(open_file) form.button_close.clicked.connect(dialog.close) form.button_satisfied_colour.clicked.connect(change_satisfied_colour) form.button_violated_colour.clicked.connect(change_violated_colour) form.button_mono_colour.clicked.connect(change_mono_colour) form.button_export.clicked.connect(export) # hook up the check box callbacks form.check_satisfied.clicked.connect(check_satisfied_click) form.check_violated.clicked.connect(check_violated_click) form.check_inter.clicked.connect(check_inter_click) form.check_intra.clicked.connect(check_intra_click) form.check_mono.clicked.connect(check_mono_click) # hook up the check box callbacks form.doublespin_threshold.valueChanged.connect(change_threshold) form.doublespin_width.valueChanged.connect(change_width) form.doublespin_mono_size.valueChanged.connect(change_mono_size) return dialog
def qtdialog(): dialog = QtWidgets.QDialog() uifile = os.path.join(os.path.dirname(__file__), 'excelexporter.ui') form = pymolqtutils.loadUi(uifile, dialog) form._dialog = dialog # pre-fill form with likely data names = pymol.cmd.get_object_list() names += ['(' + n + ')' for n in pymol.cmd.get_names('public_selections')] form.input_sele.addItems(names) checkboxes = { 'x': form.check_x, 'y': form.check_y, 'z': form.check_z, } prop_names = [ 'model', 'segi', 'chain', 'resi', 'resv', 'resn', 'name', 'alt', 'b', 'q', 'elem', 'type', 'formal_charge', 'partial_charge', 'numeric_type', 'text_type', 'stereo', 'ID', 'rank', 'index', 'vdw', 'ss', 'color', 'reps', 'protons', 'state' ] # user properties p_set = set() pymol.cmd.iterate('all', 'p_set_update(p)', space={'p_set_update': p_set.update}) prop_names.extend('p.' + prop for prop in sorted(p_set)) ncols = 3 for i, prop in enumerate(prop_names): check = QtWidgets.QCheckBox(prop, form.groupBox) form.gridLayout.addWidget(check, i // ncols, i % ncols, 1, 1) checkboxes[prop] = check # add state properties to list prop_names.extend('xyz') for prop in ['chain', 'resi', 'resn', 'name']: checkboxes[prop].setChecked(True) @form.button_ok.clicked.connect def _(*args): props = [p for p in prop_names if checkboxes[p].isChecked()] sele = form.input_sele.currentText() statetext = form.input_state.checkedButton().text() if statetext.startswith('current'): state = -1 elif statetext.startswith('all'): state = 0 else: state = STATELESS props = [p for p in props if p not in ['x', 'y', 'z']] if not _check_xlwings(): return with pymolqtutils.PopupOnException(): dumpexcel(sele, props, state) form._dialog.show()
def make_dialog(): # entry point to PyMOL's API from pymol import cmd # pymol.Qt provides the PyQt5 interface, but may support PyQt4 # and/or PySide as well from pymol.Qt import QtWidgets from pymol.Qt.utils import loadUi from PyQt5 import QtGui import os from pymol import cmd, stored import gzip import json import random import string from numpy import log import numpy as np import copy import collections # create a new Window dialog = QtWidgets.QDialog() QtWidgets.QApplication.setStyle(QtWidgets.QStyleFactory.create('Fusion')) # populate the Window from our *.ui file which was created with the Qt Designer uifile = os.path.join(os.path.dirname(__file__), 'gui_alfa3.ui') form = loadUi(uifile, dialog) # global variables Hs_files = [] Proteines_files = [] Hs_paths = [] Proteines_paths = [] Jsons_paths = [] solvent = 'non' # load protein with hot spots and json file with reference values def browse_filename_hs_protein(): # load protein protein_path = QFileDialog.getOpenFileName(form, "Open File", "C:\\User\\", 'PDB File (*.pdb)') protein_path = protein_path[0] Proteines_paths.append(protein_path) protein_path = protein_path.replace(os.path.sep, "\\") # load hs file hs_path = QFileDialog.getOpenFileName(form, "Open File", "C:\\User\\", 'MOL2 File (*.mol2)') hs_path = hs_path[0] Hs_paths.append(hs_path) hs_path = hs_path.replace(os.path.sep, "\\") # load json jsons_path = QFileDialog.getOpenFileName(form, "Open File", "C:\\User\\", 'json File (*.json)') jsons_path = jsons_path[0] Jsons_paths.append(jsons_path) if hs_path: hs_name = os.path.basename(os.path.normpath(hs_path)) hs_name = os.path.splitext(hs_name)[0] if hs_name != ' ': Hs_files.append(hs_name) form.browser_files1.setText('\n '.join(Hs_files)) protein_name = os.path.basename(os.path.normpath(protein_path)) protein_name = os.path.splitext(protein_name)[0] if protein_name != ' ': Proteines_files.append(protein_name) form.browser_files1_2.setText('\n '.join(Proteines_files)) # load files that are browsed def load_hs_protein(): if len(Hs_files) == len(Proteines_files): cmd.delete('all') for nbr in range(0, len(Hs_files)): cmd.load(Hs_paths[nbr]) cmd.select(Hs_files[nbr]) cmd.load(Proteines_paths[nbr]) rezise(nbr) try: cmd.extra_fit(','.join(Hs_files)) cmd.extra_fit(','.join(Proteines_files)) except: form.browser_files1.setText('ERROR -_-') form.browser_files1_2.setText( 'Number of HotSpots and Structures must be the same!!!') else: form.browser_files1.setText('ERROR -_-') form.browser_files1_2.setText( 'Number of HotSpots and Structures must be the same!!!') # change size of hs depends on reference_density_correction from .json file (one fil for one pond calculations) def rezise(nbrs): def is_sele(sele): return sele in cmd.get_names('all') def _random_string(n=10): return ''.join( random.choice(string.ascii_uppercase + string.digits) for _ in range(n)) refs = [] ref = 1 for i in range(0, len(Jsons_paths)): with gzip.open(Jsons_paths[i]) as f: refOne = float(json.load(f)["reference_density_correction"]) refs.append(refOne) if form.oneSolvent.isChecked(): ref = np.median(refs) if form.multipleSolvent.isChecked(): with gzip.open(Jsons_paths[nbrs]) as f: ref = float(json.load(f)["reference_density_correction"]) else: ref = np.median(refs) def hs_resize(meta_file, selection): if not is_sele(selection): raise RuntimeError( "Selection \"{}\" does not exists.".format(selection)) # Find free sele name temp_sele = _random_string() while is_sele(temp_sele): temp_sele = _random_string() states = cmd.count_states(selection=selection) for state in range(1, states + 1): stored.info = [] cmd.iterate_state(state, selection, "stored.info.append((ID, partial_charge))") for id_, partial_charge in stored.info: size = log(partial_charge / ref + 1) print(ref) print(size) cmd.select(temp_sele, "{} and id {}".format(selection, id_), state=state) cmd.set("sphere_scale", value=size, selection=temp_sele) cmd.alter(temp_sele, "b={}".format(partial_charge)) cmd.delete(temp_sele) hs_resize(Jsons_paths[nbrs], Hs_files[nbrs]) # save all hs into one mol2 file def save_all_hs(): cmd.select('sele', 'resn FIL') file_name = QFileDialog.getSaveFileName(form, 'Save File', '', 'MOL2 File (*.mol2)') file_name = file_name[0] cmd.create('all_hs', 'sele') cmd.save(file_name, 'all_hs', 0) cmd.delete('all_hs') # simplification geometric centre / hs weights def hs_sipmly(): cmd.delete('simply') def is_sele(sele): return sele in cmd.get_names("all") def find_all_coords(n, hs_id, exc_indexes=[], coords=[]): for node in n[hs_id]: if (node[0], node[3]) not in exc_indexes: exc_indexes.append((node[0], node[3])) coords.append(node[2]) find_all_coords(n, (node[0], node[3]), exc_indexes=exc_indexes, coords=coords) return exc_indexes, coords def free_hotspot_id(hs, exc_indexes): for h in hs: if (h[0], h[3]) not in exc_indexes: return h[0], h[3] return None def group_center(coords): length = coords.shape[0] sum_x = np.sum(coords[:, 0]) sum_y = np.sum(coords[:, 1]) sum_z = np.sum(coords[:, 2]) return sum_x / length, sum_y / length, sum_z / length def find_center(partial_charges, coords, nbr): dict_value_coords = {} coords_weight = [] for p, c in zip(partial_charges, coords): dict_value_coords[p] = c od_dict = collections.OrderedDict( sorted(dict_value_coords.items(), reverse=True)) partial_charges = list(od_dict.keys()) nbr = len(partial_charges) - nbr for i in range(0, nbr): try: max_hs = partial_charges[i] x = od_dict[max_hs][0] y = od_dict[max_hs][1] z = od_dict[max_hs][2] coords_weight.append([x, y, z]) except: pass return coords_weight def hs_gsimplifier(*args, **kwargs): radius = form.radius1.value() color = kwargs.get("color", "red") selections = args for selection in selections: if not is_sele(selection): raise RuntimeError( "Selection \"{}\" does not exists.".format(selection)) states = cmd.count_states(selection=selections[0]) hs_values = [] all_coords = [] for state in range(1, states + 1): stored.info = [] for selection in selections: cmd.iterate_state( state, selection, "stored.info.append([ID, partial_charge, (x,y,z), \"{}\"])" .format(selection)) for line in stored.info: partial_charge = line[1] coord = line[2] hs_values.append(partial_charge) all_coords.append(coord) hs = np.array(copy.copy(stored.info)) n = dict() for h in hs: dists = np.linalg.norm(np.array(h[2]) - list(zip(*hs))[2], axis=1) # Convert to dict due to same hotspots IDs n[(h[0], h[3])] = hs[dists <= radius] exc_indexes = [] hs_id = free_hotspot_id(hs, exc_indexes=exc_indexes) while hs_id is not None: excluded, coords = find_all_coords(n, hs_id, exc_indexes=[], coords=[]) exc_indexes.extend(excluded) if form.geometric.isChecked(): middle_point = group_center(np.array(coords)) cmd.pseudoatom(object="simply", color=color, pos=middle_point, state=state) else: middle_points = find_center(hs_values, all_coords, nbr=len(exc_indexes)) for point in middle_points: cmd.pseudoatom(object="simply", color=color, pos=point, state=state) hs_id = free_hotspot_id(hs, exc_indexes=exc_indexes) cmd.show(representation="spheres", selection="simply") cmd.select('hs2', 'resn FIL') hs_gsimplifier('hs2', color='hotpink') def save_simply(): cmd.select('simply') file_name = QFileDialog.getSaveFileName(form, 'Save File', '', 'MOL2 File (*.mol2)') file_name = file_name[0] cmd.save(file_name, 'simply') # make hs color def color_hs(): color = form.colors.currentItem() color = str(color.text()) try: cmd.spectrum("pc", ('%s' % color), 'sele') except: cmd.spectrum("pc", ('%s' % color), 'hotspot') cmd.spectrum("pc", '%s' % color, 'hs' + '*') def choose_hs(picked_hs=0): picked_hs = cmd.count_atoms('sele') form.hs_browse.setText(str(picked_hs)) cmd.create('hs', 'sele') def clear_pick_hs(): picked_hs = 0 form.hs_browse.setText(str(picked_hs)) def clean_all(): cmd.delete('all') Hs_files.clear() Proteines_files.clear() Hs_paths.clear() Proteines_paths.clear() Jsons_paths.clear() form.browser_files1_2.setText(', '.join(Proteines_files)) form.browser_files1.setText(', '.join(Proteines_files)) form.hs_browse.setText(' ') def solvent_one(): global solvent solvent = 'one' def solvent_multiple(): global solvent solvent = 'multiple' def search_groups(): radius2 = form.radius2.value() cmd.select('sele_atms', 'polymer.protein within %f of hs' % (radius2)) def save_atms(): cmd.select('sele_atms') file_name = QFileDialog.getSaveFileName(form, 'Save File', '', 'PDB File (*.pdb)') file_name = file_name[0] cmd.save(file_name, 'sele_atms', -1) # hook up button callbacks form.browse_button1.clicked.connect(browse_filename_hs_protein) form.load1.clicked.connect(load_hs_protein) form.button_close.clicked.connect(dialog.close) form.save_file1.clicked.connect(save_all_hs) form.color_button.clicked.connect(color_hs) form.clear_all.clicked.connect(clean_all) form.clear_files1.clicked.connect(clean_all) form.ok1.clicked.connect(hs_sipmly) form.save_file2_2.clicked.connect(save_simply) form.add_hs.clicked.connect(choose_hs) form.clear_hs.clicked.connect(clear_pick_hs) form.oneSolvent.clicked.connect(solvent_one) form.multipleSolvent.clicked.connect(solvent_multiple) form.ok2.clicked.connect(search_groups) form.save_file3.clicked.connect(save_atms) return dialog
def dialog(_self=None): if _self is None: from pymol import cmd as _self dialog = QtWidgets.QDialog() uifile = os.path.join(os.path.dirname(__file__), 'apbs.ui') form = loadUi(uifile, dialog) form._dialog = dialog form._proclist = [] def set_apbs_in(contents): form.apbs_template.setPlainText(contents.strip()) # hide options widgets form.optarea_prep.setVisible(False) form.optarea_apbs.setVisible(False) form.optarea_surf.setVisible(False) form.optarea_other.setVisible(False) # pre-fill form with likely data names = _self.get_object_list() names += ['(' + n + ')' for n in _self.get_names('public_selections')] if names: form.input_sele.clear() form.input_sele.addItems([ ('polymer & ' + name) if _self.count_atoms('polymer & ' + name) > 0 else name for name in names ]) form.surf_map.addItems(_self.get_names_of_type('object:map')) set_apbs_in(electrostatics.template_apbs_in) # executables from distutils.spawn import find_executable form.apbs_exe.setText(electrostatics.find_apbs_exe() or 'apbs') form.pdb2pqr_exe.setText( find_executable('pdb2pqr') or # acellera::htmd-pdb2pqr provides pdb2pqr_cli find_executable('pdb2pqr_cli') or find_executable( 'share/pdb2pqr/pdb2pqr.py', os.getenv('FREEMOL', '/usr')) or 'pdb2pqr') # for async panels form._callInMainThread = MainThreadCaller() run_impl_async = AsyncFunc(run_impl) # "Run" button callback def run(): form.tabWidget.setEnabled(False) form.button_ok.clicked.disconnect() form.button_ok.clicked.connect(abort) form.button_ok.setText('Abort') form._capture = StdOutCapture() # detach from main thread run_impl_async(form, _self) # "Run" button "finally" actions (main thread) @run_impl_async.finished.connect def run_finally(args): _, exception = args form._proclist[:] = [] stdout = form._capture.release() print(stdout) form.button_ok.setText('Run') form.button_ok.clicked.disconnect() form.button_ok.clicked.connect(run) form.button_ok.setEnabled(True) form.tabWidget.setEnabled(True) if exception is not None: handle_exception(exception, stdout) return quit_msg = "Finished with Success. Close the APBS dialog?" if QMessageBox.Yes == QMessageBox.question(form._dialog, 'Finished', quit_msg, QMessageBox.Yes, QMessageBox.No): form._dialog.close() def handle_exception(e, stdout): if isinstance(e, SilentAbort): return msg = str(e) or 'unknown error' msgbox = QMessageBox(QMessageBox.Critical, 'Error', msg, QMessageBox.Close, form._dialog) if stdout.strip(): msgbox.setDetailedText(stdout) msgbox.exec_() # "Abort" button callback def abort(): form.button_ok.setEnabled(False) while form._proclist: p = form._proclist.pop() try: p.terminate() p.returncode = -15 # SIGTERM except OSError as e: print(e) # selection checker check_sele_timer = QtCore.QTimer() check_sele_timer.setSingleShot(True) # grid auto-value form.apbs_grid_userchanged = False form.apbs_grid.setStyleSheet('background: #ff6') @form.apbs_grid.editingFinished.connect def _(): form.apbs_grid_userchanged = True form.apbs_grid.setStyleSheet('') @check_sele_timer.timeout.connect def _(): has_props = ['no', 'no'] def callback(partial_charge, elec_radius): if partial_charge: has_props[0] = 'YES' if elec_radius > 0: has_props[1] = 'YES' n = _self.iterate(form.input_sele.currentText(), 'callback(partial_charge, elec_radius)', space={'callback': callback}) # grid auto-value (keep map size in the order of 200x200x200) if n > 1 and not form.apbs_grid_userchanged: e = _self.get_extent(form.input_sele.currentText()) volume = (e[1][0] - e[0][0]) * (e[1][1] - e[0][1]) * (e[1][2] - e[0][2]) grid = max(0.5, volume**0.333 / 200.0) form.apbs_grid.setValue(grid) if n < 1: label = 'Selection is invalid' color = '#f66' elif has_props == ['YES', 'YES']: label = 'No preparation necessary, selection has charges and radii' form.do_prepare.setChecked(False) color = '#6f6' else: label = 'Selection needs preparation (partial_charge: %s, elec_radius: %s)' % tuple( has_props) form.do_prepare.setChecked(True) color = '#fc6' form.label_sele_has.setText(label) form.label_sele_has.setStyleSheet('background: %s; padding: 5' % color) check_sele_timer.start(0) @form.apbs_exe_browse.clicked.connect def _(): fnames = getOpenFileNames(None, filter='apbs (apbs*);;All Files (*)')[0] if fnames: form.apbs_exe.setText(fnames[0]) @form.pdb2pqr_exe_browse.clicked.connect def _(): fnames = getOpenFileNames( None, filter='pdb2pqr (pdb2pqr*);;All Files (*)')[0] if fnames: form.pdb2pqr_exe.setText(fnames[0]) # hook up events form.input_sele.currentIndexChanged.connect( lambda: check_sele_timer.start(0)) form.input_sele.editTextChanged.connect( lambda: check_sele_timer.start(1000)) form.button_ok.clicked.connect(run) # "Register" opens a web browser @form.button_register.clicked.connect def _(): import webbrowser webbrowser.open("http://www.poissonboltzmann.org/") @form.button_load.clicked.connect def _(): fnames = getOpenFileNames(None, filter='APBS Input (*.in);;All Files (*)')[0] if fnames: contents = load_apbs_in(form, fnames[0]) set_apbs_in(contents) @form.button_reset.clicked.connect def _(): set_apbs_in(electrostatics.template_apbs_in) form._dialog.show() form._dialog.resize(500, 600)
def dialog(_self=None): if _self is None: from pymol import cmd as _self from pymol.Qt import QtWidgets from pymol.Qt.utils import loadUi names = _self.get_object_list('enabled') if len(names) < 2 and _self.count_states('enabled') < 2: msg = "Need 2 molecular objects or one multistate object" QtWidgets.QMessageBox.warning(None, "Warning", msg) return dialog = QtWidgets.QDialog() uifile = os.path.join(os.path.dirname(__file__), 'morph.ui') form = loadUi(uifile, dialog) # pre-fill form with likely data form.input_sele1.addItems(names) form.input_sele2.addItems(names) if len(names) > 1: form.input_sele2.setEditText(names[1]) else: form.input_state1.setValue(0) form.input_name.setText(_self.get_unused_name("morph")) def get_command(*args): morph = "linear" if form.input_method_rigimol.isChecked(): morph = 'rigimol' sele1 = form.input_sele1.currentText() sele2 = form.input_sele2.currentText() try: nstates1 = _self.count_states(sele1) nstates2 = _self.count_states(sele2) form.input_state1.setMaximum(nstates1) form.input_state2.setMaximum(nstates2) except Exception as e: nstates1 = 1 print(e) state1 = form.input_state1.value() state2 = form.input_state2.value() allstates = (state1 == 0 and nstates1 > 1) if allstates: sele2 = sele1 state2 = 0 form.input_sele2.setDisabled(allstates) form.input_state2.setDisabled(allstates) form.superpose.setDisabled(allstates) command = ( 'morph %s, %s, %s, %d, %d, %d, %d, %s' % (form.input_name.text(), sele1, sele2, state1, state2, form.input_refinement.value(), form.input_steps.value(), morph)) if not allstates and form.superpose.isChecked(): command = (('align %s, %s, ' 'mobile_state=%d, target_state=%d\n' % (form.input_sele1.currentText(), form.input_sele2.currentText(), state1, state2)) + command) return command def update_output_command(*args): form.output_command.setText(get_command()) def run(): _self.do(get_command()) # hook up events form.input_sele1.editTextChanged.connect(update_output_command) form.input_sele2.editTextChanged.connect(update_output_command) form.input_state1.valueChanged.connect(update_output_command) form.input_state2.valueChanged.connect(update_output_command) form.superpose.stateChanged.connect(update_output_command) form.input_refinement.valueChanged.connect(update_output_command) form.input_steps.valueChanged.connect(update_output_command) form.input_method_rigimol.toggled.connect(update_output_command) form.input_method_linear.toggled.connect(update_output_command) form.input_name.textChanged.connect(update_output_command) form.button_ok.clicked.connect(run) update_output_command() dialog.show()
def pyvol_window(): """ """ import os from pymol.Qt import QtCore, QtWidgets from pymol.Qt.utils import loadUi dialog = QtWidgets.QDialog() uifile = os.path.join(os.path.dirname(__file__), 'pyvolgui.ui') form = loadUi(uifile, dialog) def browse_pocket_file(form): """ Launches a window to select a file """ pocket_file_name = QtWidgets.QFileDialog.getOpenFileNames( None, 'Open file', os.getcwd(), filter='Pocket Files (*.obj *.csv)')[0][0] form.pocket_file_ledit.setText(pocket_file_name) def install_pyvol(form): """ Attempts a de novo PyVOL installation using pip """ import distutils import subprocess import sys form.status_label.setText("Installing PyVOL and its dependencies") subprocess.check_output( [sys.executable, "-m", "pip", "install", "bio-pyvol"]) msms_exe = distutils.spawn.find_executable("msms") if msms_exe == None: if os.name in ['posix']: conda_path = os.path.join(os.path.dirname(sys.executable), "conda") if not os.path.isfile(conda_path): conda_path = "conda" subprocess.check_output( [conda_path, "install", "-y", "-c", "bioconda", "msms"]) msms_exe = distutils.spawn.find_executable("msms") try: from pymol import cmd from pyvol import pymol_interface cmd.extend('pocket', pymol_interface.pocket) cmd.extend('load_pocket', pymol_interface.load_pocket) except: pass refresh_installation_status(form) def uninstall_pyvol(form): """ Attempts to uninstall PyVOL using pip """ import subprocess import sys form.status_label.setText("Uninstalling PyVOL") subprocess.check_output( [sys.executable, "-m", "pip", "uninstall", "-y", "bio-pyvol"]) msg = QtWidgets.QMessageBox() msg.setIcon(QtWidgets.QMessageBox.Information) msg.setWindowTitle("PyVOL Backend Uninstalled") msg.setInformativeText( "The PyVOL backend has been uninstalled; however, the plugin must also be uninstalled using PyMOL's plugin manager." ) msg.setStandardButtons(QtWidgets.QMessageBox.Ok) msg.setMinimumSize(QtCore.QSize(600, 200)) # Doesn't seem to work msg.exec_() refresh_installation_status(form) def update_pyvol(form): """ Attempts to update PyVOL using pip """ import subprocess import sys form.status_label.setText("Updating PyVOL") subprocess.check_output( [sys.executable, "-m", "pip", "install", "--upgrade", "bio-pyvol"]) msg = QtWidgets.QMessageBox() msg.setIcon(QtWidgets.QMessageBox.Information) msg.setWindowTitle("PyVOL Updated") msg.setInformativeText( "The PyVOL backend has been updated; however, PyMOL will not load the new code until it is restarted." ) msg.setStandardButtons(QtWidgets.QMessageBox.Ok) msg.setMinimumSize(QtCore.QSize(600, 200)) # Doesn't seem to work msg.exec_() refresh_installation_status(form) def refresh_installation_status(form, check_for_updates=False): """ Check for updates and adjust the GUI to reflect the current installation status and availability of updates Args: check_for_updates (bool): query servers to see if an update is available? (Default value = False) """ import distutils.spawn import json import subprocess import sys def apply_color(string, color): """ Applies a color to html text Args: string (str): text color (str): color to apply Returns: colored_text (str): html formatted text """ return "<font color='{0}'>{1}</font>".format(color, string) all_pckgs = subprocess.check_output( [sys.executable, "-m", "pip", "list", "--format=json"]).decode('utf-8').strip() pckgs = json.loads(all_pckgs) pyvol_version = None biopython_version = None numpy_version = None pandas_version = None scipy_version = None sklearn_version = None trimesh_version = None pyvol_installed = False for pckg in pckgs: if pckg["name"] == "bio-pyvol": pyvol_version = pckg["version"] pyvol_installed = True for pckg in pckgs: if pckg["name"] == "biopython": biopython_version = pckg["version"] if pyvol_installed: biopython_version = apply_color(biopython_version, "green") elif pckg["name"] == "numpy": numpy_version = pckg["version"] if pyvol_installed: numpy_version = apply_color(numpy_version, "green") elif pckg["name"] == "pandas": pandas_version = pckg["version"] if pyvol_installed: pandas_version = apply_color(pandas_version, "green") elif pckg["name"] == "scipy": scipy_version = pckg["version"] if pyvol_installed: scipy_version = apply_color(scipy_version, "green") elif pckg["name"] == "scikit-learn": sklearn_version = pckg["version"] if pyvol_installed: sklearn_version = apply_color(sklearn_version, "green") elif pckg["name"] == "trimesh": trimesh_version = pckg["version"] if pyvol_installed: trimesh_version = apply_color(trimesh_version, "green") if pyvol_version is None: pyvol_version = apply_color("not found", "red") if biopython_version is None: biopython_version = apply_color("not found", "red") if numpy_version is None: numpy_version = apply_color("not found", "red") if pandas_version is None: pandas_version = apply_color("not found", "red") if scipy_version is None: scipy_version = apply_color("not found", "red") if sklearn_version is None: sklearn_version = apply_color("not found", "red") if trimesh_version is None: trimesh_version = apply_color("not found", "red") msms_exe = distutils.spawn.find_executable("msms") if msms_exe == None: msms_exe = apply_color("not found", "red") else: msms_exe = apply_color(msms_exe, "green") # check whether an update is available for PyVOL and modify the GUI appropriately update_available = False if pyvol_installed and (msms_exe is not None): form.run_tab.setEnabled(True) form.run_button.setEnabled(True) form.load_tab.setEnabled(True) form.uninstall_button.setEnabled(True) form.uninstall_button.clicked.connect( lambda: uninstall_pyvol(form)) form.setWindowTitle("PyVOL v{0}".format(pyvol_version)) if check_for_updates: avail_pckgs = subprocess.check_output([ sys.executable, "-m", "pip", "list", "--outdated", "--format=json" ]).decode('utf-8').strip() avail = json.loads(avail_pckgs) for pckg in avail: if pckg["name"] == "bio-pyvol": update_available = True pyvol_version = apply_color( "{0} ({1} available)".format( pyvol_version, pckg['latest_version']), "blue") break if update_available: form.status_label.setText("Update available") form.install_button.setText("Update PyVOL") form.install_button.clicked.connect( lambda: update_pyvol(form)) else: form.status_label.setText("PyVOL is up-to-date") pyvol_version = apply_color( "{0} (up-to-date)".format(pyvol_version), "green") form.install_button.setText("Check for Updates") form.install_button.clicked.connect( lambda: refresh_installation_status( form, check_for_updates=True)) else: form.install_button.setText("Check for Updates") form.status_label.setText("PyVOL is installed") form.install_button.clicked.connect( lambda: refresh_installation_status( form, check_for_updates=True)) else: if not pyvol_installed: form.status_label.setText("PyVOL is not installed") else: form.status_label.setText( "PyVOL has been installed but cannot run without MSMS") form.run_tab.setEnabled(False) form.run_button.setEnabled(False) form.load_tab.setEnabled(False) form.tabWidget.setCurrentIndex(2) form.install_button.setText("Install PyVOL") form.install_button.clicked.connect(lambda: install_pyvol(form)) form.uninstall_button.setEnabled(False) gui_version = None if pyvol_installed and (not update_available): expected_gui_version = None try: import pyvol expected_gui_version = pyvol.__guiversion__ if __version__ == expected_gui_version: gui_version = apply_color(__version__, "green") else: gui_version = apply_color( "{0} ({1} expected)".format(__version__, expected_gui_version), "blue") form.status_label.setText( "GUI version mismatch--check whether PyVOL is up-to-date and reinstall the plugin if necessary using the PyMOL plugin manager or directly from the project <a href='https://github.com/schlessingerlab/pyvol/blob/master/pyvolgui.zip'>github</a>." ) except: gui_version = __version__ else: gui_version = __version__ form.install_status_browser.setText( (" pyvol: {0}<br>" " pyvol gui: {8}<br>" " biopython: {1}<br>" " numpy: {2}<br>" " pandas: {3}<br>" " scipy: {4}<br>" " sklearn: {5}<br>" " trimesh: {6}<br>" " msms exe: {7}<br><br>").format( pyvol_version, biopython_version, numpy_version, pandas_version, scipy_version, sklearn_version, trimesh_version, msms_exe, gui_version)) def run_gui_load(form): """ Loads a precalculated pocket into PyMOL """ from pyvol import pymol_interface # Loading Parameters pocket_file = form.pocket_file_ledit.text() if form.load_solid_rbutton.isChecked(): display_mode = "solid" elif form.load_mesh_rbutton.isChecked(): display_mode = "mesh" elif form.load_spheres_rbutton.isChecked(): display_mode = "spheres" color = form.load_color_ledit.text() alpha = form.load_alpha_ledit.text() prefix = form.load_prefix_ledit.text() if color == "": color = None if alpha == "": alpha = None if prefix == "": prefix = None if not os.path.isfile(pocket_file): logger.error("Supplied file not found: {0}".format(pocket_file)) return else: pymol_interface.load_pocket(pocket_file, name=prefix, display_mode=display_mode, color=color, alpha=alpha) def run_gui_pyvol(form): """ Runs a PyVOL calculation """ from pyvol import pymol_interface # Basic Parameters protein = form.prot_sele_ledit.text() excl_org = form.excl_org_cbox.isChecked() min_rad = form.min_rad_ledit.text() max_rad = form.max_rad_ledit.text() constrain_inputs = form.constrain_cbox.isChecked() # Pocket Selection minimum_volume = None ligand = None lig_incl_rad = None lig_excl_rad = None residue = None resid = None pocket_coordinate = None if form.all_rbutton.isChecked(): mode = "all" minimum_volume = form.min_volume_ledit.text() elif form.largest_rbutton.isChecked(): mode = "largest" elif form.ligand_rbutton.isChecked(): mode = "specific" ligand = form.lig_sele_ledit.text() if form.lig_incl_rad_ledit.text() != "": lig_incl_rad = form.lig_incl_rad_ledit.text() if form.lig_excl_rad_ledit.text() != "": lig_excl_rad = form.lig_excl_rad_ledit.text() elif form.residue_rbutton.isChecked(): mode = "specific" residue = form.residue_sele_ledit.text() elif form.resid_rbutton.isChecked(): mode = "specific" resid = form.resid_ledit.text() elif form.coordinate_rbutton.isChecked(): mode = "specific" pocket_coordinate = form.coordinate_ledit.text() # Partitioning Parameters subdivide = form.subdivide_cbox.isChecked() if not subdivide: subdivide = None max_clusters = form.max_clusters_ledit.text() min_subpocket_rad = form.min_internal_rad_ledit.text() min_subpocket_surf_rad = form.min_surf_rad_ledit.text() # Display and Output Options if form.solid_rbutton.isChecked(): display_mode = "solid" elif form.mesh_rbutton.isChecked(): display_mode = "mesh" elif form.spheres_rbutton.isChecked(): display_mode = "spheres" color = form.color_ledit.text() alpha = form.alpha_ledit.text() prefix = form.prefix_ledit.text() if prefix == "": prefix = None output_dir = form.output_dir_ledit.text() if output_dir == "": output_dir = None pymol_interface.pocket(protein=protein, mode=mode, ligand=ligand, pocket_coordinate=pocket_coordinate, residue=residue, resid=resid, prefix=prefix, min_rad=min_rad, max_rad=max_rad, lig_excl_rad=lig_excl_rad, lig_incl_rad=lig_incl_rad, display_mode=display_mode, color=color, alpha=alpha, output_dir=output_dir, subdivide=subdivide, minimum_volume=minimum_volume, min_subpocket_rad=min_subpocket_rad, min_subpocket_surf_rad=min_subpocket_surf_rad, max_clusters=max_clusters, excl_org=excl_org, constrain_inputs=constrain_inputs) refresh_installation_status(form) form.close_button.clicked.connect(dialog.close) form.run_button.clicked.connect(lambda: run_gui_pyvol(form)) form.browse_button.clicked.connect(lambda: browse_pocket_file(form)) form.load_button.clicked.connect(lambda: run_gui_load(form)) dialog.show()