coolbox 0.1.4__tar.gz → 0.4.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.
- coolbox-0.4.0/PKG-INFO +164 -0
- coolbox-0.4.0/README.md +106 -0
- coolbox-0.4.0/coolbox/__init__.py +1 -0
- coolbox-0.4.0/coolbox/__main__.py +12 -0
- {coolbox-0.1.4 → coolbox-0.4.0}/coolbox/api.py +4 -2
- coolbox-0.4.0/coolbox/cli.py +373 -0
- {coolbox-0.1.4 → coolbox-0.4.0}/coolbox/core/__init__.py +0 -0
- coolbox-0.4.0/coolbox/core/browser/__init__.py +47 -0
- coolbox-0.4.0/coolbox/core/browser/base.py +268 -0
- coolbox-0.4.0/coolbox/core/browser/widgets/__init__.py +2 -0
- coolbox-0.4.0/coolbox/core/browser/widgets/base.py +37 -0
- coolbox-0.4.0/coolbox/core/browser/widgets/full.py +45 -0
- coolbox-0.4.0/coolbox/core/browser/widgets/navigation.py +265 -0
- coolbox-0.4.0/coolbox/core/browser/widgets/simple.py +35 -0
- coolbox-0.4.0/coolbox/core/coverage/__init__.py +26 -0
- coolbox-0.4.0/coolbox/core/coverage/base.py +210 -0
- coolbox-0.4.0/coolbox/core/coverage/highlights.py +179 -0
- coolbox-0.4.0/coolbox/core/coverage/hlines.py +61 -0
- coolbox-0.4.0/coolbox/core/coverage/vlines.py +140 -0
- {coolbox-0.1.4 → coolbox-0.4.0}/coolbox/core/feature.py +63 -55
- coolbox-0.4.0/coolbox/core/frame/__init__.py +4 -0
- coolbox-0.1.4/coolbox/core/frame.py → coolbox-0.4.0/coolbox/core/frame/base.py +109 -147
- coolbox-0.4.0/coolbox/core/frame/frame.py +252 -0
- coolbox-0.4.0/coolbox/core/frame/superframe/__init__.py +3 -0
- coolbox-0.4.0/coolbox/core/frame/superframe/base.py +76 -0
- coolbox-0.4.0/coolbox/core/frame/superframe/jointview.py +265 -0
- coolbox-0.4.0/coolbox/core/track/__init__.py +18 -0
- coolbox-0.4.0/coolbox/core/track/arcs/__init__.py +15 -0
- coolbox-0.4.0/coolbox/core/track/arcs/base.py +115 -0
- coolbox-0.4.0/coolbox/core/track/arcs/bedpe.py +56 -0
- coolbox-0.4.0/coolbox/core/track/arcs/hicpeaks.py +20 -0
- coolbox-0.4.0/coolbox/core/track/arcs/pairs.py +26 -0
- coolbox-0.4.0/coolbox/core/track/arcs/plot.py +220 -0
- coolbox-0.4.0/coolbox/core/track/bam.py +87 -0
- coolbox-0.4.0/coolbox/core/track/base.py +284 -0
- coolbox-0.4.0/coolbox/core/track/bed/__init__.py +2 -0
- coolbox-0.4.0/coolbox/core/track/bed/base.py +164 -0
- coolbox-0.4.0/coolbox/core/track/bed/bed.py +64 -0
- coolbox-0.4.0/coolbox/core/track/bed/plot.py +425 -0
- coolbox-0.4.0/coolbox/core/track/gtf.py +153 -0
- coolbox-0.4.0/coolbox/core/track/hicmat/__init__.py +7 -0
- coolbox-0.4.0/coolbox/core/track/hicmat/base.py +179 -0
- coolbox-0.4.0/coolbox/core/track/hicmat/cool.py +90 -0
- coolbox-0.4.0/coolbox/core/track/hicmat/dothic.py +93 -0
- coolbox-0.4.0/coolbox/core/track/hicmat/hicdiff/__init__.py +2 -0
- coolbox-0.4.0/coolbox/core/track/hicmat/hicdiff/diff.py +89 -0
- coolbox-0.4.0/coolbox/core/track/hicmat/hicdiff/selfish.py +149 -0
- coolbox-0.4.0/coolbox/core/track/hicmat/hicmat.py +24 -0
- coolbox-0.4.0/coolbox/core/track/hicmat/plot.py +271 -0
- coolbox-0.4.0/coolbox/core/track/hicmat/process.py +166 -0
- coolbox-0.4.0/coolbox/core/track/hist/__init__.py +29 -0
- coolbox-0.4.0/coolbox/core/track/hist/bam.py +45 -0
- coolbox-0.4.0/coolbox/core/track/hist/base.py +136 -0
- coolbox-0.4.0/coolbox/core/track/hist/bedgraph.py +42 -0
- coolbox-0.4.0/coolbox/core/track/hist/bigwig.py +60 -0
- coolbox-0.4.0/coolbox/core/track/hist/hicfeature.py +272 -0
- coolbox-0.4.0/coolbox/core/track/hist/plot.py +185 -0
- coolbox-0.4.0/coolbox/core/track/hist/snp.py +83 -0
- coolbox-0.4.0/coolbox/core/track/ideogram.py +121 -0
- coolbox-0.4.0/coolbox/core/track/pseudo.py +189 -0
- coolbox-0.4.0/coolbox/core/track/tad.py +236 -0
- {coolbox-0.1.4 → coolbox-0.4.0}/coolbox/genome/hg19.txt +0 -0
- {coolbox-0.1.4 → coolbox-0.4.0}/coolbox/genome/hg38.txt +0 -0
- {coolbox-0.1.4 → coolbox-0.4.0}/coolbox/genome/mm10.txt +0 -0
- {coolbox-0.1.4 → coolbox-0.4.0}/coolbox/genome/mm9.txt +0 -0
- coolbox-0.4.0/coolbox/utilities/__init__.py +89 -0
- coolbox-0.4.0/coolbox/utilities/cmd.py +33 -0
- coolbox-0.4.0/coolbox/utilities/doctool.py +131 -0
- {coolbox-0.1.4 → coolbox-0.4.0}/coolbox/utilities/figtools.py +61 -32
- {coolbox-0.1.4 → coolbox-0.4.0}/coolbox/utilities/filetool.py +26 -0
- {coolbox-0.1.4 → coolbox-0.4.0}/coolbox/utilities/fmtconvert.py +2 -7
- {coolbox-0.1.4 → coolbox-0.4.0}/coolbox/utilities/genome.py +89 -46
- {coolbox-0.1.4 → coolbox-0.4.0}/coolbox/utilities/logtools.py +0 -1
- coolbox-0.4.0/coolbox/utilities/reader/hic/__init__.py +0 -0
- coolbox-0.4.0/coolbox/utilities/reader/hic/straw.py +812 -0
- {coolbox-0.1.4/coolbox/utilities → coolbox-0.4.0/coolbox/utilities/reader}/hic/tools.py +21 -16
- {coolbox-0.1.4/coolbox/utilities → coolbox-0.4.0/coolbox/utilities/reader}/hic/wrap.py +125 -56
- coolbox-0.4.0/coolbox/utilities/reader/tab.py +563 -0
- coolbox-0.4.0/coolbox.egg-info/PKG-INFO +164 -0
- coolbox-0.4.0/coolbox.egg-info/SOURCES.txt +97 -0
- coolbox-0.4.0/coolbox.egg-info/entry_points.txt +2 -0
- coolbox-0.4.0/coolbox.egg-info/requires.txt +33 -0
- coolbox-0.4.0/pyproject.toml +85 -0
- coolbox-0.4.0/requirements.txt +17 -0
- coolbox-0.4.0/tests/test_add_rule.py +71 -0
- coolbox-0.4.0/tests/test_browser.py +31 -0
- coolbox-0.4.0/tests/test_cli.py +70 -0
- coolbox-0.4.0/tests/test_coverage.py +52 -0
- coolbox-0.4.0/tests/test_frame.py +39 -0
- coolbox-0.4.0/tests/test_superframe.py +37 -0
- coolbox-0.4.0/tests/test_tab_reader.py +232 -0
- coolbox-0.4.0/tests/test_track.py +242 -0
- coolbox-0.1.4/PKG-INFO +0 -43
- coolbox-0.1.4/README.md +0 -19
- coolbox-0.1.4/coolbox/__init__.py +0 -1
- coolbox-0.1.4/coolbox/core/browser.py +0 -48
- coolbox-0.1.4/coolbox/core/coverage.py +0 -476
- coolbox-0.1.4/coolbox/core/track.py +0 -879
- coolbox-0.1.4/coolbox/fetchdata.py +0 -431
- coolbox-0.1.4/coolbox/interact.py +0 -455
- coolbox-0.1.4/coolbox/plots/__init__.py +0 -3
- coolbox-0.1.4/coolbox/plots/coverage/__init__.py +0 -4
- coolbox-0.1.4/coolbox/plots/coverage/base.py +0 -10
- coolbox-0.1.4/coolbox/plots/coverage/hicpeaks.py +0 -201
- coolbox-0.1.4/coolbox/plots/coverage/highlights.py +0 -129
- coolbox-0.1.4/coolbox/plots/coverage/tad.py +0 -194
- coolbox-0.1.4/coolbox/plots/coverage/vlines.py +0 -68
- coolbox-0.1.4/coolbox/plots/frame.py +0 -130
- coolbox-0.1.4/coolbox/plots/track/__init__.py +0 -8
- coolbox-0.1.4/coolbox/plots/track/arcs.py +0 -139
- coolbox-0.1.4/coolbox/plots/track/base.py +0 -58
- coolbox-0.1.4/coolbox/plots/track/bed.py +0 -592
- coolbox-0.1.4/coolbox/plots/track/bedgraph.py +0 -108
- coolbox-0.1.4/coolbox/plots/track/bigwig.py +0 -196
- coolbox-0.1.4/coolbox/plots/track/cool.py +0 -5
- coolbox-0.1.4/coolbox/plots/track/dothic.py +0 -5
- coolbox-0.1.4/coolbox/plots/track/hiccompare.py +0 -128
- coolbox-0.1.4/coolbox/plots/track/hicmatrix.py +0 -380
- coolbox-0.1.4/coolbox/plots/track/pseudo.py +0 -70
- coolbox-0.1.4/coolbox/utilities/__init__.py +0 -58
- coolbox-0.1.4/coolbox/utilities/bed.py +0 -341
- coolbox-0.1.4/coolbox/utilities/hic/straw.py +0 -612
- coolbox-0.1.4/coolbox.egg-info/PKG-INFO +0 -43
- coolbox-0.1.4/coolbox.egg-info/SOURCES.txt +0 -55
- coolbox-0.1.4/coolbox.egg-info/requires.txt +0 -8
- coolbox-0.1.4/requirements.txt +0 -8
- coolbox-0.1.4/setup.py +0 -70
- {coolbox-0.1.4 → coolbox-0.4.0}/LICENSE +0 -0
- {coolbox-0.1.4 → coolbox-0.4.0}/MANIFEST.in +0 -0
- {coolbox-0.1.4/coolbox/utilities/hic → coolbox-0.4.0/coolbox/utilities/reader}/__init__.py +0 -0
- {coolbox-0.1.4 → coolbox-0.4.0}/coolbox.egg-info/dependency_links.txt +0 -0
- {coolbox-0.1.4 → coolbox-0.4.0}/coolbox.egg-info/not-zip-safe +0 -0
- {coolbox-0.1.4 → coolbox-0.4.0}/coolbox.egg-info/top_level.txt +0 -0
- {coolbox-0.1.4 → coolbox-0.4.0}/setup.cfg +0 -0
coolbox-0.4.0/PKG-INFO
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: coolbox
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Jupyter notebook based genomic data visulization toolkit.
|
|
5
|
+
Author-email: Weize Xu <vet.xwz@gmail.com>
|
|
6
|
+
License: GPLv3
|
|
7
|
+
Project-URL: Homepage, https://github.com/GangCaoLab/CoolBox
|
|
8
|
+
Project-URL: Documentation, https://gangcaolab.github.io/CoolBox/index.html
|
|
9
|
+
Project-URL: Repository, https://github.com/GangCaoLab/CoolBox
|
|
10
|
+
Project-URL: Bug Tracker, https://github.com/GangCaoLab/CoolBox/issues
|
|
11
|
+
Keywords: genomics,bioinformatics,visualization,Jupyter
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Operating System :: POSIX
|
|
14
|
+
Classifier: Programming Language :: Python
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
21
|
+
Classifier: Intended Audience :: Science/Research
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
24
|
+
Requires-Python: <4,>=3.7
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: scipy>=1.0.0
|
|
28
|
+
Requires-Dist: numpy
|
|
29
|
+
Requires-Dist: pandas>=1.0.0
|
|
30
|
+
Requires-Dist: statsmodels
|
|
31
|
+
Requires-Dist: matplotlib>=3.8.4
|
|
32
|
+
Requires-Dist: jupyter>=1.0.0
|
|
33
|
+
Requires-Dist: ipywidgets>=7.5.1
|
|
34
|
+
Requires-Dist: nbformat
|
|
35
|
+
Requires-Dist: voila
|
|
36
|
+
Requires-Dist: svgutils
|
|
37
|
+
Requires-Dist: intervaltree
|
|
38
|
+
Requires-Dist: dna_features_viewer
|
|
39
|
+
Requires-Dist: h5py
|
|
40
|
+
Requires-Dist: cooler
|
|
41
|
+
Requires-Dist: numpydoc
|
|
42
|
+
Requires-Dist: fire
|
|
43
|
+
Requires-Dist: oxbow>=0.4.2
|
|
44
|
+
Provides-Extra: doc
|
|
45
|
+
Requires-Dist: sphinx_rtd_theme; extra == "doc"
|
|
46
|
+
Requires-Dist: autodocsumm; extra == "doc"
|
|
47
|
+
Requires-Dist: recommonmark; extra == "doc"
|
|
48
|
+
Requires-Dist: nbsphinx; extra == "doc"
|
|
49
|
+
Requires-Dist: sphinx_gallery; extra == "doc"
|
|
50
|
+
Requires-Dist: sphinx-autobuild; extra == "doc"
|
|
51
|
+
Provides-Extra: strawc
|
|
52
|
+
Requires-Dist: strawC; extra == "strawc"
|
|
53
|
+
Provides-Extra: dev
|
|
54
|
+
Requires-Dist: pytest; extra == "dev"
|
|
55
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
56
|
+
Requires-Dist: build; extra == "dev"
|
|
57
|
+
Dynamic: license-file
|
|
58
|
+
|
|
59
|
+
<p align="center">
|
|
60
|
+
<img src="docs/images/banner.png">
|
|
61
|
+
</p>
|
|
62
|
+
|
|
63
|
+
<hr>
|
|
64
|
+
|
|
65
|
+
<p align="center">
|
|
66
|
+
|
|
67
|
+
<a href="https://mybinder.org/v2/gh/GangCaoLab/CoolBox/master?filepath=tests%2FTestRegion.ipynb">
|
|
68
|
+
<img src="https://mybinder.org/badge_logo.svg" alt="Binder" />
|
|
69
|
+
</a>
|
|
70
|
+
|
|
71
|
+
<a href="https://anaconda.org/bioconda/coolbox">
|
|
72
|
+
<img src="https://img.shields.io/conda/v/bioconda/coolbox" alt="Install with conda" />
|
|
73
|
+
</a>
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
<a href="https://pypi.python.org/pypi/coolbox/">
|
|
77
|
+
<img src="https://img.shields.io/pypi/v/coolbox.svg" alt="Install with PyPi" />
|
|
78
|
+
</a>
|
|
79
|
+
|
|
80
|
+
<a href="https://hub.docker.com/r/nanguage/coolbox">
|
|
81
|
+
<img src="https://img.shields.io/docker/v/nanguage/coolbox?label=docker&logo=docker&sort=semver" alt="Docker version">
|
|
82
|
+
</a>
|
|
83
|
+
|
|
84
|
+
<a href="https://github.com/GangCaoLab/CoolBox/releases">
|
|
85
|
+
<img src="https://img.shields.io/github/v/release/gangcaolab/coolbox?include_prereleases&label=github" alt="Github release">
|
|
86
|
+
</a>
|
|
87
|
+
|
|
88
|
+
<a href="https://gangcaolab.github.io/CoolBox/index.html">
|
|
89
|
+
<img src="https://readthedocs.org/projects/ansicolortags/badge/?version=latest" alt="Documentation">
|
|
90
|
+
</a>
|
|
91
|
+
|
|
92
|
+
<a href="https://pypi.python.org/pypi/coolbox">
|
|
93
|
+
<img src="https://img.shields.io/pypi/pyversions/coolbox.svg" alt="Version">
|
|
94
|
+
</a>
|
|
95
|
+
|
|
96
|
+
<a href="https://pepy.tech/project/coolbox">
|
|
97
|
+
<img src="https://pepy.tech/badge/coolbox" alt="Downloads">
|
|
98
|
+
</a>
|
|
99
|
+
|
|
100
|
+
<a href="https://pepy.tech/project/coolbox">
|
|
101
|
+
<img src="https://pepy.tech/badge/coolbox/week" alt="Downloads per week">
|
|
102
|
+
</a>
|
|
103
|
+
|
|
104
|
+
<a href="https://github.com/GangCaoLab/coolbox/actions/workflows/python-package-conda.yml">
|
|
105
|
+
<img src="https://github.com/GangCaoLab/coolbox/actions/workflows/python-package-conda.yml/badge.svg" alt="Build Status">
|
|
106
|
+
</a>
|
|
107
|
+
|
|
108
|
+
<a href="https://www.biorxiv.org/content/10.1101/2021.04.15.439923v1">
|
|
109
|
+
<img src="https://img.shields.io/badge/preprint-biorxiv-red" alt="biorxiv">
|
|
110
|
+
</a>
|
|
111
|
+
|
|
112
|
+
<a href="https://github.com/GangCaoLab/CoolBox/blob/master/LICENSE">
|
|
113
|
+
<img src="https://img.shields.io/github/license/GangCaoLab/coolbox" alt="license">
|
|
114
|
+
</a>
|
|
115
|
+
|
|
116
|
+
</p>
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
Flexible, user-friendly genomic data visualization toolkit.
|
|
120
|
+
|
|
121
|
+

