diff --git a/src/hgvs/pretty/renderer/chrom_seq_renderer.py b/src/hgvs/pretty/renderer/chrom_seq_renderer.py new file mode 100644 index 00000000..dfd888ed --- /dev/null +++ b/src/hgvs/pretty/renderer/chrom_seq_renderer.py @@ -0,0 +1,37 @@ +from hgvs.pretty.models import VariantData +from hgvs.pretty.renderer.renderer import BasicRenderer + + +class ChromSeqRendered(BasicRenderer): + + def legend(self)->str: + return "seq -> : " + + def display(self, data:VariantData)->str: + """colors the ref sequences with adenine (A, green), thymine (T, red), cytosine (C, yellow), and guanine (G, blue)""" + from hgvs.pretty_print import ENDC, TBLUE, TGREEN, TRED, TYELLOW + + var_seq = "" + for p in data.position_details: + c = p.ref + + if not c: + var_seq += "." + continue + + if self.config.useColor: + if c == "A": + var_seq += TGREEN + elif c == "T": + var_seq += TRED + elif c == "C": + var_seq += TYELLOW + elif c == "G": + var_seq += TBLUE + + var_seq += c + + if self.config.useColor: + var_seq += ENDC + + return var_seq diff --git a/src/hgvs/pretty/renderer/pos_info.py b/src/hgvs/pretty/renderer/pos_info.py new file mode 100644 index 00000000..85395c3e --- /dev/null +++ b/src/hgvs/pretty/renderer/pos_info.py @@ -0,0 +1,33 @@ +from hgvs.pretty.models import VariantData +from hgvs.pretty.renderer.renderer import BasicRenderer + + +class ChrPositionInfo(BasicRenderer): + + def legend(self): + return " : " + + def display(self, data: VariantData) -> str: + + count = -1 + var_seq = "" + for pdata in data.position_details: + count += 1 + g = pdata.chromosome_pos + + total_chars = len(var_seq) + + if total_chars > count: + continue + + if not g: + var_seq += " " + continue + + if g % 10 == 0: + var_seq += f"{g:,} " + + else: + var_seq += " " + + return var_seq.rstrip() \ No newline at end of file diff --git a/src/hgvs/pretty/renderer/prot_seq_renderer.py b/src/hgvs/pretty/renderer/prot_seq_renderer.py new file mode 100644 index 00000000..82dabddd --- /dev/null +++ b/src/hgvs/pretty/renderer/prot_seq_renderer.py @@ -0,0 +1,75 @@ +from hgvs.pretty.models import VariantData +from hgvs.pretty.renderer.renderer import BasicRenderer + + +class ProtSeqRenderer(BasicRenderer): + + def legend(self): + legend = "aa seq -> : " + if self.orientation < 0: + legend = "aa seq <- : " + return legend + + def display(self, data: VariantData) -> str: + if not data.var_c_or_n: + return "" + + from hgvs.pretty_print import ENDC, TGREEN, TRED + + var_str = "" + for pdata in data.position_details: + + p = pdata.chromosome_pos + + if not pdata.mapped_pos: + var_str += " " + continue + + ref_base = pdata.ref + + c_interval = pdata.c_interval + if not c_interval: + var_str += " " + continue + + cig = pdata.cigar_ref + c_offset = pdata.c_offset + if cig == "N" or c_offset != 0: + var_str += " " + continue + + if cig == "I": + var_str += "-" + continue + + if not ref_base or pdata.tx: + ref_base = pdata.tx + + protein_data = pdata.protein_data + + if not protein_data: + var_str += " " + continue + + aa_char = protein_data.aa_char + + # color init met and stop codon if using color: + if protein_data.is_init_met: + if self.config.useColor: + aa_char = TGREEN + aa_char + ENDC + var_str += aa_char + continue + if protein_data.is_stop_codon: + if self.config.useColor: + aa_char = TRED + aa_char + ENDC + var_str += aa_char + continue + + if not protein_data.var_p.posedit: + var_str += " " + continue + + var_str += aa_char + continue + + return var_str \ No newline at end of file diff --git a/src/hgvs/pretty/renderer/renderer.py b/src/hgvs/pretty/renderer/renderer.py new file mode 100644 index 00000000..a0d33d5e --- /dev/null +++ b/src/hgvs/pretty/renderer/renderer.py @@ -0,0 +1,14 @@ +from abc import ABC, abstractmethod + +class BasicRenderer(ABC): + def __init__(self, config, orientation:int): + self.config = config + self.orientation = orientation + + @abstractmethod + def legend(self): + pass + + @abstractmethod + def display(self): + pass diff --git a/src/hgvs/pretty/renderer/ruler.py b/src/hgvs/pretty/renderer/ruler.py new file mode 100644 index 00000000..e8d3f3cb --- /dev/null +++ b/src/hgvs/pretty/renderer/ruler.py @@ -0,0 +1,31 @@ +from hgvs.pretty.models import VariantData +from hgvs.pretty.renderer.renderer import BasicRenderer + + +class ChrRuler(BasicRenderer): + + def legend(self): + """ returns the legend for this category of display""" + return "chrom pos : " + + def display(self, data: VariantData) -> str: + """Draw a position indicator that diplays | every 10 bases and a . every 5 + + seq_start/end in interbase + """ + + ruler = "" + + for pd in data.position_details: + p = pd.chromosome_pos + if not p: + ruler += "_" + continue + + if p % 10 == 0: + ruler += "|" + elif p % 5 == 0: + ruler += "." + else: + ruler += " " + return ruler \ No newline at end of file diff --git a/src/hgvs/pretty/renderer/shuffled_variant.py b/src/hgvs/pretty/renderer/shuffled_variant.py new file mode 100644 index 00000000..74b0d735 --- /dev/null +++ b/src/hgvs/pretty/renderer/shuffled_variant.py @@ -0,0 +1,93 @@ + + +from hgvs.pretty.models import VariantCoords, VariantData +from hgvs.pretty.renderer.renderer import BasicRenderer +from hgvs.sequencevariant import SequenceVariant + + +class ShuffledVariant(BasicRenderer): + + def __init__(self, config, orientation:int, var_g: SequenceVariant, vc: VariantCoords)->None: + super().__init__(config, orientation) + + self.var_g = var_g + self.vc = vc + + def legend(self + ) ->str: + + return "region : " + + def display( + self, data: VariantData + ) -> str: + + from hgvs.pretty_print import ENDC, TBLUE, TGREEN, TRED, TYELLOW + + seq_start = data.display_start + seq_end = data.display_end + + split_char = "|" + + start = self.vc.start + end = self.vc.end + + # map interbase coordinates to 1-based display coords: + start = start + 1 + + if self.var_g.posedit.edit.type == "sub": + end = start + if len(self.vc.alt) == 1: + split_char = self.vc.alt + l = end - start + 1 + if self.var_g.posedit.edit.type == "ins" and l == 0: + start = start - 1 + end = end + 1 + split_char = "^" + + if self.var_g.posedit.edit.type == "del": + split_char = "" + if self.config.useColor: + split_char = TRED + split_char += "x" + if self.config.useColor: + split_char += ENDC + + elif self.var_g.posedit.edit.type == "identity": + split_char = "=" + # print(l,start, end , vc) + + if start < seq_start: + # raise ValueError(f"Can't create shuffled representation, since start {start} < seq_start {seq_start} ") + return "" + if end > seq_end: + return "" + # raise ValueError(f"Can't create shuffled representation, since end {end} > seq_end {seq_end} ") + + var_str = "" + in_range = False + for pdata in data.position_details: + p = pdata.chromosome_pos + + if not p: + if in_range: + var_str += "-" + else: + var_str += " " + continue + + if p == start: + var_str += split_char + in_range = True + elif p == end: + var_str += split_char + in_range = False + elif p > end and in_range: + in_range = False + var_str += " " + elif in_range: + var_str += "-" + else: + var_str += " " + + return var_str \ No newline at end of file diff --git a/src/hgvs/pretty/renderer/tx_alig_renderer.py b/src/hgvs/pretty/renderer/tx_alig_renderer.py new file mode 100644 index 00000000..eeb84b34 --- /dev/null +++ b/src/hgvs/pretty/renderer/tx_alig_renderer.py @@ -0,0 +1,96 @@ +import math +from hgvs.pretty.models import VariantData +from hgvs.pretty.renderer.renderer import BasicRenderer + + +class TxAligRenderer(BasicRenderer): + + def legend(self)->str: + orientation = "->" + if self.orientation < 0: + orientation = "<-" + return f"tx seq {orientation} : " + + + def display(self, data: VariantData) -> str: + """If transcript info is available show the details of the tx for the region.""" + if not data.var_c_or_n: + return "" + + from hgvs.pretty_print import ENDC, TYELLOW, TPURPLE + var_str = "" + + first_c = None + last_c = None + + coding = False + c_pos = None + + counter = -1 + for pdata in data.position_details: + + counter += 1 + + if not pdata.mapped_pos: + var_str += " " + continue + + + n_pos = pdata.n_pos + c_pos = pdata.c_pos + cig = pdata.cigar_ref + c_offset = pdata.c_offset + + if cig == "N" or (c_offset is not None and c_offset != 0): + coding = False + var_str += " " + continue + + + if c_pos: + # if we get here we are coding... + last_c = f"c.{c_pos}" + else: + last_c = f"n.{n_pos}" + c_pos = n_pos + if not coding: + + if not first_c: + first_c = last_c + + coding = True + + if cig == "=": + #c3 = (c_pos - 1) % 3 + if c_pos: + bg_col = math.ceil(c_pos / 3) % 2 + elif n_pos: + bg_col = math.ceil(n_pos / 3) % 2 + else: + var_str += " " + continue + + # print(p, c_pos, c3, bg_col ) + if n_pos >= 0: + base = pdata.tx + if self.config.useColor and c_pos > 0: + if bg_col: + var_str += TPURPLE + base + ENDC + else: + var_str += TYELLOW + base + ENDC + else: + if c_pos is None or c_pos < 0: + var_str += base.lower() + else: + var_str += base + continue + + elif cig == "X" or cig == "D": + # for mismatches and tx-insertions show sequence + var_str += pdata.tx + continue + + else: + var_str += "-" + + return var_str \ No newline at end of file diff --git a/src/hgvs/pretty/renderer/tx_mapping_renderer.py b/src/hgvs/pretty/renderer/tx_mapping_renderer.py new file mode 100644 index 00000000..52d21e70 --- /dev/null +++ b/src/hgvs/pretty/renderer/tx_mapping_renderer.py @@ -0,0 +1,67 @@ +from hgvs.pretty.models import VariantData +from hgvs.pretty.renderer.renderer import BasicRenderer + + +class TxMappingRenderer(BasicRenderer): + """ prints the position in c/n coordinates. """ + + def legend(self): + return "tx pos : " + + def display(self, data: VariantData) -> str: + """show the position of the transcript seq""" + + var_str = "" + + count = -1 + prev_c_pos = '' + for pdata in data.position_details: + count += 1 + if not pdata.mapped_pos: + var_str += " " + prev_c_pos = '' + continue + + c_pos = pdata.c_pos + if c_pos is None and pdata.n_pos: + c_pos = pdata.n_pos + + if c_pos is None: + var_str += " " + prev_c_pos = c_pos + continue + + if pdata.cigar_ref == 'N': + var_str += " " + prev_c_pos = c_pos + continue + + if len(var_str) > count: + prev_c_pos = c_pos + continue + + if (c_pos + 1) % 10 == 0: + var_str += "|" + prev_c_pos = c_pos + continue + + elif (c_pos + 1) % 5 == 0: + var_str += "." + prev_c_pos = c_pos + continue + + elif prev_c_pos and prev_c_pos == c_pos and pdata.c_offset > 0 and (pdata.c_offset % 10) == 0: + var_str += "^" + prev_c_pos = c_pos + continue + elif prev_c_pos and prev_c_pos == c_pos and pdata.c_offset > 0 and (pdata.c_offset % 5) == 0: + var_str += "." + prev_c_pos = c_pos + continue + + elif c_pos == 0: + var_str += "|" + + var_str += " " + + return var_str \ No newline at end of file diff --git a/src/hgvs/pretty/renderer/tx_pos.py b/src/hgvs/pretty/renderer/tx_pos.py new file mode 100644 index 00000000..9bbe19d0 --- /dev/null +++ b/src/hgvs/pretty/renderer/tx_pos.py @@ -0,0 +1,43 @@ +from hgvs.pretty.models import VariantData +from hgvs.pretty.renderer.renderer import BasicRenderer + + + + +class TxRulerRenderer(BasicRenderer): + + def legend(self)->str: + return " : " + + def display(self, data: VariantData) -> str: + """show the position of the transcript seq""" + var_str = "" + + count = -1 + for pdata in data.position_details: + count += 1 + if not pdata.mapped_pos: + var_str += " " + continue + + c_pos = pdata.c_pos + + if c_pos is None: + var_str += " " + continue + + if len(var_str) > count: + continue + + if (c_pos + 1) % 10 == 0: + # if pdata.c_interval.start.datum == Datum.CDS_END: + # var_str += "*" + var_str += f"{pdata.c_interval} " + continue + + elif c_pos == 0: + var_str += f"{pdata.c_interval} " + continue + var_str += " " + + return var_str.rstrip() \ No newline at end of file diff --git a/src/hgvs/pretty/renderer/tx_ref_disagree_renderer.py b/src/hgvs/pretty/renderer/tx_ref_disagree_renderer.py new file mode 100644 index 00000000..30ca5287 --- /dev/null +++ b/src/hgvs/pretty/renderer/tx_ref_disagree_renderer.py @@ -0,0 +1,47 @@ +from hgvs.pretty.models import VariantData +from hgvs.pretty.renderer.renderer import BasicRenderer + + +class TxRefDisagreeRenderer(BasicRenderer): + """ Display tx-ref-disagree positions""" + def legend(self)->str: + + return f"tx ref dif: " + + def display(self, data: VariantData) -> str: + """show differences between tx and ref genome, if there are any""" + + if not data.var_c_or_n: + return "" + + + from hgvs.pretty_print import ENDC, TRED + + var_str = "" + counter = -1 + for p in range(data.display_start + 1, data.display_end + 1): + counter += 1 + pdata = data.position_details[counter] + c_offset = pdata.c_offset + if not pdata.mapped_pos: + var_str += " " + continue + + cig = pdata.cigar_ref + if cig == "=": + var_str += " " + elif cig == "N" or c_offset != 0: + var_str += " " + continue + else: + # an alignment issue, show cigar string + if self.config.useColor: + var_str += TRED + cig + ENDC + else: + var_str += cig + + if var_str.isspace(): + return "" + + + return var_str \ No newline at end of file