trackplot 0.5.5__tar.gz → 0.5.6__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.
- {trackplot-0.5.5/trackplot.egg-info → trackplot-0.5.6}/PKG-INFO +2 -2
- {trackplot-0.5.5 → trackplot-0.5.6}/pyproject.toml +2 -2
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/base/ReadDepth.py +70 -63
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/cli.py +4 -2
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/file/Bam.py +5 -2
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/file/Junction.py +0 -1
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/plot.py +5 -2
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/plot_func.py +34 -56
- {trackplot-0.5.5 → trackplot-0.5.6/trackplot.egg-info}/PKG-INFO +2 -2
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot.egg-info/SOURCES.txt +0 -27
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot.egg-info/requires.txt +1 -1
- trackplot-0.5.6/trackplot.egg-info/top_level.txt +2 -0
- trackplot-0.5.5/trackplot.egg-info/top_level.txt +0 -3
- trackplot-0.5.5/trackplot_issue/OA-452-DC.bam +0 -0
- trackplot-0.5.5/trackplot_issue/OA-452-DC.bam.bai +0 -0
- trackplot-0.5.5/trackplot_issue/OA-476-DC.bam +0 -0
- trackplot-0.5.5/trackplot_issue/OA-476-DC.bam.bai +0 -0
- trackplot-0.5.5/trackplot_issue/OA-479-DC.bam +0 -0
- trackplot-0.5.5/trackplot_issue/OA-479-DC.bam.bai +0 -0
- trackplot-0.5.5/trackplot_issue/OA-488-DC.bam +0 -0
- trackplot-0.5.5/trackplot_issue/OA-488-DC.bam.bai +0 -0
- trackplot-0.5.5/trackplot_issue/OA-500-DC.bam +0 -0
- trackplot-0.5.5/trackplot_issue/OA-500-DC.bam.bai +0 -0
- trackplot-0.5.5/trackplot_issue/OA-503-DC.bam +0 -0
- trackplot-0.5.5/trackplot_issue/OA-503-DC.bam.bai +0 -0
- trackplot-0.5.5/trackplot_issue/OA-506-DC.bam +0 -0
- trackplot-0.5.5/trackplot_issue/OA-506-DC.bam.bai +0 -0
- trackplot-0.5.5/trackplot_issue/OA-514-DC.bam +0 -0
- trackplot-0.5.5/trackplot_issue/OA-514-DC.bam.bai +0 -0
- trackplot-0.5.5/trackplot_issue/OA-515-DC.bam +0 -0
- trackplot-0.5.5/trackplot_issue/OA-515-DC.bam.bai +0 -0
- trackplot-0.5.5/trackplot_issue/OA-99-DC.bam +0 -0
- trackplot-0.5.5/trackplot_issue/OA-99-DC.bam.bai +0 -0
- trackplot-0.5.5/trackplot_issue/run_trackplot.sh +0 -42
- trackplot-0.5.5/trackplot_issue/samples.bam.tsv +0 -10
- trackplot-0.5.5/trackplot_issue/test.v051.pdf +0 -0
- trackplot-0.5.5/trackplot_issue/test.v053.included_junctions.log +0 -355
- trackplot-0.5.5/trackplot_issue/test.v053.included_junctions.pdf +0 -0
- trackplot-0.5.5/trackplot_issue/test.v053.included_junctions.png +0 -0
- trackplot-0.5.5/trackplot_issue/test.v053.pdf +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/LICENSE +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/README.md +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/setup.cfg +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/__init__.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/anno/AxLabel.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/anno/__init__.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/anno/theme.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/base/CoordinateMap.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/base/GenomicLoci.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/base/Junction.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/base/Protein.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/base/Readder.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/base/Stroke.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/base/Transcript.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/base/__init__.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/base/pyUniprot.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/conf/DomainSetting.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/conf/__init__.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/conf/config.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/conf/drawing.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/conf/ui.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/file/ATAC.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/file/Annotation.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/file/BedGraph.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/file/Bigwig.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/file/Depth.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/file/Fasta.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/file/File.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/file/HiCMatrixTrack.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/file/Motif.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/file/ReadSegments.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/file/__init__.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/plot_tests.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot/server.py +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/trackplot.egg-info/dependency_links.txt +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/Home-7GzAh8lS.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/Home-BV58jH3t.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/Home-CDW3Zwoa.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/Home-DOO13BH7.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/Home-QmeAKOl4.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/Home-RdVPWns6.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/Home-jSR0MsHI.css +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/Home-zRV7yePL.css +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/Plot-BALbchCV.css +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/Plot-BmqHZ4QE.css +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/Plot-BrjU8Kwg.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/Plot-Bvyo6ju9.css +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/Plot-COvGnprQ.css +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/Plot-CTM-EDrj.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/Plot-Cnt8iJB8.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/Plot-Cyj_LlDt.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/Plot-DiuFnwNK.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/Plot-DpL7z7tp.css +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/Plot-hvkDteAn.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/Plot-rbQz1TOM.css +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/el-divider-BHm65SRq.css +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/el-divider-BVZhQIwQ.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/el-divider-Brt4-Qvr.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/el-divider-BuEUMHwE.css +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/el-divider-Cwxg0Ado.css +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/el-divider-DcvrsrBa.css +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/el-divider-IbBQ8ZK2.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/el-divider-SYT5K-ds.css +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/el-divider-VYjL3C7L.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/el-divider-eEJXnQD5.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/el-divider-i9JMIXVR.css +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/el-divider-u9f0bZWY.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/index-4hxJ_zbq.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/index-C4Mi9Kmf.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/index-CETGMNio.css +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/index-CWfdj0DH.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/index-Cexhr_fn.css +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/index-CrzyEb9s.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/index-D_Cw0sbX.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/index-Dd6Bavnk.js +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/index-DgEIiwRJ.css +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/index-O8P0XkxB.css +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/index-Sq2gI4sE.css +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/assets/index-ns9n7-F7.css +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/index.html +0 -0
- {trackplot-0.5.5 → trackplot-0.5.6}/ui/vite.svg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: trackplot
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.6
|
|
4
4
|
Summary: The trackplot is a tool for visualizing various next-generation sequencing (NGS) data, including DNA-seq, RNA-seq, single-cell RNA-seq and full-length sequencing datasets. https://sashimi.readthedocs.io/
|
|
5
5
|
Author-email: ygidtu <ygidtu@gmail.com>
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -23,7 +23,7 @@ Requires-Dist: pysam>=0.23.3
|
|
|
23
23
|
Requires-Dist: requests>=2.32.4
|
|
24
24
|
Requires-Dist: scipy>=1.15.3
|
|
25
25
|
Requires-Dist: seaborn>=0.13.2
|
|
26
|
-
Requires-Dist: xmltodict>=0.
|
|
26
|
+
Requires-Dist: xmltodict>=0.15.0
|
|
27
27
|
Dynamic: license-file
|
|
28
28
|
|
|
29
29
|
# trackplot
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "trackplot"
|
|
3
|
-
version = "0.5.
|
|
3
|
+
version = "0.5.6"
|
|
4
4
|
description = "The trackplot is a tool for visualizing various next-generation sequencing (NGS) data, including DNA-seq, RNA-seq, single-cell RNA-seq and full-length sequencing datasets. https://sashimi.readthedocs.io/"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "ygidtu", email = "ygidtu@gmail.com" }
|
|
@@ -25,7 +25,7 @@ dependencies = [
|
|
|
25
25
|
"requests>=2.32.4",
|
|
26
26
|
"scipy>=1.15.3",
|
|
27
27
|
"seaborn>=0.13.2",
|
|
28
|
-
"xmltodict>=0.
|
|
28
|
+
"xmltodict>=0.15.0",
|
|
29
29
|
]
|
|
30
30
|
|
|
31
31
|
|
|
@@ -21,13 +21,13 @@ class ReadDepth(object):
|
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
23
|
__slots__ = [
|
|
24
|
-
"
|
|
25
|
-
"
|
|
24
|
+
"__junction_dict__plus___", "__junction_dict__minus__",
|
|
25
|
+
"__minus__", "__plus__", "__number_of_merged__",
|
|
26
26
|
"strand_aware", "site_plus", "site_minus",
|
|
27
27
|
]
|
|
28
28
|
|
|
29
29
|
def __init__(self,
|
|
30
|
-
wiggle: np.
|
|
30
|
+
wiggle: np.ndarray,
|
|
31
31
|
site_plus: Optional[np.array] = None,
|
|
32
32
|
site_minus: Optional[np.array] = None,
|
|
33
33
|
minus: Optional[np.array] = None,
|
|
@@ -45,58 +45,65 @@ class ReadDepth(object):
|
|
|
45
45
|
:param junction_dict_plus: these splice junction from plus strand
|
|
46
46
|
:param junction_dict_minus: these splice junction from minus strand
|
|
47
47
|
"""
|
|
48
|
-
self.
|
|
48
|
+
self.__plus__ = wiggle
|
|
49
49
|
self.strand_aware = strand_aware
|
|
50
|
-
self.
|
|
51
|
-
self.
|
|
52
|
-
self.
|
|
50
|
+
self.__minus__ = abs(minus) if minus is not None else minus
|
|
51
|
+
self.__junction_dict__plus___ = junction_dict_plus
|
|
52
|
+
self.__junction_dict__minus__ = junction_dict_minus
|
|
53
53
|
self.site_plus = site_plus
|
|
54
54
|
self.site_minus = site_minus * -1 if site_minus is not None else site_minus
|
|
55
55
|
|
|
56
|
-
self.
|
|
56
|
+
self.__number_of_merged__ = 1
|
|
57
57
|
|
|
58
58
|
@property
|
|
59
59
|
def plus(self) -> Optional[np.array]:
|
|
60
|
-
if self.
|
|
61
|
-
return self.
|
|
62
|
-
return self.
|
|
60
|
+
if self.__plus__ is not None and self.__number_of_merged__ > 0:
|
|
61
|
+
return self.__plus__ / self.__number_of_merged__
|
|
62
|
+
return self.__plus__
|
|
63
63
|
|
|
64
64
|
@property
|
|
65
65
|
def minus(self) -> Optional[np.array]:
|
|
66
|
-
if self.
|
|
67
|
-
return self.
|
|
68
|
-
return self.
|
|
66
|
+
if self.__minus__ is not None and self.__number_of_merged__ > 0:
|
|
67
|
+
return self.__minus__ / self.__number_of_merged__
|
|
68
|
+
return self.__minus__
|
|
69
69
|
|
|
70
70
|
@property
|
|
71
|
-
def wiggle(self) -> np.
|
|
72
|
-
if (self.
|
|
71
|
+
def wiggle(self) -> np.ndarray:
|
|
72
|
+
if (self.__plus__ is None or not self.__plus__.any()) and self.__minus__ is not None:
|
|
73
73
|
return self.minus
|
|
74
74
|
|
|
75
|
-
if self.
|
|
75
|
+
if self.__plus__ is not None and self.__minus__ is not None:
|
|
76
76
|
return self.plus + self.minus
|
|
77
77
|
|
|
78
78
|
return self.plus
|
|
79
79
|
|
|
80
80
|
@property
|
|
81
|
-
def
|
|
82
|
-
if self.
|
|
83
|
-
return {k: v / self.
|
|
84
|
-
return self.
|
|
81
|
+
def mean_junctions_plus(self) -> dict:
|
|
82
|
+
if self.__number_of_merged__ > 1:
|
|
83
|
+
return {k: v / self.__number_of_merged__ for k, v in self.__junction_dict__plus___.items()}
|
|
84
|
+
return self.__junction_dict__plus___
|
|
85
85
|
|
|
86
86
|
@property
|
|
87
|
-
def
|
|
88
|
-
if self.
|
|
89
|
-
return {k: v / self.
|
|
90
|
-
return self.
|
|
87
|
+
def mean_junctions_minus(self) -> dict:
|
|
88
|
+
if self.__number_of_merged__ > 1:
|
|
89
|
+
return {k: v / self.__number_of_merged__ for k, v in self.__junction_dict__minus__.items()}
|
|
90
|
+
return self.__junction_dict__minus__
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
def junctions_dict(self) -> dict:
|
|
92
|
+
def junctions_dict(self, show_mean_jxn_number: bool = False) -> dict:
|
|
94
93
|
res = {}
|
|
95
|
-
if self._junction_dict_plus_:
|
|
96
|
-
res.update(self.junctions_plus)
|
|
97
94
|
|
|
98
|
-
if
|
|
99
|
-
|
|
95
|
+
if show_mean_jxn_number:
|
|
96
|
+
if self.__junction_dict__plus___:
|
|
97
|
+
res.update(self.mean_junctions_plus)
|
|
98
|
+
|
|
99
|
+
if self.__junction_dict__minus__:
|
|
100
|
+
res.update(self.mean_junctions_minus)
|
|
101
|
+
else:
|
|
102
|
+
if self.__junction_dict__plus___:
|
|
103
|
+
res.update(self.__junction_dict__plus___)
|
|
104
|
+
|
|
105
|
+
if self.__junction_dict__minus__:
|
|
106
|
+
res.update(self.__junction_dict__minus__)
|
|
100
107
|
return res
|
|
101
108
|
|
|
102
109
|
@property
|
|
@@ -117,27 +124,27 @@ class ReadDepth(object):
|
|
|
117
124
|
if len(self.wiggle) == len(other.wiggle):
|
|
118
125
|
junc_plus, junc_minus = {}, {}
|
|
119
126
|
|
|
120
|
-
for i in [self.
|
|
127
|
+
for i in [self.__junction_dict__plus___, other.__junction_dict__plus___]:
|
|
121
128
|
if i:
|
|
122
129
|
junc_plus.update(i)
|
|
123
|
-
for i in [self.
|
|
130
|
+
for i in [self.__junction_dict__minus__, other.__junction_dict__minus__]:
|
|
124
131
|
if i:
|
|
125
132
|
junc_minus.update(i)
|
|
126
133
|
|
|
127
134
|
minus = None
|
|
128
|
-
if self.
|
|
129
|
-
minus = self.
|
|
130
|
-
elif self.
|
|
135
|
+
if self.__minus__ is not None and other.__minus__ is not None:
|
|
136
|
+
minus = self.__minus__ + other.__minus__
|
|
137
|
+
elif self.__minus__ is None and other.__minus__ is not None:
|
|
131
138
|
minus = other.minus
|
|
132
|
-
elif self.
|
|
133
|
-
minus = self.
|
|
139
|
+
elif self.__minus__ is not None and other.__minus__ is None:
|
|
140
|
+
minus = self.__minus__
|
|
134
141
|
|
|
135
142
|
merged = ReadDepth(
|
|
136
|
-
self.
|
|
143
|
+
self.__plus__ + other.__plus__, minus=minus,
|
|
137
144
|
junction_dict_plus=junc_plus,
|
|
138
145
|
junction_dict_minus=junc_minus
|
|
139
146
|
)
|
|
140
|
-
merged.
|
|
147
|
+
merged.__number_of_merged__ = self.__number_of_merged__ + other.__number_of_merged__
|
|
141
148
|
return merged
|
|
142
149
|
else:
|
|
143
150
|
raise ValueError(f"ReadDepth objects are not equal length: {len(self.wiggle)} != {len(other.wiggle)}")
|
|
@@ -164,11 +171,11 @@ class ReadDepth(object):
|
|
|
164
171
|
:return:
|
|
165
172
|
"""
|
|
166
173
|
|
|
167
|
-
for k, v in other.
|
|
168
|
-
self.
|
|
174
|
+
for k, v in other.__junction_dict__plus___:
|
|
175
|
+
self.__junction_dict__plus___[k] = v + self.__junction_dict__plus___.get(k, 0)
|
|
169
176
|
|
|
170
|
-
for k, v in other.
|
|
171
|
-
self.
|
|
177
|
+
for k, v in other.__junction_dict__minus__:
|
|
178
|
+
self.__junction_dict__minus__[k] = v + self.__junction_dict__minus__.get(k, 0)
|
|
172
179
|
|
|
173
180
|
return self.junctions_dict
|
|
174
181
|
|
|
@@ -176,11 +183,11 @@ class ReadDepth(object):
|
|
|
176
183
|
funcs = {"10": np.log10, "2": np.log2, "zscore": zscore, "e": np.log}
|
|
177
184
|
|
|
178
185
|
if log_trans in funcs.keys():
|
|
179
|
-
if self.
|
|
180
|
-
self.
|
|
186
|
+
if self.__plus__ is not None:
|
|
187
|
+
self.__plus__ = funcs[log_trans](self.__plus__ + 1)
|
|
181
188
|
|
|
182
189
|
if self.minus is not None:
|
|
183
|
-
self.
|
|
190
|
+
self.__minus__ = funcs[log_trans](self.__minus__ + 1)
|
|
184
191
|
|
|
185
192
|
def normalize(self, size_factor: float, format_: str = "normal", read_length: float = 0):
|
|
186
193
|
u"""
|
|
@@ -192,35 +199,35 @@ class ReadDepth(object):
|
|
|
192
199
|
|
|
193
200
|
if format_ == "rpkm" and read_length > 0:
|
|
194
201
|
# for rpkm the size_factor is total reads
|
|
195
|
-
self.
|
|
196
|
-
self.
|
|
202
|
+
self.__plus__ = np.divide(
|
|
203
|
+
self.__plus__,
|
|
197
204
|
np.multiply(
|
|
198
|
-
(np.sum(self.
|
|
205
|
+
(np.sum(self.__plus__ != 0) - read_length + 1) / 1e3,
|
|
199
206
|
size_factor / 1e6
|
|
200
207
|
)
|
|
201
208
|
)
|
|
202
|
-
if self.
|
|
203
|
-
self.
|
|
204
|
-
self.
|
|
209
|
+
if self.__minus__ is not None:
|
|
210
|
+
self.__minus__ = np.divide(
|
|
211
|
+
self.__minus__,
|
|
205
212
|
np.multiply(
|
|
206
|
-
(np.sum(self.
|
|
213
|
+
(np.sum(self.__minus__ != 0) - read_length + 1) / 1e3,
|
|
207
214
|
size_factor / 1e6
|
|
208
215
|
)
|
|
209
216
|
)
|
|
210
217
|
elif format_ == "cpm" and read_length > 0:
|
|
211
218
|
# for cpm the size_factor is total reads
|
|
212
|
-
self.
|
|
213
|
-
if self.
|
|
214
|
-
self.
|
|
219
|
+
self.__plus__ = np.divide(self.__plus__, np.divide(size_factor, 1e6))
|
|
220
|
+
if self.__minus__ is not None:
|
|
221
|
+
self.__minus__ = np.divide(self.__minus__, np.divide(size_factor, 1e6))
|
|
215
222
|
elif format_ == "cpm" and read_length > 0:
|
|
216
223
|
# for cpm the size_factor is total reads
|
|
217
|
-
self.
|
|
218
|
-
if self.
|
|
219
|
-
self.
|
|
224
|
+
self.__plus__ = np.divide(self.__plus__, np.divide(size_factor, 1e6))
|
|
225
|
+
if self.__minus__ is not None:
|
|
226
|
+
self.__minus__ = np.divide(self.__minus__, np.divide(size_factor, 1e6))
|
|
220
227
|
elif size_factor is not None and size_factor > 0 and format_ == "atac":
|
|
221
|
-
self.
|
|
222
|
-
if self.
|
|
223
|
-
self.
|
|
228
|
+
self.__plus__ = np.divide(self.__plus__, size_factor) # * 100
|
|
229
|
+
if self.__minus__ is not None:
|
|
230
|
+
self.__minus__ = np.divide(self.__minus__, size_factor)
|
|
224
231
|
|
|
225
232
|
|
|
226
233
|
if __name__ == '__main__':
|
|
@@ -315,6 +315,8 @@ def process_file_list(infile: str, category: str = "density"):
|
|
|
315
315
|
help="The junction id for including, chr1:1-100", show_default=True)
|
|
316
316
|
@optgroup.option("--show-junction-num", type=click.BOOL, is_flag=True, show_default=True,
|
|
317
317
|
help="Whether to show the number of junctions")
|
|
318
|
+
@optgroup.option("--show-mean-junction-num", type=click.BOOL, is_flag=True, show_default=True,
|
|
319
|
+
help="Whether to show the mean junction count averaged across multiple samples.")
|
|
318
320
|
@optgroup.option("--fill-step", type=click.Choice(["pre", "post", "mid"]), default="post", show_default=True,
|
|
319
321
|
help="""
|
|
320
322
|
Define step if the filling should be a step function, i.e. constant in between x.
|
|
@@ -523,8 +525,6 @@ def main(**kwargs):
|
|
|
523
525
|
|
|
524
526
|
size_factors = {}
|
|
525
527
|
|
|
526
|
-
# add annotation
|
|
527
|
-
# print(kwargs.keys())
|
|
528
528
|
for key in kwargs.keys():
|
|
529
529
|
if key in IMAGE_TYPE and kwargs[key] and os.path.exists(kwargs[key]):
|
|
530
530
|
if key == "annotation":
|
|
@@ -573,6 +573,7 @@ def main(**kwargs):
|
|
|
573
573
|
color=sc_colors.get(group, f.color),
|
|
574
574
|
font_size=kwargs["font_size"],
|
|
575
575
|
show_junction_number=kwargs["show_junction_num"],
|
|
576
|
+
show_mean_jxn_number=kwargs["show_mean_junction_num"],
|
|
576
577
|
n_y_ticks=kwargs["n_y_ticks"],
|
|
577
578
|
show_y_label=not kwargs["hide_y_label"],
|
|
578
579
|
show_site_plot=kwargs["show_site"],
|
|
@@ -591,6 +592,7 @@ def main(**kwargs):
|
|
|
591
592
|
color=f.color,
|
|
592
593
|
font_size=kwargs["font_size"],
|
|
593
594
|
show_junction_number=kwargs["show_junction_num"],
|
|
595
|
+
show_mean_jxn_number=kwargs["show_mean_junction_num"],
|
|
594
596
|
n_y_ticks=kwargs["n_y_ticks"],
|
|
595
597
|
show_y_label=not kwargs["hide_y_label"],
|
|
596
598
|
show_site_plot=kwargs["show_site"],
|
|
@@ -32,7 +32,9 @@ def check_junction_exists(ref: List[Junction], dst: Junction, with_strand: bool
|
|
|
32
32
|
|
|
33
33
|
for i in ref:
|
|
34
34
|
if abs(i.start - dst.start) < 2 and abs(i.end - dst.end) < 2:
|
|
35
|
-
|
|
35
|
+
if not with_strand:
|
|
36
|
+
# in outer code, this function will called twice, with with_strand = True and False. therefore, only print log once is enough
|
|
37
|
+
logger.warning(f"1 bp mismatch between {i} (from bam file) and {dst} (user input), please check the coordinates")
|
|
36
38
|
|
|
37
39
|
if i.is_downstream(dst):
|
|
38
40
|
return False
|
|
@@ -269,7 +271,8 @@ class Bam(SingleCell):
|
|
|
269
271
|
logger.info(region)
|
|
270
272
|
logger.info(cigar_string)
|
|
271
273
|
logger.info(start, i)
|
|
272
|
-
|
|
274
|
+
logger.error(err)
|
|
275
|
+
exit(1)
|
|
273
276
|
|
|
274
277
|
# remove the deletion.
|
|
275
278
|
if cigar not in (1, 4, 5): # I, S, H
|
|
@@ -30,8 +30,8 @@ logging.getLogger('matplotlib.font_manager').setLevel(logging.ERROR)
|
|
|
30
30
|
faulthandler.enable()
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
__version__ = "0.5.
|
|
34
|
-
__author__ = "
|
|
33
|
+
__version__ = "0.5.6"
|
|
34
|
+
__author__ = "Yiming Zhang & Ran Zhou"
|
|
35
35
|
__email__ = "ygidtu@gmail.com"
|
|
36
36
|
|
|
37
37
|
|
|
@@ -572,6 +572,7 @@ class Plot(object):
|
|
|
572
572
|
color="blue",
|
|
573
573
|
font_size: int = 8,
|
|
574
574
|
show_junction_number: bool = True,
|
|
575
|
+
show_mean_jxn_number: bool = False,
|
|
575
576
|
junction_number_font_size: int = 5,
|
|
576
577
|
n_y_ticks: int = 4,
|
|
577
578
|
show_y_label: bool = True,
|
|
@@ -601,6 +602,7 @@ class Plot(object):
|
|
|
601
602
|
:param library: should be one of [frf: "fr-firststrand", frs:"fr-secondstrand", fru:"fr-unstrand"], default: fru
|
|
602
603
|
:param font_size: the font size for ticks, y-axis label and title
|
|
603
604
|
:param show_junction_number: whether to show the number of junctions
|
|
605
|
+
:param show_mean_jxn_number:
|
|
604
606
|
:param n_y_ticks: number of y ticks
|
|
605
607
|
:param junction_number_font_size:
|
|
606
608
|
:param color: color for this density plot
|
|
@@ -652,6 +654,7 @@ class Plot(object):
|
|
|
652
654
|
self.plots.append(info)
|
|
653
655
|
self.params[info] = {
|
|
654
656
|
"show_junction_number": show_junction_number,
|
|
657
|
+
"show_mean_jxn_number": show_mean_jxn_number,
|
|
655
658
|
"junction_number_font_size": junction_number_font_size,
|
|
656
659
|
"color": color,
|
|
657
660
|
"font_size": font_size,
|
|
@@ -5,10 +5,10 @@ This script contains the functions to draw different images
|
|
|
5
5
|
Modified by AD 2025/01/13
|
|
6
6
|
"""
|
|
7
7
|
import itertools # AD - for cumulative sum of graph_coords
|
|
8
|
-
|
|
8
|
+
import gzip
|
|
9
9
|
import math
|
|
10
10
|
from copy import deepcopy
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
from typing import Dict, List, Optional, Union, Tuple, Set
|
|
13
13
|
|
|
14
14
|
import matplotlib as mpl
|
|
@@ -27,7 +27,6 @@ from matplotlib.textpath import TextPath
|
|
|
27
27
|
from matplotlib.transforms import Affine2D
|
|
28
28
|
from scipy.cluster.hierarchy import dendrogram, linkage
|
|
29
29
|
from scipy.stats import gaussian_kde, zscore
|
|
30
|
-
from scipy.stats import beta # AD
|
|
31
30
|
|
|
32
31
|
from trackplot.anno.theme import Theme
|
|
33
32
|
from trackplot.base.GenomicLoci import GenomicLoci
|
|
@@ -126,7 +125,7 @@ def __merge_exons__(exons: List[List[int]]):
|
|
|
126
125
|
|
|
127
126
|
|
|
128
127
|
def init_graph_coords(region: GenomicLoci, exons: Optional[List[List[int]]] = None, exon_scale=1,
|
|
129
|
-
intron_scale=0.5) -> np.
|
|
128
|
+
intron_scale=0.5) -> np.ndarray:
|
|
130
129
|
u"""
|
|
131
130
|
init the default
|
|
132
131
|
:param region: the plot region
|
|
@@ -169,7 +168,7 @@ def init_graph_coords(region: GenomicLoci, exons: Optional[List[List[int]]] = No
|
|
|
169
168
|
exons = exons[:-1]
|
|
170
169
|
exons[0][0] = max(exons[0][0], region.start)
|
|
171
170
|
exons[-1][1] = min(exons[-1][1], region.end)
|
|
172
|
-
|
|
171
|
+
|
|
173
172
|
for i, e in enumerate(exons):
|
|
174
173
|
exons[i][0] -= region.start
|
|
175
174
|
exons[i][1] -= region.start
|
|
@@ -184,7 +183,7 @@ def init_graph_coords(region: GenomicLoci, exons: Optional[List[List[int]]] = No
|
|
|
184
183
|
step = intron_scale / interval
|
|
185
184
|
for i in range(exons[e-1][1], exons[e][0]):
|
|
186
185
|
steps[i] = step
|
|
187
|
-
|
|
186
|
+
|
|
188
187
|
if last_interval := len(region) - exons[-1][1] - 1:
|
|
189
188
|
step = intron_scale / last_interval
|
|
190
189
|
for i in range(exons[1][1] +1, len(region)):
|
|
@@ -204,7 +203,7 @@ def init_graph_coords(region: GenomicLoci, exons: Optional[List[List[int]]] = No
|
|
|
204
203
|
return graph_coords
|
|
205
204
|
|
|
206
205
|
def set_x_ticks(
|
|
207
|
-
ax
|
|
206
|
+
ax,
|
|
208
207
|
region: GenomicLoci,
|
|
209
208
|
graph_coords: Optional[Union[Dict, np.ndarray]] = None,
|
|
210
209
|
sequence: Optional[Dict[int, str]] = None,
|
|
@@ -263,7 +262,7 @@ def set_x_ticks(
|
|
|
263
262
|
|
|
264
263
|
|
|
265
264
|
def set_y_ticks(
|
|
266
|
-
ax
|
|
265
|
+
ax,
|
|
267
266
|
label: str,
|
|
268
267
|
graph_coords: Union[Dict, np.array],
|
|
269
268
|
max_used_y_val: Union[int, float],
|
|
@@ -274,7 +273,6 @@ def set_y_ticks(
|
|
|
274
273
|
font_size: int = 5,
|
|
275
274
|
show_y_label: bool = True,
|
|
276
275
|
set_label_only: bool = False,
|
|
277
|
-
y_axis_skip_zero: bool = True,
|
|
278
276
|
**kwargs
|
|
279
277
|
):
|
|
280
278
|
u"""
|
|
@@ -355,7 +353,7 @@ def set_y_ticks(
|
|
|
355
353
|
|
|
356
354
|
|
|
357
355
|
def set_focus(
|
|
358
|
-
ax
|
|
356
|
+
ax,
|
|
359
357
|
graph_coords: Union[Dict, np.array],
|
|
360
358
|
focus: Dict[int, int]
|
|
361
359
|
):
|
|
@@ -372,7 +370,7 @@ def set_focus(
|
|
|
372
370
|
|
|
373
371
|
|
|
374
372
|
def set_indicator_lines(
|
|
375
|
-
ax
|
|
373
|
+
ax,
|
|
376
374
|
graph_coords: Union[Dict, np.array],
|
|
377
375
|
sites: Dict[int, str],
|
|
378
376
|
min_y_used: Union[int, float] = 0,
|
|
@@ -399,7 +397,7 @@ def set_indicator_lines(
|
|
|
399
397
|
|
|
400
398
|
|
|
401
399
|
def plot_stroke(
|
|
402
|
-
ax
|
|
400
|
+
ax,
|
|
403
401
|
data: List[Stroke],
|
|
404
402
|
graph_coords: Optional[Union[Dict, np.ndarray]] = None,
|
|
405
403
|
font_size: int = 5,
|
|
@@ -425,7 +423,7 @@ def plot_stroke(
|
|
|
425
423
|
|
|
426
424
|
|
|
427
425
|
def plot_annotation(
|
|
428
|
-
ax
|
|
426
|
+
ax,
|
|
429
427
|
obj: Annotation,
|
|
430
428
|
graph_coords: Optional[Union[Dict, np.ndarray]] = None,
|
|
431
429
|
font_size: int = 5,
|
|
@@ -650,7 +648,7 @@ def plot_annotation(
|
|
|
650
648
|
|
|
651
649
|
|
|
652
650
|
def plot_density(
|
|
653
|
-
ax
|
|
651
|
+
ax,
|
|
654
652
|
obj: Optional[File] = None,
|
|
655
653
|
data: Optional[ReadDepth] = None,
|
|
656
654
|
region: Optional[GenomicLoci] = None,
|
|
@@ -658,6 +656,7 @@ def plot_density(
|
|
|
658
656
|
color="blue",
|
|
659
657
|
font_size: int = 8,
|
|
660
658
|
show_junction_number: bool = True,
|
|
659
|
+
show_mean_jxn_number: bool = False,
|
|
661
660
|
junction_number_font_size: int = 12,
|
|
662
661
|
n_y_ticks: int = 4,
|
|
663
662
|
distance_between_label_axis: float = .1,
|
|
@@ -665,34 +664,11 @@ def plot_density(
|
|
|
665
664
|
y_label: str = "",
|
|
666
665
|
theme: str = "ticks_blank",
|
|
667
666
|
max_used_y_val: Optional[float] = None,
|
|
668
|
-
min_used_y_val: Optional[float] = None,
|
|
669
667
|
raster: bool = False,
|
|
670
668
|
fill_step: str = "post",
|
|
671
669
|
**kwargs
|
|
672
670
|
):
|
|
673
|
-
u"""
|
|
674
|
-
draw density plot
|
|
675
|
-
:param ax: mpl.axes.Axes
|
|
676
|
-
:param data: File
|
|
677
|
-
:param data: ReadDepth
|
|
678
|
-
:param region: GenomicLoci
|
|
679
|
-
:param graph_coords:
|
|
680
|
-
:param font_size: the font size for ticks, y-axis label and title
|
|
681
|
-
:param show_junction_number: whether to show the number of junctions
|
|
682
|
-
:param distance_between_label_axis: distance between y-axis label and y-axis ticks
|
|
683
|
-
:param n_y_ticks: number of y ticks
|
|
684
|
-
:param junction_number_font_size:
|
|
685
|
-
:param obj: Bam or Bigwig object
|
|
686
|
-
:param color: color for this density plot
|
|
687
|
-
:param show_y_label: whether to show y-axis label
|
|
688
|
-
:param y_label: the text of y-axis title
|
|
689
|
-
:param theme: the theme name
|
|
690
|
-
:param max_used_y_val: used to set same max y-axis
|
|
691
|
-
:param raster:
|
|
692
|
-
:param fill_step:
|
|
693
|
-
:param kwargs:
|
|
694
|
-
:return:
|
|
695
|
-
"""
|
|
671
|
+
u""" draw density plot """
|
|
696
672
|
# max_used_y_val is None
|
|
697
673
|
# distance_between_label_axis: 0
|
|
698
674
|
if obj:
|
|
@@ -711,21 +687,21 @@ def plot_density(
|
|
|
711
687
|
data = obj.data
|
|
712
688
|
|
|
713
689
|
try:
|
|
714
|
-
jxns = data.junctions_dict
|
|
690
|
+
jxns = data.junctions_dict(show_mean_jxn_number)
|
|
715
691
|
except AttributeError:
|
|
716
692
|
# depth do not have junctions
|
|
717
693
|
jxns = {}
|
|
718
|
-
|
|
694
|
+
|
|
719
695
|
# AD - convert junction counts to log scale early if requested
|
|
696
|
+
jxn_number_log_transformed = False
|
|
720
697
|
if obj.log_trans and obj.log_trans.isdigit() and int(obj.log_trans) > 0: # in ["2", "10"]:
|
|
721
|
-
|
|
698
|
+
jxn_number_log_transformed = True
|
|
722
699
|
y_label += f" (log{obj.log_trans})"
|
|
723
700
|
denominator = np.log(int(obj.log_trans))
|
|
724
701
|
for k, v in jxns.items():
|
|
725
702
|
jxns[k] = np.log1p(v) / denominator
|
|
726
703
|
|
|
727
704
|
min_used_y_val = 0 # AD
|
|
728
|
-
fixed_min_used_y = True # AD
|
|
729
705
|
fixed_max_used_y, fixed_min_used_y = max_used_y_val is not None, min_used_y_val is not None
|
|
730
706
|
if max_used_y_val is None:
|
|
731
707
|
if isinstance(data, dict):
|
|
@@ -792,15 +768,11 @@ def plot_density(
|
|
|
792
768
|
add two new variables to make it clear which one is index, which one is genomic site
|
|
793
769
|
"""
|
|
794
770
|
ss1, ss2 = graph_coords[ss1_idx], graph_coords[ss2_idx]
|
|
795
|
-
# AD = keep junction arcs on top
|
|
796
|
-
jxn_on_top = True
|
|
797
|
-
|
|
798
771
|
# draw junction on bottom
|
|
799
772
|
if kwargs.get("density_by_strand"):
|
|
800
773
|
jxn_on_top = jxn.strand == "+"
|
|
801
774
|
else:
|
|
802
775
|
jxn_on_top = jxn_idx % 2 == 0
|
|
803
|
-
#jxn_on_top = True # AD - keep all junctions on same strand
|
|
804
776
|
if abs(min_used_y_val) < max_used_y_val:
|
|
805
777
|
min_used_y_val = -max_used_y_val
|
|
806
778
|
|
|
@@ -846,9 +818,15 @@ def plot_density(
|
|
|
846
818
|
if show_junction_number:
|
|
847
819
|
midpt = cubic_bezier(pts, .5)
|
|
848
820
|
|
|
821
|
+
val = jxns[jxn]
|
|
822
|
+
if jxn_number_log_transformed or show_mean_jxn_number:
|
|
823
|
+
val = round(val, 2)
|
|
824
|
+
else:
|
|
825
|
+
val = int(val)
|
|
826
|
+
|
|
849
827
|
t = ax.text(
|
|
850
828
|
midpt[0], midpt[1],
|
|
851
|
-
'{0}'.format(
|
|
829
|
+
'{0}'.format(val),
|
|
852
830
|
fontsize=junction_number_font_size,
|
|
853
831
|
ha='center', va='center',
|
|
854
832
|
backgroundcolor='w'
|
|
@@ -893,7 +871,7 @@ def plot_density(
|
|
|
893
871
|
|
|
894
872
|
|
|
895
873
|
def plot_site_plot(
|
|
896
|
-
ax
|
|
874
|
+
ax,
|
|
897
875
|
obj: File,
|
|
898
876
|
graph_coords: Optional[Union[Dict, np.ndarray]] = None,
|
|
899
877
|
color="blue",
|
|
@@ -975,8 +953,8 @@ def plot_site_plot(
|
|
|
975
953
|
|
|
976
954
|
|
|
977
955
|
def plot_heatmap(
|
|
978
|
-
ax
|
|
979
|
-
cbar_ax
|
|
956
|
+
ax,
|
|
957
|
+
cbar_ax,
|
|
980
958
|
data: Dict[str, ReadDepth],
|
|
981
959
|
graph_coords: Optional[Union[Dict, np.ndarray]] = None,
|
|
982
960
|
color="viridis",
|
|
@@ -1067,8 +1045,8 @@ def plot_heatmap(
|
|
|
1067
1045
|
|
|
1068
1046
|
|
|
1069
1047
|
def plot_hic(
|
|
1070
|
-
ax
|
|
1071
|
-
cbar_ax
|
|
1048
|
+
ax,
|
|
1049
|
+
cbar_ax,
|
|
1072
1050
|
obj: List[HiCTrack],
|
|
1073
1051
|
show_legend: bool = True,
|
|
1074
1052
|
graph_coords: Optional[Union[Dict, np.ndarray]] = None,
|
|
@@ -1142,7 +1120,7 @@ def plot_hic(
|
|
|
1142
1120
|
|
|
1143
1121
|
|
|
1144
1122
|
def plot_line(
|
|
1145
|
-
ax
|
|
1123
|
+
ax,
|
|
1146
1124
|
data: Dict[str, ReadDepth],
|
|
1147
1125
|
graph_coords: Union[Dict, np.ndarray],
|
|
1148
1126
|
font_size: int = 8,
|
|
@@ -1222,7 +1200,7 @@ def plot_line(
|
|
|
1222
1200
|
|
|
1223
1201
|
|
|
1224
1202
|
def plot_igv_like(
|
|
1225
|
-
ax
|
|
1203
|
+
ax,
|
|
1226
1204
|
obj: Dict[str, ReadSegment],
|
|
1227
1205
|
graph_coords: Optional[Union[Dict, np.ndarray]] = None,
|
|
1228
1206
|
y_label: str = "",
|
|
@@ -1356,7 +1334,7 @@ def plot_igv_like(
|
|
|
1356
1334
|
)
|
|
1357
1335
|
|
|
1358
1336
|
|
|
1359
|
-
def plot_links(ax
|
|
1337
|
+
def plot_links(ax,
|
|
1360
1338
|
data: List[Stroke],
|
|
1361
1339
|
graph_coords: Optional[Union[Dict, np.ndarray]] = None,
|
|
1362
1340
|
max_y: int = -10, **kwargs):
|
|
@@ -1394,7 +1372,7 @@ def make_text_elements(text, x=0.0, y=0.0, width=1.0, height=1.0,
|
|
|
1394
1372
|
return PathPatch(tp, facecolor=color, edgecolor=edgecolor)
|
|
1395
1373
|
|
|
1396
1374
|
|
|
1397
|
-
def plot_motif(ax
|
|
1375
|
+
def plot_motif(ax,
|
|
1398
1376
|
obj, # list of weighted text
|
|
1399
1377
|
graph_coords: Optional[Union[Dict, np.ndarray]] = None,
|
|
1400
1378
|
width: float = 0.8,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: trackplot
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.6
|
|
4
4
|
Summary: The trackplot is a tool for visualizing various next-generation sequencing (NGS) data, including DNA-seq, RNA-seq, single-cell RNA-seq and full-length sequencing datasets. https://sashimi.readthedocs.io/
|
|
5
5
|
Author-email: ygidtu <ygidtu@gmail.com>
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -23,7 +23,7 @@ Requires-Dist: pysam>=0.23.3
|
|
|
23
23
|
Requires-Dist: requests>=2.32.4
|
|
24
24
|
Requires-Dist: scipy>=1.15.3
|
|
25
25
|
Requires-Dist: seaborn>=0.13.2
|
|
26
|
-
Requires-Dist: xmltodict>=0.
|
|
26
|
+
Requires-Dist: xmltodict>=0.15.0
|
|
27
27
|
Dynamic: license-file
|
|
28
28
|
|
|
29
29
|
# trackplot
|