def _update_graphics_if_needed(self, trigger_name, changes): if not self.visible: return changes = changes[1] update_needed = False if (self._track_whole_model): ''' Need to update the set of ramas if atoms are added. Deletions will take care of themselves. ''' created = changes.created_atoms() if len(created): from chimerax.atomic import Residue # Only need to update if the additions are non-hydrogen protein atoms ur = created[created.element_names !='H'].unique_residues if any(ur.polymer_types == Residue.PT_AMINO): # Trigger rebuild of rama array and graphics update self.track_whole_model = True # self._prepare_ca_display() return reasons = changes.atom_reasons() if 'coord changed' in reasons: update_needed = True if 'display changed' in reasons or 'hide changed' in reasons: # self._prepare_ca_display() self._update_visible_ramas() update_needed = True if 'selected changed' in reasons: update_needed = True # if 'color changed' in reasons: # update_needed = True if update_needed: from chimerax.atomic import get_triggers get_triggers().add_handler('changes done', self.update_graphics)
def _update_graphics_if_needed(self, trigger_name, changes): if not self.visible: return changes = changes[1] update_needed = False if (self._track_whole_model): ''' Need to update the set of rotamers if atoms are added. Deletions will take care of themselves. ''' created = changes.created_atoms() if len(created): # Only need to update if we've added new non-hydrogen protein atoms from chimerax.atomic import Residue ur = created[created.element_names!='H'].unique_residues if sum(ur.polymer_types==Residue.PT_AMINO): r = self._selected_residues = self._atomic_structure.residues self._selected_rotamers = self._mgr.get_rotamers(r) update_needed = True if changes.num_deleted_atoms(): update_needed = True reasons = changes.atom_reasons() if 'coord changed' in reasons: update_needed = True if 'display changed' in reasons or 'hide changed' in reasons: update_needed = True if (update_needed): from chimerax.atomic import get_triggers get_triggers().add_handler('changes done', self.update_graphics)
def delete(self): self.region_browser.destroy() self.seq_canvas.destroy() self.alignment.detach_viewer(self) for seq in self.alignment.seqs: seq.triggers.remove_handler(self._seq_rename_handlers[seq]) from chimerax.atomic import get_triggers get_triggers().remove_handler(self._atomic_changes_handler) ToolInstance.delete(self)
def delete_rotation(self, rotater): del self.bond_rotaters[rotater.ident] rotation = rotater.rotation rotation.rotaters.remove(rotater) if not rotation.rotaters: del self.bond_rotations[rotation.bond] if not self.bond_rotations: from chimerax.atomic import get_triggers get_triggers().remove_handler(self._handler_ID) if not rotater.one_shot: self.triggers.activate_trigger(self.DELETED, rotater)
def delete_all_rotations(self): for rotater in self.bond_rotaters.values(): self.triggers.activate_trigger(self.DELETED, rotater) if self.bond_rotations: from chimerax.atomic import get_triggers get_triggers().remove_handler(self._handler_ID) for rotation in self.bond_rotations.values(): # break reference loops rotation.rotaters = [] self.bond_rotations.clear() self.bond_rotaters.clear()
def _mmap_mod_cb(self, trig_name, match_map): if len(match_map) == 0: self.disassociate(self._sseq_to_chain[match_map.struct_seq], demotion=True) del self._sseq_to_chain[match_map.struct_seq] else: if not self._modified_mmaps: from chimerax.atomic import get_triggers get_triggers().add_handler("changes done", self._atomic_changes_done) self._modified_mmaps.append(match_map)
def _set_auto_update(self, enable): h = self._auto_update_handler if enable and h is None: from chimerax.atomic import get_triggers t = get_triggers() self._auto_update_handler = t.add_handler('changes', self._atoms_changed) if self.vertices is not None: self._recompute_shape() elif not enable and h: from chimerax.atomic import get_triggers t = get_triggers() t.remove_handler(h) self._auto_update_handler = None
def _xcmd(session, group_name): if getattr(session, _continuous_attr, None) != None: from chimerax.atomic import get_triggers get_triggers().remove_handler(getattr(session, _continuous_attr)) delattr(session, _continuous_attr) pbg = session.pb_manager.get_group(group_name, create=False) pbgs = [pbg] if pbg else [] from chimerax.atomic import AtomicStructure for s in [m for m in session.models if isinstance(m, AtomicStructure)]: pbg = s.pseudobond_group(group_name, create_type=None) if pbg: pbgs.append(pbg) if pbgs: session.models.close(pbgs)
def __init__(self, session, groups, contacts, interface_residue_area_cutoff=5): # Create matplotlib panel title = '%d Chains %d Contacts' % (len(groups), len(contacts)) Graph.__init__(self, session, groups, contacts, tool_name="Chain Contacts", title=title) self.groups = groups self.contacts = contacts self.interface_residue_area_cutoff = interface_residue_area_cutoff # Show contact areas less than half maximum as dotted lines. small_area = 0.5 * max(c.buried_area for c in contacts) for c in contacts: if c.buried_area < small_area: c.style = 'dotted' c.width = 2 self.draw_graph() # When group is undisplayed update its node color. from chimerax import atomic self._handler = atomic.get_triggers(session).add_handler( 'changes', self._atom_display_change)
def __init__(self, session, structure, pause_frames = 1, movie_framerate = 25, steady_atoms = None, compute_ss = False): self.structure = structure title = 'Coordinate sets %s (%d)' % (structure.name, structure.num_coordsets) csids = structure.coordset_ids id_start, id_end = min(csids), max(csids) self.coordset_ids = set(csids) Slider.__init__(self, session, 'Model Series', 'Model', title, value_range = (id_start, id_end), pause_frames = pause_frames, pause_when_recording = True, movie_framerate = movie_framerate) from .coordset import CoordinateSetPlayer self._player = CoordinateSetPlayer(structure, id_start, id_end, istep = 1, pause_frames = pause_frames, loop = 1, compute_ss = compute_ss, steady_atoms = steady_atoms) self.update_value(structure.active_coordset_id) from chimerax import atomic t = atomic.get_triggers(session) self._coordset_change_handler = t.add_handler('changes', self.coordset_change_cb) from chimerax.core.models import REMOVE_MODELS self._model_close_handler = session.triggers.add_handler(REMOVE_MODELS, self.models_closed_cb) if not hasattr(session, '_coord_set_sliders'): session._coord_set_sliders = set() session._coord_set_sliders.add(self)
def __init__(self, session): Model.__init__(self, 'labels', session) self.on_top = True # Should labels always appear above other graphics self._window_size = session.main_view.window_size self._labels = [] # list of ObjectLabel self._object_label = { } # Map object (Atom, Residue, Pseudobond, Bond) to ObjectLabel self._num_pixel_labels = 0 # Number of labels sized in pixels. t = session.triggers self._update_graphics_handler = t.add_handler( 'graphics update', self._update_graphics_if_needed) self._model_display_handler = t.add_handler( 'model display changed', self._model_display_changed) from chimerax.core.core_settings import settings as core_settings self._background_color_handler = core_settings.triggers.add_handler( 'setting changed', self._background_changed_cb) from chimerax.atomic import get_triggers ta = get_triggers() self._structure_change_handler = ta.add_handler( 'changes', self._structure_changed) self.use_lighting = False Model.set_color(self, (255, 255, 255, 255)) # Do not modulate texture colors self._texture_width = 2048 # Pixels. self._texture_needs_update = True # Has text, color, size, font changed. self._positions_need_update = True # Has label position changed relative to atom? self._visibility_needs_update = True # Does an atom hide require a label to hide?
def disassociate(self, sseq, *, reassoc=False, demotion=False): if sseq not in self.associations or self._in_destroy: return if self.intrinsic: self.session.alignments.destroy_alignment(self) return aseq = self.associations[sseq] match_map = aseq.match_maps[sseq] del aseq.match_maps[sseq] del self.associations[sseq] match_map.mod_handler.remove() if reassoc: return if not demotion: # if the structure seq hasn't been demoted/destroyed, log the disassociation struct = sseq.structure struct_name = struct.name if '.' in struct.id_string: # ensemble struct_name += " (" + struct.id_string + ")" self.session.logger.info("Disassociated %s %s from %s" % (struct_name, sseq.name, aseq.name)) # delay notifying the observers until all chain demotions/deletions have been received num_unknown = 0 structures = set() for sseq in self.associations: try: structures.add(sseq.structure) except AttributeError: # demoted num_unknown += 1 data = { 'match map': match_map, 'num remaining associations': len(self.associations), 'max previous structures': len(structures) + num_unknown, 'num remaining structures': len(structures) } def _delay_disassoc(_, __, data=data): self._notify_observers(self.NOTE_DEL_ASSOC, data) from chimerax.core.triggerset import DEREGISTER return DEREGISTER from chimerax import atomic atomic.get_triggers().add_handler('changes done', _delay_disassoc)
def __init__(self, session, bundle_info): self.session = session self.monitored_groups = set() self.update_callbacks = {} self._distances_shown = True from chimerax.atomic import get_triggers triggers = get_triggers() triggers.add_handler("changes", self._changes_handler) self._already_restored = set()
def close(self): self.session.triggers.remove_handler(self._show_rot_vec) global_triggers = get_triggers() global_triggers.remove_handler(self._changes) for model in self.session.models.list(type=Generic3DModel): if model.name == "rotation vector": model.delete() return super().close()
def __init__(self, alignment, *args, **kw): from math import log self.scaling = log(0.5) / (-3.0) super().__init__(alignment, *args, **kw) from chimerax.atomic import get_triggers self.handlers = [ self.settings.triggers.add_handler('setting changed', self._setting_changed_cb), get_triggers().add_handler('changes', self._atomic_changes_cb) ] self._set_name()
def _ses_restore(self, data): self.clear() if 'bond_rots' in data: # old, non-backwards compatible, session data if data['bond_rots']: self.session.logger.warning('Bond-rotation data in session is obsolete and not restorable;' " skipping") return self.bond_rotations = data['rotations'] self.bond_rotaters = data['rotaters'] if self.bond_rotations: from chimerax.atomic import get_triggers self._handler_ID = get_triggers().add_handler('changes', self._changes_cb)
def new_rotation(self, bond, ident=None, move_smaller_side=True, one_shot=True): """Create bond rotation for 'bond' Parameters ---------- bond : Bond Bond to rotate ident: an integer or None Number used to refer to bond rotation in commands. If None, automatically assign one. move_smaller_side: bool If True, move the "smaller" side (side with fewer atoms attached) when the bond rotation moves. Otherwise move the bigger side. one_shot: bool True if the rotation is going to be used to change the torsion and then immediately deleted -- so don't bother firing triggers. Returns the created BondRotater """ if ident is None: ident = 1 while ident in self.bond_rotaters: ident += 1 elif ident in self.bond_rotaters: raise BondRotationError("Bond rotation identifier %s already in use" % ident) try: moving_side = bond.smaller_side except ValueError: raise BondRotationError("Bond %s is part of a ring/cycle and cannot be rotated" % bond) if not move_smaller_side: moving_side = bond.other_atom(moving_side) if not self.bond_rotations: from chimerax.atomic import get_triggers self._handler_ID = get_triggers().add_handler('changes', self._changes_cb) if bond in self.bond_rotations: rotation = self.bond_rotations[bond] else: from .bond_rot import BondRotation rotation = BondRotation(self.session, bond) self.bond_rotations[bond] = rotation rotater = rotation.new_rotater(ident, moving_side, one_shot) self.bond_rotaters[ident] = rotater if not one_shot: self.triggers.activate_trigger(self.CREATED, rotater) self.session.logger.status("Bond rotation identifier is %s" % ident, log=True) return rotater
def delete(self): from chimerax import atomic t = atomic.get_triggers(self.session) t.remove_handler(self._coordset_change_handler) self._coordset_change_handler = None self.session._coord_set_sliders.remove(self) t = self.session.triggers t.remove_handler(self._model_close_handler) self._model_close_handler = None super().delete() self.structure = None
def __init__(self, session, base_residue, rotamers): self.init_state_manager(session, "residue rotamers") self.session = session self.base_residue = base_residue self.rotamers = list( rotamers) # don't want auto-shrinking of a Collection self.group = session.models.add_group( rotamers, name="%s rotamers" % base_residue.string(omit_structure=True), parent=base_residue.structure) from chimerax.atomic import get_triggers self.handler = get_triggers().add_handler('changes', self._changes_cb) from chimerax.core.triggerset import TriggerSet self.triggers = TriggerSet() self.triggers.add_trigger('fewer rotamers') # but not zero self.triggers.add_trigger('self destroyed')
def __init__(self, session, name): super().__init__(session, name) self.tool_window = MainToolWindow(self) self.settings = _PrecisionRotateSettings(session, name) self.bonds = {} self.bond_centers = {} self.groups = {} self.perpendiculars = {} self.perp_centers = {} self.manual_center = {} self._build_ui() self._show_rot_vec = self.session.triggers.add_handler( SELECTION_CHANGED, self.show_rot_vec) global_triggers = get_triggers() self._changes = global_triggers.add_handler("changes done", self.show_rot_vec) self.show_rot_vec()
def _finalize_init(self, alignment): """TODO from chimera import triggerSet self.triggers = triggerSet.TriggerSet() self.triggers.addTrigger(ADD_ASSOC) self.triggers.addTrigger(DEL_ASSOC) self.triggers.addTrigger(MOD_ASSOC) self.triggers.addHandler(ADD_ASSOC, self._fireModAssoc, None) self.triggers.addHandler(DEL_ASSOC, self._fireModAssoc, None) self.triggers.addTrigger(ADD_SEQS) self.triggers.addTrigger(PRE_DEL_SEQS) self.triggers.addTrigger(DEL_SEQS) self.triggers.addTrigger(ADDDEL_SEQS) self.triggers.addTrigger(SEQ_RENAMED) self.triggers.addHandler(ADD_SEQS, self._fireAddDelSeq, None) self.triggers.addHandler(DEL_SEQS, self._fireAddDelSeq, None) self.triggers.addHandler(ADDDEL_SEQS, self._fireModAlign, None) self.triggers.addTrigger(MOD_ALIGN) self.associations = {} self._resAttrs = {} self._edited = False from common import getStaticSeqs seqs, fileMarkups, fileAttrs = getStaticSeqs(fileNameOrSeqs, fileType=fileType) self.seqs = seqs """ self.alignment = alignment from . import subcommand_name alignment.attach_viewer(self, subcommand_name=subcommand_name) from . import settings self.settings = settings.init(self.session) """ from SeqCanvas import shouldWrap if numberingDisplay: defaultNumbering = numberingDisplay else: defaultNumbering = (True, not shouldWrap(len(seqs), self.prefs)) self.numberingsStripped = False if getattr(seqs[0], 'numberingStart', None) is None: # see if sequence names imply numbering... startInfo = [] for seq in seqs: try: name, numbering = seq.name.rsplit('/',1) except ValueError: break try: start, end = numbering.split('-') except ValueError: start = numbering try: startInfo.append((name, int(start))) except ValueError: break if len(startInfo) == len(seqs): self.numberingsStripped = True for i, seq in enumerate(seqs): seq.name, seq.numberingStart = \ startInfo[i] else: for seq in seqs: if hasattr(seq, 'residues'): for i, r in enumerate(seq.residues): if r: seq.numberingStart = r.id.position - 1 break else: seq.numberingStart = 1 else: seq.numberingStart = 1 if not numberingDisplay: defaultNumbering = (False, False) self._defaultNumbering = defaultNumbering self.fileAttrs = fileAttrs self.fileMarkups = fileMarkups if not title: if isinstance(fileNameOrSeqs, basestring): title = os.path.split(fileNameOrSeqs)[1] else: title = "Sequence Viewer" self.title = title self.autoAssociate = autoAssociate self.quitCB = quitCB self.sessionSave = sessionSave self._runModellerWSList = [] self._runModellerLocalList = [] self._realignmentWSJobs = {'self': [], 'new': []} self._blastAnnotationServices = {} ModelessDialog.__init__(self) """ words = self.alignment.description.split() capped_words = [] for word in words: if word.islower() and word.isalpha(): capped_words.append(word.capitalize()) else: capped_words.append(word) self.display_name = " ".join( capped_words) + " [ID: %s]" % self.alignment.ident from chimerax.ui import MainToolWindow self.tool_window = MainToolWindow(self, close_destroys=True, statusbar=True) self.tool_window._dock_widget.setMouseTracking(True) self.tool_window.fill_context_menu = self.fill_context_menu self.status = self.tool_window.status parent = self.tool_window.ui_area parent.setMouseTracking(True) """TODO # SeqCanvas will use these... leftNums, rightNums = self._defaultNumbering self.leftNumberingVar = Tkinter.IntVar(parent) self.leftNumberingVar.set(leftNums) self.rightNumberingVar = Tkinter.IntVar(parent) self.rightNumberingVar.set(rightNums) """ from .seq_canvas import SeqCanvas self.seq_canvas = SeqCanvas(parent, self, self.alignment) if self.alignment.associations: # There are pre-existing associations, show them for aseq in self.alignment.seqs: if aseq.match_maps: self.seq_canvas.assoc_mod(aseq) from .region_browser import RegionBrowser rb_window = self.tool_window.create_child_window("Regions", close_destroys=False) self.region_browser = RegionBrowser(rb_window, self.seq_canvas) self._seq_rename_handlers = {} for seq in self.alignment.seqs: self._seq_rename_handlers[seq] = seq.triggers.add_handler( "rename", self.region_browser._seq_renamed_cb) if seq.match_maps: self._update_errors_gaps(seq) if self.alignment.intrinsic: self.show_ss(True) self.status("Helices/strands depicted in gold/green") """TODO if self.fileMarkups: from HeaderSequence import FixedHeaderSequence headers = [] for name, val in self.fileMarkups.items(): headers.append( FixedHeaderSequence(name, self, val)) self.addHeaders(headers) self.prefDialog = PrefDialog(self) top = parent.winfo_toplevel() cb = lambda e, rb=self.regionBrowser: rb.deleteRegion( rb.curRegion()) top.bind('<Delete>', cb) top.bind('<BackSpace>', cb) self.menuBar = Tkinter.Menu(top, type="menubar", tearoff=False) top.config(menu=self.menuBar) self.fileMenu = Tkinter.Menu(self.menuBar) self.menuBar.add_cascade(label="File", menu=self.fileMenu) self.fileMenu.add_command(label="Save As...", command=self.save) self.epsDialog = None self.fileMenu.add_command(label="Save EPS...", command=self._showEpsDialog) self.fileMenu.add_command(label="Save Association Info...", state='disabled', command=self._showAssocInfoDialog) self.fileMenu.add_separator() self.fileMenu.add_command(label="Load SCF/Seqsel File...", command=lambda: self.loadScfFile(None)) self.fileMenu.add_command(label="Load Color Scheme...", command=self._showColorSchemeDialog) self.fileMenu.add_separator() self.fileMenu.add_command(label="Hide", command=self.Hide) self.fileMenu.add_command(label="Quit", command=self.Quit) if parent == dialogParent: # if we're not part of a custom interface, # override the window-close button to quit, not hide top.protocol('WM_DELETE_WINDOW', self.Quit) self.editMenu = Tkinter.Menu(self.menuBar) self.menuBar.add_cascade(label="Edit", menu=self.editMenu) self.editMenu.add_command(label="Copy Sequence...", command=self._showCopySeqDialog) self.editMenu.add_command(label="Reorder Sequences...", command=self._showReorderDialog) self.editMenu.add_command(label="Insert All-Gap Columns...", command=self._showInsertGapDialog) self.editMenu.add_command(label="Delete Sequences/Gaps...", command=self._showDelSeqsGapsDialog) self.editMenu.add_command(label="Add Sequence...", command=self._showAddSeqDialog) self.editMenu.add_command(label="Realign Sequences...", command=self._showRealignmentDialog) self.editMenu.add_command(label="Alignment Annotations...", command=self._showAlignAttrDialog) self.editMenu.add_command(label="Edit Sequence Name...", command=self._showSeqNameEditDialog) self.editMenu.add_command(label="Show Editing Keys...", command=self._showEditKeysDialog) self.editMenu.add_command(label=u"Region \N{RIGHTWARDS ARROW} New Window", command=self.exportActiveRegion) self.editMenu.add_separator() self.editMenu.add_command(label="Find Subsequence...", command=self._showFindDialog) self.editMenu.add_command(label="Find Regular Expression...", command=self._showRegexDialog) self.editMenu.add_command(label="Find PROSITE Pattern...", command=self._showPrositeDialog) self.editMenu.add_command(label="Find Sequence Name...", command=self._showFindSeqNameDialog) self.structureMenu = Tkinter.Menu(self.menuBar) self.menuBar.add_cascade(label="Structure", menu=self.structureMenu) self.structureMenu.add_command(label="Load Structures", command=self._loadStructures) """ """ self.alignDialog = self.assessDialog = self.findDialog = None self.prositeDialog = self.regexDialog = None self.associationsDialog = self.findSeqNameDialog = None self.saveHeaderDialog = self.alignAttrDialog = None self.assocInfoDialog = self.loadHeaderDialog = None self.identityDialog = self.colorSchemeDialog = None self.modellerHomologyDialog = self.fetchAnnotationsDialog = None self.treeDialog = self.reorderDialog = self.blastPdbDialog = None self.delSeqsGapsDialog = self.insertGapDialog = None self.addSeqDialog = self.numberingsDialog = None self.editKeysDialog = self.copySeqDialog = None self.modellerLoopsDialog = self.seqNameEditDialog = None self.realignDialog = None self.structureMenu.add_command(label="Match...", state='disabled', command=self._showAlignDialog) self.structureMenu.add_command(label="Assess Match...", state='disabled', command=self._showAssessDialog) if len(self.seqs) <= 1: state = "disabled" else: state = "normal" self.structureMenu.add_command(label="Modeller (homology)...", state=state, command=self._showModellerHomologyDialog) self.structureMenu.add_command(label=self.MODEL_LOOPS_MENU_TEXT, state="disabled", command=self._showModellerLoopsDialog) if chimera.openModels.list(modelTypes=[chimera.Molecule]): assocState = 'normal' else: assocState = 'disabled' self.structureMenu.add_command(label="Associations...", state=assocState, command=self._showAssociationsDialog) self.ssMenu = Tkinter.Menu(self.structureMenu) self.structureMenu.add_cascade(label="Secondary Structure", menu=self.ssMenu) self.showSSVar = Tkinter.IntVar(parent) self.showSSVar.set(False) self.showPredictedSSVar = Tkinter.IntVar(parent) self.showPredictedSSVar.set(False) self.ssMenu.add_checkbutton(label="show actual", variable=self.showSSVar, command=lambda s=self: s.showSS(show=None)) self.ssMenu.add_checkbutton(label="show predicted", variable=self.showPredictedSSVar, command=lambda s=self: s.showSS(show=None, ssType="predicted")) # actual SS part of MOD_ASSOC handler... self._predSSHandler = self.triggers.addHandler(ADD_SEQS, lambda a1, a2, a3, s=self: s.showSS(show=None, ssType="predicted"), None) """ from chimerax.atomic import get_triggers self._atomic_changes_handler = get_triggers().add_handler( "changes", self._atomic_changes_cb) """TODO self.structureMenu.add_command(state='disabled', label="Select by Conservation...", command=lambda: self._doByConsCB("Select")) self.structureMenu.add_command(state='disabled', label="Render by Conservation...", command=lambda: self._doByConsCB("Render")) self.structureMenu.add_command(label="Expand Selection to" " Columns", state=assocState, command=self.expandSelectionByColumns) self._modAssocHandlerID = self.triggers.addHandler( MOD_ASSOC, self._modAssocCB, None) self.headersMenu = Tkinter.Menu(self.menuBar) self.menuBar.add_cascade(label="Headers", menu=self.headersMenu) self.headersMenu.add_command(label="Save...", command=self._showSaveHeaderDialog) self.headersMenu.add_command(label="Load...", command=self._showLoadHeaderDialog) self.headersMenu.add_separator() for trig in [ADD_HEADERS,DEL_HEADERS,SHOW_HEADERS,HIDE_HEADERS, MOD_ALIGN]: self.triggers.addHandler(trig, self._rebuildHeadersMenu, None) self._rebuildHeadersMenu() self.numberingsMenu = Tkinter.Menu(self.menuBar) self.menuBar.add_cascade(label="Numberings", menu=self.numberingsMenu) self.showRulerVar = Tkinter.IntVar(self.headersMenu) self.showRulerVar.set( len(self.seqs) > 1 and self.prefs[SHOW_RULER_AT_STARTUP]) self.numberingsMenu.add_checkbutton(label="Overall Alignment", selectcolor="black", variable=self.showRulerVar, command=self.setRulerDisplay) self.numberingsMenu.add_separator() self.numberingsMenu.add_checkbutton( label="Left Sequence", selectcolor="black", variable=self.leftNumberingVar, command=self.setLeftNumberingDisplay) self.numberingsMenu.add_checkbutton( label="Right Sequence", selectcolor="black", variable=self.rightNumberingVar, command=self.setRightNumberingDisplay) self.numberingsMenu.add_command( label="Adjust Sequence Numberings...", command = self._showNumberingsDialog) self.treeMenu = Tkinter.Menu(self.menuBar) self.menuBar.add_cascade(label="Tree", menu=self.treeMenu) self.treeMenu.add_command(label="Load...", command=self._showTreeDialog) self.showTreeVar = Tkinter.IntVar(self.menuBar) self.showTreeVar.set(True) self.treeMenu.add_checkbutton(label="Show Tree", selectcolor="black", variable=self.showTreeVar, command=self._showTreeCB, state='disabled') self.treeMenu.add_separator() self.treeMenu.add_command(label="Extract Subalignment", state="disabled", command=self.extractSubalignment) self.infoMenu = Tkinter.Menu(self.menuBar) self.menuBar.add_cascade(label="Info", menu=self.infoMenu) if len(self.seqs) == 1: state = "disabled" else: state = "normal" self.infoMenu.add_command(label="Percent Identity...", state=state, command=self._showIdentityDialog) self.infoMenu.add_command(label="Region Browser", command=self.regionBrowser.enter) self.infoMenu.add_command(label="Blast Protein...", command=self._showBlastPdbDialog) self.infoMenu.add_command(label="UniProt/CDD Annotations...", command=self._showFetchAnnotationsDialog) self.preferencesMenu = Tkinter.Menu(self.menuBar) self.menuBar.add_cascade(label="Preferences", menu=self.preferencesMenu) from chimera.tkgui import aquaMenuBar aquaMenuBar(self.menuBar, parent, row = 0, columnspan = 4) for tab in self.prefDialog.tabs: self.preferencesMenu.add_command(label=tab, command=lambda t=tab: [self.prefDialog.enter(), self.prefDialog.notebook.selectpage(t)]) self.status("Mouse drag to create region (replacing current)\n", blankAfter=30, followTime=40, followWith= "Shift-drag to add to current region\n" "Control-drag to add new region") self._addHandlerID = chimera.openModels.addAddHandler( self._newModelsCB, None) self._removeHandlerID = chimera.openModels.addRemoveHandler( self._closeModelsCB, None) self._closeSessionHandlerID = chimera.triggers.addHandler( CLOSE_SESSION, lambda t, a1, a2, s=self: s.Quit(), None) self._monitorChangesHandlerID = None # deregister other handlers on APPQUIT... chimera.triggers.addHandler(chimera.APPQUIT, self.destroy, None) if self.autoAssociate == None: if len(self.seqs) == 1: self.intrinsicStructure = True else: self.autoAssociate = False self.associate(None) else: self._newModelsCB(models=chimera.openModels.list()) self._makeSequenceRegions() if self.prefs[LOAD_PDB_AUTO]: # delay calling _loadStructures to give any structures # opened along with MAV a chance to load parent.after_idle(lambda: self._loadStructures(auto=1)) """ self.tool_window.manage( 'side' if self.seq_canvas.wrap_okay() else 'top')
def delete(self): from chimerax import atomic atomic.get_triggers(self._session()).remove_handler(self._handler) self._handler = None Graph.delete(self)
def delete(self): global_triggers = get_triggers() global_triggers.remove_handler(self._changes) super().delete()
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) global_triggers = get_triggers() self._changes = global_triggers.add_handler("changes", self.check_changes)
def __init__(self, session, tool_name): ToolInstance.__init__(self, session, tool_name) self.display_name = "Models" self.settings = ModelPanelSettings(session, "ModelPanel") last = self.settings.last_use from time import time now = self.settings.last_use = time() short_titles = last != None and now - last < 777700 # about 3 months from chimerax.ui import MainToolWindow self.tool_window = tw = MainToolWindow(self, close_destroys=False) parent = tw.ui_area from PyQt5.QtWidgets import QTreeWidget, QHBoxLayout, QVBoxLayout, QAbstractItemView, \ QFrame, QPushButton, QSizePolicy class SizedTreeWidget(QTreeWidget): def sizeHint(self): from PyQt5.QtCore import QSize # side buttons will keep the vertical size reasonable if getattr(self, '_first_size_hint_call', True): self._first_size_hint_call = False width = 0 else: width = self.header().length() return QSize(width, 200) self.tree = SizedTreeWidget() self.tree.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.tree.keyPressEvent = session.ui.forward_keystroke self.tree.expanded.connect(self._ensure_id_width) layout = QHBoxLayout() layout.setContentsMargins(0,0,0,0) layout.setSpacing(0) layout.addWidget(self.tree) layout.setStretchFactor(self.tree, 1) parent.setLayout(layout) shown_title = "" if short_titles else "Shown" sel_title = "" if short_titles else "Select" self.tree.setHeaderLabels(["Name", "ID", " ", shown_title, sel_title]) from chimerax.ui.icons import get_qt_icon self.tree.headerItem().setIcon(3, get_qt_icon("shown")) self.tree.headerItem().setToolTip(3, "Shown") self.tree.headerItem().setIcon(4, get_qt_icon("select")) self.tree.headerItem().setToolTip(4, "Selected") self.tree.setColumnWidth(self.NAME_COLUMN, 200) self.tree.setSelectionBehavior(QAbstractItemView.SelectRows) self.tree.setSelectionMode(QAbstractItemView.ExtendedSelection) self.tree.setAnimated(True) self.tree.setUniformRowHeights(True) self.tree.setEditTriggers(QAbstractItemView.NoEditTriggers) self.tree.itemChanged.connect(self._tree_change_cb) buttons_layout = QVBoxLayout() layout.addLayout(buttons_layout) self._items = [] for model_func in [close, hide, show, view]: button = QPushButton(model_func.__name__.capitalize()) buttons_layout.addWidget(button) button.clicked.connect(lambda chk, self=self, mf=model_func, ses=session: mf([self.models[row] for row in [self._items.index(i) for i in self.tree.selectedItems()]] or self.models, ses)) self.simply_changed_models = set() self.check_model_list = True self.countdown = 1 self.self_initiated = False from chimerax.core.models import ADD_MODELS, REMOVE_MODELS, \ MODEL_DISPLAY_CHANGED, MODEL_ID_CHANGED, MODEL_NAME_CHANGED from chimerax.core.selection import SELECTION_CHANGED session.triggers.add_handler(SELECTION_CHANGED, lambda *args: self._initiate_fill_tree(*args, countdown=3)) session.triggers.add_handler(MODEL_DISPLAY_CHANGED, lambda *args: self._initiate_fill_tree(*args, simple_change=True, countdown=(0,3))) session.triggers.add_handler(ADD_MODELS, lambda *args: self._initiate_fill_tree(*args, always_rebuild=True, countdown=(3,10))) session.triggers.add_handler(REMOVE_MODELS, lambda *args: self._initiate_fill_tree(*args, always_rebuild=True)) session.triggers.add_handler(MODEL_ID_CHANGED, lambda *args: self._initiate_fill_tree(*args, always_rebuild=True, countdown=3)) session.triggers.add_handler(MODEL_NAME_CHANGED, lambda *args: self._initiate_fill_tree(*args, simple_change=True, countdown=3)) from chimerax import atomic atomic.get_triggers().add_handler("changes", self._changes_cb) self._frame_drawn_handler = None tw.manage(placement="side") tw.shown_changed = self._shown_changed
def _cmd(session, test_atoms, name, hbond_allowance, overlap_cutoff, test_type, color, radius, *, attr_name=defaults["attr_name"], bond_separation=defaults["bond_separation"], continuous=False, dashes=None, distance_only=None, inter_model=True, inter_submodel=False, intra_model=True, intra_mol=defaults["intra_mol"], intra_res=defaults["intra_res"], log=defaults["action_log"], make_pseudobonds=defaults["action_pseudobonds"], naming_style=None, res_separation=None, restrict="any", reveal=False, save_file=None, set_attrs=defaults["action_attr"], select=defaults["action_select"], show_dist=False, summary=True): from chimerax.core.errors import UserError if test_atoms is None: from chimerax.atomic import AtomicStructure, AtomicStructures test_atoms = AtomicStructures([ s for s in session.models if isinstance(s, AtomicStructure) ]).atoms if not test_atoms: raise UserError("No atoms match given atom specifier") from chimerax.core.colors import Color if color is not None and not isinstance(color, Color): color = Color(rgba=color) from chimerax.atomic import get_triggers ongoing = False if continuous: if set_attrs or save_file != None or log: raise UserError( "log/setAttrs/saveFile not allowed with continuous detection") if getattr(session, _continuous_attr, None) == None: from inspect import getargvalues, currentframe, getfullargspec arg_names, fArgs, fKw, frame_dict = getargvalues(currentframe()) arg_spec = getfullargspec(_cmd) args = [frame_dict[an] for an in arg_names[:len(arg_spec.args)]] kw = {k: frame_dict[k] for k in arg_names[len(arg_spec.args):]} call_data = (args, kw) def changes_cb(trig_name, changes, session=session, call_data=call_data): s_reasons = changes.atomic_structure_reasons() a_reasons = changes.atom_reasons() if 'position changed' in s_reasons \ or 'active_coordset changed' in s_reasons \ or 'coord changed' in a_reasons \ or 'alt_loc changed' in a_reasons: args, kw = call_data if not args[1]: # all atoms gone delattr(session, _continuous_attr) from chimerax.core.triggerset import DEREGISTER return DEREGISTER _cmd(*tuple(args), **kw) setattr(session, _continuous_attr, get_triggers().add_handler('changes', changes_cb)) else: ongoing = True elif getattr(session, _continuous_attr, None) != None: get_triggers().remove_handler(getattr(session, _continuous_attr)) delattr(session, _continuous_attr) from .clashes import find_clashes clashes = find_clashes(session, test_atoms, attr_name=attr_name, bond_separation=bond_separation, clash_threshold=overlap_cutoff, distance_only=distance_only, hbond_allowance=hbond_allowance, inter_model=inter_model, inter_submodel=inter_submodel, intra_model=intra_model, intra_res=intra_res, intra_mol=intra_mol, res_separation=res_separation, restrict=restrict) if select: session.selection.clear() for a in clashes.keys(): a.selected = True # if relevant, put the test_atoms in the first column if restrict == "both": output_grouping = set() else: output_grouping = test_atoms test_type = "distances" if distance_only else test_type info = (overlap_cutoff, hbond_allowance, bond_separation, intra_res, intra_mol, clashes, output_grouping, test_type, res_separation) if log: import io buffer = io.StringIO() buffer.write("<pre>") _file_output(buffer, info, naming_style) buffer.write("</pre>") session.logger.info(buffer.getvalue(), is_html=True) if save_file is not None: _file_output(save_file, info, naming_style) if summary: if clashes: total = 0 for clash_list in clashes.values(): total += len(clash_list) session.logger.status("%d %s" % (total / 2, test_type), log=not ongoing) else: session.logger.status("No %s" % test_type, log=not ongoing) if not (set_attrs or make_pseudobonds or reveal): _xcmd(session, name) return clashes from chimerax.atomic import all_atoms if restrict == "both": attr_atoms = test_atoms elif restrict in ("any", "cross"): if inter_model: attr_atoms = all_atoms(session) else: attr_atoms = test_atoms.unique_structures.atoms else: from chimerax.atomic import concatenate attr_atoms = concatenate([test_atoms, restrict], remove_duplicates=True) from chimerax.atomic import Atoms clash_atoms = Atoms([a for a in attr_atoms if a in clashes]) if set_attrs: # delete the attribute in _all_ atoms... for a in all_atoms(session): if hasattr(a, attr_name): delattr(a, attr_name) for a in clash_atoms: clash_vals = list(clashes[a].values()) clash_vals.sort() setattr(a, attr_name, clash_vals[-1]) if reveal: # display sidechain or backbone as appropriate for undisplayed atoms reveal_atoms = clash_atoms.filter(clash_atoms.displays == False) reveal_residues = reveal_atoms.unique_residues sc_rv_atoms = reveal_atoms.filter(reveal_atoms.is_side_chains == True) if sc_rv_atoms: sc_residues = sc_rv_atoms.unique_residues sc_res_atoms = sc_residues.atoms sc_res_atoms.filter( sc_res_atoms.is_side_chains == True).displays = True reveal_residues = reveal_residues - sc_residues bb_rv_atoms = reveal_atoms.filter(reveal_atoms.is_backbones() == True) if bb_rv_atoms: bb_residues = bb_rv_atoms.unique_residues bb_res_atoms = bb_residues.atoms bb_res_atoms.filter( bb_res_atoms.is_backbones() == True).displays = True reveal_residues = reveal_residues - bb_residues # also reveal non-polymeric atoms reveal_residues.atoms.displays = True if make_pseudobonds: if len(attr_atoms.unique_structures) > 1: pbg = session.pb_manager.get_group(name) else: pbg = attr_atoms[0].structure.pseudobond_group(name) pbg.clear() pbg.radius = radius if color is not None: pbg.color = color.uint8x4() if dashes is not None: pbg.dashes = dashes seen = set() for a in clash_atoms: seen.add(a) for clasher in clashes[a].keys(): if clasher in seen: continue pbg.new_pseudobond(a, clasher) if show_dist: session.pb_dist_monitor.add_group(pbg) else: session.pb_dist_monitor.remove_group(pbg) if pbg.id is None: session.models.add([pbg]) else: _xcmd(session, name) return clashes