def update(self, strand5p: StrandT, idx: int = None): """Pass ``idx`` to this method in order to install a floating Xover for the forced xover tool Args: strand5p: Description idx: Default is ``None`` """ self._strand5p = strand5p strand3p = strand5p.connection3p() vhi5p = self._virtual_helix_item part_item = vhi5p.partItem() # This condition is for floating xovers idx_3_prime = idx if idx else strand5p.idx3Prime() if self._node5 is None: self._node5 = XoverNode5(vhi5p, self, strand5p, idx_3_prime) if strand3p is not None: if self._node3 is None: vhi3p = part_item.idToVirtualHelixItem(strand3p.idNum()) self._node3 = XoverNode3(vhi3p, self, strand3p, strand3p.idx5Prime()) else: self._node5.setIdx(idx_3_prime) self._node3.setIdx(strand3p.idx5Prime()) self._node5.setPartnerVirtualHelix(strand5p) self._updatePath(strand5p) else: if self._node3: self._node3.destroyItem() self._node3 = None
def removeStrand(self, strand: StrandT, use_undostack: bool = True, solo: bool = True): """Remove a :class:`Strand` from the set Args: strand: the :class:`Strand` to remove use_undostack (optional): default = ``True`` solo ( optional): solo is an argument to enable limiting signals emiting from the command in the case the command is instantiated part of a larger command, default=``True`` """ cmds = [] if not self.isStrandInSet(strand): raise IndexError("Strandset.removeStrand: strand not in set") if strand.sequence() is not None: cmds.append(strand.oligo().applySequenceCMD(None)) cmds += strand.clearDecoratorCommands() cmds.append(RemoveStrandCommand(self, strand, solo=solo)) util.execCommandList(self, cmds, desc="Remove strand", use_undostack=use_undostack)
def setPartnerVirtualHelix(self, strand: StrandT): """ Args: strand: Description """ if strand.connection3p(): self._partner_virtual_helix_id_num = strand.connection3p().idNum() else: self._partner_virtual_helix_id_num = None
def __init__(self, strand: StrandT, idx: int, length: int): super(AddInsertionCommand, self).__init__("add insertion") self._strand = strand id_num = strand.idNum() self._insertions = strand.part().insertions()[id_num] self._idx = idx self._length = length self._insertion = Insertion(idx, length) self._comp_strand = \ strand.strandSet().complementStrandSet().getStrand(idx)
def __init__(self, strand: StrandT, idx: int, length: int): super(AddInsertionCommand, self).__init__("add insertion") self._strand = strand id_num = strand.idNum() self._insertions = strand.part().insertions()[id_num] self._idx = idx self._length = length self._insertion = Insertion(idx, length) self._comp_strand = \ strand.strandSet().complementStrandSet().getStrand(idx)
def __init__(self, model_strand: StrandT, virtual_helix_item: PathVirtualHelixItemT): """The parent should be a VirtualHelixItem. Args: model_strand: virtual_helix_item: """ super(StrandItem, self).__init__(virtual_helix_item) self._model_strand = model_strand self._virtual_helix_item = virtual_helix_item self._viewroot: PathRootItemT = virtual_helix_item._viewroot self._getActiveTool = self._viewroot.manager.activeToolGetter self._controller = StrandItemController(self, model_strand) is_forward = model_strand.strandSet().isForward() self._strand_filter = model_strand.strandFilter() self._insertion_items = {} # caps self._low_cap = EndpointItem(self, 'low', is_forward) self._high_cap = EndpointItem(self, 'high', is_forward) self._dual_cap = EndpointItem(self, 'dual', is_forward) # orientation self.is_forward = is_forward self._seq_label = QGraphicsSimpleTextItem(self) self.refreshInsertionItems(model_strand) if not getBatch(): self._updateSequenceText() # create a larger click area rect to capture mouse events self._click_area = c_a = QGraphicsRectItem(_DEFAULT_RECT, self) c_a.mousePressEvent = self.mousePressEvent c_a.setPen(_NO_PEN) self.setAcceptHoverEvents(True) c_a.setAcceptHoverEvents(True) c_a.hoverMoveEvent = self.hoverMoveEvent self.setZValue(styles.ZSTRANDITEM) # xover comming from the 3p end self.xover_3p_end = XoverItem(self, virtual_helix_item) if not getBatch(): # initial refresh self._updateColor(model_strand) self._updateAppearance(model_strand) self.setZValue(styles.ZSTRANDITEM) self.setFlag(QGraphicsItem.ItemIsSelectable)
def __init__(self, model_strand: StrandT, virtual_helix_item: PathVirtualHelixItemT): """The parent should be a VirtualHelixItem. Args: model_strand: virtual_helix_item: """ super(StrandItem, self).__init__(virtual_helix_item) self._model_strand = model_strand self._virtual_helix_item = virtual_helix_item self._viewroot: PathRootItemT = virtual_helix_item._viewroot self._getActiveTool = self._viewroot.manager.activeToolGetter self._controller = StrandItemController(self, model_strand) is_forward = model_strand.strandSet().isForward() self._strand_filter = model_strand.strandFilter() self._insertion_items = {} # caps self._low_cap = EndpointItem(self, 'low', is_forward) self._high_cap = EndpointItem(self, 'high', is_forward) self._dual_cap = EndpointItem(self, 'dual', is_forward) # orientation self.is_forward = is_forward self._seq_label = QGraphicsSimpleTextItem(self) self.refreshInsertionItems(model_strand) if not getBatch(): self._updateSequenceText() # create a larger click area rect to capture mouse events self._click_area = c_a = QGraphicsRectItem(_DEFAULT_RECT, self) c_a.mousePressEvent = self.mousePressEvent c_a.setPen(_NO_PEN) self.setAcceptHoverEvents(True) c_a.setAcceptHoverEvents(True) c_a.hoverMoveEvent = self.hoverMoveEvent self.setZValue(styles.ZSTRANDITEM) # xover comming from the 3p end self.xover_3p_end = XoverItem(self, virtual_helix_item) if not getBatch(): # initial refresh self._updateColor(model_strand) self._updateAppearance(model_strand) self.setZValue(styles.ZSTRANDITEM) self.setFlag(QGraphicsItem.ItemIsSelectable)
def canInstallXoverAt(self, idx: int, from_strand: StrandT, from_idx: int) -> bool: """Assumes idx is: self.lowIdx() <= idx <= self.highIdx() """ if self.hasXoverAt(idx): return False ss = self.strandSet() is_same_strand = from_strand == self is_forward = ss.isForward() index_diff_H = self.highIdx() - idx index_diff_L = idx - self.lowIdx() idx3p = self.idx3Prime() idx5p = self.idx5Prime() # ensure 2 bps from 3p end if not the 3p end index3_lim = idx3p - 1 if is_forward else idx3p + 1 if is_same_strand: index_diff_strands = from_idx - idx if idx == idx5p or idx == index3_lim: return True elif index_diff_strands > -3 and index_diff_strands < 3: return False # end if for same Strand else: from_idx3p = from_strand.idx3Prime() from_idx5p = from_strand.idx5Prime() if idx == idx5p or idx == index3_lim: if from_idx3p == from_idx: return True elif (abs(from_idx3p - from_idx) > 1 and abs(from_idx5p - from_idx) > 1): return True else: # print("this:", idx, idx3p, idx5p) # print("from:", from_idx, from_idx3p, from_idx5p) return False elif index_diff_H > 2 and index_diff_L > 1: if from_idx3p == from_idx: return True elif (abs(from_idx3p - from_idx) > 1 and abs(from_idx5p - from_idx) > 1): return True else: return False else: # print("default", index_diff_H, index_diff_L) return False
def __init__(self, virtual_helix_item: PathVirtualHelixItemT, xover_item: 'ForcedXoverItem', strand3p: StrandT, idx: int): """Summary Args: virtual_helix_item: from vhi xover_item (TYPE): Description strand3p (Strand): reference to the 3' strand idx (int): the base index within the virtual helix """ super(ForcedXoverNode3, self).__init__(virtual_helix_item) self._vhi = virtual_helix_item self._xover_item = xover_item self._idx = idx self.is_forward = strand3p.strandSet().isForward() self._is_on_top = self.is_forward self._partner_virtual_helix = virtual_helix_item self._blank_thing = QGraphicsRectItem(_blankRect, self) self._blank_thing.setBrush(QBrush(Qt.white)) self._path_thing = QGraphicsPathItem(self) self.configurePath() self._label = None self.setPen(_NO_PEN) self.setBrush(_NO_BRUSH) self.setRect(_rect) self.setZValue(styles.ZENDPOINTITEM + 1)
def strandCanBeSplit(self, strand: StrandT, base_idx: int) -> bool: """Make sure the base index is within the strand Don't split right next to a 3Prime end Don't split on endpoint (AKA a crossover) Args: strand: the :class:`Strand` base_idx: the index to split at Returns: ``True`` if can be split, ``False`` otherwise """ # no endpoints lo, hi = strand.idxs() if base_idx == lo or base_idx == hi: return False # make sure the base index within the strand elif lo > base_idx or base_idx > hi: return False elif self._is_fwd: if base_idx - lo > 0 and hi - base_idx > 1: return True else: return False elif base_idx - lo > 1 and hi - base_idx > 0: # reverse return True else: return False
def strandCanBeSplit(self, strand: StrandT, base_idx: int) -> bool: """Make sure the base index is within the strand Don't split right next to a 3Prime end Don't split on endpoint (AKA a crossover) Args: strand: the :class:`Strand` base_idx: the index to split at Returns: ``True`` if can be split, ``False`` otherwise """ # no endpoints lo, hi = strand.idxs() if base_idx == lo or base_idx == hi: return False # make sure the base index within the strand elif lo > base_idx or base_idx > hi: return False elif self._is_fwd: if base_idx - lo > 0 and hi - base_idx > 1: return True else: return False elif base_idx - lo > 1 and hi - base_idx > 0: # reverse return True else: return False
def __init__(self, virtual_helix_item: PathVirtualHelixItemT, xover_item: 'ForcedXoverItem', strand3p: StrandT, idx: int): """Summary Args: virtual_helix_item: from vhi xover_item (TYPE): Description strand3p (Strand): reference to the 3' strand idx (int): the base index within the virtual helix """ super(ForcedXoverNode3, self).__init__(virtual_helix_item) self._vhi = virtual_helix_item self._xover_item = xover_item self._idx = idx self.is_forward = strand3p.strandSet().isForward() self._is_on_top = self.is_forward self._partner_virtual_helix = virtual_helix_item self._blank_thing = QGraphicsRectItem(_blankRect, self) self._blank_thing.setBrush(QBrush(Qt.white)) self._path_thing = QGraphicsPathItem(self) self.configurePath() self._label = None self.setPen(_NO_PEN) self.setBrush(_NO_BRUSH) self.setRect(_rect) self.setZValue(styles.ZENDPOINTITEM + 1)
def __init__(self, document: DocT, strand: StrandT, idx: int, mod_id: str): super(AddModsCommand, self).__init__() self._strand = strand self._id_num = strand.idNum() self._idx = idx self._mod_id = mod_id self.document = document
def __init__(self, document: DocT, strand: StrandT, idx: int, mod_id: str): super(AddModsCommand, self).__init__() self._strand = strand self._id_num = strand.idNum() self._idx = idx self._mod_id = mod_id self.document = document
def strandResizedSlot(self, strand: StrandT, indices: SegmentT): """Slot for handling resizing of this StrandItem Args: strand: indices: low and high indices """ low_moved, group_low = self._low_cap.updatePosIfNecessary( self.idxs()[0]) high_moved, group_high = self._high_cap.updatePosIfNecessary( self.idxs()[1]) group = self.group() self.tempReparent() if low_moved: self.updateLine(self._low_cap) if high_moved: self.updateLine(self._high_cap) if strand.connection3p(): self.xover_3p_end.update(strand) self.refreshInsertionItems(strand) self._updateSequenceText() if group: group.addToGroup(self) if group_low is not None: group_low.addToGroup(self._low_cap) if group_high is not None: group_high.addToGroup(self._high_cap)
def strandResizedSlot(self, strand: StrandT, indices: SegmentT): """Slot for handling resizing of this StrandItem Args: strand: indices: low and high indices """ low_moved, group_low = self._low_cap.updatePosIfNecessary(self.idxs()[0]) high_moved, group_high = self._high_cap.updatePosIfNecessary(self.idxs()[1]) group = self.group() self.tempReparent() if low_moved: self.updateLine(self._low_cap) if high_moved: self.updateLine(self._high_cap) if strand.connection3p(): self.xover_3p_end.update(strand) self.refreshInsertionItems(strand) self._updateSequenceText() if group: group.addToGroup(self) if group_low is not None: group_low.addToGroup(self._low_cap) if group_high is not None: group_high.addToGroup(self._high_cap)
def upperLeftCornerOfBase(self, idx: int, strand: StrandT) -> Vec2T: """ Args: idx: the base index within the virtual helix strand: Description Returns: Tuple of upperLeftCornerOfBase """ x = idx * _BASE_WIDTH y = 0 if strand.isForward() else _BASE_WIDTH return x, y
def __init__(self, strand: StrandT, new_idxs: SegmentT, update_segments: bool = True): super(ResizeCommand, self).__init__("resize strand") self.strand = strand self.old_indices = o_i = strand.idxs() self.new_idxs = new_idxs # an increase in length leads to positive delta self.delta = (new_idxs[1] - new_idxs[0]) - (o_i[1] - o_i[0]) # now handle insertion deltas oldInsertions = strand.insertionsOnStrand(*o_i) newInsertions = strand.insertionsOnStrand(*new_idxs) o_l = 0 for i in oldInsertions: o_l += i.length() n_l = 0 for i in newInsertions: n_l += i.length() self.delta += (n_l - o_l) self.update_segments = update_segments
def removeStrand(self, strand: StrandT, use_undostack: bool = True, solo: bool = True): """Remove a :class:`Strand` from the set Args: strand: the :class:`Strand` to remove use_undostack (optional): default = ``True`` solo ( optional): solo is an argument to enable limiting signals emiting from the command in the case the command is instantiated part of a larger command, default=``True`` """ cmds = [] if not self.isStrandInSet(strand): raise IndexError("Strandset.removeStrand: strand not in set") if strand.sequence() is not None: cmds.append(strand.oligo().applySequenceCMD(None)) cmds += strand.clearDecoratorCommands() cmds.append(RemoveStrandCommand(self, strand, solo=solo)) util.execCommandList(self, cmds, desc="Remove strand", use_undostack=use_undostack)
def upperLeftCornerOfBase(self, idx: int, strand: StrandT) -> Vec2T: """ Args: idx: the base index within the virtual helix strand: Description Returns: Tuple of upperLeftCornerOfBase """ x = idx * _BASE_WIDTH y = 0 if strand.isForward() else _BASE_WIDTH return x, y
def _addToStrandList(self, strand: StrandT, update_segments: bool = True): """Inserts strand into the strand_array at idx Args: strand: the strand to add update_segments (optional): whether to signal default=``True`` """ idx_low, idx_high = strand.idxs() for i in range(idx_low, idx_high+1): self.strand_array[i] = strand insort_left(self.strand_heap, strand) if update_segments: self._part.refreshSegments(self._id_num)
def __init__(self, strand: StrandT, new_idxs: SegmentT, update_segments: bool = True): super(ResizeCommand, self).__init__("resize strand") self.strand = strand self.old_indices = o_i = strand.idxs() self.new_idxs = new_idxs # an increase in length leads to positive delta self.delta = (new_idxs[1] - new_idxs[0]) - (o_i[1] - o_i[0]) # now handle insertion deltas oldInsertions = strand.insertionsOnStrand(*o_i) newInsertions = strand.insertionsOnStrand(*new_idxs) o_l = 0 for i in oldInsertions: o_l += i.length() n_l = 0 for i in newInsertions: n_l += i.length() self.delta += (n_l - o_l) self.update_segments = update_segments
def strandHasNewOligoSlot(self, strand: StrandT): """Slot for changing the `Oligo` of the model `Strand` Args: strand: """ strand = self._model_strand self._controller.reconnectOligoSignals() self._updateColor(strand) if strand.connection3p(): self.xover_3p_end._updateColor(strand) for insertion in self.insertionItems().values(): insertion.updateItem()
def _addToStrandList(self, strand: StrandT, update_segments: bool = True): """Inserts strand into the strand_array at idx Args: strand: the strand to add update_segments (optional): whether to signal default=``True`` """ idx_low, idx_high = strand.idxs() for i in range(idx_low, idx_high + 1): self.strand_array[i] = strand insort_left(self.strand_heap, strand) if update_segments: self._part.refreshSegments(self._id_num)
def strandHasNewOligoSlot(self, strand: StrandT): """Slot for changing the `Oligo` of the model `Strand` Args: strand: """ strand = self._model_strand self._controller.reconnectOligoSignals() self._updateColor(strand) if strand.connection3p(): self.xover_3p_end._updateColor(strand) for insertion in self.insertionItems().values(): insertion.updateItem()
def updateForFloatFromStrand(self, virtual_helix_item: PathVirtualHelixItemT, strand3p: StrandT, idx: int): """ Args: virtual_helix_item: Description strand3p: reference to the 3' strand idx: the base index within the virtual helix """ self._vhi = virtual_helix_item self._strand = strand3p self.setParentItem(virtual_helix_item) self._idx = idx self._is_on_top = self.is_forward = strand3p.strandSet().isForward() self.updatePositionAndAppearance()
def _removeFromStrandList(self, strand: StrandT, update_segments: bool = True): """Remove strand from strand_array. Args: strand: the strand update_segments (optional): whether to signal default=``True`` """ self._document.removeStrandFromSelection(strand) # make sure the strand is no longer selected idx_low, idx_high = strand.idxs() for i in range(idx_low, idx_high + 1): self.strand_array[i] = None i = bisect_left(self.strand_heap, strand) self.strand_heap.pop(i) if update_segments: self._part.refreshSegments(self._id_num)
def updateForFloatFromStrand(self, virtual_helix_item: PathVirtualHelixItemT, strand3p: StrandT, idx: int): """ Args: virtual_helix_item: Description strand3p: reference to the 3' strand idx: the base index within the virtual helix """ self._vhi = virtual_helix_item self._strand = strand3p self.setParentItem(virtual_helix_item) self._idx = idx self._is_on_top = self.is_forward = strand3p.strandSet().isForward() self.updatePositionAndAppearance()
def _removeFromStrandList(self, strand: StrandT, update_segments: bool = True): """Remove strand from strand_array. Args: strand: the strand update_segments (optional): whether to signal default=``True`` """ self._document.removeStrandFromSelection(strand) # make sure the strand is no longer selected idx_low, idx_high = strand.idxs() for i in range(idx_low, idx_high + 1): self.strand_array[i] = None i = bisect_left(self.strand_heap, strand) self.strand_heap.pop(i) if update_segments: self._part.refreshSegments(self._id_num)
def oligoStrandRemover(self, strand: StrandT, cmds: List[UndoCommand], solo: bool = True): """Used for removing all :class:`Strand`s from an :class:`Oligo` Args: strand: a strand to remove cmds: a list of :class:`UndoCommand` objects to append to solo (:optional): to pass on to ``RemoveStrandCommand``, default=``True`` """ if not self.isStrandInSet(strand): raise IndexError("Strandset.oligoStrandRemover: strand not in set") cmds += strand.clearDecoratorCommands() cmds.append(RemoveStrandCommand(self, strand, solo=solo))
def oligoStrandRemover(self, strand: StrandT, cmds: List[UndoCommand], solo: bool = True): """Used for removing all :class:`Strand`s from an :class:`Oligo` Args: strand: a strand to remove cmds: a list of :class:`UndoCommand` objects to append to solo (:optional): to pass on to ``RemoveStrandCommand``, default=``True`` """ if not self.isStrandInSet(strand): raise IndexError("Strandset.oligoStrandRemover: strand not in set") cmds += strand.clearDecoratorCommands() cmds.append(RemoveStrandCommand(self, strand, solo=solo))
def _updateColor(self, strand: StrandT): oligo = strand.oligo() color = SELECT_COLOR if self.isSelected() else oligo.getColor() if oligo.shouldHighlight(): alpha = 128 pen_width = styles.PATH_STRAND_HIGHLIGHT_STROKE_WIDTH else: pen_width = styles.PATH_STRAND_STROKE_WIDTH alpha = None self.xover_3p_end._updateColor(strand) pen = getPenObj(color, pen_width, alpha=alpha, capstyle=Qt.FlatCap) brush = getBrushObj(color, alpha=alpha) self.setPen(pen) self._low_cap.updateHighlight(brush) self._high_cap.updateHighlight(brush) self._dual_cap.updateHighlight(brush)
def strandModsChangedSlot(self, strand: StrandT, document: DocT, mod_id: str, idx: int): """Slot for changing a modification on the Strand Args: strand: document: mod_id: idx: """ idx_l, idx_h = strand.idxs() color = document.getModProperties(mod_id)['color'] if idx == idx_h: self._high_cap.changeMod(mod_id, color) else: self._low_cap.changeMod(mod_id, color)
def strandModsRemovedSlot(self, strand: StrandT, document: DocT, mod_id: str, idx: int): """Slot for removing a modification on the Strand Args: strand: document: mod_id: idx: """ idx_l, idx_h = strand.idxs() # color = document.getModProperties(mod_id)['color'] if idx == idx_h: self._high_cap.destroyMod() else: self._low_cap.destroyMod()
def __init__(self, virtual_helix_item: PathVirtualHelixItemT, strand: StrandT, insertion: InsertionT): super(InsertionItem, self).__init__(virtual_helix_item) self.hide() self._strand = strand self._insertion = insertion self._seq_item = QGraphicsPathItem(parent=self) self._is_on_top = is_on_top = strand.isForward() y = 0 if is_on_top else _BW self.setPos(_BW*insertion.idx(), y) self.setZValue(styles.ZINSERTHANDLE) self._initLabel() self._initClickArea() self.updateItem() self.show()
def _updateColor(self, strand: StrandT): oligo = strand.oligo() color = SELECT_COLOR if self.isSelected() else oligo.getColor() if oligo.shouldHighlight(): alpha = 128 pen_width = styles.PATH_STRAND_HIGHLIGHT_STROKE_WIDTH else: pen_width = styles.PATH_STRAND_STROKE_WIDTH alpha = None self.xover_3p_end._updateColor(strand) pen = getPenObj(color, pen_width, alpha=alpha, capstyle=Qt.FlatCap) brush = getBrushObj(color, alpha=alpha) self.setPen(pen) self._low_cap.updateHighlight(brush) self._high_cap.updateHighlight(brush) self._dual_cap.updateHighlight(brush)
def strandModsAddedSlot(self, strand: StrandT, document: DocT, mod_id: str, idx: int): """Slot for adding a modification on the Strand Args: strand: document: mod_id: idx: """ if self._viewroot.are_signals_on: idx_l, idx_h = strand.idxs() color = document.getModProperties(mod_id)['color'] if idx == idx_h: self._high_cap.showMod(mod_id, color) else: self._low_cap.showMod(mod_id, color)
def strandModsChangedSlot(self, strand: StrandT, document: DocT, mod_id: str, idx: int): """Slot for changing a modification on the Strand Args: strand: document: mod_id: idx: """ idx_l, idx_h = strand.idxs() color = document.getModProperties(mod_id)['color'] if idx == idx_h: self._high_cap.changeMod(mod_id, color) else: self._low_cap.changeMod(mod_id, color)
def strandModsRemovedSlot(self, strand: StrandT, document: DocT, mod_id: str, idx: int): """Slot for removing a modification on the Strand Args: strand: document: mod_id: idx: """ idx_l, idx_h = strand.idxs() # color = document.getModProperties(mod_id)['color'] if idx == idx_h: self._high_cap.destroyMod() else: self._low_cap.destroyMod()
def strandModsAddedSlot(self, strand: StrandT, document: DocT, mod_id: str, idx: int): """Slot for adding a modification on the Strand Args: strand: document: mod_id: idx: """ if self._viewroot.are_signals_on: idx_l, idx_h = strand.idxs() color = document.getModProperties(mod_id)['color'] if idx == idx_h: self._high_cap.showMod(mod_id, color) else: self._low_cap.showMod(mod_id, color)
def _updateColor(self, strand: StrandT): """ Args: strand (TYPE): Description """ oligo = strand.oligo() color = self.pen().color().name() if self.isSelected( ) else oligo.getColor() if color is None: print("None color:", color, self.isSelected()) color = '#cc0000' if oligo.shouldHighlight(): pen_width = styles.PATH_STRAND_HIGHLIGHT_STROKE_WIDTH alpha = 128 else: pen_width = styles.PATH_STRAND_STROKE_WIDTH alpha = 255 pen = getPenObj(color, pen_width, alpha=alpha, capstyle=Qt.FlatCap) self.setPen(pen)
def __init__(self, virtual_helix_item: PathVirtualHelixItemT, xover_item: PathXoverItemT, strand3p: StrandT, idx: int): """ Args: virtual_helix_item: Description xover_item: Description strand3p: reference to the 3' strand idx: the base index within the virtual helix """ super(XoverNode3, self).__init__(virtual_helix_item) self._vhi = virtual_helix_item self._xover_item = xover_item self._idx = idx self.is_forward = strand3p.strandSet().isForward() self.setPartnerVirtualHelix(strand3p) self.setPen(getNoPen()) self._label = None self.setBrush(_NO_BRUSH) self.setRect(_RECT) self.setZValue(styles.ZXOVERITEM)
def refreshInsertionItems(self, strand: StrandT): i_items = self.insertionItems() i_model = strand.insertionsOnStrand() was_in_use = set(i_items) in_use = set() # add in the ones supposed to be there for insertion in i_model: idx = insertion.idx() in_use.add(idx) if idx in i_items: pass else: i_items[insertion.idx()] = \ InsertionItem(self._virtual_helix_item, strand, insertion) # end for # remove all in items not_in_use = was_in_use - in_use for index in not_in_use: i_items[index].destroyItem() del i_items[index]
def refreshInsertionItems(self, strand: StrandT): i_items = self.insertionItems() i_model = strand.insertionsOnStrand() was_in_use = set(i_items) in_use = set() # add in the ones supposed to be there for insertion in i_model: idx = insertion.idx() in_use.add(idx) if idx in i_items: pass else: i_items[insertion.idx()] = \ InsertionItem(self._virtual_helix_item, strand, insertion) # end for # remove all in items not_in_use = was_in_use - in_use for index in not_in_use: i_items[index].destroyItem() del i_items[index]
def isStrandInSet(self, strand: StrandT) -> bool: sl = self.strand_array if sl[strand.lowIdx()] == strand and sl[strand.highIdx()] == strand: return True else: return False
def setComplementSequence(self, sequence: str, strand: StrandT) -> str: """This version takes anothers strand and only sets the indices that align with the given complimentary strand. As it depends which direction this is going, and strings are stored in memory left to right, we need to test for is_forward to map the reverse compliment appropriately, as we traverse overlapping strands. We reverse the sequence ahead of time if we are applying it 5' to 3', otherwise we reverse the sequence post parsing if it's 3' to 5' Again, sequences are stored as strings in memory 5' to 3' so we need to jump through these hoops to iterate 5' to 3' through them correctly Perhaps it's wiser to merely store them left to right and reverse them at draw time, or export time Args: sequence (str): strand (Strand): Returns: str: the used portion of the sequence """ s_low_idx, s_high_idx = self._base_idx_low, self._base_idx_high c_low_idx, c_high_idx = strand.idxs() is_forward = self._is_forward self_seq = self._sequence # get the ovelap low_idx, high_idx = util.overlap(s_low_idx, s_high_idx, c_low_idx, c_high_idx) # only get the characters we're using, while we're at it, make it the # reverse compliment total_length = self.totalLength() # see if we are applying if sequence is None: # clear out string for in case of not total overlap use_seq = ''.join([' ' for x in range(total_length)]) else: # use the string as is use_seq = sequence[::-1] if is_forward else sequence temp = array(ARRAY_TYPE, sixb(use_seq)) if self_seq is None: temp_self = array(ARRAY_TYPE, sixb(''.join([' ' for x in range(total_length)]))) else: temp_self = array(ARRAY_TYPE, sixb(self_seq) if is_forward else sixb(self_seq[::-1])) # generate the index into the compliment string a = self.insertionLengthBetweenIdxs(s_low_idx, low_idx - 1) b = self.insertionLengthBetweenIdxs(low_idx, high_idx) c = strand.insertionLengthBetweenIdxs(c_low_idx, low_idx - 1) start = low_idx - c_low_idx + c end = start + b + high_idx - low_idx + 1 temp_self[low_idx - s_low_idx + a:high_idx - s_low_idx + 1 + a + b] = temp[start:end] # print("old sequence", self_seq) self._sequence = tostring(temp_self) # if we need to reverse it do it now if not is_forward: self._sequence = self._sequence[::-1] # test to see if the string is empty(), annoyingly expensive # if len(self._sequence.strip()) == 0: if not self._sequence: self._sequence = None # print("new sequence", self._sequence) return self._sequence
def _updateAppearance(self, strand: StrandT): """Prepare Strand for drawing, positions are relative to the :class:`PathVirtualHelixItem`: 1. Show or hide caps depending on L and R connectivity. 2. Determine line coordinates. 3. Apply paint styles. """ # 0. Setup vhi = self._virtual_helix_item bw = _BASE_WIDTH half_base_width = bw / 2.0 low_idx, high_idx = strand.lowIdx(), strand.highIdx() l_upper_left_x, l_upper_left_y = vhi.upperLeftCornerOfBase( low_idx, strand) h_upper_left_x, h_upper_left_y = vhi.upperLeftCornerOfBase( high_idx, strand) low_cap = self._low_cap high_cap = self._high_cap dual_cap = self._dual_cap # 1. Cap visibilty lx = l_upper_left_x + bw # draw from right edge of base low_cap.safeSetPos(l_upper_left_x, l_upper_left_y) if strand.connectionLow() is not None: # has low xover # if we are hiding it, we might as well make sure it is reparented to the StrandItem low_cap.restoreParent() low_cap.hide() else: # has low cap if not low_cap.isVisible(): low_cap.show() hx = h_upper_left_x # draw to edge of base high_cap.safeSetPos(h_upper_left_x, h_upper_left_y) if strand.connectionHigh() is not None: # has high xover # if we are hiding it, we might as well make sure it is reparented to the StrandItem high_cap.restoreParent() high_cap.hide() else: # has high cap if not high_cap.isVisible(): high_cap.show() # special case: single-base strand with no L or H connections, # (unconnected caps were made visible in previous block of code) if strand.length() == 1 and (low_cap.isVisible() and high_cap.isVisible()): low_cap.hide() high_cap.hide() dual_cap.safeSetPos(l_upper_left_x, l_upper_left_y) dual_cap.show() else: dual_cap.hide() # 2. Xover drawing xo = self.xover_3p_end if strand.connection3p(): xo.update(strand) xo.showIt() else: xo.restoreParent() xo.hideIt() # 3. Refresh insertionItems if necessary drawing self.refreshInsertionItems(strand) # 4. Line drawing hy = ly = l_upper_left_y + half_base_width self.setLine(lx, ly, hx, hy) rectf = QRectF(l_upper_left_x + bw, l_upper_left_y, bw * (high_idx - low_idx - 1), bw) self._click_area.setRect(rectf) self._updateColor(strand)
def isStrandInSet(self, strand: StrandT) -> bool: sl = self.strand_array if sl[strand.lowIdx()] == strand and sl[strand.highIdx()] == strand: return True else: return False
def _updateAppearance(self, strand: StrandT): """Prepare Strand for drawing, positions are relative to the :class:`PathVirtualHelixItem`: 1. Show or hide caps depending on L and R connectivity. 2. Determine line coordinates. 3. Apply paint styles. """ # 0. Setup vhi = self._virtual_helix_item bw = _BASE_WIDTH half_base_width = bw / 2.0 low_idx, high_idx = strand.lowIdx(), strand.highIdx() l_upper_left_x, l_upper_left_y = vhi.upperLeftCornerOfBase(low_idx, strand) h_upper_left_x, h_upper_left_y = vhi.upperLeftCornerOfBase(high_idx, strand) low_cap = self._low_cap high_cap = self._high_cap dual_cap = self._dual_cap # 1. Cap visibilty lx = l_upper_left_x + bw # draw from right edge of base low_cap.safeSetPos(l_upper_left_x, l_upper_left_y) if strand.connectionLow() is not None: # has low xover # if we are hiding it, we might as well make sure it is reparented to the StrandItem low_cap.restoreParent() low_cap.hide() else: # has low cap if not low_cap.isVisible(): low_cap.show() hx = h_upper_left_x # draw to edge of base high_cap.safeSetPos(h_upper_left_x, h_upper_left_y) if strand.connectionHigh() is not None: # has high xover # if we are hiding it, we might as well make sure it is reparented to the StrandItem high_cap.restoreParent() high_cap.hide() else: # has high cap if not high_cap.isVisible(): high_cap.show() # special case: single-base strand with no L or H connections, # (unconnected caps were made visible in previous block of code) if strand.length() == 1 and (low_cap.isVisible() and high_cap.isVisible()): low_cap.hide() high_cap.hide() dual_cap.safeSetPos(l_upper_left_x, l_upper_left_y) dual_cap.show() else: dual_cap.hide() # 2. Xover drawing xo = self.xover_3p_end if strand.connection3p(): xo.update(strand) xo.showIt() else: xo.restoreParent() xo.hideIt() # 3. Refresh insertionItems if necessary drawing self.refreshInsertionItems(strand) # 4. Line drawing hy = ly = l_upper_left_y + half_base_width self.setLine(lx, ly, hx, hy) rectf = QRectF(l_upper_left_x + bw, l_upper_left_y, bw*(high_idx - low_idx - 1), bw) self._click_area.setRect(rectf) self._updateColor(strand)
def __init__(self, strand_item, model_strand: StrandT): self._model_strand = model_strand self._model_oligo = model_strand.oligo() self._strand_item = strand_item self.connectSignals()
def __init__(self, strand_item, model_strand: StrandT): self._model_strand = model_strand self._model_oligo = model_strand.oligo() self._strand_item = strand_item self.connectSignals()