Attention une mise à jour du service Gitlab va être effectuée le mardi 18 janvier (et non lundi 17 comme annoncé précédemment) entre 18h00 et 18h30. Cette mise à jour va générer une interruption du service dont nous ne maîtrisons pas complètement la durée mais qui ne devrait pas excéder quelques minutes.

Commit 01a5e779 authored by YAO Hua-Ting's avatar YAO Hua-Ting
Browse files

Merge branch 'feature/annotation' into 'master'

Feature/annotation

See merge request !1
parents ecdb281e 0c76bfcd
An `Annotation` object represents a textual annotation added to a VARNA drawing.
The object stores the text and other informtation needed.
One can add `Annotation` to drawing using [VARNA.add_annotation](varna.md#varnaapi.VARNA.add_annotation).
Four annotation types allowed in VARNA are represented by four objects below.
::: varnaapi
selection:
members: ["BaseAnnotation", "LoopAnnotation", "HelixAnnotation", "StaticAnnotation"]
::: varnaapi
selection:
filters: ["!^VARNA", "!^_", "__init__"]
filters: ["!^VARNA", "!^_", "__init__", "!Annotation"]
......@@ -8,6 +8,7 @@ theme:
nav:
- Overview: index.md
- API: varnaapi.md
- Annotation: annotation.md
- VARNA: varna.md
plugins:
......@@ -19,6 +20,8 @@ plugins:
filters:
- "!^_"
- "^__init__$"
rendering:
show_root_toc_entry: False
watch:
- varnaapi.py
......
import re
import os
import abc
from string import ascii_lowercase, ascii_uppercase
from typing import Union
......@@ -127,6 +128,97 @@ class BasesStyle:
return ",".join(lst)
class _Annotation:
"""Basic Annotation
"""
def __init__(self, text, type, color="#000000", size=10):
self.text = text
self.type = type
self.color = color
self.size = size #: int: font size
def asdict(self):
return {'text': self.text, 'type': self.type, 'color': self.color,
'size': self.size}
@abc.abstractmethod
def to_cmd(self):
pass
class _ObjectAnnotation(_Annotation):
def __init__(self, text, type, anchor, color="#000000", size=10):
super().__init__(text, type, color, size)
self.anchor = anchor
def asdict(self):
d = super().asdict()
d['anchor'] = self.anchor
return d
def to_cmd(self):
return "{text}:type={type},anchor={anchor},color={color},size={size}"\
.format(**self.asdict())
class BaseAnnotation(_ObjectAnnotation):
def __init__(self, text:str, anchor:int, color="#000000", size=10):
"""Annoation on a base.
Args:
text: Annotation caption
anchor: Index of base to annotate
color (Hex): Annotation color
size (int): Font size
"""
super().__init__(text, 'B', color, size)
class LoopAnnotation(_ObjectAnnotation):
"""Same as [BaseAnnotation][varnaapi.BaseAnnotation] but on a loop.
Argument `anchor` can be index of any base in the loop of interest.
"""
def __init__(self, text, anchor, color="#000000", size=10):
super().__init__(text, 'L', anchor, color, size)
class HelixAnnotation(_ObjectAnnotation):
"""Same as [BaseAnnotation][varnaapi.BaseAnnotation] but on an helix.
Argument `anchor` can be index of any base in the helix of interest.
"""
def __init__(self, text, anchor, color="#000000", size=10):
super().__init__(text, 'H', anchor, color, size)
class StaticAnnotation(_Annotation):
def __init__(self, text, x, y, color="#000000", size=10):
"""Annotation on a specified position in VARNA drawing.
Unlike [BaseAnnotation][varnaapi.BaseAnnotation], argument `anchor` is omitted.
However, arguments `x` and `y` are needed to specify annotation position.
__Note:__ It is unrecommended to use static annotation unless you know what you're doing
Args:
x (int): x-coordinate of position
y (int): y-ccordinate of position
Examples:
>>> sa = StaticAnnotation("Hello World", 100, 150, color="#FF0000")
"""
super().__init__(text, 'P', color, size)
self.x = x
self.y = y
def asdict(self):
d = super().asdict()
d['x'] = self.x
d['y'] = self.y
return d
def to_cmd(self):
return "{text}:type={type},x={x},y={y},color={color},size={size}"\
.format(**self.asdict())
def is_hex_color(color):
match = HEX.search(color)
if match:
......@@ -202,6 +294,7 @@ class VARNA:
self.options = {}
self.title = None
self.bases_styles = {}
self.annotations = []
if structure is not None:
if isinstance(structure, list):
......@@ -416,7 +509,7 @@ class VARNA:
>>> style2 = BasesStyle(fill="#FFFF00" outline="#00FF00")
>>> varna.add_bases_style(style1, [0,2,4])
>>> varna.add_bases_style(setye1, [10,11,12])
>>> varna.aff_bases_style(style2, [4,5,6,7])
>>> varna.add_bases_style(style2, [4,5,6,7])
"""
if not isinstance(style, BasesStyle):
......@@ -424,6 +517,20 @@ class VARNA:
if len(bases) > 0:
self.bases_styles[style] = self.bases_styles.get(style, set()).union({i+1 for i in bases})
def add_annotation(self, annotation:_Annotation):
"""Add an annotation.
Argument should be a valid [Annotation](/annotation/) 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)
def _gen_command(self):
"""
Return command to run VARNA
......@@ -465,6 +572,9 @@ class VARNA:
cmd += " -basesStyle{} {}".format(ind+1, str(style))
cmd += " -applyBasesStyle{}on {}".format(ind+1, ','.join(map(str, bases)))
# Annotations
cmd += " -annotations \"{}\"".format(';'.join([t.to_cmd() for t in self.annotations]))
return cmd
def savefig(self, output):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment