使用 matplotlib Polar=True 更改用作径向/角度位置的轴(使用 Bio.Phylo 创建圆形系统发育树)

问题描述 投票:0回答:1

如果我使用 Biopython Phylo 模块创建系统发育树,它是从左到右定向的,例如:

import matplotlib.pyplot as plt
from Bio import Phylo
from io import StringIO

handle = StringIO("(((A,B),(C,D)),(E,F,G));")
tree = Phylo.read(handle, "newick")

fig, ax = plt.subplots(1, 1, figsize=(6, 6))
Phylo.draw(tree, axes=ax, do_show=False)
plt.savefig("./tree_rect.png")
plt.close(fig)

产生

如果我现在尝试使用 matplotlib 的内置极坐标变换将其转换为圆形树,我会得到:

fig, ax = plt.subplots(subplot_kw=dict(polar=True), figsize=(6, 6))
Phylo.draw(tree, axes=ax, do_show=False)
plt.savefig("./tree_circ.png")
plt.close(fig)

我得到了

即matplotlib以y轴为径向轴,以x轴为角度。这与我获得正确布局所需的相反,我可以这样做,例如使用 ete3:

from ete3 import Tree, TreeStyle
t = Tree("(((A,B),(C,D)),(E,F,G));")
circular_style = TreeStyle()
circular_style.mode = "c"
circular_style.scale = 20
t.render("tree_ete3.png", w=183, units="mm", tree_style=circular_style)

(如何)使用 Bio.Phylo 可以完成此操作?我想可能性是

  • 更改
    Phylo.draw
    中的布局,使树朝上
  • 告诉 matplotlib 极坐标变换使用 x 轴作为径向向量,y 轴作为角度

但我也不知道该怎么做(以及是否可以做到。)

相关问题:Python:如何将系统发育树转换为循环格式?

python matplotlib bioinformatics biopython phylogeny
1个回答
0
投票

好吧,这里是一个示例,演示了至少正确交换 matplotlib 极坐标图中的“

x
”和“
y
”坐标,以便至少树正确分支。需要做进一步的工作来模拟在分支点处绘制极圆圆周(即弧)的部分,就像通常在径向系统发育图中看到的那样。

下面,我展示了代码中不同的缩放参数 (

'Scale'
r
) 会影响生成的树,并且还提供了与地图的正常
Bio.Phylo.draw(tree)
版本的比较。

import matplotlib.pyplot as plt
import numpy as np
from Bio import Phylo
from io import StringIO


def transform_coordinates(
    clade, r=0, theta=0, delta_theta=np.pi / 32, coordinates=None
):
    if coordinates is None:
        coordinates = {}

    coordinates[clade] = (r, theta)

    if clade.is_terminal():
        theta += delta_theta
    else:
        for child in clade:
            theta = transform_coordinates(
                child, r + 1, theta, delta_theta, coordinates
            )

    return theta


def plot_tree(tree, coordinates, scale=1):
    fig, ax = plt.subplots(subplot_kw=dict(polar=True), figsize=(6, 6))
    for clade in tree.find_clades():
        if not clade.is_terminal():
            for child in clade:
                x1, y1 = coordinates[clade]
                x2, y2 = coordinates[child]
                ax.plot([y1, y2], [x1, x2], "k-")
                if child.is_terminal():
                    # print(child.name, x2, y2, np.cos(x2), np.cos(y2))
                    shift_y = 0.05
                    shift_x = 0.025
                    if np.cos(y2) < 0:
                        shift_y += 0.15
                        shift_x *= 2
                    else:
                        shift_x *= -1
                    ax.annotate(
                        child.name, xy=(y2 * 1.02, x2 + shift_y), color="red"
                    )
                ax.grid("off")
                ax.patch.set_visible(False)
                ax.spines["polar"].set_visible(False)
                ax.xaxis.grid(False)
                ax.xaxis.set_visible(False)
                ax.yaxis.grid(False)
                ax.yaxis.set_visible(False)
    plt.title(f"Scale = {scale}\n")
    plt.show()


handle = StringIO("((((A,B),(X,Y,Z),(H,I,J))),(((C,L),(D,K)),(E,F,G)));")
tree = Phylo.read(handle, "newick")
coordinates = {}

for r in range(12, 36, 4):
    transform_coordinates(
        tree.clade, coordinates=coordinates, delta_theta=np.pi / r
    )
    plot_tree(tree, coordinates, scale=r)


注意

plot_tree
内x和y坐标的交换:
ax.plot([y1, y2], [x1, x2], "k-")

© www.soinside.com 2019 - 2024. All rights reserved.