Skip to content

VARNA Classes

In VARNA API, we offer three Python classes VARNA, Comparison, and Motif for RNA secondary structure visualisation. The first two correspond to the classic and the comparison mode in VARNA. The last one is the special case for motif drawing. Both Comparison and Motif are inherited classes of VARNA.

VARNA

__init__(self, seq=None, structure=None) special

Classic VARNA drawing mode. Constructor from given RNA sequence or/and secondary structure. If sequence and structure have different size, the larger one is used and s or .s will be added to sequence or structure to complement.

Parameters:

Name Type Description Default
seq str

Raw nucleotide sequence for the displayed RNA. Each base must be encoded in a single character. Letters others than A, C, G, U and space are tolerated.

None
structure str or list

RNA (pseudoknotted) secondary structure in one of three formats

  • Dot-Bracket Notation (DBN)
  • List of pair of int representing a list of base-pairs
  • List of int, in which i-th value is j if (i,j) is a base pair or -1 if i-th base is unpaired
None
Source code in varna-api/varnaapi.py
def __init__(self, seq:str=None, structure=None):
    """Classic VARNA drawing mode. Constructor from given RNA sequence or/and secondary structure.
    If sequence and structure have different size, the larger one is used
    and ` `s or `.`s will be added to sequence or structure to complement.

    Args:
        seq: Raw nucleotide sequence for the displayed RNA.
             Each base must be encoded in a single character.
             Letters others than `A`, `C`, `G`, `U` and space are tolerated.
        structure (str or list): RNA (pseudoknotted) secondary structure in one of three formats

          - Dot-Bracket Notation (DBN)
          - List of pair of int representing a list of base-pairs
          - List of int, in which i-th value is `j` if `(i,j)` is a base pair or `-1` if i-th base is unpaired

    """
    self.length = -1
    self.structure = []
    self.sequence = ""
    self._init_features()

    if structure is not None:
        if isinstance(structure, list):
            if len(structure) > 0:
                first = structure[0]
                if len(first)==1:
                    self.structure = check_structure(structure)
                elif len(first)==2:
                    self.structure = _bp_to_struct(structure)
                else:
                    raise Exception("Unrecognized structure format for %s"%(structure))
        # Dot-Bracket Notation
        elif isinstance(structure, str):
            self.structure = _parse_vienna(structure)
            self.dbn = structure
        self.length = len(self.structure)
    if seq is not None:
        self.length = max(self.length,len(seq))
        self.sequence = seq
    # Now we know the length, let's extend the sequence and structure if necessary
    self.sequence += " "*(self.length-len(self.sequence))
    self.structure += [-1]*(self.length-len(self.structure))

add_annotation(self, annotation)

Add an annotation. Argument should be a valid Annotation object

Examples:

>>> a = LoopAnnotation("L1", 6, color="#FF00FF")
>>> varna.add_annotation(a)
Source code in varna-api/varnaapi.py
def add_annotation(self, annotation:_Annotation):
    """Add an annotation.
    Argument should be a valid [Annotation](annotation.md) object

    Examples:
        >>> a = LoopAnnotation("L1", 6, color="#FF00FF")
        >>> varna.add_annotation(a)
    """
    # Assert is annotation
    if not isinstance(annotation, _Annotation):
        raise Exception("Should be a valid annotation object")
    self.annotations.append(annotation)

add_aux_BP(self, i, j, edge5='wc', edge3='wc', stericity='cis', color='#0000FF', thickness=1.0)

Add an additional base pair (i,j), possibly defining and using custom style

Parameters:

Name Type Description Default
i int

5' position of base pair

required
j int

3' position of base pair

required
edge5 str

Edge 5' used for interaction in non-canonical base-pairs, as defined by the Leontis/Westhof classification of base-pairs. Admissible values are wc (Watson/Crick edge), h (Hoogsteen edge) and s (Sugar edge).

'wc'
edge3 str

Edge 3' used for interaction in non-canonical base-pairs. Admissible values are wc, h and s.

'wc'
stericity str

Orientation of the strands. Admissible values are cis and trans

'cis'
color Hex

Base-pair color in Hex color codes

'#0000FF'
thickness float

Base-pair thickness

