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 _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 _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 _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 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 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 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 __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 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