|
|
122
|
+
|
|
123
|
+
## Highlights:
|
|
124
|
+
|
|
125
|
+
* Multi-omics data interactively visualization.
|
|
126
|
+
* User-friendly [API (ggplot2-like Python EDSL)](https://gangcaolab.github.io/CoolBox/quick_start_API.html) and [CLI](https://gangcaolab.github.io/CoolBox/quick_start_CLI.html).
|
|
127
|
+
* Show within Jupyter notebook.
|
|
128
|
+
* Ease to fetch data and in cooperation with other Python package.
|
|
129
|
+
* Ease to implement/add custom track and integrate into CoolBox.
|
|
130
|
+
|
|
131
|
+
More details please read the [documentation](https://gangcaolab.github.io/CoolBox/index.html).
|
|
132
|
+
Interactively online demo: [binder](https://mybinder.org/v2/gh/GangCaoLab/CoolBox/master?filepath=tests%2FTestRegion.ipynb)
|
|
133
|
+
|
|
134
|
+
## Develop
|
|
135
|
+
|
|
136
|
+
See [CONTRIBUTING.md](https://github.com/GangCaoLab/CoolBox/blob/master/CONTRIBUTING.md)
|
|
137
|
+
|
|
138
|
+
## Citation
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
@article{xu2021coolbox,
|
|
142
|
+
title={CoolBox: A flexible toolkit for visual analysis of genomics data},
|
|
143
|
+
author={Xu, Weize and Zhong, Quan and Lin, Da and Zuo, Ya and Dai, Jinxia and Li, Guoliang and Cao, Gang},
|
|
144
|
+
journal={BMC bioinformatics},
|
|
145
|
+
volume={22},
|
|
146
|
+
number={1},
|
|
147
|
+
pages={1--9},
|
|
148
|
+
year={2021},
|
|
149
|
+
publisher={Springer}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Thanks
|
|
154
|
+
|
|
155
|
+
+ [pyGenomeTracks](https://github.com/deeptools/pyGenomeTracks),
|
|
156
|
+
CoolBox's plot system is fork from it.
|
|
157
|
+
|
|
158
|
+
### Contributors
|
|
159
|
+
This project exists thanks to all the people who contribute.
|
|
160
|
+
|
|
161
|
+
<a href="https://github.com/GangCaoLab/CoolBox/graphs/contributors">
|
|
162
|
+
<img src="https://contrib.rocks/image?repo=GangCaoLab/CoolBox" />
|
|
163
|
+
</a>
|
|
164
|
+
|
coolbox-0.4.0/README.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/images/banner.png">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<hr>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
|
|
9
|
+
<a href="https://mybinder.org/v2/gh/GangCaoLab/CoolBox/master?filepath=tests%2FTestRegion.ipynb">
|
|
10
|
+
<img src="https://mybinder.org/badge_logo.svg" alt="Binder" />
|
|
11
|
+
</a>
|
|
12
|
+
|
|
13
|
+
<a href="https://anaconda.org/bioconda/coolbox">
|
|
14
|
+
<img src="https://img.shields.io/conda/v/bioconda/coolbox" alt="Install with conda" />
|
|
15
|
+
</a>
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
<a href="https://pypi.python.org/pypi/coolbox/">
|
|
19
|
+
<img src="https://img.shields.io/pypi/v/coolbox.svg" alt="Install with PyPi" />
|
|
20
|
+
</a>
|
|
21
|
+
|
|
22
|
+
<a href="https://hub.docker.com/r/nanguage/coolbox">
|
|
23
|
+
<img src="https://img.shields.io/docker/v/nanguage/coolbox?label=docker&logo=docker&sort=semver" alt="Docker version">
|
|
24
|
+
</a>
|
|
25
|
+
|
|
26
|
+
<a href="https://github.com/GangCaoLab/CoolBox/releases">
|
|
27
|
+
<img src="https://img.shields.io/github/v/release/gangcaolab/coolbox?include_prereleases&label=github" alt="Github release">
|
|
28
|
+
</a>
|
|
29
|
+
|
|
30
|
+
<a href="https://gangcaolab.github.io/CoolBox/index.html">
|
|
31
|
+
<img src="https://readthedocs.org/projects/ansicolortags/badge/?version=latest" alt="Documentation">
|
|
32
|
+
</a>
|
|
33
|
+
|
|
34
|
+
<a href="https://pypi.python.org/pypi/coolbox">
|
|
35
|
+
<img src="https://img.shields.io/pypi/pyversions/coolbox.svg" alt="Version">
|
|
36
|
+
</a>
|
|
37
|
+
|
|
38
|
+
<a href="https://pepy.tech/project/coolbox">
|
|
39
|
+
<img src="https://pepy.tech/badge/coolbox" alt="Downloads">
|
|
40
|
+
</a>
|
|
41
|
+
|
|
42
|
+
<a href="https://pepy.tech/project/coolbox">
|
|
43
|
+
<img src="https://pepy.tech/badge/coolbox/week" alt="Downloads per week">
|
|
44
|
+
</a>
|
|
45
|
+
|
|
46
|
+
<a href="https://github.com/GangCaoLab/coolbox/actions/workflows/python-package-conda.yml">
|
|
47
|
+
<img src="https://github.com/GangCaoLab/coolbox/actions/workflows/python-package-conda.yml/badge.svg" alt="Build Status">
|
|
48
|
+
</a>
|
|
49
|
+
|
|
50
|
+
<a href="https://www.biorxiv.org/content/10.1101/2021.04.15.439923v1">
|
|
51
|
+
<img src="https://img.shields.io/badge/preprint-biorxiv-red" alt="biorxiv">
|
|
52
|
+
</a>
|
|
53
|
+
|
|
54
|
+
<a href="https://github.com/GangCaoLab/CoolBox/blob/master/LICENSE">
|
|
55
|
+
<img src="https://img.shields.io/github/license/GangCaoLab/coolbox" alt="license">
|
|
56
|
+
</a>
|
|
57
|
+
|
|
58
|
+
</p>
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
Flexible, user-friendly genomic data visualization toolkit.
|
|
62
|
+
|
|
63
|
+

|
|
64
|
+
|
|
65
|
+
## Highlights:
|
|
66
|
+
|
|
67
|
+
* Multi-omics data interactively visualization.
|
|
68
|
+
* User-friendly [API (ggplot2-like Python EDSL)](https://gangcaolab.github.io/CoolBox/quick_start_API.html) and [CLI](https://gangcaolab.github.io/CoolBox/quick_start_CLI.html).
|
|
69
|
+
* Show within Jupyter notebook.
|
|
70
|
+
* Ease to fetch data and in cooperation with other Python package.
|
|
71
|
+
* Ease to implement/add custom track and integrate into CoolBox.
|
|
72
|
+
|
|
73
|
+
More details please read the [documentation](https://gangcaolab.github.io/CoolBox/index.html).
|
|
74
|
+
Interactively online demo: [binder](https://mybinder.org/v2/gh/GangCaoLab/CoolBox/master?filepath=tests%2FTestRegion.ipynb)
|
|
75
|
+
|
|
76
|
+
## Develop
|
|
77
|
+
|
|
78
|
+
See [CONTRIBUTING.md](https://github.com/GangCaoLab/CoolBox/blob/master/CONTRIBUTING.md)
|
|
79
|
+
|
|
80
|
+
## Citation
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
@article{xu2021coolbox,
|
|
84
|
+
title={CoolBox: A flexible toolkit for visual analysis of genomics data},
|
|
85
|
+
author={Xu, Weize and Zhong, Quan and Lin, Da and Zuo, Ya and Dai, Jinxia and Li, Guoliang and Cao, Gang},
|
|
86
|
+
journal={BMC bioinformatics},
|
|
87
|
+
volume={22},
|
|
88
|
+
number={1},
|
|
89
|
+
pages={1--9},
|
|
90
|
+
year={2021},
|
|
91
|
+
publisher={Springer}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Thanks
|
|
96
|
+
|
|
97
|
+
+ [pyGenomeTracks](https://github.com/deeptools/pyGenomeTracks),
|
|
98
|
+
CoolBox's plot system is fork from it.
|
|
99
|
+
|
|
100
|
+
### Contributors
|
|
101
|
+
This project exists thanks to all the people who contribute.
|
|
102
|
+
|
|
103
|
+
<a href="https://github.com/GangCaoLab/CoolBox/graphs/contributors">
|
|
104
|
+
<img src="https://contrib.rocks/image?repo=GangCaoLab/CoolBox" />
|
|
105
|
+
</a>
|
|
106
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '0.4.0'
|
|
@@ -64,11 +64,13 @@ The rule of element composition:
|
|
|
64
64
|
"""
|
|
65
65
|
|
|
66
66
|
import warnings
|
|
67
|
+
|
|
67
68
|
warnings.filterwarnings('ignore')
|
|
68
69
|
|
|
69
70
|
from coolbox.core.track import *
|
|
70
|
-
from coolbox.core.frame import
|
|
71
|
+
from coolbox.core.frame import *
|
|
71
72
|
from coolbox.core.feature import *
|
|
72
73
|
from coolbox.core.coverage import *
|
|
73
74
|
from coolbox.core.browser import *
|
|
74
|
-
|
|
75
|
+
from coolbox.core.frame.superframe import JointView
|
|
76
|
+
from coolbox.utilities.genome import GenomeRange
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import os.path as osp
|
|
3
|
+
import subprocess as subp
|
|
4
|
+
from typing import Tuple
|
|
5
|
+
import runpy
|
|
6
|
+
|
|
7
|
+
import fire
|
|
8
|
+
import nbformat as nbf
|
|
9
|
+
|
|
10
|
+
import coolbox
|
|
11
|
+
from coolbox.utilities import get_logger
|
|
12
|
+
from coolbox.utilities.genome import GenomeRange
|
|
13
|
+
from coolbox.api import *
|
|
14
|
+
|
|
15
|
+
log = get_logger("CoolBox CLI")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_element_type_by_str(elem_str):
|
|
19
|
+
import coolbox.api
|
|
20
|
+
try:
|
|
21
|
+
elem_tp = eval("coolbox.api." + elem_str)
|
|
22
|
+
except NameError:
|
|
23
|
+
log.error(
|
|
24
|
+
f"No element type name as {elem_tp}, all elements type see: " +
|
|
25
|
+
"https://gangcaolab.github.io/CoolBox/api.html"
|
|
26
|
+
)
|
|
27
|
+
return elem_tp
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def get_compose_code(elem_str, args, kwargs):
|
|
31
|
+
compose_code = elem_str + "("
|
|
32
|
+
compose_code += ", ".join(
|
|
33
|
+
[repr(arg) for arg in args] +
|
|
34
|
+
[f"{k} = {repr(v)}" for k, v in kwargs.items()]
|
|
35
|
+
)
|
|
36
|
+
compose_code += ")"
|
|
37
|
+
return compose_code
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
FRAME_POS = ("left", "right", "top", "bottom", "center")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class CLI(object):
|
|
44
|
+
"""
|
|
45
|
+
CoolBox Command Line Interface
|
|
46
|
+
|
|
47
|
+
You can use this cli to create coolbox browser instance,
|
|
48
|
+
visualize your data directly in shell.
|
|
49
|
+
|
|
50
|
+
example:
|
|
51
|
+
|
|
52
|
+
1. Draw tracks within a genome range, save figure to a pdf file:
|
|
53
|
+
|
|
54
|
+
$ coolbox add XAxis - add BigWig test.bw - goto "chr1:5000000-6000000" - plot test.pdf
|
|
55
|
+
|
|
56
|
+
2. Generate a notebook and run jupyter to open browser:
|
|
57
|
+
|
|
58
|
+
$ coolbox add XAxis - add BigWig test.bw - goto "chr1:5000000-6000000" - run_jupyter
|
|
59
|
+
|
|
60
|
+
3. Run a independent web application.
|
|
61
|
+
|
|
62
|
+
$ coolbox add XAxis - add BigWig test.bw - goto "chr1:5000000-6000000" - run_webapp
|
|
63
|
+
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
def __init__(self, genome="hg19", genome_range: str = None, genome_range2: str = None):
|
|
67
|
+
self._indent = 0
|
|
68
|
+
self.current_range = [None, None]
|
|
69
|
+
self.goto(genome_range, genome_range2)
|
|
70
|
+
self.genome = genome
|
|
71
|
+
self.frame_pos = None
|
|
72
|
+
self.frames = {}
|
|
73
|
+
|
|
74
|
+
@staticmethod
|
|
75
|
+
def version():
|
|
76
|
+
"""print coolbox version"""
|
|
77
|
+
print(coolbox.__version__)
|
|
78
|
+
|
|
79
|
+
def set_genome(self, genome):
|
|
80
|
+
"""Set reference genome for browser object.
|
|
81
|
+
|
|
82
|
+
:param genome: Reference genome (hg19, hg38, mm9, mm10),
|
|
83
|
+
or the path to chromosomes size file(tab splited chromname-size).
|
|
84
|
+
"""
|
|
85
|
+
self.genome = genome
|
|
86
|
+
return self
|
|
87
|
+
|
|
88
|
+
def goto(self, genome_range: str = None, genome_range2: str = None):
|
|
89
|
+
"""Goto a genome range.
|
|
90
|
+
|
|
91
|
+
:param genome_range: Genome range string, like "chr9:4000000-6000000".
|
|
92
|
+
:param genome_range2: Genome range string, like "chr9:4000000-6000000. Only required in JointView mode".
|
|
93
|
+
"""
|
|
94
|
+
if genome_range2 is None:
|
|
95
|
+
genome_range2 = genome_range
|
|
96
|
+
# validate genome range
|
|
97
|
+
if genome_range:
|
|
98
|
+
gr = GenomeRange(genome_range)
|
|
99
|
+
if genome_range2:
|
|
100
|
+
gr = GenomeRange(genome_range2)
|
|
101
|
+
log.info(f"Goto genome range '{genome_range}' '{genome_range2}'")
|
|
102
|
+
self.current_range = [genome_range, genome_range2]
|
|
103
|
+
|
|
104
|
+
return self
|
|
105
|
+
|
|
106
|
+
@staticmethod
|
|
107
|
+
def show_doc(elem_str):
|
|
108
|
+
"""Print the document of specified Element type. For example: coolbox show_doc Cool"""
|
|
109
|
+
elem_tp = get_element_type_by_str(elem_str)
|
|
110
|
+
print(elem_tp.__doc__)
|
|
111
|
+
|
|
112
|
+
def joint_view(self, frame_pos: str = "top"):
|
|
113
|
+
"""Start a new frame positioned at the specified frame_pos in the final joint view.
|
|
114
|
+
The center frame should be a single Cool, HicMat, DotHic track.
|
|
115
|
+
|
|
116
|
+
For example:
|
|
117
|
+
coolbox - \
|
|
118
|
+
joint_view top - \
|
|
119
|
+
add BigWig BW_PATH - \
|
|
120
|
+
joint_view right - \
|
|
121
|
+
add GTF BTF_PATH - \
|
|
122
|
+
joint_view center - \
|
|
123
|
+
add Cool - \
|
|
124
|
+
goto 'chr1:100000-200000' 'chr2:200000-30000' - \
|
|
125
|
+
plot /tmp/test_joint_view.svg
|
|
126
|
+
|
|
127
|
+
Parameters
|
|
128
|
+
----------
|
|
129
|
+
frame_pos: str
|
|
130
|
+
Add a frame in the given position in the joint view.
|
|
131
|
+
Should be one of 'top', 'left', 'center', 'bottom', 'right'.
|
|
132
|
+
|
|
133
|
+
Returns
|
|
134
|
+
-------
|
|
135
|
+
|
|
136
|
+
"""
|
|
137
|
+
if frame_pos not in FRAME_POS:
|
|
138
|
+
raise ValueError(f"Frame position should be one of {FRAME_POS}")
|
|
139
|
+
if frame_pos not in self.frames:
|
|
140
|
+
self.frames[frame_pos] = "frame = Frame()\n"
|
|
141
|
+
self.frame_pos = frame_pos
|
|
142
|
+
|
|
143
|
+
return self
|
|
144
|
+
|
|
145
|
+
def add(self, elem_str, *args, **kwargs):
|
|
146
|
+
"""Add a Element(Track, Coverage, Feature), for example: coolbox add XAxis
|
|
147
|
+
|
|
148
|
+
:param elem_str: Element type string. Like BAM, BigWig, Cool ...
|
|
149
|
+
Full list of Track types
|
|
150
|
+
can be found here(https://gangcaolab.github.io/CoolBox/quick_start_API.html#Track-types).
|
|
151
|
+
:param args: Positional args for create elements.
|
|
152
|
+
:param kwargs: Keyword args for create elements.
|
|
153
|
+
"""
|
|
154
|
+
if ("help" in args) or ("help" in kwargs):
|
|
155
|
+
self.show_doc(elem_str)
|
|
156
|
+
return
|
|
157
|
+
if self.frame_pos is None:
|
|
158
|
+
self.joint_view("top")
|
|
159
|
+
|
|
160
|
+
compose_code = get_compose_code(elem_str, args, kwargs)
|
|
161
|
+
log.info(f"Create element, compose code: {compose_code}")
|
|
162
|
+
self.frames[self.frame_pos] += " " * self._indent + "frame += " + compose_code + "\n"
|
|
163
|
+
return self
|
|
164
|
+
|
|
165
|
+
def start_with(self, elem_str, *args, **kwargs):
|
|
166
|
+
"""Start a 'with' block, apply the element to all elements within the block.
|
|
167
|
+
|
|
168
|
+
:param elem_str: Element type string. Like VLines, Color, MinValue ...
|
|
169
|
+
:param args: Positional args for create elements.
|
|
170
|
+
:param kwargs: Keyword args for create elements.
|
|
171
|
+
"""
|
|
172
|
+
if ("help" in args) or ("help" in kwargs):
|
|
173
|
+
self.show_doc(elem_str)
|
|
174
|
+
return
|
|
175
|
+
if self.frame_pos is None:
|
|
176
|
+
self.joint_view("top")
|
|
177
|
+
|
|
178
|
+
compose_code = get_compose_code(elem_str, args, kwargs)
|
|
179
|
+
log.info(f"Create a with block, compose code: {compose_code}")
|
|
180
|
+
self.frames[self.frame_pos] += " " * self._indent + f"with {compose_code}:\n"
|
|
181
|
+
self._indent += 1
|
|
182
|
+
return self
|
|
183
|
+
|
|
184
|
+
def end_with(self):
|
|
185
|
+
"""End the with block"""
|
|
186
|
+
if self._indent <= 0:
|
|
187
|
+
raise ValueError("Expect a 'start_with' command before end_with clause.")
|
|
188
|
+
self._indent -= 1
|
|
189
|
+
return self
|
|
190
|
+
|
|
191
|
+
@staticmethod
|
|
192
|
+
def _fetch_frame_src(pos: str, source: str) -> Tuple[str, str]:
|
|
193
|
+
"""
|
|
194
|
+
|
|
195
|
+
Parameters
|
|
196
|
+
----------
|
|
197
|
+
pos
|
|
198
|
+
source
|
|
199
|
+
|
|
200
|
+
Returns
|
|
201
|
+
-------
|
|
202
|
+
Tuple[str, str].
|
|
203
|
+
The first string is the frame's variable name, and the second string is the function's source code
|
|
204
|
+
"""
|
|
205
|
+
# center frame return the first track. expected a Cool, DotHiC, HicMat
|
|
206
|
+
if pos != 'center':
|
|
207
|
+
source += "return frame\n"
|
|
208
|
+
else:
|
|
209
|
+
source += "return list(frame.tracks.values())[0]\n"
|
|
210
|
+
source = "\n".join(" " + line for line in source.split("\n")) + "\n"
|
|
211
|
+
# generate function and call
|
|
212
|
+
frame_var = f"{pos}_frame"
|
|
213
|
+
source = f"def fetch_{frame_var}():\n" + source
|
|
214
|
+
source += f"{frame_var} = fetch_{frame_var}()\n"
|
|
215
|
+
|
|
216
|
+
return frame_var, source
|
|
217
|
+
|
|
218
|
+
def source(self) -> str:
|
|
219
|
+
num_frames = len(self.frames)
|
|
220
|
+
if num_frames == 0:
|
|
221
|
+
raise RuntimeError("No frame has been added yet.")
|
|
222
|
+
|
|
223
|
+
if num_frames > 1 and 'center' not in self.frames:
|
|
224
|
+
raise RuntimeError("JointView mode needs a center frame. "
|
|
225
|
+
"Use `joint_view center ADD xxx` to add center track/frame.")
|
|
226
|
+
gr1, gr2 = self.current_range
|
|
227
|
+
if gr1 is None:
|
|
228
|
+
raise RuntimeError("No genome range found."
|
|
229
|
+
"Use `goto chr1:5000000-6000000` to set the genome range.")
|
|
230
|
+
|
|
231
|
+
frame_dict = {}
|
|
232
|
+
source = ""
|
|
233
|
+
for pos, src in self.frames.items():
|
|
234
|
+
frame_var, frame_src = self._fetch_frame_src(pos, src)
|
|
235
|
+
source += frame_src
|
|
236
|
+
frame_dict[pos] = frame_var
|
|
237
|
+
|
|
238
|
+
if 'center' in self.frames:
|
|
239
|
+
source += f"frame = JointView({frame_dict['center']}, " \
|
|
240
|
+
f"left={frame_dict.get('left')}, " \
|
|
241
|
+
f"right={frame_dict.get('right')}, " \
|
|
242
|
+
f"bottom={frame_dict.get('bottom')}, " \
|
|
243
|
+
f"top={frame_dict.get('top')}" \
|
|
244
|
+
f")\n"
|
|
245
|
+
else:
|
|
246
|
+
source += f"frame = {list(frame_dict.values())[0]}\n"
|
|
247
|
+
|
|
248
|
+
return source
|
|
249
|
+
|
|
250
|
+
def print_source(self):
|
|
251
|
+
"""Print the browser composing code."""
|
|
252
|
+
print(self.source())
|
|
253
|
+
|
|
254
|
+
def gen_notebook(self, notebook_path, notes=True, figsave=True):
|
|
255
|
+
"""Generate The notebook contain codes for run coolbox browser.
|
|
256
|
+
|
|
257
|
+
:param notebook_path: The output notebook path.
|
|
258
|
+
:param notes: Generate markdown notes in notebook or not.
|
|
259
|
+
:param figsave: Generate codes for saving figure or not.
|
|
260
|
+
"""
|
|
261
|
+
code = nbf.v4.new_code_cell
|
|
262
|
+
markdown = nbf.v4.new_markdown_cell
|
|
263
|
+
nb = nbf.v4.new_notebook()
|
|
264
|
+
cells = []
|
|
265
|
+
if notes:
|
|
266
|
+
cells.append(
|
|
267
|
+
markdown("**Run the cell bellow to start the CoolBox browser.**")
|
|
268
|
+
)
|
|
269
|
+
cells.append(
|
|
270
|
+
code(
|
|
271
|
+
f"import os; os.chdir('{os.getcwd()}')\n"
|
|
272
|
+
"import coolbox.api\n" +
|
|
273
|
+
"from coolbox.api import *\n" +
|
|
274
|
+
self.source() +
|
|
275
|
+
f"bsr = Browser(frame, reference_genome='{self.genome}')\n" +
|
|
276
|
+
(f"bsr.goto('{str(self.current_range[0])}')\n" if self.current_range[0] else "") +
|
|
277
|
+
"bsr.show()"
|
|
278
|
+
),
|
|
279
|
+
)
|
|
280
|
+
if figsave:
|
|
281
|
+
if notes:
|
|
282
|
+
cells.append(
|
|
283
|
+
markdown("**Run the cell bellow to save your figure.**"),
|
|
284
|
+
)
|
|
285
|
+
cells.append(
|
|
286
|
+
code("bsr.save('test.pdf')"),
|
|
287
|
+
)
|
|
288
|
+
nb['cells'] = cells
|
|
289
|
+
nbf.write(nb, notebook_path)
|
|
290
|
+
|
|
291
|
+
def run_jupyter(self, jupyter_args="--ip=0.0.0.0"):
|
|
292
|
+
"""Create a notebook according to command line, then start a jupyter process.
|
|
293
|
+
|
|
294
|
+
:param jupyter_args: Arguments for run jupyter.
|
|
295
|
+
"""
|
|
296
|
+
i = 0
|
|
297
|
+
tmp_notebook = lambda: f"/tmp/coolbox_tmp.{i}.ipynb"
|
|
298
|
+
while osp.exists(tmp_notebook()):
|
|
299
|
+
i += 1
|
|
300
|
+
tmp = tmp_notebook()
|
|
301
|
+
self.gen_notebook(tmp)
|
|
302
|
+
subp.check_call(f"jupyter notebook {tmp} " + jupyter_args, shell=True)
|
|
303
|
+
|
|
304
|
+
def plot(self, fig_path, genome_range=None, genome_range2=None):
|
|
305
|
+
"""Draw a figure within a genome range and save to file
|
|
306
|
+
|
|
307
|
+
:param fig_path: Figure save path
|
|
308
|
+
:param genome_range: Genome range string, like "chr9:4000000-6000000".
|
|
309
|
+
:param genome_range2: Genome range string, like "chr9:4000000-6000000".
|
|
310
|
+
"""
|
|
311
|
+
if genome_range is None:
|
|
312
|
+
if self.current_range[0] is None:
|
|
313
|
+
raise ValueError("Should specify the gr")
|
|
314
|
+
else:
|
|
315
|
+
self.goto(genome_range, genome_range2)
|
|
316
|
+
source = "from coolbox.api import *\n" + self.source() + "\n"
|
|
317
|
+
gr1, gr2 = self.current_range
|
|
318
|
+
if 'center' in self.frames:
|
|
319
|
+
source += f"fig = frame.plot('{gr1}', '{gr2}')\n"
|
|
320
|
+
# TODO: svgutils.compose.Figure can only save to svg, convert it?
|
|
321
|
+
if not fig_path.endswith('.svg'):
|
|
322
|
+
fig_path = fig_path[:-4] + '.svg'
|
|
323
|
+
log.warning(f"The JointView only support save to svg now. Save fig to: {fig_path}.")
|
|
324
|
+
source += f"fig.save('{fig_path}')\n"
|
|
325
|
+
else:
|
|
326
|
+
source += f"fig = frame.plot('{gr1}')\n"
|
|
327
|
+
source += f"fig.savefig('{fig_path}')\n"
|
|
328
|
+
try:
|
|
329
|
+
code = compile(source, "coolbox_cli_source", "exec")
|
|
330
|
+
eval(code)
|
|
331
|
+
except Exception as e:
|
|
332
|
+
log.error(
|
|
333
|
+
"Error when execute the generated source code:\n\n" +
|
|
334
|
+
"------------------------\n" +
|
|
335
|
+
source + "\n" +
|
|
336
|
+
"------------------------\n\n"
|
|
337
|
+
)
|
|
338
|
+
if type(e) == NameError:
|
|
339
|
+
log.error(
|
|
340
|
+
f"All elements type see: " +
|
|
341
|
+
"https://gangcaolab.github.io/CoolBox/api.html"
|
|
342
|
+
)
|
|
343
|
+
raise e
|
|
344
|
+
|
|
345
|
+
def run_webapp(self, voila_args="--Voila.ip=0.0.0.0"):
|
|
346
|
+
"""Run a independent coolbox browser web app.
|
|
347
|
+
(Create notebook and run voila)
|
|
348
|
+
|
|
349
|
+
:param voila_args: Arguments for run jupyter.
|
|
350
|
+
"""
|
|
351
|
+
i = 0
|
|
352
|
+
tmp_notebook = lambda: f"/tmp/coolbox_tmp.{i}.ipynb"
|
|
353
|
+
while osp.exists(tmp_notebook()):
|
|
354
|
+
i += 1
|
|
355
|
+
tmp = tmp_notebook()
|
|
356
|
+
self.gen_notebook(tmp, notes=False, figsave=False)
|
|
357
|
+
subp.check_call(f"voila {tmp} " + voila_args, shell=True)
|
|
358
|
+
|
|
359
|
+
def load_module(self, mod_str):
|
|
360
|
+
"""
|
|
361
|
+
Import custom tracks from a module/package for example:
|
|
362
|
+
|
|
363
|
+
$ coolbox - load_module ./my_custom.py - add XAxis - add CustomTrack - goto "chr1:5000000-6000000" - run_webapp
|
|
364
|
+
|
|
365
|
+
:param mod_str: Path to the module.
|
|
366
|
+
"""
|
|
367
|
+
globals().update(runpy.run_path(mod_str, init_globals=globals()))
|
|
368
|
+
return self
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
if __name__ == "__main__":
|
|
372
|
+
fire.Fire(CLI)
|
|
373
|
+
|
|
File without changes
|