ggtree-py 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. ggtree_py-0.1.0/.gitignore +11 -0
  2. ggtree_py-0.1.0/CHANGELOG.md +14 -0
  3. ggtree_py-0.1.0/CONDUCT.md +24 -0
  4. ggtree_py-0.1.0/CONTRIBUTING.md +40 -0
  5. ggtree_py-0.1.0/LICENSE +164 -0
  6. ggtree_py-0.1.0/PKG-INFO +198 -0
  7. ggtree_py-0.1.0/README.md +173 -0
  8. ggtree_py-0.1.0/docs/annotations_and_compositions.md +147 -0
  9. ggtree_py-0.1.0/docs/api_reference.md +94 -0
  10. ggtree_py-0.1.0/docs/getting_started.md +103 -0
  11. ggtree_py-0.1.0/docs/index.md +26 -0
  12. ggtree_py-0.1.0/docs/layouts_and_manipulation.md +91 -0
  13. ggtree_py-0.1.0/docs/r_to_python_migration.md +53 -0
  14. ggtree_py-0.1.0/examples/run_all_examples.py +352 -0
  15. ggtree_py-0.1.0/ggtree/__init__.py +569 -0
  16. ggtree_py-0.1.0/ggtree/aes.py +385 -0
  17. ggtree_py-0.1.0/ggtree/compose.py +1351 -0
  18. ggtree_py-0.1.0/ggtree/dataframe.py +1439 -0
  19. ggtree_py-0.1.0/ggtree/extdata/FluA_H3_AA.fas +684 -0
  20. ggtree_py-0.1.0/ggtree/extdata/Genotype.txt +77 -0
  21. ggtree_py-0.1.0/ggtree/extdata/MCC_FluA_H3.tree +165 -0
  22. ggtree_py-0.1.0/ggtree/extdata/NAG_inHA1.txt +151 -0
  23. ggtree_py-0.1.0/ggtree/extdata/RAxML_bipartitions.H3 +1 -0
  24. ggtree_py-0.1.0/ggtree/extdata/ggdensitree_example.tree +12 -0
  25. ggtree_py-0.1.0/ggtree/extdata/mtCDNA_timetree.nex +27 -0
  26. ggtree_py-0.1.0/ggtree/extdata/pa.fas +784 -0
  27. ggtree_py-0.1.0/ggtree/extdata/pa.nwk +1 -0
  28. ggtree_py-0.1.0/ggtree/extdata/pa_subs.csv +28 -0
  29. ggtree_py-0.1.0/ggtree/extdata/sample.jplace +14 -0
  30. ggtree_py-0.1.0/ggtree/extdata/sample.nwk +1 -0
  31. ggtree_py-0.1.0/ggtree/extdata/sites.txt +82 -0
  32. ggtree_py-0.1.0/ggtree/geoms.py +1640 -0
  33. ggtree_py-0.1.0/ggtree/layout.py +1652 -0
  34. ggtree_py-0.1.0/ggtree/manipulate.py +836 -0
  35. ggtree_py-0.1.0/ggtree/plot.py +1679 -0
  36. ggtree_py-0.1.0/ggtree/themes_scales.py +667 -0
  37. ggtree_py-0.1.0/ggtree/tidytree.py +735 -0
  38. ggtree_py-0.1.0/ggtree/tree.py +1615 -0
  39. ggtree_py-0.1.0/pyproject.toml +64 -0
  40. ggtree_py-0.1.0/tests/test_examples.py +390 -0
  41. ggtree_py-0.1.0/tests/test_ggtree.py +970 -0
