phylotree


Namephylotree JSON
Version 0.1.1 PyPI version JSON
download
home_page
SummaryA Rust backed package to deal with phylogenetic trees
upload_time2023-06-21 17:45:34
maintainer
docs_urlNone
authorLuc Blassel
requires_python>=3.7
licenseGPL3
keywords phylogenetic tree distance matrix
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # PhyloTree

[![license_badge](https://img.shields.io/crates/l/phylotree)](https://choosealicense.com/licenses/gpl-3.0/) [![crate version](https://img.shields.io/crates/v/phylotree)](https://crates.io/crates/phylotree) [![rust doc](https://img.shields.io/docsrs/phylotree)](https://docs.rs/phylotree)

This crate aims to be a general purpose package to deal with phylogenetic trees and simulate them. Is also comes with a simple CLI tool to manipulate and simulate phylogenetic trees directly from the command line.

- [Crate usage](#using-this-crate)
- [CLI usage](#using-the-cli)
- [Python package](#python-package)

## Installing `phylotree`

### Crate

To use this crate just run `cargo add phylotree` in your cargo project or add `phylotree = "0.1.0"` to your `Cargo.toml` file.

### Cli

To install the CLI you can use
`cargo install phylotree`

Or you can build the project from source:

```shell
git clone https://github.com/lucblassel/phylotree.git
cd phylotree
cargo build --release
mv target/release/phylotree <somewhere/in/your/PATH>
```

## Using this crate

Below is some sample usage of the `phylotree` crate, please see [docs.rs/phylotree](https://docs.rs/phylotree) for the full documentation.

```rust
use phylotree::tree::Tree;

//////////////////////////////////
// Building a tree from scratch //
//////////////////////////////////
let mut tree = Tree::new();

// Add the root node
let root = tree.add(Node::new());

// Add a child to the root
let child1 = tree.add_child(Node::new_named("Child_1"), root, None).unwrap();
// Add a child to the root with a branch length
let child2 = tree.add_child(Node::new_named("Child_2"), root, Some(0.5)).unwrap();

// Add more children
let child3 = tree.add_child(Node::new_named("Child_3"), child1, None).unwrap();

// Get depth of child
assert_eq!(tree.get(&child3).unwrap().get_depth(), 2)

///////////////////////////////
// Reading and writing trees //
///////////////////////////////
let newick_str = "((A:0.1,B:0.2)F:0.6,(C:0.3,D:0.4)E:0.5)G;";
let tree = Tree::from_newick(newick_str).unwrap();

assert_eq!(tree.to_newick().unwrap(), newick_string)

//////////////////////
// Traversing trees //
//////////////////////
let newick_str = "((A,B)C,(D,E)F)G;";
let mut tree = Tree::from_newick(newick_str).unwrap();
let root = tree.get_root().unwrap();

let preorder: Vec<_> = tree.preorder(&root).unwrap()
    .iter()
    .map(|node_id| tree.get(node_id).unwrap().name.clone().unwrap())
    .collect();

assert_eq!(preorder, vec!["G", "C", "A", "B", "F", "D", "E"]);


/////////////////////
// Comparing trees //
/////////////////////

// The second tree is just a random rotation of the first,
// they represent the same phylogeney
let newick_orig = "((A:0.1,B:0.2)F:0.6,(C:0.3,D:0.4)E:0.5)G;";
let newick_rota = "((D:0.3,C:0.4)E:0.5,(B:0.2,A:0.1)F:0.6)G;";

let tree_orig = Tree::from_newick(newick_orig).unwrap();
let tree_rota = Tree::from_newick(newick_rota).unwrap();

let rf = tree_orig.robinson_foulds(&tree_rota).unwrap();

assert_eq!(rf, 0)


/////////////////////////////////
// Computing a distance matrix //
/////////////////////////////////
let newick = "((T3:0.2,T1:0.2):0.3,(T2:0.4,T0:0.5):0.6);";
let tree = Tree::from_newick(newick).unwrap();
// Compute the whole distance matrix
let matrix = tree.distance_matrix_recursive().unwrap();
let phylip="\
4
T0    0  1.6  0.9  1.6
T1    1.6  0  1.5  0.4
T2    0.9  1.5  0  1.5
T3    1.6  0.4  1.5  0
";

assert_eq!(matrix.to_phylip(true).unwrap(), phylip)
```

## Using the CLI

There is a simple CLI that comes with this package:

```
A simple command line tool to manipulate phylogenetic trees

Usage: phylotree <COMMAND>

Commands:
  generate     Generate random tree(s)
  stats        Get statistics about a tree
  compare      Compare two phylogenetic trees
  matrix       Output the phylogenetic distance matrix of the tree
  distance     Outputs a subset of phylogenetic distances
  collapse     Collapse branches that are under a certain branch length threshold
  remove       Remove tips from the trees
  deduplicate  Remove or collapse branches corresponding to identical sequences in a reference alignment
  help         Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help
```

## Python package

A python package has also been implemented, using PyO3 to create the python bindings. It is available on [PyPi](https://pypi.org/project/phylotree/0.1.1/), you can see the API of the package [here](./phylotree/__init__.py).

Example usage:

```python
from phylotree import Tree

# Read a newick file
tree = Tree.from_newick("path/to/tree.nwk")

# Read a newick string
tree = Tree.from_string("((A,(C,E)D)B,((H)I)G)F;")

# Print newick formatted string of the tree
tree.to_newick()

# Get information about the tree
tree.n_nodes()
tree.n_tips()
tree.height()
tree.diameter()
tree.n_cherries()
tree.colless()
tree.sackin()
tree.is_binary
tree.is_rooted

# Get information about nodes
names = tree.get_leaf_names()
info = tree.get_node_attributes(name=names[0])
print(f"Parent edge has length: {info['parent_edge']}")
dist_branches, dist_topo = tree.get_distance(names=(names[0], names[1]))

distance_matrix = tree.to_matrix()
dist_mat = distance_matrix[(names[0], names[1])]
assert dist_branches == dist_mat

# Modify the tree
tree.compress() # Remove nodes with 1 parent and 1 child
tree.rescale() # Change branch lengths
tree.prune(name="D") # Remove sbutree rooted a specific node

# Traverse the tree in a given order
for node_id in tree.traversal(order="levelorder"):
    node = tree.get_node_attributes(id=node_id)
    print(node.name)
```

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "phylotree",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": "",
    "keywords": "phylogenetic tree distance matrix",
    "author": "Luc Blassel",
    "author_email": "",
    "download_url": "https://files.pythonhosted.org/packages/f4/9a/807394a52e8c072d021eee3772ee1ec0025927d767ec3372f2edacc4bdfe/phylotree-0.1.1.tar.gz",
    "platform": null,
    "description": "# PhyloTree\n\n[![license_badge](https://img.shields.io/crates/l/phylotree)](https://choosealicense.com/licenses/gpl-3.0/) [![crate version](https://img.shields.io/crates/v/phylotree)](https://crates.io/crates/phylotree) [![rust doc](https://img.shields.io/docsrs/phylotree)](https://docs.rs/phylotree)\n\nThis crate aims to be a general purpose package to deal with phylogenetic trees and simulate them. Is also comes with a simple CLI tool to manipulate and simulate phylogenetic trees directly from the command line.\n\n- [Crate usage](#using-this-crate)\n- [CLI usage](#using-the-cli)\n- [Python package](#python-package)\n\n## Installing `phylotree`\n\n### Crate\n\nTo use this crate just run `cargo add phylotree` in your cargo project or add `phylotree = \"0.1.0\"` to your `Cargo.toml` file.\n\n### Cli\n\nTo install the CLI you can use\n`cargo install phylotree`\n\nOr you can build the project from source:\n\n```shell\ngit clone https://github.com/lucblassel/phylotree.git\ncd phylotree\ncargo build --release\nmv target/release/phylotree <somewhere/in/your/PATH>\n```\n\n## Using this crate\n\nBelow is some sample usage of the `phylotree` crate, please see [docs.rs/phylotree](https://docs.rs/phylotree) for the full documentation.\n\n```rust\nuse phylotree::tree::Tree;\n\n//////////////////////////////////\n// Building a tree from scratch //\n//////////////////////////////////\nlet mut tree = Tree::new();\n\n// Add the root node\nlet root = tree.add(Node::new());\n\n// Add a child to the root\nlet child1 = tree.add_child(Node::new_named(\"Child_1\"), root, None).unwrap();\n// Add a child to the root with a branch length\nlet child2 = tree.add_child(Node::new_named(\"Child_2\"), root, Some(0.5)).unwrap();\n\n// Add more children\nlet child3 = tree.add_child(Node::new_named(\"Child_3\"), child1, None).unwrap();\n\n// Get depth of child\nassert_eq!(tree.get(&child3).unwrap().get_depth(), 2)\n\n///////////////////////////////\n// Reading and writing trees //\n///////////////////////////////\nlet newick_str = \"((A:0.1,B:0.2)F:0.6,(C:0.3,D:0.4)E:0.5)G;\";\nlet tree = Tree::from_newick(newick_str).unwrap();\n\nassert_eq!(tree.to_newick().unwrap(), newick_string)\n\n//////////////////////\n// Traversing trees //\n//////////////////////\nlet newick_str = \"((A,B)C,(D,E)F)G;\";\nlet mut tree = Tree::from_newick(newick_str).unwrap();\nlet root = tree.get_root().unwrap();\n\nlet preorder: Vec<_> = tree.preorder(&root).unwrap()\n    .iter()\n    .map(|node_id| tree.get(node_id).unwrap().name.clone().unwrap())\n    .collect();\n\nassert_eq!(preorder, vec![\"G\", \"C\", \"A\", \"B\", \"F\", \"D\", \"E\"]);\n\n\n/////////////////////\n// Comparing trees //\n/////////////////////\n\n// The second tree is just a random rotation of the first,\n// they represent the same phylogeney\nlet newick_orig = \"((A:0.1,B:0.2)F:0.6,(C:0.3,D:0.4)E:0.5)G;\";\nlet newick_rota = \"((D:0.3,C:0.4)E:0.5,(B:0.2,A:0.1)F:0.6)G;\";\n\nlet tree_orig = Tree::from_newick(newick_orig).unwrap();\nlet tree_rota = Tree::from_newick(newick_rota).unwrap();\n\nlet rf = tree_orig.robinson_foulds(&tree_rota).unwrap();\n\nassert_eq!(rf, 0)\n\n\n/////////////////////////////////\n// Computing a distance matrix //\n/////////////////////////////////\nlet newick = \"((T3:0.2,T1:0.2):0.3,(T2:0.4,T0:0.5):0.6);\";\nlet tree = Tree::from_newick(newick).unwrap();\n// Compute the whole distance matrix\nlet matrix = tree.distance_matrix_recursive().unwrap();\nlet phylip=\"\\\n4\nT0    0  1.6  0.9  1.6\nT1    1.6  0  1.5  0.4\nT2    0.9  1.5  0  1.5\nT3    1.6  0.4  1.5  0\n\";\n\nassert_eq!(matrix.to_phylip(true).unwrap(), phylip)\n```\n\n## Using the CLI\n\nThere is a simple CLI that comes with this package:\n\n```\nA simple command line tool to manipulate phylogenetic trees\n\nUsage: phylotree <COMMAND>\n\nCommands:\n  generate     Generate random tree(s)\n  stats        Get statistics about a tree\n  compare      Compare two phylogenetic trees\n  matrix       Output the phylogenetic distance matrix of the tree\n  distance     Outputs a subset of phylogenetic distances\n  collapse     Collapse branches that are under a certain branch length threshold\n  remove       Remove tips from the trees\n  deduplicate  Remove or collapse branches corresponding to identical sequences in a reference alignment\n  help         Print this message or the help of the given subcommand(s)\n\nOptions:\n  -h, --help  Print help\n```\n\n## Python package\n\nA python package has also been implemented, using PyO3 to create the python bindings. It is available on [PyPi](https://pypi.org/project/phylotree/0.1.1/), you can see the API of the package [here](./phylotree/__init__.py).\n\nExample usage:\n\n```python\nfrom phylotree import Tree\n\n# Read a newick file\ntree = Tree.from_newick(\"path/to/tree.nwk\")\n\n# Read a newick string\ntree = Tree.from_string(\"((A,(C,E)D)B,((H)I)G)F;\")\n\n# Print newick formatted string of the tree\ntree.to_newick()\n\n# Get information about the tree\ntree.n_nodes()\ntree.n_tips()\ntree.height()\ntree.diameter()\ntree.n_cherries()\ntree.colless()\ntree.sackin()\ntree.is_binary\ntree.is_rooted\n\n# Get information about nodes\nnames = tree.get_leaf_names()\ninfo = tree.get_node_attributes(name=names[0])\nprint(f\"Parent edge has length: {info['parent_edge']}\")\ndist_branches, dist_topo = tree.get_distance(names=(names[0], names[1]))\n\ndistance_matrix = tree.to_matrix()\ndist_mat = distance_matrix[(names[0], names[1])]\nassert dist_branches == dist_mat\n\n# Modify the tree\ntree.compress() # Remove nodes with 1 parent and 1 child\ntree.rescale() # Change branch lengths\ntree.prune(name=\"D\") # Remove sbutree rooted a specific node\n\n# Traverse the tree in a given order\nfor node_id in tree.traversal(order=\"levelorder\"):\n    node = tree.get_node_attributes(id=node_id)\n    print(node.name)\n```\n",
    "bugtrack_url": null,
    "license": "GPL3",
    "summary": "A Rust backed package to deal with phylogenetic trees",
    "version": "0.1.1",
    "project_urls": {
        "Bug Tracker": "https://github.com/lucblassel/phylotree-rs/issues",
        "Documentation": "https://github.com/lucblassel/phylotree-rs",
        "Source Code": "https://github.com/lucblassel/phylotree-rs"
    },
    "split_keywords": [
        "phylogenetic",
        "tree",
        "distance",
        "matrix"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "f49a807394a52e8c072d021eee3772ee1ec0025927d767ec3372f2edacc4bdfe",
                "md5": "06222057400f3c0cd8135f05c43e486b",
                "sha256": "50a3d61800857573b643027ca69145598a7f867c7f42688a825411c2adb6237f"
            },
            "downloads": -1,
            "filename": "phylotree-0.1.1.tar.gz",
            "has_sig": false,
            "md5_digest": "06222057400f3c0cd8135f05c43e486b",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 49605,
            "upload_time": "2023-06-21T17:45:34",
            "upload_time_iso_8601": "2023-06-21T17:45:34.989245Z",
            "url": "https://files.pythonhosted.org/packages/f4/9a/807394a52e8c072d021eee3772ee1ec0025927d767ec3372f2edacc4bdfe/phylotree-0.1.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-06-21 17:45:34",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "lucblassel",
    "github_project": "phylotree-rs",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "phylotree"
}
        
Elapsed time: 0.08700s