1.0
Source code in varna-api/varnaapi.py
def add_aux_BP(self, i:int, j:int, edge5:str='wc', edge3:str='wc', stericity:str='cis', color='#0000FF', thickness:float=1.0):
    """Add an additional base pair `(i,j)`, possibly defining and using custom style

    Args:
        i: 5' position of base pair
        j: 3' position of base pair
        edge5: Edge 5' used for interaction in non-canonical base-pairs, as defined by the Leontis/Westhof classification of base-pairs. Admissible values are __wc__ (Watson/Crick edge), __h__ (Hoogsteen edge) and __s__ (Sugar edge).
        edge3: Edge 3' used for interaction in non-canonical base-pairs. Admissible values are __wc__, __h__ and __s__.
        stericity: Orientation of the strands. Admissible values are __cis__ and __trans__
        color (Hex): Base-pair color in Hex color codes
        thickness: Base-pair thickness
    """
    assert_valid_interval(self.length, i, j)
    if edge5 not in ['wc', 's', 'h']:
        raise Exception("edge5 should be one of wc, s, and h")
    if edge3 not in ['wc', 's', 'h']:
        raise Exception("edge3 should be one of wc, s, and h")
    if stericity not in ['cis', 'trans']:
        raise Exception("stericity should be either cis or trans")
    color = assert_hex_color(color)
    assert_is_number('thickness', thickness)

    self.aux_BPs.append((i+1, j+1, color, thickness, edge5, edge3, stericity))

add_bases_style(self, style, bases)

Apply a BasesStyle to a list of positions. If a position is assigned to more than one styles, one of them will be randomly used.

Parameters:

Name Type Description Default
style BasesStyle

Style to apply

required
bases list

List of 0-indexed positions

required

Examples:

>>> style1 = BasesStyle(fill="#FF0000")
>>> style2 = BasesStyle(fill="#FFFF00" outline="#00FF00")
>>> varna.add_bases_style(style1, [0,2,4])
>>> varna.add_bases_style(setye1, [10,11,12])
>>> varna.add_bases_style(style2, [4,5,6,7])
Source code in varna-api/varnaapi.py
def add_bases_style(self, style:BasesStyle, bases:list):
    """Apply a [BasesStyle][varnaapi.BasesStyle] to a list of positions.
    If a position is assigned to more than one styles,
    one of them will be randomly used.

    Args:
        style: Style to apply
        bases: List of 0-indexed positions

    Examples:
        >>> style1 = BasesStyle(fill="#FF0000")
        >>> style2 = BasesStyle(fill="#FFFF00" outline="#00FF00")
        >>> varna.add_bases_style(style1, [0,2,4])
        >>> varna.add_bases_style(setye1, [10,11,12])
        >>> varna.add_bases_style(style2, [4,5,6,7])

    """
    if not isinstance(style, BasesStyle):
        raise Exception("style should be BasesStyle object")
    if len(bases) > 0:
        self.bases_styles[style] = self.bases_styles.get(style, set()).union({i+1 for i in bases})

add_highlight_region(self, i, j, radius=15.0, fill='#9999FF', outline='#3333FF')

Highlights a region by drawing a polygon of predefined radius, fill color and outline color around it. A region consists in an interval from base i to base j.

Parameters:

Name Type Description Default
i int

5'-end of the highlight

required
j int

3'-end of the highlight

required
radius float

Thickness of the highlight

15.0
fill Hex

The color used to fill the highlight

'#9999FF'
outline Hex

The color used to draw the line around the highlight

'#3333FF'
Source code in varna-api/varnaapi.py
def add_highlight_region(self, i:int, j:int, radius:float=15.0, fill="#9999FF", outline="#3333FF"):
    """Highlights a region by drawing a polygon of predefined radius,
    fill color and outline color around it.
    A region consists in an interval from base `i` to base `j`.

    Args:
        i: 5'-end of the highlight
        j: 3'-end of the highlight
        radius: Thickness of the highlight
        fill (Hex): The color used to fill the highlight
        outline (Hex): The color used to draw the line around the highlight
    """
    assert_valid_interval(self.length, i, j)
    fill = assert_hex_color(fill)
    outline = assert_hex_color(outline)
    assert_is_number('radius', radius)

    self.highlight_regions.append((i+1, j+1, radius, fill, outline))

format_structure(self)

Return secondary structure in dot-brackaet notation

Source code in varna-api/varnaapi.py
def format_structure(self):
    """Return secondary structure in dot-brackaet notation
    """
    def greedy_fill(c1, c2, res, ss, i, j):
        if i <= j:
            k = ss[i]
            if k == -1:
                greedy_fill(c1, c2, res, ss, i+1, j)
            elif k > i:
                if k <= j:
                    res[i], res[k] = c1, c2
                    ss[i], ss[k] = -1, -1
                    greedy_fill(c1, c2, res, ss, i+1, k-1)
                    greedy_fill(c1, c2, res, ss, k+1, j)

    res = ["." for _ in range(self.length)]
    ss = self.structure[:]
    for c1, c2 in PARENTHESES_SYSTEMS:
        greedy_fill(c1, c2, res, ss, i=0, j=self.length-1)
        finished = True
        for i in ss:
            if i != -1:
                finished = False
        if finished:
            break
    return "".join(res)