@@ -0,0 +1,11 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ build/
5
+ dist/
6
+ *.egg-info/
7
+ .venv/
8
+ .pytest_cache/
9
+ examples/output/
10
+ .DS_Store
11
+ .env
@@ -0,0 +1,14 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 (2026-11-14)
4
+
5
+ Initial Python release (`ggtree-py`, imported as `ggtree`), ported from Bioconductor `ggtree` (`4.3.2`).
6
+
7
+ ### Highlights
8
+ - **Tree parsers & structures (`ggtree.tree`)**: Newick (`read_tree`), BEAST NEXUS (`read_beast`), NHX (`read_nhx`), jplace (`read_jplace`), FASTA (`read_fasta`), `Phylo`, `TreeData`, `MultiPhylo`, `TreeDataList`, `Hclust`/`hclust`, and bundled sample datasets (`system_file`).
9
+ - **Tidy tree operations (`ggtree.tidytree`)**: `MRCA`, `groupOTU`, `groupClade`, `offspring`, `ancestor`, `parent`, `child`, `sibling`, `nodeid`, `nodelab`, `tree_subset`, `td_filter`, `td_mutate`, and `td_unnest`.
10
+ - **12+ tree layouts (`ggtree.layout`)**: `rectangular`, `slanted`, `circular`, `fan`, `inward_circular`, `dendrogram`, `equal_angle`, `daylight` (`unrooted`), `tidy`, `ellipse`, `roundrect`, `radial`, `ape`, and `tree_and_leaf`, plus time-scaled MRSD coordinates (`Date2decimal`, `decimal2Date`).
11
+ - **Grammar-of-graphics geoms & scales (`ggtree.aes`, `ggtree.geoms`, `ggtree.themes_scales`)**: Symbolic expressions (`aes`, `isTip`, `parent`), `geom_tree`, `geom_tiplab`, `geom_tiplab2`, `geom_nodelab`, `geom_point2`, `geom_tippoint`, `geom_nodepoint`, `geom_rootpoint`, `geom_rootedge`, `geom_aline`, `geom_hilight`, `geom_balance`, `geom_cladelab`, `geom_strip`, `geom_taxalink`, `geom_tanglelink`, `geom_range`, `geom_treescale`, `new_scale_fill`, `new_scale_color`, Viridis/Magma/Plasma/Inferno/Cividis/Brewer/gradient scales, and `theme_tree`, `theme_tree2`, `theme_dendrogram`.
12
+ - **Manipulation & composite plots (`ggtree.manipulate`, `ggtree.compose`)**: `collapse`, `expand`, `rotate`, `flip`, `scaleClade`, `viewClade`, `zoomClade`, `open_tree`, `rotate_tree`, `gheatmap`, `msaplot`, `geom_facet`/`facet_plot`, `nodepie`/`nodebar`/`inset`, `ggdensitree`, `as_tanglegram`/`ggdoubletree`, `multiplot`, `plot_list`, and `|`/`/` patchwork composition.
13
+ - **Zero-external-dependency SVG & PNG renderer (`ggtree.plot`)**: Direct vector SVG rendering and PNG export via `ggsave()`, `to_svg()`, and `to_png()` (using `rsvg-convert` when present, with pure-NumPy RGBA fallback).
14
+ - **Verified**: All 49 tests pass (`tests/test_examples.py` + `tests/test_ggtree.py`).
@@ -0,0 +1,24 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who
4
+ contribute through reporting issues, posting feature requests, updating documentation,
5
+ submitting pull requests or patches, and other activities.
6
+
7
+ We are committed to making participation in this project a harassment-free experience for
8
+ everyone, regardless of level of experience, gender, gender identity and expression,
9
+ sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
10
+
11
+ Examples of unacceptable behavior by participants include the use of sexual language or
12
+ imagery, derogatory comments or personal attacks, trolling, public or private harassment,
13
+ insults, or other unprofessional conduct.
14
+
15
+ Project maintainers have the right and responsibility to remove, edit, or reject comments,
16
+ commits, code, wiki edits, issues, and other contributions that are not aligned to this
17
+ Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed
18
+ from the project team.
19
+
20
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by
21
+ opening an issue or contacting one or more of the project maintainers.
22
+
23
+ This Code of Conduct is adapted from the Contributor Covenant
24
+ (http://contributor-covenant.org), version 1.0.0.
@@ -0,0 +1,40 @@
1
+ # Contributing to `ggtree-py`
2
+
3
+ Thank you for considering contributing to `ggtree-py`!
4
+
5
+ ## Development Setup
6
+
7
+ ```bash
8
+ git clone <repo-url>
9
+ cd ggtree.py
10
+ python3 -m pip install -e ".[dev]"
11
+ ```
12
+
13
+ Only `numpy>=1.22` is required at runtime (Python `>= 3.10`). Installing `rsvg-convert` (from `librsvg`) on your `PATH` enables high-resolution vector-to-PNG rasterization in `ggsave("out.png")`; without it, `ggtree` falls back to its built-in pure-NumPy PNG rasterizer.
14
+
15
+ ## Running Tests and Examples
16
+
17
+ Run the full unit test suite (all 49 tests covering ported R manual examples and `testthat` suites):
18
+
19
+ ```bash
20
+ python3 -s -m unittest discover -s tests -v
21
+ ```
22
+
23
+ Generate all 14 composite example figures (SVG + PNG) in `examples/output/`:
24
+
25
+ ```bash
26
+ python3 -s examples/run_all_examples.py
27
+ ```
28
+
29
+ ## Building Distributions
30
+
31
+ ```bash
32
+ uv build
33
+ ```
34
+
35
+ ## Submitting Pull Requests
36
+
37
+ - Keep core runtime dependencies restricted to the Python standard library and `numpy`.
38
+ - Add or update tests in `tests/test_ggtree.py` or `tests/test_examples.py`.
39
+ - Update the relevant documentation under `docs/` when adding or modifying public APIs.
40
+ - Follow the [Contributor Code of Conduct](CONDUCT.md).
@@ -0,0 +1,164 @@
1
+ The Artistic License 2.0
2
+
3
+ Copyright (c) 2014-2026 Guangchuang Yu (upstream R/Bioconductor ggtree authors)
4
+
5
+ Everyone is permitted to copy and distribute verbatim copies
6
+ of this license document, but changing it is not allowed.
7
+
8
+ Preamble
9
+
10
+ This license establishes the terms under which a given free software
11
+ Package may be copied, modified, distributed, and/or redistributed.
12
+ The intent is that the Copyright Holder maintains some artistic
13
+ control over the development of that Package while still keeping the
14
+ Package available as open source and free software.
15
+
16
+ You are always permitted to make arrangements wholly outside of this
17
+ license directly with the Copyright Holder of a given Package. If the
18
+ terms of this license do not permit the full use that you propose to
19
+ make of the Package, you should contact the Copyright Holder and seek
20
+ a different licensing arrangement.
21
+
22
+ Definitions
23
+
24
+ "Copyright Holder" means the individual(s) or organization(s)
25
+ named in the copyright notice for the entire Package.
26
+
27
+ "Contributor" means any party that has contributed code or other
28
+ material to the Package, in accordance with the Copyright Holder's
29
+ procedures.
30
+
31
+ "You" and "your" means any person who would like to copy,
32
+ distribute, or modify the Package.
33
+
34
+ "Package" means the collection of files distributed by the
35
+ Copyright Holder, and derivatives of that collection and/or
36
+ of those files. A given Package may consist of either the Standard
37
+ Version, or a Modified Version.
38
+
39
+ "Distribute" means providing a copy of the Package or making it
40
+ accessible to anyone else, or in the case of a company or
41
+ organization, to others outside of your company or organization.
42
+
43
+ "Distributor Fee" means any fee that you charge for Distributing
44
+ this Package or providing support for this Package to another
45
+ party. It does not mean branding.
46
+
47
+ "Standard Version" refers to the Package if it has not been
48
+ modified, or has been modified only in ways explicitly requested
49
+ by the Copyright Holder.
50
+
51
+ "Modified Version" means the Package, when it has been changed,
52
+ and such changes were not explicitly requested by the Copyright
53
+ Holder.
54
+
55
+ "Original License" means this Artistic License as Distributed with
56
+ the Standard Version of the Package, in its current version or as
57
+ it may be modified by The Perl Foundation in the future.
58
+
59
+ "Source" form means the source code, documentation source, and
60
+ configuration files for the Package.
61
+
62
+ "Compiled" form means the compiled binary or object code or
63
+ executable, including generated binary files, generated
64
+ computer code, or translated or converted binary files.
65
+
66
+ "Application" means the problem solving program, application, or
67
+ other business function or application to which the Package is
68
+ linked.
69
+
70
+ "Aggregation" means a compilation of a number of separate
71
+ independent programs, not based on the Package, which are
72
+ not specifically written for the purpose of combining the Package
73
+ with the independent programs.
74
+
75
+ "Distribution" means the collection of files that constitute the
76
+ Package as it is distributed by you.
77
+
78
+ "Derivative Work" means any work derived from the Package,
79
+ either through copyright or contract.
80
+
81
+ Permission for Use and Modification Without Distribution
82
+
83
+ (1) You are permitted to use the Standard Version and create and use
84
+ Modified Versions for any purpose without restriction, provided that
85
+ you do not Distribute the Modified Version.
86
+
87
+ Permissions for Redistribution of the Standard Version
88
+
89
+ (2) You may Distribute verbatim copies of the Source form of the
90
+ Standard Version of this Package in any medium without restriction,
91
+ either gratis or for a Distributor Fee, provided that you duplicate
92
+ all of the original copyright notices and associated disclaimers. At
93
+ your discretion, such binary files may be included under the conditions
94
+ that you may Distribute them as provided in (3).
95
+
96
+ Permissions for Redistribution of Modified Versions of the Source
97
+ Form as a Standard Version
98
+
99
+ (3) You may Distribute any Modified Version in Source form under the
100
+ conditions of section (2) above, provided that you include prominent
101
+ notices stating how and when you changed the Package, and provided that
102
+ the Modified Version is clearly distinguished from the Standard Version
103
+ in one of the following ways:
104
+
105
+ (a) make the Modified Version available as the Standard Version,
106
+ with the Modified Version clearly named, so that the User
107
+ can easily find the source of the Modified Version, and the
108
+ Package name and version number are clearly present.
109
+
110
+ (b) make sure that the Modified Version has a different package
111
+ name than the Standard Version.
112
+
113
+ (c) make sure that any non-Standard Version clearly carries a
114
+ different version number or name from the Standard Version.
115
+
116
+ Permissions for Redistribution of Modified Versions of the Source
117
+ Form as a Non-Standard Version
118
+
119
+ (4) You may Distribute any Modified Version in Source form without
120
+ distinguishing it from the Standard Version as required by section (3)
121
+ above, if you distribute the Modified Version exclusively in your own
122
+ organization or company, and do not distribute it to anyone outside your
123
+ organization or company.
124
+
125
+ Permissions for Redistribution of Non-Source Forms of Modified Versions
126
+
127
+ (5) You may Distribute Non-Source Forms of a Modified Version
128
+ provided that you do the following with each Non-Source Form:
129
+
130
+ (a) do at least one of the following:
131
+
132
+ (i) make the Source form of the Modified Version available
133
+ under the Original License, and include instructions on
134
+ how to acquire the Source form from the Copyright Holder;
135
+
136
+ (ii) ensure that the Source form of the Modified Version is
137
+ made available under the Original License as provided
138
+ by the Copyright Holder;
139
+
140
+ (iii) make the Source form available from the same place
141
+ as the Non-Source Form;
142
+
143
+ (b) keep intact all copyright notices and disclaimers;
144
+
145
+ (c) clearly distinguish the Modified Version from the Standard
146
+ Version.
147
+
148
+ Permissions for Aggregation
149
+
150
+ (6) You may Aggregate the Package with other independent programs
151
+ and distribute the Aggregation provided that you do not state or imply
152
+ that the Package is your own, or that the Aggregation is your own.
153
+
154
+ Permissions for Linking
155
+
156
+ (7) You may link the Package with other files to produce an
157
+ Application, and distribute the Application without restriction under
158
+ the terms of this license.
159
+
160
+ Disclaimer of Warranty
161
+
162
+ (8) THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
163
+ IMPLIED WARRANTIES. INCLUDING, WITHOUT LIMITATION, THE IMPLIED
164
+ WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
@@ -0,0 +1,198 @@
1
+ Metadata-Version: 2.5
2
+ Name: ggtree-py
3
+ Version: 0.1.0
4
+ Summary: Grammar of Graphics for Phylogenetic Trees in Python — an R-compatible port of Bioconductor ggtree.
5
+ Project-URL: Homepage, https://yulab-smu.top/treedata-book/
6
+ Project-URL: Upstream, https://github.com/YuLab-SMU/ggtree
7
+ Author: Guangchuang Yu, Tommy Tsan-Yuk Lam, Shuangbin Xu
8
+ License-Expression: Artistic-2.0
9
+ License-File: LICENSE
10
+ Keywords: beast,bioinformatics,evolution,ggplot2,ggtree,newick,phylogenetics,phylogeny,tree-visualization
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
19
+ Classifier: Topic :: Scientific/Engineering :: Visualization
20
+ Requires-Python: >=3.10
21
+ Requires-Dist: numpy>=1.22
22
+ Provides-Extra: dev
23
+ Requires-Dist: pytest>=7.0; extra == 'dev'
24
+ Description-Content-Type: text/markdown
25
+
26
+ # ggtree-py
27
+
28
+ **Grammar of Graphics for Phylogenetic Trees in Python** — an R-compatible Python port of the Bioconductor [`ggtree`](https://github.com/YuLab-SMU/ggtree) ecosystem (`treeio`, `tidytree`, `treelayout`, `ggtree`).
29
+
30
+ `ggtree-py` provides the `ggtree` Python package (`import ggtree`) with layered `+` plot composition, symbolic `aes(...)` expressions, 12+ phylogenetic tree layouts, evolutionary time-scale mapping (`mrsd`, `revts()`), clade manipulation, heatmaps (`gheatmap`), multiple sequence alignments (`msaplot`), multi-panel facets (`geom_facet`), node pie/bar insets (`nodepie`, `nodebar`, `inset`), tanglegrams (`ggdoubletree`), and built-in vector SVG and PNG rendering with **only `numpy` required at runtime**.
31
+
32
+ ---
33
+
34
+ ## Installation
35
+
36
+ ```bash
37
+ pip install ggtree-py
38
+ ```
39
+
40
+ ### Requirements
41
+
42
+ - **Python** `>= 3.10`
43
+ - **Runtime dependency**: `numpy >= 1.22`
44
+ - **Optional external rasterizer**: [`rsvg-convert`](https://wiki.gnome.org/Projects/LibRsvg) (`librsvg`) on `PATH` for high-resolution rasterization when calling `ggsave("plot.png")` or `plot.to_png()` (falls back automatically to a built-in pure-NumPy RGBA PNG rasterizer when `rsvg-convert` is not installed).
45
+
46
+ ### Local Development Install
47
+
48
+ ```bash
49
+ git clone <repo-url>
50
+ cd ggtree.py
51
+ pip install -e ".[dev]"
52
+ python3 -s -m unittest discover -s tests -v
53
+ python3 -s examples/run_all_examples.py
54
+ ```
55
+
56
+ ---
57
+
58
+ ## Quickstart
59
+
60
+ ### 1. Annotated Tree (`+` Layers & Clade Highlights)
61
+
62
+ ```python
63
+ import ggtree as gg
64
+
65
+ tree = gg.read_tree(gg.system_file("extdata", "sample.nwk", package="treeio"))
66
+ mrca_il = gg.MRCA(tree, "I", "L")
67
+
68
+ p = (
69
+ gg.ggtree(tree)
70
+ + gg.geom_tippoint(color="steelblue", size=2)
71
+ + gg.geom_nodepoint(gg.aes(subset=~gg.isTip), color="orange", size=2)
72
+ + gg.geom_text2(gg.aes(subset=~gg.isTip, label=gg.node), hjust=-0.3, size=2.5)
73
+ + gg.geom_tiplab(align=True, linetype="dotted", offset=0.2)
74
+ + gg.geom_hilight(node=mrca_il, fill="steelblue", alpha=0.35, to_bottom=True)
75
+ + gg.geom_cladelab(node=mrca_il, label="italic('Clade IL')", parse=True, offset=2.0)
76
+ + gg.geom_strip("A", "C", label="Strip AC", offset=2.0, angle="auto")
77
+ + gg.geom_taxalink("A", "E", color="firebrick")
78
+ + gg.geom_treescale()
79
+ + gg.theme_tree2()
80
+ + gg.ggtitle("Annotated Sample Tree")
81
+ )
82
+
83
+ gg.ggsave("annotated_tree.svg", plot=p, width=9.5, height=6.5)
84
+ gg.ggsave("annotated_tree.png", plot=p, width=9.5, height=6.5, dpi=100)
85
+ ```
86
+
87
+ ### 2. Time-Scaled BEAST Tree + HPD Intervals + Genotype Heatmap
88
+
89
+ ```python
90
+ from ggtree import *
91
+
92
+ beast_tree = read_beast(system_file("extdata/MCC_FluA_H3.tree", package="ggtree"))
93
+ genotype = read_table(system_file("extdata/Genotype.txt", package="ggtree"), sep="\t")
94
+
95
+ p_beast = (
96
+ ggtree(beast_tree, mrsd="2013-01-01")
97
+ + geom_range("height_0.95_HPD", color="red", size=1.5, alpha=0.5)
98
+ + geom_tiplab(size=2)
99
+ + theme_tree2()
100
+ )
101
+
102
+ p_hm = (
103
+ gheatmap(p_beast, genotype, offset=5, width=0.5, font_size=3, colnames_angle=-45, hjust=0)
104
+ + ggtitle("FluA H3 BEAST Tree + Genotype Heatmap")
105
+ )
106
+ ggsave("beast_gheatmap.png", plot=p_hm, width=11, height=11, dpi=100)
107
+ ```
108
+
109
+ ### 3. Multi-Scale Circular Heatmaps (`new_scale_fill`)
110
+
111
+ ```python
112
+ from ggtree import *
113
+
114
+ set_seed(2026)
115
+ tr = read_tree(system_file("extdata", "sample.nwk", package="treeio"))
116
+ df1 = DataFrame(
117
+ {
118
+ "first": ["a", "b", "a", "c", "d", "d", "a", "b", "e", "e", "f", "c", "f"],
119
+ "second": ["z", "z", "z", "z", "y", "y", "y", "y", "x", "x", "x", "a", "a"],
120
+ },
121
+ rownames=tr.tip_label,
122
+ )
123
+ df2 = DataFrame({"M1": rnorm(13).tolist(), "M2": rnorm(13).tolist()}, rownames=tr.tip_label)
124
+
125
+ p1 = gheatmap(ggtree(tr, layout="circular"), df1, offset=0.8, width=0.2) + scale_fill_viridis_d(option="D") + new_scale_fill()
126
+ p2 = gheatmap(p1, df2, offset=12.8, width=0.3) + scale_fill_viridis_c(option="A")
127
+ ggsave("circular_stacked_heatmap.svg", plot=p2, width=9, height=8.5)
128
+ ```
129
+
130
+ ### 4. Composite Plots, MSA, Facets, and Tanglegrams
131
+
132
+ ```python
133
+ from ggtree import *
134
+
135
+ # Patchwork composition with | and /
136
+ p_patch = (
137
+ (ggtree(tr) + geom_tiplab(size=2.5) + ggtitle("Rectangular"))
138
+ | (ggtree(tr, layout="fan", open_angle=120) + ggtitle("Fan"))
139
+ ) / (ggtree(tr, layout="tidy") + geom_tiplab(size=2.5) + ggtitle("Tidy"))
140
+
141
+ # Multiple sequence alignment
142
+ pa_tree = read_tree(system_file("extdata/pa.nwk", package="ggtree"))
143
+ p_msa = msaplot(ggtree(pa_tree) + geom_tiplab(size=2.5), fasta=system_file("extdata/pa.fas", package="ggtree"), window=(1, 60))
144
+
145
+ # Phylogeny + trait panel facet_plot / geom_facet
146
+ trait_df = DataFrame({"id": tr.tip_label, "value": rnorm(len(tr.tip_label)).tolist()})
147
+ p_facet = ggtree(tr) + geom_tiplab() + geom_facet(panel="Trait", data=trait_df, geom=geom_point, mapping=aes(x="value"))
148
+
149
+ # Crossing-minimized tanglegram
150
+ t1 = read_tree(text="(((a:1,b:1):1,c:2):1,(d:1.5,e:1.5):1.5);")
151
+ t2 = read_tree(text="((e:1.5,d:1.5):1.5,(c:2,(b:1,a:1):1):1);")
152
+ p_tangle = ggdoubletree(ggtree(t1) + geom_tiplab(), ggtree(t2) + geom_tiplab(), optimize=True, optimize_side="both")
153
+ ```
154
+
155
+ ---
156
+
157
+ ## R ↔ Python Operator & Syntax Cheatsheet
158
+
159
+ | R `ggtree` | Python `ggtree` | Notes |
160
+ | --- | --- | --- |
161
+ | `p + layer` | `p + layer` | Immutable copy returning updated `GGTree` |
162
+ | `p %<+% df` | `p % df` (also `<<`, `@`) | Left-joins external `DataFrame` onto tree node data |
163
+ | `p %<% new_tree` | `p % new_tree` (also `<<`, `@`) | Replaces the underlying tree while preserving layers/themes |
164
+ | `aes(subset = !isTip)` | `aes(subset=~isTip)` | Bitwise `~` negates symbolic expressions (`~isTip`, `"!isTip"`) |
165
+ | `read.tree(...)`, `read.beast(...)` | `read_tree(...)`, `read_beast(...)`, or `read.tree(...)`, `read.beast(...)` | Dot-call proxies (`read`, `write`, `system`, `data`, `set_`, `as_`, `is_`) supported |
166
+ | `p1 \| p2`, `p1 / p2` | `p1 \| p2`, `p1 / p2` | Nested patchwork composition returning `PlotList` |
167
+ | `TRUE`, `FALSE`, `NA`, `NULL` | `True`/`TRUE`, `False`/`FALSE`, `None`/`NA`/`NULL` | R constants exported from `ggtree` |
168
+
169
+ ---
170
+
171
+ ## Documentation
172
+
173
+ Full guides and reference pages live in [`docs/`](docs/index.md):
174
+
175
+ - [Documentation Index](docs/index.md)
176
+ - [Getting Started & Tree Data I/O](docs/getting_started.md)
177
+ - [Layouts & Tree Manipulation](docs/layouts_and_manipulation.md)
178
+ - [Annotations, Heatmaps, Facets & Multi-Tree Compositions](docs/annotations_and_compositions.md)
179
+ - [API Reference](docs/api_reference.md)
180
+ - [R-to-Python Migration Guide](docs/r_to_python_migration.md)
181
+
182
+ ---
183
+
184
+ ## Citation & Upstream Credit
185
+
186
+ This library is a Python port of **Bioconductor `ggtree`** (`v4.3.2`) originally created by **Guangchuang Yu**, **Tommy Tsan-Yuk Lam**, **Shuangbin Xu**, and contributors ([YuLab-SMU/ggtree](https://github.com/YuLab-SMU/ggtree)).
187
+
188
+ If you use `ggtree` in published research, please cite the original papers:
189
+
190
+ 1. S Xu, L Li, X Luo, M Chen, W Tang, L Zhan, Z Dai, TT Lam, Y Guan, **G Yu**. Ggtree: A serialized data object for visualization of a phylogenetic tree and annotation data. ***iMeta***, 2022, 1(4):e56. doi: [10.1002/imt2.56](https://doi.org/10.1002/imt2.56)
191
+ 2. **G Yu**. *Data Integration, Manipulation and Visualization of Phylogenetic Trees* (1st edition). ***Chapman and Hall/CRC***, 2022. doi: [10.1201/9781003279242](https://doi.org/10.1201/9781003279242)
192
+ 3. **G Yu**. Using ggtree to visualize data on tree-like structures. ***Current Protocols in Bioinformatics***, 2020, 69:e96. doi: [10.1002/cpbi.96](https://doi.org/10.1002/cpbi.96)
193
+ 4. **G Yu**, TTY Lam, H Zhu, Y Guan. Two methods for mapping and visualizing associated data on phylogeny using ggtree. ***Molecular Biology and Evolution***, 2018, 35(12):3041–3043. doi: [10.1093/molbev/msy194](https://doi.org/10.1093/molbev/msy194)
194
+ 5. **G Yu**, DK Smith, H Zhu, Y Guan, TTY Lam. ggtree: an R package for visualization and annotation of phylogenetic trees with their covariates and other associated data. ***Methods in Ecology and Evolution***, 2017, 8(1):28–36. doi: [10.1111/2041-210X.12628](https://doi.org/10.1111/2041-210X.12628)
195
+
196
+ ## License
197
+
198
+ Artistic License 2.0 — see [LICENSE](LICENSE).
@@ -0,0 +1,173 @@
1
+ # ggtree-py
2
+
3
+ **Grammar of Graphics for Phylogenetic Trees in Python** — an R-compatible Python port of the Bioconductor [`ggtree`](https://github.com/YuLab-SMU/ggtree) ecosystem (`treeio`, `tidytree`, `treelayout`, `ggtree`).
4
+
5
+ `ggtree-py` provides the `ggtree` Python package (`import ggtree`) with layered `+` plot composition, symbolic `aes(...)` expressions, 12+ phylogenetic tree layouts, evolutionary time-scale mapping (`mrsd`, `revts()`), clade manipulation, heatmaps (`gheatmap`), multiple sequence alignments (`msaplot`), multi-panel facets (`geom_facet`), node pie/bar insets (`nodepie`, `nodebar`, `inset`), tanglegrams (`ggdoubletree`), and built-in vector SVG and PNG rendering with **only `numpy` required at runtime**.
6
+
7
+ ---
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ pip install ggtree-py
13
+ ```
14
+
15
+ ### Requirements
16
+
17
+ - **Python** `>= 3.10`
18
+ - **Runtime dependency**: `numpy >= 1.22`
19
+ - **Optional external rasterizer**: [`rsvg-convert`](https://wiki.gnome.org/Projects/LibRsvg) (`librsvg`) on `PATH` for high-resolution rasterization when calling `ggsave("plot.png")` or `plot.to_png()` (falls back automatically to a built-in pure-NumPy RGBA PNG rasterizer when `rsvg-convert` is not installed).
20
+
21
+ ### Local Development Install
22
+
23
+ ```bash
24
+ git clone <repo-url>
25
+ cd ggtree.py
26
+ pip install -e ".[dev]"
27
+ python3 -s -m unittest discover -s tests -v
28
+ python3 -s examples/run_all_examples.py
29
+ ```
30
+
31
+ ---
32
+
33
+ ## Quickstart
34
+
35
+ ### 1. Annotated Tree (`+` Layers & Clade Highlights)
36
+
37
+ ```python
38
+ import ggtree as gg
39
+
40
+ tree = gg.read_tree(gg.system_file("extdata", "sample.nwk", package="treeio"))
41
+ mrca_il = gg.MRCA(tree, "I", "L")
42
+
43
+ p = (
44
+ gg.ggtree(tree)
45
+ + gg.geom_tippoint(color="steelblue", size=2)
46
+ + gg.geom_nodepoint(gg.aes(subset=~gg.isTip), color="orange", size=2)
47
+ + gg.geom_text2(gg.aes(subset=~gg.isTip, label=gg.node), hjust=-0.3, size=2.5)
48
+ + gg.geom_tiplab(align=True, linetype="dotted", offset=0.2)
49
+ + gg.geom_hilight(node=mrca_il, fill="steelblue", alpha=0.35, to_bottom=True)
50
+ + gg.geom_cladelab(node=mrca_il, label="italic('Clade IL')", parse=True, offset=2.0)
51
+ + gg.geom_strip("A", "C", label="Strip AC", offset=2.0, angle="auto")
52
+ + gg.geom_taxalink("A", "E", color="firebrick")
53
+ + gg.geom_treescale()
54
+ + gg.theme_tree2()
55
+ + gg.ggtitle("Annotated Sample Tree")
56
+ )
57
+
58
+ gg.ggsave("annotated_tree.svg", plot=p, width=9.5, height=6.5)
59
+ gg.ggsave("annotated_tree.png", plot=p, width=9.5, height=6.5, dpi=100)
60
+ ```
61
+
62
+ ### 2. Time-Scaled BEAST Tree + HPD Intervals + Genotype Heatmap
63
+
64
+ ```python
65
+ from ggtree import *
66
+
67
+ beast_tree = read_beast(system_file("extdata/MCC_FluA_H3.tree", package="ggtree"))
68
+ genotype = read_table(system_file("extdata/Genotype.txt", package="ggtree"), sep="\t")
69
+
70
+ p_beast = (
71
+ ggtree(beast_tree, mrsd="2013-01-01")
72
+ + geom_range("height_0.95_HPD", color="red", size=1.5, alpha=0.5)
73
+ + geom_tiplab(size=2)
74
+ + theme_tree2()
75
+ )
76
+
77
+ p_hm = (
78
+ gheatmap(p_beast, genotype, offset=5, width=0.5, font_size=3, colnames_angle=-45, hjust=0)
79
+ + ggtitle("FluA H3 BEAST Tree + Genotype Heatmap")
80
+ )
81
+ ggsave("beast_gheatmap.png", plot=p_hm, width=11, height=11, dpi=100)
82
+ ```
83
+
84
+ ### 3. Multi-Scale Circular Heatmaps (`new_scale_fill`)
85
+
86
+ ```python
87
+ from ggtree import *
88
+
89
+ set_seed(2026)
90
+ tr = read_tree(system_file("extdata", "sample.nwk", package="treeio"))
91
+ df1 = DataFrame(
92
+ {
93
+ "first": ["a", "b", "a", "c", "d", "d", "a", "b", "e", "e", "f", "c", "f"],
94
+ "second": ["z", "z", "z", "z", "y", "y", "y", "y", "x", "x", "x", "a", "a"],
95
+ },
96
+ rownames=tr.tip_label,
97
+ )
98
+ df2 = DataFrame({"M1": rnorm(13).tolist(), "M2": rnorm(13).tolist()}, rownames=tr.tip_label)
99
+
100
+ p1 = gheatmap(ggtree(tr, layout="circular"), df1, offset=0.8, width=0.2) + scale_fill_viridis_d(option="D") + new_scale_fill()
101
+ p2 = gheatmap(p1, df2, offset=12.8, width=0.3) + scale_fill_viridis_c(option="A")
102
+ ggsave("circular_stacked_heatmap.svg", plot=p2, width=9, height=8.5)
103
+ ```
104
+
105
+ ### 4. Composite Plots, MSA, Facets, and Tanglegrams
106
+
107
+ ```python
108
+ from ggtree import *
109
+
110
+ # Patchwork composition with | and /
111
+ p_patch = (
112
+ (ggtree(tr) + geom_tiplab(size=2.5) + ggtitle("Rectangular"))
113
+ | (ggtree(tr, layout="fan", open_angle=120) + ggtitle("Fan"))
114
+ ) / (ggtree(tr, layout="tidy") + geom_tiplab(size=2.5) + ggtitle("Tidy"))
115
+
116
+ # Multiple sequence alignment
117
+ pa_tree = read_tree(system_file("extdata/pa.nwk", package="ggtree"))
118
+ p_msa = msaplot(ggtree(pa_tree) + geom_tiplab(size=2.5), fasta=system_file("extdata/pa.fas", package="ggtree"), window=(1, 60))
119
+
120
+ # Phylogeny + trait panel facet_plot / geom_facet
121
+ trait_df = DataFrame({"id": tr.tip_label, "value": rnorm(len(tr.tip_label)).tolist()})
122
+ p_facet = ggtree(tr) + geom_tiplab() + geom_facet(panel="Trait", data=trait_df, geom=geom_point, mapping=aes(x="value"))
123
+
124
+ # Crossing-minimized tanglegram
125
+ t1 = read_tree(text="(((a:1,b:1):1,c:2):1,(d:1.5,e:1.5):1.5);")
126
+ t2 = read_tree(text="((e:1.5,d:1.5):1.5,(c:2,(b:1,a:1):1):1);")
127
+ p_tangle = ggdoubletree(ggtree(t1) + geom_tiplab(), ggtree(t2) + geom_tiplab(), optimize=True, optimize_side="both")
128
+ ```
129
+
130
+ ---
131
+
132
+ ## R ↔ Python Operator & Syntax Cheatsheet
133
+
134
+ | R `ggtree` | Python `ggtree` | Notes |
135
+ | --- | --- | --- |
136
+ | `p + layer` | `p + layer` | Immutable copy returning updated `GGTree` |
137
+ | `p %<+% df` | `p % df` (also `<<`, `@`) | Left-joins external `DataFrame` onto tree node data |
138
+ | `p %<% new_tree` | `p % new_tree` (also `<<`, `@`) | Replaces the underlying tree while preserving layers/themes |
139
+ | `aes(subset = !isTip)` | `aes(subset=~isTip)` | Bitwise `~` negates symbolic expressions (`~isTip`, `"!isTip"`) |
140
+ | `read.tree(...)`, `read.beast(...)` | `read_tree(...)`, `read_beast(...)`, or `read.tree(...)`, `read.beast(...)` | Dot-call proxies (`read`, `write`, `system`, `data`, `set_`, `as_`, `is_`) supported |
141
+ | `p1 \| p2`, `p1 / p2` | `p1 \| p2`, `p1 / p2` | Nested patchwork composition returning `PlotList` |
142
+ | `TRUE`, `FALSE`, `NA`, `NULL` | `True`/`TRUE`, `False`/`FALSE`, `None`/`NA`/`NULL` | R constants exported from `ggtree` |
143
+
144
+ ---
145
+
146
+ ## Documentation
147
+
148
+ Full guides and reference pages live in [`docs/`](docs/index.md):
149
+
150
+ - [Documentation Index](docs/index.md)
151
+ - [Getting Started & Tree Data I/O](docs/getting_started.md)
152
+ - [Layouts & Tree Manipulation](docs/layouts_and_manipulation.md)
153
+ - [Annotations, Heatmaps, Facets & Multi-Tree Compositions](docs/annotations_and_compositions.md)
154
+ - [API Reference](docs/api_reference.md)
155
+ - [R-to-Python Migration Guide](docs/r_to_python_migration.md)
156
+
157
+ ---
158
+
159
+ ## Citation & Upstream Credit
160
+
161
+ This library is a Python port of **Bioconductor `ggtree`** (`v4.3.2`) originally created by **Guangchuang Yu**, **Tommy Tsan-Yuk Lam**, **Shuangbin Xu**, and contributors ([YuLab-SMU/ggtree](https://github.com/YuLab-SMU/ggtree)).
162
+
163
+ If you use `ggtree` in published research, please cite the original papers:
164
+
165
+ 1. S Xu, L Li, X Luo, M Chen, W Tang, L Zhan, Z Dai, TT Lam, Y Guan, **G Yu**. Ggtree: A serialized data object for visualization of a phylogenetic tree and annotation data. ***iMeta***, 2022, 1(4):e56. doi: [10.1002/imt2.56](https://doi.org/10.1002/imt2.56)
166
+ 2. **G Yu**. *Data Integration, Manipulation and Visualization of Phylogenetic Trees* (1st edition). ***Chapman and Hall/CRC***, 2022. doi: [10.1201/9781003279242](https://doi.org/10.1201/9781003279242)
167
+ 3. **G Yu**. Using ggtree to visualize data on tree-like structures. ***Current Protocols in Bioinformatics***, 2020, 69:e96. doi: [10.1002/cpbi.96](https://doi.org/10.1002/cpbi.96)
168
+ 4. **G Yu**, TTY Lam, H Zhu, Y Guan. Two methods for mapping and visualizing associated data on phylogeny using ggtree. ***Molecular Biology and Evolution***, 2018, 35(12):3041–3043. doi: [10.1093/molbev/msy194](https://doi.org/10.1093/molbev/msy194)
169
+ 5. **G Yu**, DK Smith, H Zhu, Y Guan, TTY Lam. ggtree: an R package for visualization and annotation of phylogenetic trees with their covariates and other associated data. ***Methods in Ecology and Evolution***, 2017, 8(1):28–36. doi: [10.1111/2041-210X.12628](https://doi.org/10.1111/2041-210X.12628)
170
+
171
+ ## License
172
+
173
+ Artistic License 2.0 — see [LICENSE](LICENSE).