Module pycircos.tree
Expand source code
import math
import numpy as np
from Bio import Phylo
from pycircos.pycircos import Garc
from pycircos.pycircos import Gcircle
class Tarc(Garc):
def __init__(self, arc_id=None, tree=None, format="newick", interspace=3, raxis_range=(900, 950), facecolor=None, edgecolor="#303030", linewidth=0, label=None, labelposition=0, labelsize=10, label_visible=False):
"""
Parameters
----------
arc_id : str, optional
Unique identifier for the Garc class object. In the event an id
value is not provided, an original unique ID is automatically
generated for Garc object. The default is None.
tree : str
File name of phylogenetic tree
format : str
Format of phylogenetic tree. The default is "newick".
interspace : float, optional
Distance angle (deg) to the adjacent arc section in clockwise
sequence. The actual interspace size in the circle is determined by
the actual arc section width in the resultant circle is determined
by the ratio of size to the combined sum of the size and interspace
values of the Garc class objects in the Gcircle class object.
The default is 3.
raxis_range : tuple (top=int, bottom=int), optional
Radial axis range where line plot is drawn. The default is (900, 950).
facecolor : str or tuple representing color code, optional
Color for filling. The default is None.
edgecolor : str or tuple representing color code, optional
Edge color of the filled area. The default is "#303030".
linewidth : float, optional
Edge line width. The default is 0.
label : str, optional
Label of the arc section. The default is None.
labelposition : int, optional
Relative label height from the center of the arc section.
The default is 0.
labelsize : int, optional
Font size of the label. The default is 10.
label_visible : bool, optional
If True, label of the Garc object is shown on the arc section.
The default is False.
Returns
-------
None
"""
self.tree = Phylo.read(tree, format)
self.size = len(self.tree.get_terminals())
self._tree_plotted = 0
self._parental_gcircle = None
if arc_id == None:
self.arc_id = str(Garc._arcnum)
else:
self.arc_id = arc_id
self.interspace = 2 * np.pi * (interspace / 360)
self.raxis_range = raxis_range
self.facecolor = facecolor
self.edgecolor = edgecolor
self.linewidth = linewidth
if label is None:
self.label = arc_id
else:
self.label = label
self.label_visible = label_visible
self.labelposition = labelposition
self.labelsize = labelsize
self._get_col_positions()
self._get_row_positions()
Garc._arcnum += 1
def _get_col_positions(self):
taxa = self.tree.get_terminals()
depths = self.tree.depths()
max_label_width = max(len(str(taxon)) for taxon in taxa)
drawing_width = 100 - max_label_width - 1
if max(depths.values()) == 0:
depths = self.tree.depths(unit_branch_lengths=True)
fudge_margin = math.log(len(taxa), 2)
cols_per_branch_unit = (drawing_width - fudge_margin) / float(max(depths.values()))
positions = {clade: blen * cols_per_branch_unit + 1.0 for clade, blen in depths.items()}
self._col_positions = positions
def _get_row_positions(self):
taxa = self.tree.get_terminals()
positions = {taxon: 2 * idx for idx, taxon in enumerate(taxa)}
def calc_row(clade):
for subclade in clade:
if subclade not in positions:
calc_row(subclade)
positions[clade] = (
positions[clade.clades[0]] + positions[clade.clades[-1]]
) // 2
calc_row(self.tree.root)
self._row_positions = positions
self.clade_dict = {}
self.terminal_dict = {}
self.nonterminal_dict = {}
keys = list(self._row_positions.keys())
keys.sort(key=lambda x: self._row_positions[x])
for key in keys:
if key in taxa:
self.terminal_dict[key.name] = key
else:
self.nonterminal_dict[key.name] = key
self.clade_dict[key.name] = key
def _convert(self, thetalim, rlim):
col_values = list(self._col_positions.values())
row_values = list(self._row_positions.values())
row_min, row_max = np.min(row_values), np.max(row_values)
col_min, col_max = np.min(col_values), np.max(col_values)
theta_positions = [thetalim[0] + (v * abs(thetalim[1]-thetalim[0])/abs(row_min-row_max)) for v in row_values]
if rlim[0] < rlim[1]:
r_positions = [rlim[0] + (v * abs(rlim[1]-rlim[0])/abs(col_min-col_max)) for v in col_values]
else:
r_positions = [rlim[0] - (v * abs(rlim[1]-rlim[0])/abs(col_min-col_max)) for v in col_values]
self._theta_dict = dict(zip(list(self._row_positions.keys()) ,theta_positions))
self._r_dict = dict(zip(list(self._col_positions.keys()) ,r_positions))
def _plot_tree(self, ax, thetalim=None, rlim=None, cladevisual_dict=None, highlight_dict=None, linewidth=None, linecolor=None):
if linewidth is None:
linewidth = 0.5
if linecolor is None:
linecolor = "k"
if cladevisual_dict is None:
cladevisual_dict = {}
self._tree_rlim = rlim
if rlim[0] < rlim[1]:
self._tree_direction = "inner"
else:
self._tree_direction = "outer"
self._convert(thetalim, rlim)
s = []
c = []
ecs = []
lws = []
for clade in self._theta_dict:
if clade.name not in cladevisual_dict:
cladevisual_dict[clade.name] = {}
cladevisual_dict[clade.name].setdefault("size",0)
cladevisual_dict[clade.name].setdefault("color","k")
cladevisual_dict[clade.name].setdefault("edgecolor","k")
cladevisual_dict[clade.name].setdefault("linewidth",0.1)
s.append(cladevisual_dict[clade.name]["size"])
c.append(cladevisual_dict[clade.name]["color"])
ecs.append(cladevisual_dict[clade.name]["edgecolor"])
lws.append(cladevisual_dict[clade.name]["linewidth"])
ax.scatter(self._theta_dict.values(), [self._r_dict[clade] for clade in self._theta_dict], s=s, c=c, edgecolors=ecs, linewidths=lws, zorder=1100)
for clade in self._theta_dict:
subclades = clade.clades
if len(subclades) > 0:
sc_thetas = [self._theta_dict[sc] for sc in subclades]
minsc_theta = min(sc_thetas)
maxsc_theta = max(sc_thetas)
thetas = np.linspace(minsc_theta, maxsc_theta, 100)
rs = [self._r_dict[clade]] * len(thetas)
ax.plot(thetas, rs, lw=linewidth, color=linecolor, zorder=0)
for sc, sc_theta in zip(subclades, sc_thetas):
ax.plot([sc_theta, sc_theta], [self._r_dict[sc], self._r_dict[clade]], lw=linewidth, color=linecolor, zorder=0)
if highlight_dict is not None:
self.plot_highlight(ax, highlight_dict)
self._tree_plotted = 1
def _plot_highlight(self, ax, highlight_dict=None):
if self._tree_plotted == 0:
raise ValueError("Please run `plot_tree` before running `plot_highlight`")
for clade_names in highlight_dict:
highlight_dict[clade_names].setdefault("color", "#000000")
highlight_dict[clade_names].setdefault("alpha", 0.25)
highlight_dict[clade_names].setdefault("label", None)
highlight_dict[clade_names].setdefault("y", None)
highlight_dict[clade_names].setdefault("fontsize", self.labelsize)
color = highlight_dict[clade_names]["color"]
alpha = highlight_dict[clade_names]["alpha"]
label = highlight_dict[clade_names]["label"]
fontsize = highlight_dict[clade_names]["fontsize"]
yloc = highlight_dict[clade_names]["y"]
if type(clade_names) is tuple:
ca = self.tree.common_ancestor([self.clade_dict[name] for name in clade_names])
clades = [self.clade_dict[name] for name in clade_names]
else:
ca = self.clade_dict[clade_names]
clades = ca.get_terminals()
c_thetas = [self._theta_dict[c] for c in clades]
minc_theta = min(c_thetas)
maxc_theta = max(c_thetas)
if self._tree_direction == "inner":
c_rs = [self._r_dict[c] for c in clades]
maxc_r = max(c_rs)
width = minc_theta - maxc_theta
loc = (minc_theta + maxc_theta) / 2
ax.bar([loc], [self._tree_rlim[1] - self._r_dict[ca]], bottom=self._r_dict[ca], width=width, color=color, alpha=alpha, linewidth=0, zorder=1000 + maxc_r)
if highlight_dict[clade_names]["label"] is None:
pass
else:
rot = loc*360/(2*np.pi)
if 90 < rot < 270:
rot = 180-rot
else:
rot = -1 * rot
if yloc is None:
yloc = self._tree_rlim[1] - abs(self._tree_rlim[1]-self._tree_rlim[0]) * 0.1
ax.text(loc, yloc, str(label), rotation=rot, ha="center", va="center", fontsize=fontsize, zorder=1000 + maxc_r + 0.1)
else:
c_rs = [self._r_dict[c] for c in clades]
minc_r = min(c_rs)
width = minc_theta - maxc_theta
loc = (minc_theta + maxc_theta) / 2
ax.bar([loc], [self._r_dict[ca] - self._tree_rlim[1]], bottom=self._tree_rlim[1], width=width, color=color, alpha=alpha, linewidth=0, zorder=1000 + (-1 * minc_r))
if highlight_dict[clade_names]["label"] is None:
pass
else:
rot = loc*360/(2*np.pi)
if 90 < rot < 270:
rot = 180-rot
else:
rot = -1 * rot
if yloc is None:
yloc = self._tree_rlim[1] + abs(self._tree_rlim[1]-self._tree_rlim[0]) * 0.1
ax.text(loc, yloc, str(label), rotation=rot, ha="center", va="center", fontsize=fontsize, zorder=1000 + (-1 * minc_r) + 0.1)
class Tcircle(Gcircle):
"""
Tcircle class is the subclass of Gcircle. All methods implemented in the
Gcircle class also can be used. Then, the two additional methods set_tarc,
plot_tree and plot_highlight is provided in the Tcircle class.
"""
def __init__(self, fig=None, figsize=None):
"""
Parameters
----------
fig : matplotlib.pyplot.figure object, optional
Matplotlib Figure class object
figsize : tuple, optional
Figure size for the circular map
"""
super().__init__(fig=fig, figsize=figsize)
def __getattr__(self, name):
if name == "tarc_dict":
return self._garc_dict
def add_tarc(self, tarc):
"""
Add a new Tarc or Garc class object into tarc_dict.
Parameters
----------
tarc : Tarc or Garc class object
Tarc or Garc class object to be added.
Returns
-------
None
"""
self._garc_dict[tarc.arc_id] = tarc
def set_tarcs(self, start=0, end=360):
"""
Visualize the arc rectangles of the Tarc class objects in .garc_dict on
the drawing space. After the execution of this method, a new Tarc class
object cannot be added to garc_dict and figure parameter representing
matplotlib.pyplot.figure object will be created in Tcircle object.
Parameters
----------
start : int, optional
Start angle of the circos plot. The value range is -360 ~ 360.
The default is 0.
end : int, optional
End angle of the circos plot. The value range is -360 ~ 360.
The default is 360.
Returns
-------
None
"""
sum_length = sum(list(map(lambda x: self._garc_dict[x]["size"], list(self._garc_dict.keys()))))
sum_interspace = sum(list(map(lambda x: self._garc_dict[x]["interspace"], list(self._garc_dict.keys()))))
start = 2 * np.pi * start / 360
end = (2 * np.pi * end / 360) - sum_interspace
s = 0
sum_interspace = 0
for key in self._garc_dict.keys():
size = self._garc_dict[key].size
self._garc_dict[key].coordinates = [None, None]
self._garc_dict[key].coordinates[0] = sum_interspace + start + ((end-start) * s/sum_length)
self._garc_dict[key].coordinates[1] = sum_interspace + start + ((end-start) * (s+size)/sum_length)
s = s + size
sum_interspace += self._garc_dict[key].interspace
if self.fig_is_ext:
self.ax = self.figure.add_axes([0, 0, self.figsize[0], self.figsize[1]], polar=True)
else:
self.ax = self.figure.add_axes([0, 0, 1, 1], polar=True)
self.ax.set_theta_zero_location("N")
self.ax.set_theta_direction(-1)
self.ax.set_ylim(0,1000)
self.ax.spines['polar'].set_visible(False)
self.ax.xaxis.set_ticks([])
self.ax.xaxis.set_ticklabels([])
self.ax.yaxis.set_ticks([])
self.ax.yaxis.set_ticklabels([])
for i, key in enumerate(self._garc_dict.keys()):
pos = self._garc_dict[key].coordinates[0]
width = self._garc_dict[key].coordinates[-1] - self._garc_dict[key].coordinates[0]
height = abs(self._garc_dict[key].raxis_range[1] - self._garc_dict[key].raxis_range[0])
bottom = self._garc_dict[key].raxis_range[0]
facecolor = self._garc_dict[key].facecolor
edgecolor = self._garc_dict[key].edgecolor
linewidth = self._garc_dict[key].linewidth
if facecolor is None:
facecolor = (0, 0, 0, 0)
if facecolor == (0, 0, 0, 0) and linewidth == 0:
pass
else:
self.ax.bar([pos], [height], bottom=bottom, width=width, facecolor=facecolor, linewidth=linewidth, edgecolor=edgecolor, align="edge")
if self._garc_dict[key].label_visible == True:
rot = (self._garc_dict[key].coordinates[0] + self._garc_dict[key].coordinates[1]) / 2
rot = rot*360/(2*np.pi)
if 90 < rot < 270:
rot = 180-rot
else:
rot = -1 * rot
height = bottom + height/2 + self._garc_dict[key].labelposition
self.ax.text(pos + width/2, height, self._garc_dict[key].label, rotation=rot, ha="center", va="center", fontsize=self._garc_dict[key].labelsize)
def plot_tree(self, tarc_id, rlim=(0,700), cladevisual_dict=None, highlight_dict=None, linecolor="#303030", linewidth=0.5):
"""
Draw circular phylogenetic tree
Parameters
---------
tarc_id : str
ID of the Tarc class object. The ID should be in Tcircle object.tarc_dict.
rlim : tuple (top=int, bottom=int)
The top and bottom r limits in data coordinates. The default is (0, 700).
cladevisual_dict : dict
Dictionary composed of pairs of clade name and a sub-dict holding
parameters to visualize the clade. A sub-dict is composed of
the following key-value pairs:
- `size` : `float`
Size of dot. The default is 5.
- `color` : `float or str` representing color code.
Face color of dot. The default is "#303030".
- `edgecolor` : `float or str` representing color code.
Edge line color of dot. The default is "#303030".
- `linewidth` : `float`
Edge line width of dot. The default is 0.5.
highlight_dict : dict
Dictionary composed of pairs of internal clade name and a sub-dict.
Instead of clade name, tuples of terminal clade names can also be
A sub-dict is composed of the following key-value pairs:
- `color` : `str`
Color of highlight for clades. The default is "#000000".
- `alpha` : `float`
Alpha of highlight for clades. The default is 0.25.
- `label` : `str`
Label. The default is None.
- `fontsize` : `float`
Fontsize of label. The default is 10.
- `y` : `float`
Y location of the text. The default is the bottom edge of the highlight.
linecolor : str or tuple representing color code, optional
Color of the tree line. The default is "#303030".
linewidth : float
Line width of tree. The default is 0.5.
Returns
-------
None
"""
start = self._garc_dict[tarc_id].coordinates[0]
end = self._garc_dict[tarc_id].coordinates[-1]
positions = np.linspace(start, end, self._garc_dict[tarc_id].size, endpoint=False)
positions = positions + abs(positions[1]-positions[0]) * 0.5
start, end = positions[0], positions[-1]
self._garc_dict[tarc_id]._plot_tree(self.ax, thetalim=(start, end), rlim=rlim, cladevisual_dict=cladevisual_dict, highlight_dict=highlight_dict, linecolor=linecolor, linewidth=linewidth)
def plot_highlight(self, tarc_id, highlight_dict=None):
"""
Add highlight for specific clade under the given internal clade
Parameters
----------
tarc_id : str
ID of the Tarc class object. The ID should be in Tcircle object.tarc_dict.
highlight_dict : dict
Dictionary composed of pairs of internal clade name and a sub-dict.
Instead of clade name, tuples of terminal clade names can also be used.
A sub-dict is composed of the following key-value pairs:
- `color` : `str`
Color of highlight for clades. The default is "#000000".
- `alpha` : `float`
Alpha of highlight for clades. The default is 0.25.
- `label` : `str`
Label. The default is None.
- `fontsize` : `float`
Fontsize of label. The default is 10.
- `y` : `float`
Y location of the text. The default is the bottom edge of the highlight.
Returns
-------
None
"""
self._garc_dict[tarc_id]._plot_highlight(self.ax, highlight_dict=highlight_dict)
if __name__ == "__main__":
pass
"""
tree = next(Phylo.parse("../tutorial/sample_data/hmptree.xml", "phyloxml"))
col_positions = get_col_positions(tree)
row_positions = get_row_positions(tree)
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(5,5))
ax = fig.add_axes([0, 0, 1, 1], polar=True)
theta_dict, r_dict = convert(tree, col_positions, row_positions, (0, np.pi), (0,10))
#ax.scatter(theta_dict.values(), [r_dict[clade] for clade in theta_dict], s=1, color="k")
plot_lines(ax, theta_dict, r_dict)
ax.set_ylim([0,10])
fig.savefig("test.pdf", bbox_inches="tight")
"""
Classes
class Tarc (arc_id=None, tree=None, format='newick', interspace=3, raxis_range=(900, 950), facecolor=None, edgecolor='#303030', linewidth=0, label=None, labelposition=0, labelsize=10, label_visible=False)
-
Parameters
arc_id
:str
, optional- Unique identifier for the Garc class object. In the event an id value is not provided, an original unique ID is automatically generated for Garc object. The default is None.
tree
:str
- File name of phylogenetic tree
format
:str
- Format of phylogenetic tree. The default is "newick".
interspace
:float
, optional- Distance angle (deg) to the adjacent arc section in clockwise sequence. The actual interspace size in the circle is determined by the actual arc section width in the resultant circle is determined by the ratio of size to the combined sum of the size and interspace values of the Garc class objects in the Gcircle class object. The default is 3.
raxis_range
:tuple (top=int, bottom=int)
, optional- Radial axis range where line plot is drawn. The default is (900, 950).
facecolor
:str
ortuple representing color code
, optional- Color for filling. The default is None.
edgecolor
:str
ortuple representing color code
, optional- Edge color of the filled area. The default is "#303030".
linewidth
:float
, optional- Edge line width. The default is 0.
label
:str
, optional- Label of the arc section. The default is None.
labelposition
:int
, optional- Relative label height from the center of the arc section. The default is 0.
labelsize
:int
, optional- Font size of the label. The default is 10.
label_visible
:bool
, optional- If True, label of the Garc object is shown on the arc section. The default is False.
Returns
None
Expand source code
class Tarc(Garc): def __init__(self, arc_id=None, tree=None, format="newick", interspace=3, raxis_range=(900, 950), facecolor=None, edgecolor="#303030", linewidth=0, label=None, labelposition=0, labelsize=10, label_visible=False): """ Parameters ---------- arc_id : str, optional Unique identifier for the Garc class object. In the event an id value is not provided, an original unique ID is automatically generated for Garc object. The default is None. tree : str File name of phylogenetic tree format : str Format of phylogenetic tree. The default is "newick". interspace : float, optional Distance angle (deg) to the adjacent arc section in clockwise sequence. The actual interspace size in the circle is determined by the actual arc section width in the resultant circle is determined by the ratio of size to the combined sum of the size and interspace values of the Garc class objects in the Gcircle class object. The default is 3. raxis_range : tuple (top=int, bottom=int), optional Radial axis range where line plot is drawn. The default is (900, 950). facecolor : str or tuple representing color code, optional Color for filling. The default is None. edgecolor : str or tuple representing color code, optional Edge color of the filled area. The default is "#303030". linewidth : float, optional Edge line width. The default is 0. label : str, optional Label of the arc section. The default is None. labelposition : int, optional Relative label height from the center of the arc section. The default is 0. labelsize : int, optional Font size of the label. The default is 10. label_visible : bool, optional If True, label of the Garc object is shown on the arc section. The default is False. Returns ------- None """ self.tree = Phylo.read(tree, format) self.size = len(self.tree.get_terminals()) self._tree_plotted = 0 self._parental_gcircle = None if arc_id == None: self.arc_id = str(Garc._arcnum) else: self.arc_id = arc_id self.interspace = 2 * np.pi * (interspace / 360) self.raxis_range = raxis_range self.facecolor = facecolor self.edgecolor = edgecolor self.linewidth = linewidth if label is None: self.label = arc_id else: self.label = label self.label_visible = label_visible self.labelposition = labelposition self.labelsize = labelsize self._get_col_positions() self._get_row_positions() Garc._arcnum += 1 def _get_col_positions(self): taxa = self.tree.get_terminals() depths = self.tree.depths() max_label_width = max(len(str(taxon)) for taxon in taxa) drawing_width = 100 - max_label_width - 1 if max(depths.values()) == 0: depths = self.tree.depths(unit_branch_lengths=True) fudge_margin = math.log(len(taxa), 2) cols_per_branch_unit = (drawing_width - fudge_margin) / float(max(depths.values())) positions = {clade: blen * cols_per_branch_unit + 1.0 for clade, blen in depths.items()} self._col_positions = positions def _get_row_positions(self): taxa = self.tree.get_terminals() positions = {taxon: 2 * idx for idx, taxon in enumerate(taxa)} def calc_row(clade): for subclade in clade: if subclade not in positions: calc_row(subclade) positions[clade] = ( positions[clade.clades[0]] + positions[clade.clades[-1]] ) // 2 calc_row(self.tree.root) self._row_positions = positions self.clade_dict = {} self.terminal_dict = {} self.nonterminal_dict = {} keys = list(self._row_positions.keys()) keys.sort(key=lambda x: self._row_positions[x]) for key in keys: if key in taxa: self.terminal_dict[key.name] = key else: self.nonterminal_dict[key.name] = key self.clade_dict[key.name] = key def _convert(self, thetalim, rlim): col_values = list(self._col_positions.values()) row_values = list(self._row_positions.values()) row_min, row_max = np.min(row_values), np.max(row_values) col_min, col_max = np.min(col_values), np.max(col_values) theta_positions = [thetalim[0] + (v * abs(thetalim[1]-thetalim[0])/abs(row_min-row_max)) for v in row_values] if rlim[0] < rlim[1]: r_positions = [rlim[0] + (v * abs(rlim[1]-rlim[0])/abs(col_min-col_max)) for v in col_values] else: r_positions = [rlim[0] - (v * abs(rlim[1]-rlim[0])/abs(col_min-col_max)) for v in col_values] self._theta_dict = dict(zip(list(self._row_positions.keys()) ,theta_positions)) self._r_dict = dict(zip(list(self._col_positions.keys()) ,r_positions)) def _plot_tree(self, ax, thetalim=None, rlim=None, cladevisual_dict=None, highlight_dict=None, linewidth=None, linecolor=None): if linewidth is None: linewidth = 0.5 if linecolor is None: linecolor = "k" if cladevisual_dict is None: cladevisual_dict = {} self._tree_rlim = rlim if rlim[0] < rlim[1]: self._tree_direction = "inner" else: self._tree_direction = "outer" self._convert(thetalim, rlim) s = [] c = [] ecs = [] lws = [] for clade in self._theta_dict: if clade.name not in cladevisual_dict: cladevisual_dict[clade.name] = {} cladevisual_dict[clade.name].setdefault("size",0) cladevisual_dict[clade.name].setdefault("color","k") cladevisual_dict[clade.name].setdefault("edgecolor","k") cladevisual_dict[clade.name].setdefault("linewidth",0.1) s.append(cladevisual_dict[clade.name]["size"]) c.append(cladevisual_dict[clade.name]["color"]) ecs.append(cladevisual_dict[clade.name]["edgecolor"]) lws.append(cladevisual_dict[clade.name]["linewidth"]) ax.scatter(self._theta_dict.values(), [self._r_dict[clade] for clade in self._theta_dict], s=s, c=c, edgecolors=ecs, linewidths=lws, zorder=1100) for clade in self._theta_dict: subclades = clade.clades if len(subclades) > 0: sc_thetas = [self._theta_dict[sc] for sc in subclades] minsc_theta = min(sc_thetas) maxsc_theta = max(sc_thetas) thetas = np.linspace(minsc_theta, maxsc_theta, 100) rs = [self._r_dict[clade]] * len(thetas) ax.plot(thetas, rs, lw=linewidth, color=linecolor, zorder=0) for sc, sc_theta in zip(subclades, sc_thetas): ax.plot([sc_theta, sc_theta], [self._r_dict[sc], self._r_dict[clade]], lw=linewidth, color=linecolor, zorder=0) if highlight_dict is not None: self.plot_highlight(ax, highlight_dict) self._tree_plotted = 1 def _plot_highlight(self, ax, highlight_dict=None): if self._tree_plotted == 0: raise ValueError("Please run `plot_tree` before running `plot_highlight`") for clade_names in highlight_dict: highlight_dict[clade_names].setdefault("color", "#000000") highlight_dict[clade_names].setdefault("alpha", 0.25) highlight_dict[clade_names].setdefault("label", None) highlight_dict[clade_names].setdefault("y", None) highlight_dict[clade_names].setdefault("fontsize", self.labelsize) color = highlight_dict[clade_names]["color"] alpha = highlight_dict[clade_names]["alpha"] label = highlight_dict[clade_names]["label"] fontsize = highlight_dict[clade_names]["fontsize"] yloc = highlight_dict[clade_names]["y"] if type(clade_names) is tuple: ca = self.tree.common_ancestor([self.clade_dict[name] for name in clade_names]) clades = [self.clade_dict[name] for name in clade_names] else: ca = self.clade_dict[clade_names] clades = ca.get_terminals() c_thetas = [self._theta_dict[c] for c in clades] minc_theta = min(c_thetas) maxc_theta = max(c_thetas) if self._tree_direction == "inner": c_rs = [self._r_dict[c] for c in clades] maxc_r = max(c_rs) width = minc_theta - maxc_theta loc = (minc_theta + maxc_theta) / 2 ax.bar([loc], [self._tree_rlim[1] - self._r_dict[ca]], bottom=self._r_dict[ca], width=width, color=color, alpha=alpha, linewidth=0, zorder=1000 + maxc_r) if highlight_dict[clade_names]["label"] is None: pass else: rot = loc*360/(2*np.pi) if 90 < rot < 270: rot = 180-rot else: rot = -1 * rot if yloc is None: yloc = self._tree_rlim[1] - abs(self._tree_rlim[1]-self._tree_rlim[0]) * 0.1 ax.text(loc, yloc, str(label), rotation=rot, ha="center", va="center", fontsize=fontsize, zorder=1000 + maxc_r + 0.1) else: c_rs = [self._r_dict[c] for c in clades] minc_r = min(c_rs) width = minc_theta - maxc_theta loc = (minc_theta + maxc_theta) / 2 ax.bar([loc], [self._r_dict[ca] - self._tree_rlim[1]], bottom=self._tree_rlim[1], width=width, color=color, alpha=alpha, linewidth=0, zorder=1000 + (-1 * minc_r)) if highlight_dict[clade_names]["label"] is None: pass else: rot = loc*360/(2*np.pi) if 90 < rot < 270: rot = 180-rot else: rot = -1 * rot if yloc is None: yloc = self._tree_rlim[1] + abs(self._tree_rlim[1]-self._tree_rlim[0]) * 0.1 ax.text(loc, yloc, str(label), rotation=rot, ha="center", va="center", fontsize=fontsize, zorder=1000 + (-1 * minc_r) + 0.1)
Ancestors
Inherited members
class Tcircle (fig=None, figsize=None)
-
Tcircle class is the subclass of Gcircle. All methods implemented in the Gcircle class also can be used. Then, the two additional methods set_tarc, plot_tree and plot_highlight is provided in the Tcircle class.
Parameters
fig
:matplotlib.pyplot.figure object
, optional- Matplotlib Figure class object
figsize
:tuple
, optional- Figure size for the circular map
Expand source code
class Tcircle(Gcircle): """ Tcircle class is the subclass of Gcircle. All methods implemented in the Gcircle class also can be used. Then, the two additional methods set_tarc, plot_tree and plot_highlight is provided in the Tcircle class. """ def __init__(self, fig=None, figsize=None): """ Parameters ---------- fig : matplotlib.pyplot.figure object, optional Matplotlib Figure class object figsize : tuple, optional Figure size for the circular map """ super().__init__(fig=fig, figsize=figsize) def __getattr__(self, name): if name == "tarc_dict": return self._garc_dict def add_tarc(self, tarc): """ Add a new Tarc or Garc class object into tarc_dict. Parameters ---------- tarc : Tarc or Garc class object Tarc or Garc class object to be added. Returns ------- None """ self._garc_dict[tarc.arc_id] = tarc def set_tarcs(self, start=0, end=360): """ Visualize the arc rectangles of the Tarc class objects in .garc_dict on the drawing space. After the execution of this method, a new Tarc class object cannot be added to garc_dict and figure parameter representing matplotlib.pyplot.figure object will be created in Tcircle object. Parameters ---------- start : int, optional Start angle of the circos plot. The value range is -360 ~ 360. The default is 0. end : int, optional End angle of the circos plot. The value range is -360 ~ 360. The default is 360. Returns ------- None """ sum_length = sum(list(map(lambda x: self._garc_dict[x]["size"], list(self._garc_dict.keys())))) sum_interspace = sum(list(map(lambda x: self._garc_dict[x]["interspace"], list(self._garc_dict.keys())))) start = 2 * np.pi * start / 360 end = (2 * np.pi * end / 360) - sum_interspace s = 0 sum_interspace = 0 for key in self._garc_dict.keys(): size = self._garc_dict[key].size self._garc_dict[key].coordinates = [None, None] self._garc_dict[key].coordinates[0] = sum_interspace + start + ((end-start) * s/sum_length) self._garc_dict[key].coordinates[1] = sum_interspace + start + ((end-start) * (s+size)/sum_length) s = s + size sum_interspace += self._garc_dict[key].interspace if self.fig_is_ext: self.ax = self.figure.add_axes([0, 0, self.figsize[0], self.figsize[1]], polar=True) else: self.ax = self.figure.add_axes([0, 0, 1, 1], polar=True) self.ax.set_theta_zero_location("N") self.ax.set_theta_direction(-1) self.ax.set_ylim(0,1000) self.ax.spines['polar'].set_visible(False) self.ax.xaxis.set_ticks([]) self.ax.xaxis.set_ticklabels([]) self.ax.yaxis.set_ticks([]) self.ax.yaxis.set_ticklabels([]) for i, key in enumerate(self._garc_dict.keys()): pos = self._garc_dict[key].coordinates[0] width = self._garc_dict[key].coordinates[-1] - self._garc_dict[key].coordinates[0] height = abs(self._garc_dict[key].raxis_range[1] - self._garc_dict[key].raxis_range[0]) bottom = self._garc_dict[key].raxis_range[0] facecolor = self._garc_dict[key].facecolor edgecolor = self._garc_dict[key].edgecolor linewidth = self._garc_dict[key].linewidth if facecolor is None: facecolor = (0, 0, 0, 0) if facecolor == (0, 0, 0, 0) and linewidth == 0: pass else: self.ax.bar([pos], [height], bottom=bottom, width=width, facecolor=facecolor, linewidth=linewidth, edgecolor=edgecolor, align="edge") if self._garc_dict[key].label_visible == True: rot = (self._garc_dict[key].coordinates[0] + self._garc_dict[key].coordinates[1]) / 2 rot = rot*360/(2*np.pi) if 90 < rot < 270: rot = 180-rot else: rot = -1 * rot height = bottom + height/2 + self._garc_dict[key].labelposition self.ax.text(pos + width/2, height, self._garc_dict[key].label, rotation=rot, ha="center", va="center", fontsize=self._garc_dict[key].labelsize) def plot_tree(self, tarc_id, rlim=(0,700), cladevisual_dict=None, highlight_dict=None, linecolor="#303030", linewidth=0.5): """ Draw circular phylogenetic tree Parameters --------- tarc_id : str ID of the Tarc class object. The ID should be in Tcircle object.tarc_dict. rlim : tuple (top=int, bottom=int) The top and bottom r limits in data coordinates. The default is (0, 700). cladevisual_dict : dict Dictionary composed of pairs of clade name and a sub-dict holding parameters to visualize the clade. A sub-dict is composed of the following key-value pairs: - `size` : `float` Size of dot. The default is 5. - `color` : `float or str` representing color code. Face color of dot. The default is "#303030". - `edgecolor` : `float or str` representing color code. Edge line color of dot. The default is "#303030". - `linewidth` : `float` Edge line width of dot. The default is 0.5. highlight_dict : dict Dictionary composed of pairs of internal clade name and a sub-dict. Instead of clade name, tuples of terminal clade names can also be A sub-dict is composed of the following key-value pairs: - `color` : `str` Color of highlight for clades. The default is "#000000". - `alpha` : `float` Alpha of highlight for clades. The default is 0.25. - `label` : `str` Label. The default is None. - `fontsize` : `float` Fontsize of label. The default is 10. - `y` : `float` Y location of the text. The default is the bottom edge of the highlight. linecolor : str or tuple representing color code, optional Color of the tree line. The default is "#303030". linewidth : float Line width of tree. The default is 0.5. Returns ------- None """ start = self._garc_dict[tarc_id].coordinates[0] end = self._garc_dict[tarc_id].coordinates[-1] positions = np.linspace(start, end, self._garc_dict[tarc_id].size, endpoint=False) positions = positions + abs(positions[1]-positions[0]) * 0.5 start, end = positions[0], positions[-1] self._garc_dict[tarc_id]._plot_tree(self.ax, thetalim=(start, end), rlim=rlim, cladevisual_dict=cladevisual_dict, highlight_dict=highlight_dict, linecolor=linecolor, linewidth=linewidth) def plot_highlight(self, tarc_id, highlight_dict=None): """ Add highlight for specific clade under the given internal clade Parameters ---------- tarc_id : str ID of the Tarc class object. The ID should be in Tcircle object.tarc_dict. highlight_dict : dict Dictionary composed of pairs of internal clade name and a sub-dict. Instead of clade name, tuples of terminal clade names can also be used. A sub-dict is composed of the following key-value pairs: - `color` : `str` Color of highlight for clades. The default is "#000000". - `alpha` : `float` Alpha of highlight for clades. The default is 0.25. - `label` : `str` Label. The default is None. - `fontsize` : `float` Fontsize of label. The default is 10. - `y` : `float` Y location of the text. The default is the bottom edge of the highlight. Returns ------- None """ self._garc_dict[tarc_id]._plot_highlight(self.ax, highlight_dict=highlight_dict)
Ancestors
Methods
def add_tarc(self, tarc)
-
Add a new Tarc or Garc class object into tarc_dict.
Parameters
tarc
:Tarc
orGarc class object
- Tarc or Garc class object to be added.
Returns
None
Expand source code
def add_tarc(self, tarc): """ Add a new Tarc or Garc class object into tarc_dict. Parameters ---------- tarc : Tarc or Garc class object Tarc or Garc class object to be added. Returns ------- None """ self._garc_dict[tarc.arc_id] = tarc
def set_tarcs(self, start=0, end=360)
-
Visualize the arc rectangles of the Tarc class objects in .garc_dict on the drawing space. After the execution of this method, a new Tarc class object cannot be added to garc_dict and figure parameter representing matplotlib.pyplot.figure object will be created in Tcircle object.
Parameters
start
:int
, optional- Start angle of the circos plot. The value range is -360 ~ 360. The default is 0.
end
:int
, optional- End angle of the circos plot. The value range is -360 ~ 360. The default is 360.
Returns
None
Expand source code
def set_tarcs(self, start=0, end=360): """ Visualize the arc rectangles of the Tarc class objects in .garc_dict on the drawing space. After the execution of this method, a new Tarc class object cannot be added to garc_dict and figure parameter representing matplotlib.pyplot.figure object will be created in Tcircle object. Parameters ---------- start : int, optional Start angle of the circos plot. The value range is -360 ~ 360. The default is 0. end : int, optional End angle of the circos plot. The value range is -360 ~ 360. The default is 360. Returns ------- None """ sum_length = sum(list(map(lambda x: self._garc_dict[x]["size"], list(self._garc_dict.keys())))) sum_interspace = sum(list(map(lambda x: self._garc_dict[x]["interspace"], list(self._garc_dict.keys())))) start = 2 * np.pi * start / 360 end = (2 * np.pi * end / 360) - sum_interspace s = 0 sum_interspace = 0 for key in self._garc_dict.keys(): size = self._garc_dict[key].size self._garc_dict[key].coordinates = [None, None] self._garc_dict[key].coordinates[0] = sum_interspace + start + ((end-start) * s/sum_length) self._garc_dict[key].coordinates[1] = sum_interspace + start + ((end-start) * (s+size)/sum_length) s = s + size sum_interspace += self._garc_dict[key].interspace if self.fig_is_ext: self.ax = self.figure.add_axes([0, 0, self.figsize[0], self.figsize[1]], polar=True) else: self.ax = self.figure.add_axes([0, 0, 1, 1], polar=True) self.ax.set_theta_zero_location("N") self.ax.set_theta_direction(-1) self.ax.set_ylim(0,1000) self.ax.spines['polar'].set_visible(False) self.ax.xaxis.set_ticks([]) self.ax.xaxis.set_ticklabels([]) self.ax.yaxis.set_ticks([]) self.ax.yaxis.set_ticklabels([]) for i, key in enumerate(self._garc_dict.keys()): pos = self._garc_dict[key].coordinates[0] width = self._garc_dict[key].coordinates[-1] - self._garc_dict[key].coordinates[0] height = abs(self._garc_dict[key].raxis_range[1] - self._garc_dict[key].raxis_range[0]) bottom = self._garc_dict[key].raxis_range[0] facecolor = self._garc_dict[key].facecolor edgecolor = self._garc_dict[key].edgecolor linewidth = self._garc_dict[key].linewidth if facecolor is None: facecolor = (0, 0, 0, 0) if facecolor == (0, 0, 0, 0) and linewidth == 0: pass else: self.ax.bar([pos], [height], bottom=bottom, width=width, facecolor=facecolor, linewidth=linewidth, edgecolor=edgecolor, align="edge") if self._garc_dict[key].label_visible == True: rot = (self._garc_dict[key].coordinates[0] + self._garc_dict[key].coordinates[1]) / 2 rot = rot*360/(2*np.pi) if 90 < rot < 270: rot = 180-rot else: rot = -1 * rot height = bottom + height/2 + self._garc_dict[key].labelposition self.ax.text(pos + width/2, height, self._garc_dict[key].label, rotation=rot, ha="center", va="center", fontsize=self._garc_dict[key].labelsize)
def plot_tree(self, tarc_id, rlim=(0, 700), cladevisual_dict=None, highlight_dict=None, linecolor='#303030', linewidth=0.5)
-
Draw circular phylogenetic tree
Parameters
tarc_id
:str
- ID of the Tarc class object. The ID should be in Tcircle object.tarc_dict.
rlim
:tuple (top=int, bottom=int)
- The top and bottom r limits in data coordinates. The default is (0, 700).
cladevisual_dict
:dict
-
Dictionary composed of pairs of clade name and a sub-dict holding parameters to visualize the clade. A sub-dict is composed of the following key-value pairs:
size
:float
Size of dot. The default is 5.color
:float or str
representing color code.
Face color of dot. The default is "#303030".edgecolor
:float or str
representing color code.
Edge line color of dot. The default is "#303030".linewidth
:float
Edge line width of dot. The default is 0.5.
highlight_dict
:dict
-
Dictionary composed of pairs of internal clade name and a sub-dict. Instead of clade name, tuples of terminal clade names can also be A sub-dict is composed of the following key-value pairs:
color
:str
Color of highlight for clades. The default is "#000000".alpha
:float
Alpha of highlight for clades. The default is 0.25.label
:str
Label. The default is None.fontsize
:float
Fontsize of label. The default is 10.y
:float
Y location of the text. The default is the bottom edge of the highlight.
linecolor
:str
ortuple representing color code
, optional- Color of the tree line. The default is "#303030".
linewidth
:float
- Line width of tree. The default is 0.5.
Returns
None
Expand source code
def plot_tree(self, tarc_id, rlim=(0,700), cladevisual_dict=None, highlight_dict=None, linecolor="#303030", linewidth=0.5): """ Draw circular phylogenetic tree Parameters --------- tarc_id : str ID of the Tarc class object. The ID should be in Tcircle object.tarc_dict. rlim : tuple (top=int, bottom=int) The top and bottom r limits in data coordinates. The default is (0, 700). cladevisual_dict : dict Dictionary composed of pairs of clade name and a sub-dict holding parameters to visualize the clade. A sub-dict is composed of the following key-value pairs: - `size` : `float` Size of dot. The default is 5. - `color` : `float or str` representing color code. Face color of dot. The default is "#303030". - `edgecolor` : `float or str` representing color code. Edge line color of dot. The default is "#303030". - `linewidth` : `float` Edge line width of dot. The default is 0.5. highlight_dict : dict Dictionary composed of pairs of internal clade name and a sub-dict. Instead of clade name, tuples of terminal clade names can also be A sub-dict is composed of the following key-value pairs: - `color` : `str` Color of highlight for clades. The default is "#000000". - `alpha` : `float` Alpha of highlight for clades. The default is 0.25. - `label` : `str` Label. The default is None. - `fontsize` : `float` Fontsize of label. The default is 10. - `y` : `float` Y location of the text. The default is the bottom edge of the highlight. linecolor : str or tuple representing color code, optional Color of the tree line. The default is "#303030". linewidth : float Line width of tree. The default is 0.5. Returns ------- None """ start = self._garc_dict[tarc_id].coordinates[0] end = self._garc_dict[tarc_id].coordinates[-1] positions = np.linspace(start, end, self._garc_dict[tarc_id].size, endpoint=False) positions = positions + abs(positions[1]-positions[0]) * 0.5 start, end = positions[0], positions[-1] self._garc_dict[tarc_id]._plot_tree(self.ax, thetalim=(start, end), rlim=rlim, cladevisual_dict=cladevisual_dict, highlight_dict=highlight_dict, linecolor=linecolor, linewidth=linewidth)
def plot_highlight(self, tarc_id, highlight_dict=None)
-
Add highlight for specific clade under the given internal clade
Parameters
tarc_id
:str
- ID of the Tarc class object. The ID should be in Tcircle object.tarc_dict.
highlight_dict
:dict
-
Dictionary composed of pairs of internal clade name and a sub-dict. Instead of clade name, tuples of terminal clade names can also be used. A sub-dict is composed of the following key-value pairs:
color
:str
Color of highlight for clades. The default is "#000000".alpha
:float
Alpha of highlight for clades. The default is 0.25.label
:str
Label. The default is None.fontsize
:float
Fontsize of label. The default is 10.y
:float
Y location of the text. The default is the bottom edge of the highlight.
Returns
None
Expand source code
def plot_highlight(self, tarc_id, highlight_dict=None): """ Add highlight for specific clade under the given internal clade Parameters ---------- tarc_id : str ID of the Tarc class object. The ID should be in Tcircle object.tarc_dict. highlight_dict : dict Dictionary composed of pairs of internal clade name and a sub-dict. Instead of clade name, tuples of terminal clade names can also be used. A sub-dict is composed of the following key-value pairs: - `color` : `str` Color of highlight for clades. The default is "#000000". - `alpha` : `float` Alpha of highlight for clades. The default is 0.25. - `label` : `str` Label. The default is None. - `fontsize` : `float` Fontsize of label. The default is 10. - `y` : `float` Y location of the text. The default is the bottom edge of the highlight. Returns ------- None """ self._garc_dict[tarc_id]._plot_highlight(self.ax, highlight_dict=highlight_dict)
Inherited members