savefig(self, output)

Call VARNA to draw and store the paint in output

Source code in varna-api/varnaapi.py
def savefig(self, output):
    """
    Call VARNA to draw and store the paint in output
    """
    self.output = output
    cmd = self._gen_command()
    print(cmd)
    os.popen(cmd).close()

set_algorithm(self, algo)

Set algorithm other than naview to draw secondary structure. Supported options are line, circular, radiate and naview.

Source code in varna-api/varnaapi.py
def set_algorithm(self, algo):
    """Set algorithm other than __naview__ to draw secondary structure.
    Supported options are __line__, __circular__, __radiate__ and __naview__.
    """
    if algo not in ['line', 'circular', 'radiate', 'naview']:
        raise Exception("Sould be one of line, circular, radiate or naview")
    self.params['algorithm'] = algo

set_border(self, border)

Sets the width and height of the panel border, i.e. the gap between the panel boundaries and those of the surface used to draw the RNA. Parameter border is in format "wxh" where w and h are width and height separated by x.

Examples:

>>> set_border("20x30")
Source code in varna-api/varnaapi.py
def set_border(self, border:str):
    """Sets the width and height of the panel border, _i.e._ the gap
    between the panel boundaries and those of the surface used to draw the RNA.
    Parameter `border` is in format `"wxh"` where `w` and `h` are width and height separated by `x`.

    Example:
        >>> set_border("20x30")
    """
    match = BORDER.search(border)
    if not match:
        raise Exception("border should be the format nxm where n and m are numbers")
    self.params['border'] = "\"{}\"".format(border)

set_bp_increment(self, value)

In linear drawing mode, defines the vertical increment used to separate two successive, nested base-pairs.

Examples:

>>> varna.set_bp_increment(1.2)
Source code in varna-api/varnaapi.py
def set_bp_increment(self, value:float):
    """In linear drawing mode, defines the vertical increment used to
    separate two successive, nested base-pairs.

    Example:
        >>> varna.set_bp_increment(1.2)
    """
    assert_is_number('value', value)
    self.params['bpIncrement'] = float(value)

set_bp_style(self, style)

Set default style for base-pairs rendering, chosen among BP_STYLES

Note: lw is set by default

Examples:

>>> varna.set_bp_style("simple")
Source code in varna-api/varnaapi.py
def set_bp_style(self, style:str):
    """Set default style for base-pairs rendering, chosen among [BP_STYLES][varnaapi.BP_STYLES]

    __Note:__ `lw` is set by default

    Example:
        >>> varna.set_bp_style("simple")
    """
    if style not in BP_STYLES:
        raise Exception('Should be one of {}'.format(BP_STYLES))
    self.params['bpStyle'] = style

set_default_color(self, **kwargs)

Set default color used for different objects in the panel.

Parameters:

Name Type Description Default
**kwargs dict

See DEFAULT_COLOR_LIST for the list of allowed keywords. Value of a keyword is the default color, in Hex color codes, used for the related object.

{}

Examples:

>>> set_default_color({'backbone': '#000000', 'bp':'#FFFF00'})
Source code in varna-api/varnaapi.py
def set_default_color(self, **kwargs):
    """Set default color used for different objects in the panel.

    Args:
        **kwargs (dict): See [DEFAULT_COLOR_LIST][varnaapi.DEFAULT_COLOR_LIST] for the list of allowed keywords.
            Value of a keyword is the default color, in Hex color codes, used for the related object.

    Examples:
        >>> set_default_color({'backbone': '#000000', 'bp':'#FFFF00'})

    """
    for key, value in kwargs.items():
        if key not in DEFAULT_COLOR_LIST:
            raise Exception("{} is not a valid keyword".format(key))
        assert_hex_color(value)
    self.default_color = kwargs

set_numeric_params(self, **kwargs)

Change value of numeric parameters in one function. This is equivalent to use setting function of each parameter, such as set_bp_increment.

Parameters:

Name Type Description Default
**kwargs dict

See NUMERIC_PARAMS for allowed keywords.

{}
Source code in varna-api/varnaapi.py
def set_numeric_params(self, **kwargs):
    """Change value of numeric parameters in one function.
    This is equivalent to use setting function of each parameter,
    such as [set_bp_increment][varnaapi.VARNA.set_bp_increment].

    Args:
        **kwargs (dict): See [NUMERIC_PARAMS][varnaapi.NUMERIC_PARAMS] for allowed keywords.

    """
    for key, value in kwargs.items():
        if key not in NUMERIC_PARAMS:
            raise Exception("{} is not a valid keyword".format(key))
        assert_is_number(key, value)
        if key == "periodNum":
            self.params['periodNum'] = int(value)
        else:
            self.params[key] = float(value)

set_title(self, title, color='#808080', size=10)

Set title displayed at the bottom of the panel with color and font size

Source code in varna-api/varnaapi.py
def set_title(self, title:str, color:str='#808080', size:int=10):
    """Set title displayed at the bottom of the panel with color and font size
    """
    self.title = (title, color, size)

set_zoom_level(self, level)

Defines the level of zoom and zoom increment used to display the RNA within this panel

Source code in varna-api/varnaapi.py
def set_zoom_level(self, level:float):
    """Defines the level of zoom and zoom increment used to display the RNA within this panel"""
    self.params['zoom'] = level

toggle_options(self, **kwargs)

Enable or disable options of drawing

Parameters:

Name Type Description Default
**kwargs dict

See OPTIONS for detailed option lists. Value of keyword is either True or False

{}
Source code in varna-api/varnaapi.py
def toggle_options(self, **kwargs):
    """Enable or disable options of drawing

    Args:
        **kwargs (dict): See [OPTIONS][varnaapi.OPTIONS] for detailed option lists.
                  Value of keyword is either `True` or `False`


    """
    for key, value in kwargs.items():
        if key not in OPTIONS:
            raise Exception("{} is not a valid keyword".format(key))
        if not isinstance(value, bool):
            raise Exception(key + "should be a boolean")
    self.options = kwargs

Comparison

__init__(self, seq1, structure1, seq2, structure2) special

Drawing of two aligned RNAs. Unlike classic VARNA mode, both sequences and structures MUST be specified and have the same size. Additionally, the merged secondary structures must currently be without any crossing interactions (e.g. pseudoknots), and merging them should give a secondary structure. Gap character is ..

Parameters:

Name Type Description Default
seq1 str

Sets the gapped nucleotide sequence for the first RNA sequence

required
structure1 str

Sets the first secondary structure in Dot-Bracket Notation

required
seq2 str

Sets the gapped nucleotide sequence for the second sequence

required
strcuture2 str

Sets the second secondary structure in Doc-Bracket Notation

required
Source code in varna-api/varnaapi.py
def __init__(self, seq1, structure1, seq2, structure2):
    """Drawing of two aligned RNAs.
    Unlike classic [VARNA][varnaapi.VARNA] mode,
    both sequences and structures __MUST__ be specified and have the same size.
    Additionally, the merged secondary structures must currently be without any crossing
    interactions (e.g. pseudoknots), and merging them should give a secondary structure.
    Gap character is `.`.
    Args:
        seq1 (str): Sets the gapped nucleotide sequence for the first RNA sequence
        structure1 (str): Sets the first secondary structure in Dot-Bracket Notation
        seq2 (str): Sets the gapped nucleotide sequence for the second sequence
        strcuture2 (str): Sets the second secondary structure in Doc-Bracket Notation
    """
    if not (len(seq1) == len(structure1) == len(seq2) == len(structure2)):
        raise Exception("All length should be equal")
    self.seq1 = seq1
    self.structure1 = structure1
    self.seq2 = seq2
    self.structure2 = structure2
    self.length = len(seq1)
    self._init_features()

Motif

__init__(self, motif, sequence=None) special

Special class for motif drawing. A motif is a rooted ordered tree, similar to a secondary structure, but whose leaves may represent base paired positions, named open base pairs or open paired leaves and denoted by (*), and the root always represents a closing base pair. A motif can also be seen as an union of consecutive loops. The figure below represents ((*)(*)(((*)(*)))).

Motif class inherits from VARNA with some pre-set parameters.

  • rotation is set at 180
  • default base pair style is simple
  • base number is hidden by setting default color to white (default background color)

A dummy base pair is added after each open base pair and in front of the root, as shown in the figure below. Therefore, the index of bases is changed after creating the object. For example, the index of first base of root is 1 instead of 0. The default bases style for root is BasesStyle(fill="#606060", outline="#FFFFFF",number="#FFFFFF") and BasesStyle(fill="#DDDDDD", outline="#FFFFFF", number="#FFFFFF") for dummy bases. One can change them using set_root_bases_style and set_dummy_bases_style.

