-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rotate the tree 180 degree #2
Comments
There is no functionality in phyTreeViz to do what you want to do. |
I implemented the orientation functionality you suggested in newly released v0.2.0. It was easier than I thought it would be. Code Example from phytreeviz import TreeViz, load_example_tree_file
# Plot tree in `left` orientation
tree_file = load_example_tree_file("medium_example.nwk")
tv = TreeViz(tree_file, orientation="left")
tv.savefig("example.png")
# x and y coordinates of the leaf labels?
# No further coordinate information exists in phyTreeViz
for leaf_label in tv.leaf_labels:
leaf_line_tip_xy = tv.name2xy[leaf_label]
rect_for_highlight = tv.name2rect[leaf_label]
print(leaf_label, leaf_line_tip_xy, rect_for_highlight) |
Dear @moshi4 , Thank you very much for your update! The code to mirror a tree is quite elegant. However, I encountered an issue while attempting to create a tanglegram using the following code: from phytreeviz import TreeViz, load_example_tree_file
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
tree_file = load_example_tree_file("small_example.nwk")
tree_file2 = load_example_tree_file("small_example.nwk")
tv1 = TreeViz(tree_file, orientation="right")
tv2 = TreeViz(tree_file2, orientation="left")
fig = plt.figure(figsize=(9, 7))
gs = GridSpec(1, 2, width_ratios=[1,1])
ax1 = fig.add_subplot(gs[0,0])
ax2 = fig.add_subplot(gs[0,1])
tv1.plotfig(ax=ax1)
tv2.plotfig(ax=ax2)
fig.tight_layout()
plt.subplots_adjust(wspace=0, hspace=0) Unfortunately, it seems that the labels of the two trees are overlapping: Upon investigation, I discovered that this is due to the x-limit (xlim) of the axis extending only from the root to the furthest node, instead of encompassing the entire width of the tree including the labels. To address this, I attempted to extend the xlim to the farthest label using the code below: from phytreeviz import TreeViz
class PS_Treeviz(TreeViz):
def __init__(
self,
tree_data: str | Path | Tree, # type: ignore
# invert_: bool = False,
orientation: str = "right",
*,
format: str = "newick",
height: float = 0.5,
width: float = 8,
align_leaf_label: bool = False,
ignore_branch_length: bool = False,
leaf_label_size: float = 12,
innode_label_size: float = 0,
show_auto_innode_label: bool = True,
leaf_label_xmargin_ratio: float = 0.01,
innode_label_xmargin_ratio: float = 0.01,
reverse: bool = False,
):
super(PS_Treeviz, self).__init__(
tree_data,
orientation=orientation,
format=format,
height=height,
width=width,
align_leaf_label=align_leaf_label,
ignore_branch_length=ignore_branch_length,
leaf_label_size=leaf_label_size,
innode_label_size=innode_label_size,
show_auto_innode_label=show_auto_innode_label,
leaf_label_xmargin_ratio=leaf_label_xmargin_ratio,
innode_label_xmargin_ratio=innode_label_xmargin_ratio,
reverse=reverse,
)
# for setting xlim
self.tree_lengths: list = [self.max_tree_depth]
@property
def xlim(self) -> tuple[float, float]:
"""Axes xlim"""
if self._orientation == "left":
return (max(self.tree_lengths), 0)
else:
return (0, max(self.tree_lengths))
def _plot_node_label(self, ax: Axes) -> None:
"""Plot tree node label
Parameters
----------
ax : Axes
Matplotlib axes for plotting
"""
node: Clade
self.tree_lengths: list = [self.max_tree_depth]
for node in self.tree.find_clades():
# Get label x, y position
x, y = self.name2xy[str(node.name)]
# Get label size & xmargin
if node.is_terminal():
label_size = self._leaf_label_size
label_xmargin_ratio = self._leaf_label_xmargin_ratio
else:
label_size = self._innode_label_size
label_xmargin_ratio = self._innode_label_xmargin_ratio
label_xmargin = self.max_tree_depth * label_xmargin_ratio
# Set label x position with margin
if node.is_terminal() and self._align_leaf_label:
x = self.max_tree_depth + label_xmargin
else:
x += label_xmargin
# Skip if 'label is auto set name' or 'no label size'
if label_size <= 0:
continue
is_auto_innode_label = node.name in self._auto_innode_labels
if not self._show_auto_innode_label and is_auto_innode_label:
continue
# Plot label
text_kws = dict(size=label_size, ha="left", va="center_baseline")
text_kws.update(self._node2label_props[str(node.name)])
if self._orientation == "left":
text_kws.update(ha="right")
ax_text = ax.text(x, y, s=node.name, **text_kws)
trans_bbox = self.ax.transData.inverted().transform_bbox(ax_text.get_window_extent())
text_length = trans_bbox.width # trans_bbox.xmax - trans_bbox.xmin
# get toot to text width
if node.is_terminal():
# text_length = self._get_texts_rect(node.name).get_width()
length = x + text_length
self.tree_lengths.append(length)
self._init_axes(self.ax)
tree_file = load_example_tree_file("small_example.nwk")
tree_file2 = load_example_tree_file("small_example.nwk")
tv1 = PS_Treeviz(tree_file, orientation="right")
tv2 = PS_Treeviz(tree_file2, orientation="left")
fig = plt.figure(figsize=(9, 7))
gs = GridSpec(1, 2, width_ratios=[1,1])
ax1 = fig.add_subplot(gs[0,0])
ax2 = fig.add_subplot(gs[0,1])
tv1.plotfig(ax=ax1)
tv2.plotfig(ax=ax2)
fig.tight_layout()
plt.subplots_adjust(wspace=0, hspace=0) However, some overlaps persist: It's worth noting that extending the xlim in this manner could also enhance our ability to draw alignment figures alongside the tree (related to #1 ssue). Interestingly, my modified code works seamlessly when there's only one tree: tree_file = load_example_tree_file("small_example.nwk")
tv = PS_Treeviz(tree_file, orientation='right')
tv.show_branch_length(color="red")
tv.show_confidence(color="blue")
tv.show_scale_bar()
fig = plt.figure(figsize=(9, 7))
gs = GridSpec(1, 3, width_ratios=[4, 1, 1])
ax1 = fig.add_subplot(gs[0,0])
ax2 = fig.add_subplot(gs[0,1])
ax3 = fig.add_subplot(gs[0,2])
ax1.sharey(ax2)
ax2.sharey(ax3)
ax2.axis('off')
ax2.grid(False)
ax3.axis('off')
ax3.grid(False)
def draw_piechart(ax, labels, sizes, center, radius, start_angle):
total = sum(sizes)
theta1 = start_angle
for size in sizes:
theta2 = theta1 + (size / total) * 360.0
wedge = Wedge(center, radius, theta1, theta2, edgecolor=ColorCycler(), facecolor=ColorCycler())
ax.add_patch(wedge)
theta1 = theta2
tv.plotfig(ax=ax1)
ax1.grid(True)
categories = [1, 2, 3, 4, 5, 6, 7]
values = [25, 40, 30, 20, 40, 10, 30]
ax3.barh(categories, values, color='skyblue')
labels = ['Category A', 'Category B', 'Category C', 'Category D']
sizes = [25, 30, 20, 25]
radius = 0.3
ax2.set_xlim(0, radius*2)
start_angle = 0
ax2.set_aspect('equal', adjustable='box')
for leaf in tv.leaf_labels:
x, y = tv.name2xy_center[leaf]
center = (0.3, y)
draw_piechart(ax2, labels, sizes, center, radius, start_angle)
x_total = tv.xlim[1] - tv.xlim[0]
y_total = tv.ylim[1] - tv.ylim[0]
in_axs_wh = 0.1
radius = 0.5
for node in tv.innode_labels:
x, y = tv.name2xy_center[node]
center = (0.5,0.5)
x_ = (x-in_axs_wh/2)/x_total
y_ = y/y_total
in_axs = ax1.inset_axes([x_,y_,in_axs_wh,in_axs_wh])
in_axs.axis('off')
in_axs.grid(False)
in_axs.set_aspect('equal', adjustable='box')
draw_piechart(in_axs, labels, sizes, center, radius, start_angle)
fig.tight_layout()
plt.subplots_adjust(wspace=0, hspace=0) Do you have any insights into why the code works for one tree but fails for two trees? Additionally, do you have any suggestions for achieving the desired outcome more effectively? On a side note, it appears that the scale bar is not displaying correctly in my figure. I'm uncertain about the cause of this issue. Thank you for your patience and assistance! Sincerely, Dong |
I think what you want to do is a challenging task in using matplotlib. With patchworklib, you may possibly be able to solve your problem. Code Example1
from phytreeviz import TreeViz, load_example_tree_file
import patchworklib as pw
tree_file = load_example_tree_file("small_example.nwk")
tv1 = TreeViz(tree_file, orientation="right")
tv1.highlight(["Homo_sapiens", "Pan_paniscus"], color="salmon")
tv2 = TreeViz(tree_file, orientation="left")
tv2.highlight(["Hylobates_moloch", "Nomascus_leucogenys"], color="skyblue")
ax1 = pw.Brick(figsize=(3, 7))
ax2 = pw.Brick(figsize=(3, 7))
tv1.plotfig(ax=ax1)
tv2.plotfig(ax=ax2)
ax12 = ax1 | ax2
ax12.savefig("example1.png") example1.png Code Example2 from phytreeviz import TreeViz, load_example_tree_file
import patchworklib as pw
from matplotlib.patches import Wedge
import random
random.seed(0)
# Plot tree (ax1)
tree_file = load_example_tree_file("small_example.nwk")
tv = TreeViz(tree_file, orientation="right")
tv.highlight(["Homo_sapiens", "Pan_paniscus"], color="salmon")
tv.show_branch_length(color="red")
tv.show_confidence(color="blue")
tv.show_scale_bar()
ax1 = pw.Brick(figsize=(3, 7))
tv.plotfig(ax=ax1)
# Plot piechart (ax2)
def draw_piechart(ax, sizes, center, radius):
total = sum(sizes)
theta1 = 0
colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf']
for idx, size in enumerate(sizes):
theta2 = theta1 + (size / total) * 360.0
wedge = Wedge(center, radius, theta1, theta2, edgecolor=colors[idx], facecolor=colors[idx])
ax.add_patch(wedge)
theta1 = theta2
ax2 = pw.Brick(figsize=(1, 7))
ax2.set_xlim(0, 1)
ax2.set_ylim(*tv.ylim)
ax2.set_axis_off()
ax2.set_aspect(aspect=1)
for i in range(len(tv.leaf_labels)):
draw_piechart(ax2, [10, 20, 30, 40], center=(0.5, i + 1), radius=0.35)
# Plot bar (ax3)
ax3 = pw.Brick(figsize=(3, 7))
ax3.set_ylim(*tv.ylim)
ax3.set_axis_off()
y = list(range(1, len(tv.leaf_labels) + 1))
x = [random.randint(1, 10) for _ in range(len(tv.leaf_labels))]
ax3.barh(y, x, color="skyblue")
# Concatenate axes
ax123 = ax1 | ax2 | ax3
ax123.savefig("example2.png") example2.png I can't advise you on anything more than this, as it is a difficult problem for me as well. |
Dear @moshi4, Thank you for providing the suggested codes; they resolved my problem. I'm also delighted to discover patchworklib—it's a fantastic package and has been quite helpful.
A quick overview of the fundamental work for phyTreeViz we have completed: One of my previous questions remains unresolved: I've noticed that in your code, there is a scale bar when using |
Your use of phyTreeViz is out of the basic usage originally expected. |
Thank you @moshi4 , I discovered that the issue was caused by the size_vertical parameter of AnchoredSizeBar. When I set it to 0.1, I was able to see the bar. |
Dear developer,
Thank you for your previous suggestion. I discovered that phyTreeViz is a useful tool that can integrate Matplotlib components. Currently, I'm developing a function to create a tangled tree. To accomplish this, I first need to mirror the tree so that it faces left (i.e., rotate the tree 180 degrees). The second step is to obtain the x and y coordinates of the leaf labels in the mirrored tree. Do you have any suggested code for achieving this?
The resulting tree should resemble the following:
Sincerely,
Dong
The text was updated successfully, but these errors were encountered: