From 48b8963f7d7773cc68d5d179799342d1bb615bf9 Mon Sep 17 00:00:00 2001 From: colganwi Date: Wed, 22 May 2024 11:55:34 -0400 Subject: [PATCH 1/6] clades --- docs/api.md | 10 +++++ src/pycea/tl/__init__.py | 1 + src/pycea/tl/clades.py | 82 ++++++++++++++++++++++++++++++++++++++++ tests/test_clades.py | 47 +++++++++++++++++++++++ 4 files changed, 140 insertions(+) create mode 100755 src/pycea/tl/clades.py create mode 100755 tests/test_clades.py diff --git a/docs/api.md b/docs/api.md index 5af4400..9694185 100644 --- a/docs/api.md +++ b/docs/api.md @@ -4,6 +4,16 @@ ## Tools +```{eval-rst} +.. module:: pycea.tl +.. currentmodule:: pycea + +.. autosummary:: + :toctree: generated + + tl.clades +``` + ## Plotting ```{eval-rst} diff --git a/src/pycea/tl/__init__.py b/src/pycea/tl/__init__.py index e69de29..3221966 100644 --- a/src/pycea/tl/__init__.py +++ b/src/pycea/tl/__init__.py @@ -0,0 +1 @@ +from .clades import clades diff --git a/src/pycea/tl/clades.py b/src/pycea/tl/clades.py new file mode 100755 index 0000000..20b50a2 --- /dev/null +++ b/src/pycea/tl/clades.py @@ -0,0 +1,82 @@ +from __future__ import annotations + +from collections.abc import Mapping, Sequence + +import networkx as nx +import treedata as td + +from pycea.utils import get_root + + +def _nodes_at_depth(tree, parent, nodes, depth, depth_key): + """Recursively finds nodes at a given depth.""" + if tree.nodes[parent][depth_key] >= depth: + nodes.append(parent) + else: + for child in tree.successors(parent): + _nodes_at_depth(tree, child, nodes, depth, depth_key) + return nodes + + +def clades( + tdata: td.TreeData, + key: str | Sequence[str] = None, + depth: int | float = None, + depth_key: str = "depth", + clades: str | Sequence[str] = None, + clade_key: str = "clade", + copy: bool = False, +) -> None | Mapping: + """Identifies clades in a tree. + + Parameters + ---------- + tdata + The TreeData object. + key + The `obst` key of the tree. + depth + Depth to cut tree at. Must be specified if clades is None. + depth_key + Key where depth is stored. + clades + A dictionary mapping nodes to clades. + clade_key + Key to store clades in. + copy + If True, returns a dictionary mapping nodes to clades. + + Returns + ------- + None or Mapping + If copy is True, returns a dictionary mapping nodes to clades. + """ + # Get tree + if not key: + key = tdata.obs_keys()[0] + tree = tdata.obst[key] + # Get clades + if (depth is not None) and (clades is None): + nodes = _nodes_at_depth(tree, get_root(tree), [], depth, depth_key) + clades = {node: str(clade) for clade, node in enumerate(nodes)} + elif (clades is not None) and (depth is None): + pass + else: + raise ValueError("Must specify either clades or depth.") + # Set clades + leaf_clades = {} + for node, clade in clades.items(): + # Leaf + if tree.out_degree(node) == 0: + leaf_clades[node] = clade + tree.nodes[node][clade_key] = clade + # Internal node + for u, v in nx.dfs_edges(tree, node): + tree.nodes[u][clade_key] = clade + tree.edges[u, v][clade_key] = clade + if tree.out_degree(v) == 0: + leaf_clades[v] = clade + tree.nodes[v][clade_key] = clade + tdata.obs[clade_key] = tdata.obs.index.map(leaf_clades) + if copy: + return clades diff --git a/tests/test_clades.py b/tests/test_clades.py new file mode 100755 index 0000000..a6aa5f2 --- /dev/null +++ b/tests/test_clades.py @@ -0,0 +1,47 @@ +import networkx as nx +import pandas as pd +import pytest +import treedata as td + +from pycea.tl.clades import _nodes_at_depth, clades + + +@pytest.fixture +def tree(): + t = nx.DiGraph() + t.add_edges_from([("A", "B"), ("A", "C"), ("C", "D"), ("C", "E")]) + nx.set_node_attributes(t, {"A": 0, "B": 2, "C": 1, "D": 2, "E": 2}, "depth") + yield t + + +@pytest.fixture +def tdata(tree): + tdata = td.TreeData(obs=pd.DataFrame(index=["B", "D", "E"]), obst={"tree": tree}) + yield tdata + + +def test_nodes_at_depth(tree): + assert _nodes_at_depth(tree, "A", [], 0, "depth") == ["A"] + assert _nodes_at_depth(tree, "A", [], 1, "depth") == ["B", "C"] + assert _nodes_at_depth(tree, "A", [], 2, "depth") == ["B", "D", "E"] + + +def test_clades_given_dict(tdata, tree): + clades(tdata, clades={"B": 0, "C": 1}) + assert tdata.obs["clade"].tolist() == [0, 1, 1] + assert tdata.obst["tree"].nodes["C"]["clade"] == 1 + assert tdata.obst["tree"].edges[("C", "D")]["clade"] == 1 + clades(tdata, clades={"A": "0"}, clade_key="all") + assert tdata.obs["all"].tolist() == ["0", "0", "0"] + assert tdata.obst["tree"].nodes["A"]["all"] == "0" + assert tdata.obst["tree"].edges[("C", "D")]["all"] == "0" + + +def test_clades_given_depth(tdata): + clades(tdata, depth=0) + assert tdata.obs["clade"].tolist() == ["0", "0", "0"] + nodes = clades(tdata, depth=1, copy=True) + assert tdata.obs["clade"].tolist() == ["0", "1", "1"] + assert nodes == {"B": "0", "C": "1"} + clades(tdata, depth=2) + assert tdata.obs["clade"].tolist() == ["0", "1", "2"] From 08c54f6935d6a10875e322c1630b0652e2bbea60 Mon Sep 17 00:00:00 2001 From: colganwi Date: Fri, 24 May 2024 14:12:15 -0400 Subject: [PATCH 2/6] plot multiple trees --- src/pycea/pl/_utils.py | 119 +++++++++++++++++++++++++------------ src/pycea/pl/plot_tree.py | 121 ++++++++++++++++++++++++-------------- src/pycea/utils.py | 69 ++++++++++++++++++---- tests/data/tdata.h5ad | Bin 1612504 -> 1607616 bytes tests/test_plot_tree.py | 31 ++++------ tests/test_plot_utils.py | 48 ++++++++++----- tests/test_utils.py | 8 ++- 7 files changed, 266 insertions(+), 130 deletions(-) diff --git a/src/pycea/pl/_utils.py b/src/pycea/pl/_utils.py index fb60491..5b4daa8 100755 --- a/src/pycea/pl/_utils.py +++ b/src/pycea/pl/_utils.py @@ -1,7 +1,8 @@ """Plotting utilities""" +from __future__ import annotations -import collections.abc as cabc import warnings +from collections.abc import Mapping, Sequence import cycler import matplotlib as mpl @@ -11,22 +12,24 @@ import numpy as np from scanpy.plotting import palettes -from pycea.utils import get_root +from pycea.utils import get_leaves, get_root -def layout_tree( +def layout_nodes_and_branches( tree: nx.DiGraph, - depth_key: str = "time", + leaf_coords: Mapping[str], + depth_key: str = "depth", polar: bool = False, - extend_branches: bool = True, angled_branches: bool = False, ): - """Given a tree, computes the coordinates of the nodes and branches. + """Given a tree and leaf coordinates, computes the coordinates of the nodes and branches. Parameters ---------- tree The `nx.DiGraph` representing the tree. + leaf_coords + A dictionary mapping leaves to their coordinates. depth_key The node attribute to use as the depth of the nodes. polar @@ -42,38 +45,15 @@ def layout_tree( A dictionary mapping nodes to their coordinates. branch_coords A dictionary mapping edges to their coordinates. - leaves - A list of the leaves of the tree. - max_depth - The maximum depth of the tree. """ - # Get node depths - n_leaves = 0 - root = get_root(tree) - depths = {} - for node in tree.nodes(): - if tree.out_degree(node) == 0: - n_leaves += 1 - depths[node] = tree.nodes[node].get(depth_key) - max_depth = max(depths.values()) # Get node coordinates - i = 0 - leaves = [] - node_coords = {} - for node in nx.dfs_postorder_nodes(tree, root): - if tree.out_degree(node) == 0: - lon = (i / (n_leaves)) * 2 * np.pi # + 2 * np.pi / n_leaves - if extend_branches: - node_coords[node] = (max_depth, lon) - else: - node_coords[node] = (depths[node], lon) - leaves.append(node) - i += 1 - else: + node_coords = leaf_coords.copy() + for node in nx.dfs_postorder_nodes(tree, get_root(tree)): + if tree.out_degree(node) != 0: children = list(tree.successors(node)) min_lon = min(node_coords[child][1] for child in children) max_lon = max(node_coords[child][1] for child in children) - node_coords[node] = (depths[node], (min_lon + max_lon) / 2) + node_coords[node] = (tree.nodes[node].get(depth_key), (min_lon + max_lon) / 2) # Get branch coordinates branch_coords = {} for parent, child in tree.edges(): @@ -96,9 +76,69 @@ def layout_tree( inter_lons = np.linspace(lons[0], lons[1], int(np.ceil(angle / min_angle))) inter_lats = [lats[0]] * len(inter_lons) branch_coords[(parent, child)] = (np.append(inter_lats, lats[-1]), np.append(inter_lons, lons[-1])) + return node_coords, branch_coords + + +def layout_trees( + trees: Mapping[str], + depth_key: str = "depth", + polar: bool = False, + extend_branches: bool = True, + angled_branches: bool = False, +): + """Given a list of trees, computes the coordinates of the nodes and branches. + + Parameters + ---------- + trees + A dictionary mapping tree names to `nx.DiGraph` representing the trees. + depth_key + The node attribute to use as the depth of the nodes. + polar + Whether to plot the tree in polar coordinates. + extend_branches + Whether to extend branches so the tips are at the same depth. + angled_branches + Whether to plot branches at an angle. + + Returns + ------- + node_coords + A dictionary mapping nodes to their coordinates. + branch_coords + A dictionary mapping edges to their coordinates. + leaves + A list of the leaves of the tree. + max_depth + The maximum depth of the tree. + """ + # Get leaf coordinates + leaves = [] + depths = [] + for _ , tree in trees.items(): + tree_leaves = get_leaves(tree) + leaves.extend(tree_leaves) + depths.extend(tree.nodes[leaf].get(depth_key) for leaf in tree_leaves) + max_depth = max(depths) + n_leaves = len(leaves) + leaf_coords = {} + for i in range(n_leaves): + lon = (i / n_leaves) * 2 * np.pi + if extend_branches: + leaf_coords[leaves[i]] = (max_depth, lon) + else: + leaf_coords[leaves[i]] = (depths[i], lon) + # Layout trees + node_coords = {} + branch_coords = {} + for key, tree in trees.items(): + tree_node_coords,tree_branch_coords = layout_nodes_and_branches(tree, leaf_coords, depth_key, polar, angled_branches) + node_coords.update({f"{key}-{node}": coords for node, coords in tree_node_coords.items()}) + branch_coords.update({(f"{key}-{parent}", f"{key}-{child}"): coords for (parent, child), coords in tree_branch_coords.items()}) return node_coords, branch_coords, leaves, max_depth + def _get_default_categorical_colors(length): """Get default categorical colors for plotting.""" # check if default matplotlib palette has enough colors @@ -133,7 +173,7 @@ def _get_categorical_colors(tdata, key, data, palette=None): # Use default colors if no palette is provided if palette is None: colors_list = tdata.uns.get(key + "_colors", None) - if colors_list is None or len(colors_list) > len(categories): + if (colors_list is None) or (len(colors_list) < len(categories)): colors_list = _get_default_categorical_colors(len(categories)) # Use provided palette else: @@ -141,12 +181,12 @@ def _get_categorical_colors(tdata, key, data, palette=None): # this creates a palette from a colormap. E.g. 'Accent, Dark2, tab20' cmap = plt.get_cmap(palette) colors_list = [mcolors.to_hex(x, keep_alpha=True) for x in cmap(np.linspace(0, 1, len(categories)))] - elif isinstance(palette, cabc.Mapping): + elif isinstance(palette, Mapping): colors_list = [mcolors.to_hex(palette[k], keep_alpha=True) for k in categories] else: # check if palette is a list and convert it to a cycler, thus # it doesnt matter if the list is shorter than the categories length: - if isinstance(palette, cabc.Sequence): + if isinstance(palette, Sequence): if len(palette) < len(categories): warnings.warn( "Length of palette colors is smaller than the number of " @@ -173,7 +213,8 @@ def _get_categorical_colors(tdata, key, data, palette=None): cc = palette() colors_list = [mcolors.to_hex(next(cc)["color"], keep_alpha=True) for x in range(len(categories))] # store colors in tdata - tdata.uns[key + "_colors"] = colors_list + if len(categories) <= len(palettes.default_102): + tdata.uns[key + "_colors"] = colors_list return dict(zip(categories, colors_list)) @@ -191,10 +232,10 @@ def _get_categorical_markers(tdata, key, data, markers=None): markers_list = default_markers[: len(categories)] # Use provided markers else: - if isinstance(markers, cabc.Mapping): + if isinstance(markers, Mapping): markers_list = [markers[k] for k in categories] else: - if not isinstance(markers, cabc.Sequence): + if not isinstance(markers, Sequence): raise ValueError("Please check that the value of 'markers' is a valid " "list of marker names.") if len(markers) < len(categories): warnings.warn( diff --git a/src/pycea/pl/plot_tree.py b/src/pycea/pl/plot_tree.py index f44fa55..c77bbc6 100644 --- a/src/pycea/pl/plot_tree.py +++ b/src/pycea/pl/plot_tree.py @@ -9,18 +9,19 @@ import matplotlib.markers as mmarkers import matplotlib.pyplot as plt import numpy as np +import pandas as pd import treedata as td from matplotlib.axes import Axes from matplotlib.collections import LineCollection -from pycea.utils import get_keyed_edge_data, get_keyed_node_data, get_keyed_obs_data +from pycea.utils import get_keyed_edge_data, get_keyed_node_data, get_keyed_obs_data, get_trees from ._docs import _doc_params, doc_common_plot_args from ._utils import ( _get_categorical_colors, _get_categorical_markers, _series_to_rgb_array, - layout_tree, + layout_trees, ) @@ -29,12 +30,13 @@ ) def branches( tdata: td.TreeData, - keys: str | Sequence[str] = None, polar: bool = False, extend_branches: bool = False, angled_branches: bool = False, color: str = "black", linewidth: int | float | str = 1, + depth_key: str = "depth", + tree: str | Sequence[str] | None = None, cmap: str | mcolors.Colormap = "viridis", palette: cycler.Cycler | mcolors.ListedColormap | Sequence[str] | Mapping[str] | None = None, na_color: str = "lightgrey", @@ -49,8 +51,6 @@ def branches( ---------- tdata The `treedata.TreeData` object. - keys - The `obst` key or keys of the trees to plot. polar Whether to plot the tree in polar coordinates. extend_branches @@ -61,6 +61,10 @@ def branches( Either a color name, or a key for an attribute of the edges to color by. linewidth Either an numeric width, or a key for an attribute of the edges to set the linewidth. + depth_key + The key for the depth of the nodes. + tree + The `obst` key or keys of the trees to plot. If `None`, all trees are plotted. {common_plot_args} na_color The color to use for edges with missing data. @@ -74,22 +78,17 @@ def branches( ax - The axes that the plot was drawn on. """ # noqa: D205 # Setup + tree_keys = tree if not ax: ax = plt.gca() if (ax.name == "polar" and not polar) or (ax.name != "polar" and polar): warnings.warn("Polar setting of axes does not match requested type. Creating new axes.", stacklevel=2) fig, ax = plt.subplots(subplot_kw={"projection": "polar"} if polar else None) kwargs = kwargs if kwargs else {} - if not keys: - key = next(iter(tdata.obst.keys())) - elif isinstance(keys, str): - key = keys - else: - raise ValueError("Passing a list of keys not implemented. Please pass a single key.") - tree = tdata.obst[key] + trees = get_trees(tdata, tree_keys) # Get layout - node_coords, branch_coords, leaves, depth = layout_tree( - tree, polar=polar, extend_branches=extend_branches, angled_branches=angled_branches + node_coords, branch_coords, leaves, depth = layout_trees( + trees, depth_key= depth_key ,polar=polar, extend_branches=extend_branches, angled_branches=angled_branches ) segments = [] edges = [] @@ -102,13 +101,19 @@ def branches( if mcolors.is_color_like(color): kwargs.update({"color": color}) elif isinstance(color, str): - color_data = get_keyed_edge_data(tree, color) + color_data = get_keyed_edge_data(trees, color) if color_data.dtype.kind in ["i", "f"]: norm = plt.Normalize(vmin=color_data.min(), vmax=color_data.max()) cmap = plt.get_cmap(cmap) colors = [cmap(norm(color_data[edge])) if edge in color_data.index else na_color for edge in edges] kwargs.update({"color": colors}) else: + if color in tdata.obs.columns: + if tdata.obs[color].dtype.kind not in ["i", "f"]: + tdata.obs[color] = tdata.obs[color].astype("category") + if set(color_data.unique()).issubset(tdata.obs[color].cat.categories): + color_data = pd.Series(pd.Categorical(color_data, + categories=tdata.obs[color].cat.categories),index=color_data.index) cmap = _get_categorical_colors(tdata, color, color_data, palette) colors = [cmap[color_data[edge]] if edge in color_data.index else na_color for edge in edges] kwargs.update({"color": colors}) @@ -118,7 +123,7 @@ def branches( if isinstance(linewidth, (int, float)): kwargs.update({"linewidth": linewidth}) elif isinstance(linewidth, str): - linewidth_data = get_keyed_edge_data(tree, linewidth) + linewidth_data = get_keyed_edge_data(trees, linewidth) if linewidth_data.dtype.kind in ["i", "f"]: linewidths = [linewidth_data[edge] if edge in linewidth_data.index else na_linewidth for edge in edges] kwargs.update({"linewidth": linewidths}) @@ -147,7 +152,7 @@ def branches( "depth": depth, "offset": depth, "polar": polar, - "tree_key": key, + "tree_keys": list(trees.keys()), } return ax @@ -166,6 +171,7 @@ def nodes( style: str = "o", size: int | float | str = 10, cmap: str | mcolors.Colormap = None, + tree:str | Sequence[str] | None = None, palette: cycler.Cycler | mcolors.ListedColormap | Sequence[str] | Mapping[str] | None = None, markers: Sequence[str] | Mapping[str] = None, vmax: int | float | None = None, @@ -192,6 +198,8 @@ def nodes( Can be numeric but will always be treated as a categorical variable. size Either an numeric size, or a key for an attribute of the nodes to set the size. + tree + The `obst` key or keys of the trees to plot. If `None`, all trees are plotted. {common_plot_args} markers Object determining how to draw the markers for different levels of the style variable. @@ -219,17 +227,27 @@ def nodes( if not cmap: cmap = mpl.rcParams["image.cmap"] cmap = plt.get_cmap(cmap) - tree = tdata.obst[attrs["tree_key"]] + if tree is None: + tree_keys = attrs["tree_keys"] + else: + tree_keys = tree + trees = get_trees(tdata, attrs["tree_keys"]) # Get nodes - all_nodes = list(attrs["node_coords"].keys()) - leaves = list(attrs["leaves"]) + all_nodes = set() + for node in list(attrs["node_coords"].keys()): + if any(node.startswith(key) for key in tree_keys): + all_nodes.add(node) + leaves = set(attrs["leaves"]) if nodes == "all": - nodes = all_nodes + nodes = list(all_nodes) elif nodes == "leaves": - nodes = leaves + nodes = list(all_nodes.intersection(leaves)) elif nodes == "internal": - nodes = [node for node in all_nodes if node not in leaves] + nodes = list(all_nodes.difference(leaves)) elif isinstance(nodes, Sequence): + if len(attrs["tree_keys"]) > 1 and isinstance(tree_keys, str): + raise ValueError("Multiple trees are present. To plot a list of nodes, you must specify the tree.") + nodes = [f"{tree_key}-{node}" for tree_key in tree_keys for node in nodes] if set(nodes).issubset(all_nodes): nodes = list(nodes) else: @@ -247,7 +265,7 @@ def nodes( if mcolors.is_color_like(color): kwargs.update({"color": color}) elif isinstance(color, str): - color_data = get_keyed_node_data(tree, color) + color_data = get_keyed_node_data(trees, color) if color_data.dtype.kind in ["i", "f"]: if not vmin: vmin = color_data.min() @@ -257,6 +275,12 @@ def nodes( colors = [cmap(norm(color_data[node])) if node in color_data.index else na_color for node in nodes] kwargs.update({"color": colors}) else: + if color in tdata.obs.columns: + if tdata.obs[color].dtype.kind not in ["i", "f"]: + tdata.obs[color] = tdata.obs[color].astype("category") + if set(color_data.unique()).issubset(tdata.obs[color].cat.categories): + color_data = pd.Series(pd.Categorical(color_data, + categories=tdata.obs[color].cat.categories),index=color_data.index) cmap = _get_categorical_colors(tdata, color, color_data, palette) colors = [cmap[color_data[node]] if node in color_data.index else na_color for node in nodes] kwargs.update({"color": colors}) @@ -266,7 +290,7 @@ def nodes( if isinstance(size, (int, float)): kwargs.update({"s": size}) elif isinstance(size, str): - size_data = get_keyed_node_data(tree, size) + size_data = get_keyed_node_data(trees, size) sizes = [size_data[node] if node in size_data.index else na_size for node in nodes] kwargs.update({"s": sizes}) else: @@ -275,7 +299,7 @@ def nodes( if style in mmarkers.MarkerStyle.markers: kwargs.update({"marker": style}) elif isinstance(style, str): - style_data = get_keyed_node_data(tree, style) + style_data = get_keyed_node_data(trees, style) mmap = _get_categorical_markers(tdata, style, style_data, markers) styles = [mmap[style_data[node]] if node in style_data.index else na_style for node in nodes] for style in set(styles): @@ -313,6 +337,7 @@ def annotation( gap: int | float = 0.03, label: bool | str | Sequence[str] = True, border_width: int | float = 0, + tree: str | Sequence[str] | None = None, cmap: str | mcolors.Colormap = None, palette: cycler.Cycler | mcolors.ListedColormap | Sequence[str] | Mapping[str] | None = None, vmax: int | float | None = None, @@ -339,6 +364,8 @@ def annotation( If a string or a sequence of strings, the strings are used as labels. border_width The width of the border around the annotation bar. + tree + The `obst` key or keys of the trees to plot. If `None`, all trees are plotted. {common_plot_args} na_color The color to use for annotations with missing data. @@ -350,6 +377,8 @@ def annotation( ax - The axes that the plot was drawn on. """ # noqa: D205 # Setup + if tree: #TODO: Annotate only the leaves for the given tree + pass if not ax: ax = plt.gca() attrs = ax._attrs if hasattr(ax, "_attrs") else None @@ -361,9 +390,10 @@ def annotation( if not cmap: cmap = mpl.rcParams["image.cmap"] cmap = plt.get_cmap(cmap) + leaves = attrs["leaves"] # Get data data, is_array = get_keyed_obs_data(tdata, keys) - data = data.loc[attrs["leaves"]] + data = data.loc[leaves] numeric_data = data.select_dtypes(exclude="category") if len(numeric_data) > 0 and not vmin: vmin = numeric_data.min().min() @@ -372,6 +402,8 @@ def annotation( # Get labels if label is True: labels = keys + elif label is False: + labels = [] elif isinstance(label, str): labels = [label] elif isinstance(label, Sequence): @@ -382,30 +414,29 @@ def annotation( start_lat = attrs["offset"] + attrs["depth"] * gap end_lat = start_lat + attrs["depth"] * width * data.shape[1] lats = np.linspace(start_lat, end_lat, data.shape[1] + 1) - lons = np.linspace(0, 2 * np.pi, data.shape[0] + 1) - lons = lons - np.pi / len(attrs["leaves"]) + lons = np.linspace(0, 2 * np.pi, len(leaves) + 1) + lons = lons - np.pi / len(leaves) # Covert to RGB array rgb_array = [] if is_array: if data.shape[0] == data.shape[1]: - data = data.loc[attrs["leaves"], reversed(attrs["leaves"])] + data = data.loc[leaves, reversed(leaves)] end_lat = start_lat + attrs["depth"] + 2 * np.pi lats = np.linspace(start_lat, end_lat, data.shape[1] + 1) for col in data.columns: - rgb_array.append(_series_to_rgb_array(data[col], cmap, vmin=vmin, vmax=vmax, na_color=na_color)) + rgb_array.append(_series_to_rgb_array(data.loc[col], cmap, vmin=vmin, vmax=vmax, na_color=na_color)) else: for key in keys: if data[key].dtype == "category": - colors = _get_categorical_colors(tdata, key, data[key], palette) - rgb_array.append(_series_to_rgb_array(data[key], colors, na_color=na_color)) + colors = _get_categorical_colors(tdata, key, data.loc[leaves,key], palette) + rgb_array.append(_series_to_rgb_array(data.loc[leaves,key], colors, na_color=na_color)) else: - rgb_array.append(_series_to_rgb_array(data[key], cmap, vmin=vmin, vmax=vmax, na_color=na_color)) + rgb_array.append(_series_to_rgb_array(data.loc[leaves,key], cmap, vmin=vmin, vmax=vmax, na_color=na_color)) rgb_array = np.stack(rgb_array, axis=1) # Plot if attrs["polar"]: ax.pcolormesh(lons, lats, rgb_array.swapaxes(0, 1), zorder=2, **kwargs) ax.set_ylim(-attrs["depth"] * 0.05, end_lat) - # ax.plot([0, np.pi, np.pi, 0, 0], [start_lat, start_lat, end_lat, end_lat, start_lat], color="black") else: ax.pcolormesh(lats, lons, rgb_array, zorder=2, **kwargs) ax.set_xlim(-attrs["depth"] * 0.05, end_lat + attrs["depth"] * width * 0.5) @@ -443,11 +474,12 @@ def annotation( def tree( tdata: td.TreeData, keys: str | Sequence[str] = None, + tree: str | Sequence[str] | None = None, nodes: str | Sequence[str] = None, - annotation_keys: str | Sequence[str] = None, polar: bool = False, extend_branches: bool = False, angled_branches: bool = False, + depth_key: str = "depth", branch_color: str = "black", branch_linewidth: int | float | str = 1, node_color: str = "black", @@ -467,17 +499,19 @@ def tree( tdata The TreeData object. keys - The `obst` key or keys of the trees to plot. + One or more `obs_keys`, `var_names`, `obsm_keys`, or `obsp_keys` annotations. + tree + The `obst` key or keys of the trees to plot. If `None`, all trees are plotted. nodes Either "all", "leaves", "internal", or a list of nodes to plot. - annotation_keys - One or more `obs_keys`, `var_names`, `obsm_keys`, or `obsp_keys` to plot. polar Whether to plot the tree in polar coordinates. extend_branches Whether to extend branches so the tips are at the same depth. angled_branches Whether to plot branches at an angle. + depth_key + The key for the depth of the nodes. branch_color Either a color name, or a key for an attribute of the edges to color by. branch_linewidth @@ -499,12 +533,13 @@ def tree( # Plot branches ax = _branches( tdata, - keys=keys, polar=polar, + depth_key=depth_key, extend_branches=extend_branches, angled_branches=angled_branches, color=branch_color, linewidth=branch_linewidth, + tree=tree, cmap=cmap, palette=palette, ax=ax, @@ -512,9 +547,9 @@ def tree( # Plot nodes if nodes: ax = _nodes( - tdata, nodes=nodes, color=node_color, style=node_style, size=node_size, cmap=cmap, palette=palette, ax=ax + tdata, nodes=nodes, color=node_color, style=node_style, size=node_size, tree=tree, cmap=cmap, palette=palette, ax=ax ) # Plot annotations - if annotation_keys: - ax = _annotation(tdata, keys=annotation_keys, width=annotation_width, cmap=cmap, palette=palette, ax=ax) + if keys: + ax = _annotation(tdata, keys=keys, width=annotation_width, cmap=cmap, palette=palette, ax=ax) return ax diff --git a/src/pycea/utils.py b/src/pycea/utils.py index 2ffa0e5..f4959bf 100755 --- a/src/pycea/utils.py +++ b/src/pycea/utils.py @@ -1,6 +1,6 @@ from __future__ import annotations -from collections.abc import Sequence +from collections.abc import Sequence, Mapping import networkx as nx import pandas as pd @@ -19,21 +19,48 @@ def get_root(tree: nx.DiGraph): node = parent[0] -def get_keyed_edge_data(tree: nx.DiGraph, key: str) -> pd.Series: - """Gets edge data for a given key from a tree.""" - edge_data = { - (parent, child): data.get(key) - for parent, child, data in tree.edges(data=True) - if key in data and data[key] is not None - } +def get_leaves(tree: nx.DiGraph): + """Finds the leaves of a tree""" + return [node for node in nx.dfs_postorder_nodes(tree, get_root(tree)) if tree.out_degree(node) == 0] + + +def get_keyed_edge_data(tree: nx.DiGraph | Mapping[str, nx.DiGraph], key: str) -> pd.Series: + """Gets edge data for a given key from a tree or set of trees.""" + if isinstance(tree, nx.DiGraph): + trees = {"": tree} + sep = "" + else: + trees = tree + sep = "-" + edge_data = {} + for name, tree in trees.items(): + edge_data.update( + { + (f"{name}{sep}{parent}", f"{name}{sep}{child}"): data.get(key) + for parent, child, data in tree.edges(data=True) + if key in data and data[key] is not None + }) if len(edge_data) == 0: raise ValueError(f"Key {key!r} is not present in any edge.") return pd.Series(edge_data, name=key) -def get_keyed_node_data(tree: nx.DiGraph, key: str) -> pd.Series: - """Gets node data for a given key from a tree.""" - node_data = {node: data.get(key) for node, data in tree.nodes(data=True) if key in data and data[key] is not None} +def get_keyed_node_data(tree: nx.DiGraph | Mapping[str, nx.DiGraph], key: str) -> pd.Series: + """Gets node data for a given key a tree or set of trees.""" + if isinstance(tree, nx.DiGraph): + trees = {"": tree} + sep = "" + else: + trees = tree + sep = "-" + node_data = {} + for name, tree in trees.items(): + node_data.update( + { + f"{name}{sep}{node}": data.get(key) + for node, data in tree.nodes(data=True) + if key in data and data[key] is not None + }) if len(node_data) == 0: raise ValueError(f"Key {key!r} is not present in any node.") return pd.Series(node_data, name=key) @@ -80,3 +107,23 @@ def get_keyed_obs_data(tdata: td.TreeData, keys: Sequence[str], layer: str = Non if data.shape[0] == data.shape[1]: data.columns = tdata.obs_names return data, array_keys + + +def get_trees(tdata: td.TreeData, tree_keys: str | Sequence[str] | None) -> Mapping[str, nx.DiGraph]: + """Gets tree data for a given key from a tree.""" + trees = {} + if tree_keys is None: + tree_keys = tdata.obst.keys() + elif isinstance(tree_keys, str): + tree_keys = [tree_keys] + elif isinstance(tree_keys, Sequence): + if tdata.allow_overlap: + raise ValueError("Cannot request multiple trees when tdata.allow_overlap is True.") + tree_keys = list(tree_keys) + else: + raise ValueError("Tree keys must be a string, list of strings, or None.") + for key in tree_keys: + if key not in tdata.obst.keys(): + raise ValueError(f"Key {key!r} is not present in obst.") + trees[key] = tdata.obst[key] + return trees diff --git a/tests/data/tdata.h5ad b/tests/data/tdata.h5ad index 6c98c3793885e80860a125c1350dd9f9f513c9b5..dfbd5e7b3c37eac95e538580738fb83e94288460 100755 GIT binary patch delta 167489 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 z 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
-phWC*kpUZX6z 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 delta 163882 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 z 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�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 diff --git a/tests/test_plot_tree.py b/tests/test_plot_tree.py index 0aeec21..95169a6 100755 --- a/tests/test_plot_tree.py +++ b/tests/test_plot_tree.py @@ -10,7 +10,8 @@ def test_polar_with_clades(tdata): fig, ax = plt.subplots(dpi=300, subplot_kw={"polar": True}) - pycea.pl.branches(tdata, keys="tree", polar=True, color="clade", palette="Set1", na_color="black", ax=ax) + pycea.pl.branches(tdata, tree = "clone1", polar=True, color="clade", depth_key= "time", + palette="Set1", na_color="black", ax=ax) pycea.pl.nodes(tdata, color="clade", palette="Set1", style="clade", ax=ax) pycea.pl.annotation(tdata, keys="clade", ax=ax) plt.savefig(plot_path / "polar_clades.png") @@ -18,9 +19,8 @@ def test_polar_with_clades(tdata): def test_angled_numeric_annotations(tdata): - pycea.pl.branches( - tdata, keys="tree", polar=False, color="length", cmap="hsv", linewidth="length", angled_branches=True - ) + pycea.pl.branches(tdata, polar=False, color="length", cmap="hsv", linewidth="length", + depth_key="time",angled_branches=True) pycea.pl.nodes(tdata, nodes="all", color="time", style="s", size=20) pycea.pl.annotation(tdata, keys=["x", "y"], cmap="magma", width=0.1, gap=0.05, border_width=2) pycea.pl.annotation(tdata, keys=["0", "1", "2", "3", "4", "5"], label="genes", border_width=2) @@ -30,15 +30,8 @@ def test_angled_numeric_annotations(tdata): def test_matrix_annotation(tdata): fig, ax = plt.subplots(dpi=300) - pycea.pl.tree( - tdata, - keys="tree", - nodes="internal", - node_color="clade", - node_size="time", - annotation_keys=["spatial_distance"], - ax=ax, - ) + pycea.pl.tree(tdata,nodes="internal",node_color="clade",node_size="time",depth_key="time", + annotation_keys=["spatial_distance"],ax=ax) plt.savefig(plot_path / "matrix_annotation.png") plt.close() @@ -46,12 +39,12 @@ def test_matrix_annotation(tdata): def test_branches_bad_input(tdata): fig, ax = plt.subplots() with pytest.raises(ValueError): - pycea.pl.branches(tdata, keys="tree", color=["bad"] * 5) + pycea.pl.branches(tdata, color=["bad"] * 5,depth_key="time") with pytest.raises(ValueError): - pycea.pl.branches(tdata, keys="tree", linewidth=["bad"] * 5) + pycea.pl.branches(tdata, linewidth=["bad"] * 5,depth_key="time") # Warns about polar with pytest.warns(match="Polar"): - pycea.pl.branches(tdata, keys="tree", polar=True, ax=ax) + pycea.pl.branches(tdata, polar=True, ax=ax,depth_key="time") plt.close() @@ -60,11 +53,9 @@ def test_annotation_bad_input(tdata): fig, ax = plt.subplots() with pytest.raises(ValueError): pycea.pl.annotation(tdata, keys="clade") - pycea.pl.branches(tdata, keys="tree", ax=ax) + pycea.pl.branches(tdata, ax=ax,depth_key="time") with pytest.raises(ValueError): - pycea.pl.annotation(tdata, keys=None, ax=ax) - with pytest.raises(ValueError): - pycea.pl.annotation(tdata, keys=False, ax=ax) + pycea.pl.annotation(tdata, tree="bad", ax=ax) with pytest.raises(ValueError): pycea.pl.annotation(tdata, keys="clade", label={}, ax=ax) plt.close() diff --git a/tests/test_plot_utils.py b/tests/test_plot_utils.py index b18faa2..a2a272a 100755 --- a/tests/test_plot_utils.py +++ b/tests/test_plot_utils.py @@ -10,7 +10,7 @@ _get_categorical_markers, _get_default_categorical_colors, _series_to_rgb_array, - layout_tree, + layout_trees, ) @@ -18,46 +18,62 @@ def test_layout_empty_tree(): tree = nx.DiGraph() with pytest.raises(ValueError): - layout_tree(tree) + layout_trees({"tree":tree}) def test_layout_tree(): tree = nx.DiGraph() tree.add_nodes_from( - [("A", {"time": 0}), ("B", {"time": 1}), ("C", {"time": 2}), ("D", {"time": 2}), ("E", {"time": 2})] + [("A", {"depth": 0}), ("B", {"depth": 1}), ("C", {"depth": 2}), ("D", {"depth": 2}), ("E", {"depth": 2})] ) edges = [("A", "B"), ("B", "C"), ("B", "D"), ("A", "E")] + expected_edges = [("tree-A", "tree-B"), ("tree-B", "tree-C"), ("tree-B", "tree-D"), ("tree-A", "tree-E")] tree.add_edges_from(edges) - node_coords, branch_coords, leaves, max_depth = layout_tree(tree, extend_branches=True) + node_coords, branch_coords, leaves, max_depth = layout_trees({"tree":tree}, extend_branches=True) assert sorted(leaves) == ["C", "D", "E"] assert max_depth == 2 - assert set(branch_coords.keys()) == set(edges) - assert branch_coords[("B", "C")][0] == [1, 1, 2] - assert branch_coords[("B", "C")][1] == [node_coords["B"][1], node_coords["C"][1], node_coords["C"][1]] + assert set(branch_coords.keys()) == set(expected_edges) + assert branch_coords[("tree-B", "tree-C")][0] == [1, 1, 2] + assert branch_coords[("tree-B", "tree-C")][1] == [node_coords["tree-B"][1], node_coords["tree-C"][1], node_coords["tree-C"][1]] + + +def test_layout_multiple_trees(): + tree1 = nx.DiGraph([("root","A")]) + tree1.nodes["root"]["depth"] = 0 + tree1.nodes["A"]["depth"] = 1 + tree2 = nx.DiGraph([("root","B")]) + tree2.nodes["root"]["depth"] = 0 + tree2.nodes["B"]["depth"] = 2 + expected_edges = [("1-root", "1-A"), ("2-root", "2-B")] + node_coords, branch_coords, leaves, max_depth = layout_trees({1:tree1,2:tree2}, extend_branches=False) + assert leaves == ["A","B"] + assert max_depth == 2 + assert set(branch_coords.keys()) == set(expected_edges) + assert branch_coords[("1-root", "1-A")][0] == [0, 0, 1] def test_layout_polar_coordinates(): tree = nx.DiGraph() tree.add_nodes_from( [ - ("A", {"time": 0}), - ("B", {"time": 1}), - ("C", {"time": 2}), - ("D", {"time": 2}), + ("A", {"depth": 0}), + ("B", {"depth": 1}), + ("C", {"depth": 2}), + ("D", {"depth": 2}), ] ) tree.add_edges_from([("A", "B"), ("B", "C"), ("B", "D")]) - node_coords, branch_coords, _, _ = layout_tree(tree, polar=True) - assert len(branch_coords[("B", "C")][1]) > 2 - assert np.mean(branch_coords[("B", "C")][0][:-2]) == 1 + node_coords, branch_coords, _, _ = layout_trees({"tree":tree}, polar=True) + assert len(branch_coords[("tree-B", "tree-C")][1]) > 2 + assert np.mean(branch_coords[("tree-B", "tree-C")][0][:-2]) == 1 def test_layout_angled_branches(): tree = nx.DiGraph() tree.add_nodes_from([("A", {"time": 0}), ("B", {"time": 1})]) tree.add_edge("A", "B") - _, branch_coords, _, _ = layout_tree(tree, angled_branches=True) - assert len(branch_coords[("A", "B")][1]) == 2 + _, branch_coords, _, _ = layout_trees({"tree":tree}, angled_branches=True,depth_key="time") + assert len(branch_coords[("tree-A", "tree-B")][1]) == 2 # Test _get_default_categorical_colors diff --git a/tests/test_utils.py b/tests/test_utils.py index d1f936c..3f401d5 100755 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -2,7 +2,7 @@ import pandas as pd import pytest -from pycea.utils import get_keyed_edge_data, get_keyed_node_data, get_keyed_obs_data, get_root +from pycea.utils import get_keyed_edge_data, get_keyed_node_data, get_keyed_obs_data, get_root, get_leaves @pytest.fixture @@ -25,6 +25,12 @@ def test_get_root(tree): assert get_root(single_node_tree) == "A" +def test_get_leaves(tree): + assert get_leaves(tree) == ["D", "E"] + # test with empty graph + assert get_leaves(nx.DiGraph()) == [] + + def test_get_keyed_edge_data(tree): result = get_keyed_edge_data(tree, "weight") expected_keys = [("A", "B"), ("B", "D"), ("C", "E")] From 2ef822cbb9f4338fc75ab3a913c003370ba030e1 Mon Sep 17 00:00:00 2001 From: colganwi Date: Fri, 24 May 2024 15:35:17 -0400 Subject: [PATCH 3/6] plot multiple trees --- src/pycea/pl/plot_tree.py | 44 ++++++++++++++++++++++++++----------- tests/test_plot_tree.py | 46 ++++++++++++++++++++++++++++++--------- 2 files changed, 67 insertions(+), 23 deletions(-) diff --git a/src/pycea/pl/plot_tree.py b/src/pycea/pl/plot_tree.py index c77bbc6..a35b3e6 100644 --- a/src/pycea/pl/plot_tree.py +++ b/src/pycea/pl/plot_tree.py @@ -88,7 +88,7 @@ def branches( trees = get_trees(tdata, tree_keys) # Get layout node_coords, branch_coords, leaves, depth = layout_trees( - trees, depth_key= depth_key ,polar=polar, extend_branches=extend_branches, angled_branches=angled_branches + trees, depth_key=depth_key, polar=polar, extend_branches=extend_branches, angled_branches=angled_branches ) segments = [] edges = [] @@ -112,8 +112,10 @@ def branches( if tdata.obs[color].dtype.kind not in ["i", "f"]: tdata.obs[color] = tdata.obs[color].astype("category") if set(color_data.unique()).issubset(tdata.obs[color].cat.categories): - color_data = pd.Series(pd.Categorical(color_data, - categories=tdata.obs[color].cat.categories),index=color_data.index) + color_data = pd.Series( + pd.Categorical(color_data, categories=tdata.obs[color].cat.categories), + index=color_data.index, + ) cmap = _get_categorical_colors(tdata, color, color_data, palette) colors = [cmap[color_data[edge]] if edge in color_data.index else na_color for edge in edges] kwargs.update({"color": colors}) @@ -171,7 +173,7 @@ def nodes( style: str = "o", size: int | float | str = 10, cmap: str | mcolors.Colormap = None, - tree:str | Sequence[str] | None = None, + tree: str | Sequence[str] | None = None, palette: cycler.Cycler | mcolors.ListedColormap | Sequence[str] | Mapping[str] | None = None, markers: Sequence[str] | Mapping[str] = None, vmax: int | float | None = None, @@ -231,6 +233,10 @@ def nodes( tree_keys = attrs["tree_keys"] else: tree_keys = tree + if isinstance(tree_keys, str): + tree_keys = [tree_keys] + if not set(tree_keys).issubset(attrs["tree_keys"]): + raise ValueError("Invalid tree key. Must be one of the keys used to plot the branches.") trees = get_trees(tdata, attrs["tree_keys"]) # Get nodes all_nodes = set() @@ -245,9 +251,9 @@ def nodes( elif nodes == "internal": nodes = list(all_nodes.difference(leaves)) elif isinstance(nodes, Sequence): - if len(attrs["tree_keys"]) > 1 and isinstance(tree_keys, str): + if len(attrs["tree_keys"]) > 1 and len(tree_keys) > 1: raise ValueError("Multiple trees are present. To plot a list of nodes, you must specify the tree.") - nodes = [f"{tree_key}-{node}" for tree_key in tree_keys for node in nodes] + nodes = [f"{tree_keys[0]}-{node}" for node in nodes] if set(nodes).issubset(all_nodes): nodes = list(nodes) else: @@ -279,8 +285,10 @@ def nodes( if tdata.obs[color].dtype.kind not in ["i", "f"]: tdata.obs[color] = tdata.obs[color].astype("category") if set(color_data.unique()).issubset(tdata.obs[color].cat.categories): - color_data = pd.Series(pd.Categorical(color_data, - categories=tdata.obs[color].cat.categories),index=color_data.index) + color_data = pd.Series( + pd.Categorical(color_data, categories=tdata.obs[color].cat.categories), + index=color_data.index, + ) cmap = _get_categorical_colors(tdata, color, color_data, palette) colors = [cmap[color_data[node]] if node in color_data.index else na_color for node in nodes] kwargs.update({"color": colors}) @@ -377,7 +385,7 @@ def annotation( ax - The axes that the plot was drawn on. """ # noqa: D205 # Setup - if tree: #TODO: Annotate only the leaves for the given tree + if tree: # TODO: Annotate only the leaves for the given tree pass if not ax: ax = plt.gca() @@ -428,10 +436,12 @@ def annotation( else: for key in keys: if data[key].dtype == "category": - colors = _get_categorical_colors(tdata, key, data.loc[leaves,key], palette) - rgb_array.append(_series_to_rgb_array(data.loc[leaves,key], colors, na_color=na_color)) + colors = _get_categorical_colors(tdata, key, data.loc[leaves, key], palette) + rgb_array.append(_series_to_rgb_array(data.loc[leaves, key], colors, na_color=na_color)) else: - rgb_array.append(_series_to_rgb_array(data.loc[leaves,key], cmap, vmin=vmin, vmax=vmax, na_color=na_color)) + rgb_array.append( + _series_to_rgb_array(data.loc[leaves, key], cmap, vmin=vmin, vmax=vmax, na_color=na_color) + ) rgb_array = np.stack(rgb_array, axis=1) # Plot if attrs["polar"]: @@ -547,7 +557,15 @@ def tree( # Plot nodes if nodes: ax = _nodes( - tdata, nodes=nodes, color=node_color, style=node_style, size=node_size, tree=tree, cmap=cmap, palette=palette, ax=ax + tdata, + nodes=nodes, + color=node_color, + style=node_style, + size=node_size, + tree=tree, + cmap=cmap, + palette=palette, + ax=ax, ) # Plot annotations if keys: diff --git a/tests/test_plot_tree.py b/tests/test_plot_tree.py index 95169a6..371f5cd 100755 --- a/tests/test_plot_tree.py +++ b/tests/test_plot_tree.py @@ -10,8 +10,9 @@ def test_polar_with_clades(tdata): fig, ax = plt.subplots(dpi=300, subplot_kw={"polar": True}) - pycea.pl.branches(tdata, tree = "clone1", polar=True, color="clade", depth_key= "time", - palette="Set1", na_color="black", ax=ax) + pycea.pl.branches( + tdata, tree="clone1", polar=True, color="clade", depth_key="time", palette="Set1", na_color="black", ax=ax + ) pycea.pl.nodes(tdata, color="clade", palette="Set1", style="clade", ax=ax) pycea.pl.annotation(tdata, keys="clade", ax=ax) plt.savefig(plot_path / "polar_clades.png") @@ -19,9 +20,11 @@ def test_polar_with_clades(tdata): def test_angled_numeric_annotations(tdata): - pycea.pl.branches(tdata, polar=False, color="length", cmap="hsv", linewidth="length", - depth_key="time",angled_branches=True) + pycea.pl.branches( + tdata, polar=False, color="length", cmap="hsv", linewidth="length", depth_key="time", angled_branches=True + ) pycea.pl.nodes(tdata, nodes="all", color="time", style="s", size=20) + pycea.pl.nodes(tdata, nodes=["5"], tree="clone2", color="black", style="*", size=200) pycea.pl.annotation(tdata, keys=["x", "y"], cmap="magma", width=0.1, gap=0.05, border_width=2) pycea.pl.annotation(tdata, keys=["0", "1", "2", "3", "4", "5"], label="genes", border_width=2) plt.savefig(plot_path / "angled_numeric.png") @@ -30,8 +33,15 @@ def test_angled_numeric_annotations(tdata): def test_matrix_annotation(tdata): fig, ax = plt.subplots(dpi=300) - pycea.pl.tree(tdata,nodes="internal",node_color="clade",node_size="time",depth_key="time", - annotation_keys=["spatial_distance"],ax=ax) + pycea.pl.tree( + tdata, + nodes="internal", + node_color="clade", + node_size="time", + depth_key="time", + annotation_keys=["spatial_distance"], + ax=ax, + ) plt.savefig(plot_path / "matrix_annotation.png") plt.close() @@ -39,12 +49,28 @@ def test_matrix_annotation(tdata): def test_branches_bad_input(tdata): fig, ax = plt.subplots() with pytest.raises(ValueError): - pycea.pl.branches(tdata, color=["bad"] * 5,depth_key="time") + pycea.pl.branches(tdata, color=["bad"] * 5, depth_key="time") with pytest.raises(ValueError): - pycea.pl.branches(tdata, linewidth=["bad"] * 5,depth_key="time") + pycea.pl.branches(tdata, linewidth=["bad"] * 5, depth_key="time") # Warns about polar with pytest.warns(match="Polar"): - pycea.pl.branches(tdata, polar=True, ax=ax,depth_key="time") + pycea.pl.branches(tdata, polar=True, ax=ax, depth_key="time") + plt.close() + + +def test_nodes_bad_input(tdata): + fig, ax = plt.subplots() + pycea.pl.branches(tdata, depth_key="time", ax=ax) + with pytest.raises(ValueError): + pycea.pl.nodes(tdata, nodes="bad", color="clade", ax=ax) + with pytest.raises(ValueError): + pycea.pl.nodes(tdata, nodes="all", color="bad", ax=ax) + with pytest.raises(ValueError): + pycea.pl.nodes(tdata, nodes="all", style="bad", ax=ax) + with pytest.raises(ValueError): + pycea.pl.nodes(tdata, nodes="all", size="bad", ax=ax) + with pytest.raises(ValueError): + pycea.pl.nodes(tdata, nodes="all", tree="bad", ax=ax) plt.close() @@ -53,7 +79,7 @@ def test_annotation_bad_input(tdata): fig, ax = plt.subplots() with pytest.raises(ValueError): pycea.pl.annotation(tdata, keys="clade") - pycea.pl.branches(tdata, ax=ax,depth_key="time") + pycea.pl.branches(tdata, ax=ax, depth_key="time") with pytest.raises(ValueError): pycea.pl.annotation(tdata, tree="bad", ax=ax) with pytest.raises(ValueError): From 37b772c84c6b24fe70968f7540fe58e396deea60 Mon Sep 17 00:00:00 2001 From: colganwi Date: Fri, 24 May 2024 16:30:46 -0400 Subject: [PATCH 4/6] clades for multiple trees --- src/pycea/tl/clades.py | 93 +++++++++++++++++++++++++++--------------- tests/test_clades.py | 30 +++++++++++++- 2 files changed, 87 insertions(+), 36 deletions(-) diff --git a/src/pycea/tl/clades.py b/src/pycea/tl/clades.py index 20b50a2..806ab97 100755 --- a/src/pycea/tl/clades.py +++ b/src/pycea/tl/clades.py @@ -3,9 +3,10 @@ from collections.abc import Mapping, Sequence import networkx as nx +import pandas as pd import treedata as td -from pycea.utils import get_root +from pycea.utils import get_root, get_trees def _nodes_at_depth(tree, parent, nodes, depth, depth_key): @@ -18,13 +19,46 @@ def _nodes_at_depth(tree, parent, nodes, depth, depth_key): return nodes +def _clade_name_generator(): + """Generates clade names.""" + i = 0 + while True: + yield str(i) + i += 1 + + +def _clades(tree, depth, depth_key, clades, clade_key, name_generator): + """Identifies clades in a tree.""" + if (depth is not None) and (clades is None): + nodes = _nodes_at_depth(tree, get_root(tree), [], depth, depth_key) + clades = dict(zip(nodes, name_generator)) + elif (clades is not None) and (depth is None): + pass + else: + raise ValueError("Must specify either clades or depth.") + leaf_to_clade = {} + for node, clade in clades.items(): + # Leaf + if tree.out_degree(node) == 0: + leaf_to_clade[node] = clade + tree.nodes[node][clade_key] = clade + # Internal node + for u, v in nx.dfs_edges(tree, node): + tree.nodes[u][clade_key] = clade + tree.edges[u, v][clade_key] = clade + if tree.out_degree(v) == 0: + leaf_to_clade[v] = clade + tree.nodes[v][clade_key] = clade + return clades, leaf_to_clade + + def clades( tdata: td.TreeData, - key: str | Sequence[str] = None, depth: int | float = None, depth_key: str = "depth", clades: str | Sequence[str] = None, clade_key: str = "clade", + tree: str | Sequence[str] | None = None, copy: bool = False, ) -> None | Mapping: """Identifies clades in a tree. @@ -33,8 +67,6 @@ def clades( ---------- tdata The TreeData object. - key - The `obst` key of the tree. depth Depth to cut tree at. Must be specified if clades is None. depth_key @@ -43,40 +75,33 @@ def clades( A dictionary mapping nodes to clades. clade_key Key to store clades in. + tree + The `obst` key or keys of the trees to use. If `None`, all trees are used. copy - If True, returns a dictionary mapping nodes to clades. + If True, returns a pd.DataFrame with clade nodes. Returns ------- None or Mapping - If copy is True, returns a dictionary mapping nodes to clades. + If copy is True, returns pd.DataFrame with clade nodes. """ - # Get tree - if not key: - key = tdata.obs_keys()[0] - tree = tdata.obst[key] - # Get clades - if (depth is not None) and (clades is None): - nodes = _nodes_at_depth(tree, get_root(tree), [], depth, depth_key) - clades = {node: str(clade) for clade, node in enumerate(nodes)} - elif (clades is not None) and (depth is None): - pass - else: - raise ValueError("Must specify either clades or depth.") - # Set clades - leaf_clades = {} - for node, clade in clades.items(): - # Leaf - if tree.out_degree(node) == 0: - leaf_clades[node] = clade - tree.nodes[node][clade_key] = clade - # Internal node - for u, v in nx.dfs_edges(tree, node): - tree.nodes[u][clade_key] = clade - tree.edges[u, v][clade_key] = clade - if tree.out_degree(v) == 0: - leaf_clades[v] = clade - tree.nodes[v][clade_key] = clade - tdata.obs[clade_key] = tdata.obs.index.map(leaf_clades) + # Setup + tree_keys = tree + trees = get_trees(tdata, tree_keys) + if clades and len(trees) > 1: + raise ValueError("Multiple trees are present. Must specify a single tree if clades are given.") + # Identify clades + name_generator = _clade_name_generator() + leaf_to_clade = {} + clade_nodes = [] + for key, tree in trees.items(): + tree_nodes, tree_leaves = _clades(tree, depth, depth_key, clades, clade_key, name_generator) + tree_nodes = pd.DataFrame(tree_nodes.items(), columns=["node", clade_key]) + tree_nodes["tree"] = key + clade_nodes.append(tree_nodes) + leaf_to_clade.update(tree_leaves) + # Update TreeData and return + tdata.obs[clade_key] = tdata.obs.index.map(leaf_to_clade) + clade_nodes = pd.concat(clade_nodes) if copy: - return clades + return clade_nodes diff --git a/tests/test_clades.py b/tests/test_clades.py index a6aa5f2..aeb888d 100755 --- a/tests/test_clades.py +++ b/tests/test_clades.py @@ -40,8 +40,34 @@ def test_clades_given_dict(tdata, tree): def test_clades_given_depth(tdata): clades(tdata, depth=0) assert tdata.obs["clade"].tolist() == ["0", "0", "0"] - nodes = clades(tdata, depth=1, copy=True) + clade_nodes = clades(tdata, depth=1, copy=True) + assert clade_nodes["node"].tolist() == ["B", "C"] + assert clade_nodes["clade"].tolist() == ["0", "1"] assert tdata.obs["clade"].tolist() == ["0", "1", "1"] - assert nodes == {"B": "0", "C": "1"} clades(tdata, depth=2) assert tdata.obs["clade"].tolist() == ["0", "1", "2"] + + +def test_clades_multiple_trees(): + tree1 = nx.DiGraph([("root", "A")]) + nx.set_node_attributes(tree1, {"root": 0, "A": 1}, "depth") + tree2 = nx.DiGraph([("root", "B")]) + nx.set_node_attributes(tree2, {"root": 0, "B": 2}, "depth") + tdata = td.TreeData(obs=pd.DataFrame(index=["A", "B"]), obst={"tree1": tree1, "tree2": tree2}) + clades(tdata, depth=0) + assert tdata.obs["clade"].tolist() == ["0", "1"] + # need to specify tree with clade input + with pytest.raises(ValueError): + clades(tdata, clades={"root": 0}) + clades(tdata, clades={"root": "0"}, tree="tree1", clade_key="test") + assert tdata.obs.loc["A", "test"] == "0" + assert pd.isna(tdata.obs.loc["B", "test"]) + + +def test_clades_invalid(tdata): + with pytest.raises(ValueError): + clades(td.TreeData(), clades={"A": 0}, depth=0) + with pytest.raises(ValueError): + clades(tdata, clades={"A": 0}, depth=0) + with pytest.raises(KeyError): + clades(tdata, clades={"bad": 0}, clade_key="clade") From c08307d76de7dbc353a151a90461a72f5bfb73b3 Mon Sep 17 00:00:00 2001 From: colganwi Date: Fri, 24 May 2024 17:01:23 -0400 Subject: [PATCH 5/6] sort --- docs/api.md | 1 + src/pycea/tl/__init__.py | 1 + src/pycea/tl/sort.py | 40 ++++++++++++++++++++++++++++++++++++++++ tests/test_sort.py | 30 ++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+) create mode 100755 src/pycea/tl/sort.py create mode 100755 tests/test_sort.py diff --git a/docs/api.md b/docs/api.md index 9694185..1fa80ef 100644 --- a/docs/api.md +++ b/docs/api.md @@ -12,6 +12,7 @@ :toctree: generated tl.clades + tl.sort ``` ## Plotting diff --git a/src/pycea/tl/__init__.py b/src/pycea/tl/__init__.py index 3221966..a3522c7 100644 --- a/src/pycea/tl/__init__.py +++ b/src/pycea/tl/__init__.py @@ -1 +1,2 @@ from .clades import clades +from .sort import sort diff --git a/src/pycea/tl/sort.py b/src/pycea/tl/sort.py new file mode 100755 index 0000000..ef64d76 --- /dev/null +++ b/src/pycea/tl/sort.py @@ -0,0 +1,40 @@ +from __future__ import annotations + +from collections.abc import Sequence + +import networkx as nx +import treedata as td + +from pycea.utils import get_root, get_trees + + +def _sort_tree(tree, key, reverse=False): + for node in nx.dfs_postorder_nodes(tree, get_root(tree)): + if tree.out_degree(node) > 1: + try: + sorted_children = sorted(tree.successors(node), key=lambda x: tree.nodes[x][key], reverse=reverse) + except KeyError as err: + raise KeyError(f"Node {next(tree.successors(node))} does not have a {key} attribute.") from err + tree.remove_edges_from([(node, child) for child in tree.successors(node)]) + tree.add_edges_from([(node, child) for child in sorted_children]) + return tree + + +def sort(tdata: td.TreeData, key: str, reverse: bool = False, tree: str | Sequence[str] | None = None) -> None: + """Sorts the children of each internal node in a tree based on a given key. + + Parameters + ---------- + tdata + TreeData object. + key + Node attribute to sort by. + reverse + If True, sort in descending order. + tree + The `obst` key or keys of the trees to use. If `None`, all trees are used. + """ + trees = get_trees(tdata, tree) + for name, tree in trees.items(): + tdata.obst[name] = _sort_tree(tree.copy(), key, reverse) + return None diff --git a/tests/test_sort.py b/tests/test_sort.py new file mode 100755 index 0000000..4c77659 --- /dev/null +++ b/tests/test_sort.py @@ -0,0 +1,30 @@ +import networkx as nx +import pandas as pd +import pytest +import treedata as td + +from pycea.tl.sort import sort + + +@pytest.fixture +def tdata(): + tree1 = nx.DiGraph([("root", "B"), ("root", "C")]) + nx.set_node_attributes(tree1, {"root": 1, "B": 3, "C": 2}, "value") + tree2 = nx.DiGraph([("root", "D"), ("root", "E")]) + nx.set_node_attributes(tree2, {"root": "1", "D": "2", "E": "3"}, "str_value") + nx.set_node_attributes(tree2, {"root": 1, "D": 2, "E": 3}, "value") + tdata = td.TreeData(obs=pd.DataFrame(index=["B", "C", "D", "E"]), obst={"tree1": tree1, "tree2": tree2}) + yield tdata + + +def test_sort(tdata): + sort(tdata, "value", reverse=False) + assert list(tdata.obst["tree1"].successors("root")) == ["C", "B"] + assert list(tdata.obst["tree2"].successors("root")) == ["D", "E"] + sort(tdata, "str_value", tree="tree2", reverse=True) + assert list(tdata.obst["tree2"].successors("root")) == ["E", "D"] + + +def test_sort_invalid(tdata): + with pytest.raises(KeyError): + sort(tdata, "bad") From 0302d9a87970e54db0d158ee5675272e1dc3464c Mon Sep 17 00:00:00 2001 From: colganwi Date: Fri, 24 May 2024 17:40:06 -0400 Subject: [PATCH 6/6] Check nx error --- tests/test_clades.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_clades.py b/tests/test_clades.py index aeb888d..b1af2d6 100755 --- a/tests/test_clades.py +++ b/tests/test_clades.py @@ -69,5 +69,5 @@ def test_clades_invalid(tdata): clades(td.TreeData(), clades={"A": 0}, depth=0) with pytest.raises(ValueError): clades(tdata, clades={"A": 0}, depth=0) - with pytest.raises(KeyError): + with pytest.raises((KeyError, nx.NetworkXError)): clades(tdata, clades={"bad": 0}, clade_key="clade")