Parameters:

Name Type Description Default
motif str

Motif in Dot-Bracket Notation. (*) is used to represent open base pair.

required
sequence str

Chain of characters for motif. Note that sequence should exactly match with motif, i.e. Equal length and same positions for all *.

None
Source code in varna-api/varnaapi.py
def __init__(self, motif, sequence=None):
    """Special class for motif drawing.
    A motif is a rooted ordered tree, similar to a secondary structure,
    but whose leaves may represent base paired positions, named open base
    pairs or open paired leaves and denoted by `(*)`, and the root always
    represents a closing base pair. A motif can also be seen as an union
    of consecutive loops. The figure below represents `((*)(*)(((*)(*))))`.

    Motif class inherits from [VARNA][varnaapi.VARNA] with some pre-set
    parameters.

    - rotation is set at `180`
    - default base pair style is `simple`
    - base number is hidden by setting default color to white
    (default background color)

    A dummy base pair is added after each open base pair and in front of
    the root, as shown in the figure below.
    Therefore, the index of bases is changed after creating the object.
    For example, the index of first base of root is `1` instead of `0`.
    The default bases style for root is
    `BasesStyle(fill="#606060", outline="#FFFFFF",number="#FFFFFF")` and
    `BasesStyle(fill="#DDDDDD", outline="#FFFFFF", number="#FFFFFF")` for
    dummy bases. One can change them using
    [set_root_bases_style][varnaapi.Motif.set_root_bases_style] and
    [set_dummy_bases_style][varnaapi.Motif.set_dummy_bases_style].

    Args:
        motif (str): Motif in Dot-Bracket Notation.
            `(*)` is used to represent open base pair.
        sequence (str): Chain of characters for motif. Note that sequence
            should exactly match with motif, _i.e._ Equal length and same
            positions for all `*`.

    """
    seq = ""
    struct = ""
    extra_bps = []
    pos = 0
    for i in range(len(motif)):
        c = motif[i]
        if c=="*":
            if sequence is not None and not sequence[i] == '*':
                raise Exception("Motif and sequence are not compatible at position {}".format(i))
            extra_bps.append((pos + 1, pos + 2))
            seq += " & "
            struct += "(&)"
            pos += 2
        else:
            if sequence is not None:
                w = sequence[i]
            else:
                w = " "
            if w == '*':
                raise Exception("Motif and sequence are not compatible at position {}".format(i))
            seq += w
            struct += c
            pos += 1
    seq = " " + seq + " "
    struct = "(" + struct + ")"
    self.sequence = seq
    self.structure = struct
    self.length = pos + 2
    extra_bps.append((0, self.length - 1))
    self.extra_bps = extra_bps

    self._init_features()
    # Default Bases Styles
    self.rootBasesStyle = BasesStyle(fill="#606060", outline="#FFFFFF",number="#FFFFFF")
    self.dummyBasesStyle = BasesStyle(fill="#DDDDDD", outline="#FFFFFF", number="#FFFFFF")

    self.default_color['baseNum'] = "#FFFFFF"
    self.params['bpStyle'] = 'simple'
    self.params['rotation'] = 180

set_dummy_bases_style(self, style)

Set style for dummy bases. Argument is a BasesStyle object.

Source code in varna-api/varnaapi.py
def set_dummy_bases_style(self, style):
    """Set style for dummy bases. Argument is a [BasesStyle][varnaapi.BasesStyle] object.
    """
    if not isinstance(style, BasesStyle):
        raise Exception('The argument should be BasesStyle object')
    self.dummyBasesStyle = style

set_root_bases_style(self, style)

Set style for root bases. Argument is a BasesStyle object.

Source code in varna-api/varnaapi.py
def set_root_bases_style(self, style):
    """Set style for root bases. Argument is a [BasesStyle][varnaapi.BasesStyle] object.
    """
    if not isinstance(style, BasesStyle):
        raise Exception('The argument should be BasesStyle object')
    self.rootBasesStyle = style

Motif ((*)(*)(((*)(*))))

Motif ((*)(*)(((*)(*))))

Example

Figure above is created with

from varnaapi import Motif, BaseAnnotation
m = Motif("((*)(*)(((*)(*))))", sequence="  *AU* CC *  *    ")
m.add_annotation(BaseAnnotation(" Root", 1))
m.add_annotation(BaseAnnotation("Dummy", 13))
# Show how base indices work for motif.
# Remeber that VARNA is 1-indexed
m.set_default_color(baseNum="#a6a6a6")
m.set_numeric_params(periodNum=4)
m.savefig("motif_ex.png")