tmquick 1.0.0__py3-none-any.whl
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.
- tmq/__init__.py +14 -0
- tmq/cli.py +250 -0
- tmq/commands/__init__.py +2 -0
- tmq/commands/average_trajmap_cli.py +36 -0
- tmq/commands/csv2shift_cli.py +27 -0
- tmq/commands/diff2graph_cli.py +35 -0
- tmq/commands/hotspot_cli.py +89 -0
- tmq/commands/pdb2csv_cli.py +29 -0
- tmq/commands/shift2graph_cli.py +29 -0
- tmq/commands/traj2pdb_cli.py +21 -0
- tmq/commands/trajmap_cli.py +29 -0
- tmq/core/__init__.py +2 -0
- tmq/core/average_trajmap.py +35 -0
- tmq/core/csv2shift.py +17 -0
- tmq/core/diff2graph.py +75 -0
- tmq/core/hotspot.py +164 -0
- tmq/core/pdb2csv.py +53 -0
- tmq/core/shift2graph.py +63 -0
- tmq/core/traj2pdb.py +12 -0
- tmq/core/trajmap.py +52 -0
- tmq/utils/__init__.py +2 -0
- tmq/utils/utils.py +233 -0
- tmquick-1.0.0.dist-info/METADATA +23 -0
- tmquick-1.0.0.dist-info/RECORD +28 -0
- tmquick-1.0.0.dist-info/WHEEL +5 -0
- tmquick-1.0.0.dist-info/entry_points.txt +2 -0
- tmquick-1.0.0.dist-info/licenses/LICENSE.md +21 -0
- tmquick-1.0.0.dist-info/top_level.txt +1 -0
tmq/__init__.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
__version__ = "1.0"
|
|
2
|
+
from .core.traj2pdb import traj2pdb
|
|
3
|
+
from .core.pdb2csv import pdb2csv
|
|
4
|
+
from .core.trajmap import trajmap
|
|
5
|
+
from .core.csv2shift import shift
|
|
6
|
+
from .core.shift2graph import shift2graph
|
|
7
|
+
from .core.hotspot import detect_shifts
|
|
8
|
+
from .core.hotspot import create_submatrices
|
|
9
|
+
from .core.hotspot import plot_shift_regions
|
|
10
|
+
from .core.hotspot import slice_shifts
|
|
11
|
+
from .core.hotspot import plot_slice_regions
|
|
12
|
+
from .core.hotspot import plot_hotspot_regions
|
|
13
|
+
from .core.diff2graph import diff_map
|
|
14
|
+
from .core.average_trajmap import avg_trajmap
|
tmq/cli.py
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"""Main CLI launcher
|
|
2
|
+
"""
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
import time
|
|
6
|
+
from .commands.traj2pdb_cli import traj2pdb_cli
|
|
7
|
+
from .commands.pdb2csv_cli import pdb2csv_cli
|
|
8
|
+
from .commands.trajmap_cli import trajmap_cli
|
|
9
|
+
from .commands.csv2shift_cli import shift_cli
|
|
10
|
+
from .commands.shift2graph_cli import shift2graph_cli
|
|
11
|
+
from .commands.hotspot_cli import detect_shift_cli
|
|
12
|
+
from .commands.hotspot_cli import create_submatrices_cli
|
|
13
|
+
from .commands.hotspot_cli import slice_shifts_cli
|
|
14
|
+
from .commands.hotspot_cli import run_hotspot_cli
|
|
15
|
+
from .commands.diff2graph_cli import diff_map_cli
|
|
16
|
+
from .commands.average_trajmap_cli import avg_trajmap_cli
|
|
17
|
+
from colorama import init, Fore, Style
|
|
18
|
+
init(convert=False)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
"""Time counter"""
|
|
22
|
+
def print_final_message(total):
|
|
23
|
+
print(
|
|
24
|
+
Fore.GREEN +
|
|
25
|
+
"\nTrajMapQuick analysis complete. \n" +
|
|
26
|
+
Fore.CYAN +
|
|
27
|
+
"\nAll tasks completed successfully.\n"+
|
|
28
|
+
Style.RESET_ALL
|
|
29
|
+
)
|
|
30
|
+
print(f"Total computation time: {total:.2f} seconds \n" +
|
|
31
|
+
Fore.MAGENTA +
|
|
32
|
+
"\nThank you for using TrajMapQuick 1.0 — ResLaR Labs, Afe Babalola University, Ado-Ekiti Nigeria.\n" +
|
|
33
|
+
Style.RESET_ALL)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
"""Display logo"""
|
|
37
|
+
def main():
|
|
38
|
+
start_time = time.perf_counter()
|
|
39
|
+
init()
|
|
40
|
+
print(Fore.GREEN + r"""
|
|
41
|
+
|
|
42
|
+
_______ _ __ __ ____
|
|
43
|
+
|__ __| (_) \/ | / __ \
|
|
44
|
+
| |_ __ __ _ _| \ / | __ _ _ __ | | | |
|
|
45
|
+
| | '__/ _` | | |\/| |/ _` | '_ \| | | |
|
|
46
|
+
| | | | (_| | | | | | (_| | |_) | |__| |
|
|
47
|
+
|_|_| \__,_| |_| |_|\__,_| .__/ \___\_\
|
|
48
|
+
_/ | | |
|
|
49
|
+
|__/ |_|
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
""" + Style.RESET_ALL)
|
|
53
|
+
print("========== Welcome to TrajMapQuick 1.0 ==========")
|
|
54
|
+
print("")
|
|
55
|
+
print("Authors : " + Fore.BLUE + "Wande M. Oluyemi, Adeniyi T. Adewumi, Shadrach C. Eze & Stephen C. Nnemolisa @ ResLaR Labs, Afe Babalola University, Ado-Ekiti Nigeria" + Style.RESET_ALL)
|
|
56
|
+
print("")
|
|
57
|
+
print("")
|
|
58
|
+
|
|
59
|
+
parser = argparse.ArgumentParser(
|
|
60
|
+
prog="tmq",
|
|
61
|
+
add_help=False,
|
|
62
|
+
formatter_class=argparse.RawTextHelpFormatter,
|
|
63
|
+
description="""
|
|
64
|
+
A command-line toolkit for MD trajectory map analysis:
|
|
65
|
+
• matrix extraction
|
|
66
|
+
• shift computation
|
|
67
|
+
• visualization
|
|
68
|
+
|
|
69
|
+
Built on the original work of Kožić & Bertoša, 2024,
|
|
70
|
+
Trajectory maps: molecular dynamics visualization and analysis,
|
|
71
|
+
https://doi.org/10.1093/nargab/lqad114
|
|
72
|
+
|
|
73
|
+
TrajMapQuick is faster, improves batch processing, and allows
|
|
74
|
+
automatic shift detection from trajectory maps.
|
|
75
|
+
"""
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
parser.add_argument(
|
|
79
|
+
"-h", "--help",
|
|
80
|
+
action="help",
|
|
81
|
+
help="Show usage information")
|
|
82
|
+
|
|
83
|
+
subparsers = parser.add_subparsers(
|
|
84
|
+
title="Available subcommands",
|
|
85
|
+
dest="command",
|
|
86
|
+
metavar=""
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
"""SHIFT SUBCOMMAND"""
|
|
90
|
+
shift_parser = subparsers.add_parser(
|
|
91
|
+
"shift",
|
|
92
|
+
help="Extract matrices, compute residue-residue shifts and make plots: For more, use tmq shift --help",
|
|
93
|
+
description=(
|
|
94
|
+
"Converts your trajectory into pdb multimodel form and then to a CSV file, "
|
|
95
|
+
"extracts a distance matrix from the CSV file and computes "
|
|
96
|
+
"a shift value between a residue range over a specified frame.\n\n"
|
|
97
|
+
"Example:\n"
|
|
98
|
+
" tmq shift --traj traj.pdb --top top.parmtop --str 1 --resr 1-300 --resrs 110-125 --cent backbone --plot --out shift_output\n\n"
|
|
99
|
+
"This will compute the shift of the backbone atoms, for residues 110-125, across the trajectory of a protein with residues 1-300, and will generate plots automatically."),
|
|
100
|
+
formatter_class=argparse.RawTextHelpFormatter
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
shift_parser.add_argument("-tr", "--traj", required=True,
|
|
104
|
+
help="Input trajectory, accepts pdb, nc, xtc xtr")
|
|
105
|
+
shift_parser.add_argument("-to", "--top", required=True,
|
|
106
|
+
help="Topology file, accepts parmtop, pdb, gro")
|
|
107
|
+
shift_parser.add_argument("-st", "--str", type=int, default=1,
|
|
108
|
+
help="Stride of the trajectory, (default: 1)")
|
|
109
|
+
shift_parser.add_argument("-rr", "--resr", type=str, required=True,
|
|
110
|
+
help="Residue range of your protein in the form start-end (e.g., 1-300")
|
|
111
|
+
shift_parser.add_argument("-rs", "--resrs", type=str, required=True,
|
|
112
|
+
help="Residue range for shift calculation, in the form start-end (e.g., 110-125")
|
|
113
|
+
shift_parser.add_argument("-ce", "--cent", type=str, default="backbone", required=True,
|
|
114
|
+
help="Centre of calculations, either the backbone " \
|
|
115
|
+
"atoms or the ca atoms, (default: backbone)")
|
|
116
|
+
shift_parser.add_argument("-ma", "--max", type=int, default=5, required=False,
|
|
117
|
+
help="Max shift value for color scaling, (default: 5)")
|
|
118
|
+
shift_parser.add_argument("-o", "--out", type=str, required=True,
|
|
119
|
+
help="Basename for all outputs")
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
"""HOTSPOT SUBCOMMAND"""
|
|
123
|
+
dehot_parser = subparsers.add_parser(
|
|
124
|
+
"hotspot",
|
|
125
|
+
help="Detect hotspots in residue shifts and create plots: For more, use tmq hotspot --help",
|
|
126
|
+
description=(
|
|
127
|
+
"Detect hotspots in residue shifts and creates publication-ready plot with trajectory map"
|
|
128
|
+
"and hotspot regions annotated, and also generates shift graphs for detected hotspot regions.\n\n"
|
|
129
|
+
"Example:\n"
|
|
130
|
+
" tmq hotspot --traj traj.pdb --top top.parmtop --str 1 --resr 1-300 --cent backbone --out hotspot_output\n\n"
|
|
131
|
+
),
|
|
132
|
+
formatter_class=argparse.RawTextHelpFormatter
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
dehot_parser.add_argument("-tr", "--traj", required=True,
|
|
136
|
+
help="Input trajectory, accepts Pdb, nc, xtc xtr")
|
|
137
|
+
dehot_parser.add_argument("-to", "--top", required=True,
|
|
138
|
+
help="Topology file, accepts .parmtop, pdb, gro")
|
|
139
|
+
dehot_parser.add_argument("-st", "--str", type=int, default=1,
|
|
140
|
+
help="Stride of the trajectory, (default: 1)")
|
|
141
|
+
dehot_parser.add_argument("-rr", "--resr", type=str, required=True,
|
|
142
|
+
help="Residue range of your protein in the form start-end (e.g., 1-300")
|
|
143
|
+
dehot_parser.add_argument("-ce", "--cent", type=str, default="backbone", required=True,
|
|
144
|
+
help="Centre of calculations, either the backbone " \
|
|
145
|
+
"atoms or the ca atoms, (default: backbone)")
|
|
146
|
+
dehot_parser.add_argument("-win", "--window", type=int, default=5, required=False,
|
|
147
|
+
help="Rolling window size for smoothing, (default: 5) (Not Required)")
|
|
148
|
+
dehot_parser.add_argument("-md", "--mindist", type=int, default=3, required=False,
|
|
149
|
+
help="Minimum distance between peaks, (default: 3) (Not Required)")
|
|
150
|
+
dehot_parser.add_argument("-hs", "--hot", type=int, default=10, required=False,
|
|
151
|
+
help="Number of top peaks to extract, (default: 10) (Not Required)")
|
|
152
|
+
dehot_parser.add_argument("-ma", "--max", type=int, default=5, required=False,
|
|
153
|
+
help="Max shift value for color scaling, (default: 5) (Not Required)")
|
|
154
|
+
dehot_parser.add_argument("-o", "--out", type=str, required=True,
|
|
155
|
+
help="Basename for outputs")
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
"""DIFFERENCE SUBCOMMAND"""
|
|
159
|
+
dehot_parser = subparsers.add_parser(
|
|
160
|
+
"diff",
|
|
161
|
+
help="Computes difference between two matrices and creates the difference map: For more, use tmq diff --help",
|
|
162
|
+
description=(
|
|
163
|
+
"Computes difference between two matrices and creates publication-ready plot with difference map.\n\n"
|
|
164
|
+
"The input matrices must be supplied by the names of the output of previous 'Shift' runs.\n\n"
|
|
165
|
+
"A subsequent downstream processing after 'Shift' runs; thus, matrices must have equal lengths.\n\n"
|
|
166
|
+
"Example:\n"
|
|
167
|
+
" tmq diff --mat1 apo --mat2 holo --resr 1-300 --max 8 --out my_diff\n\n"
|
|
168
|
+
),
|
|
169
|
+
formatter_class=argparse.RawTextHelpFormatter
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
dehot_parser.add_argument("-m1", "--mat1", required=True,
|
|
173
|
+
help="First matrix, accepts only the name without extension")
|
|
174
|
+
dehot_parser.add_argument("-m2", "--mat2", required=True,
|
|
175
|
+
help="Second matrix, accepts only the name without extension")
|
|
176
|
+
dehot_parser.add_argument("-rr", "--resr", type=str, required=True,
|
|
177
|
+
help="Residue range of your protein in the form start-end (e.g., 1-300")
|
|
178
|
+
dehot_parser.add_argument("-ma", "--max", type=int, default=5, required=True,
|
|
179
|
+
help="Max shift value for color scaling, (default: 5)")
|
|
180
|
+
dehot_parser.add_argument("-o", "--out", type=str, required=True,
|
|
181
|
+
help="Basename for outputs")
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
"""DIFFERENCE SUBCOMMAND"""
|
|
186
|
+
dehot_parser = subparsers.add_parser(
|
|
187
|
+
"average",
|
|
188
|
+
help="Computes average of n matrices and creates the average map: For more, use tmq average --help",
|
|
189
|
+
description=(
|
|
190
|
+
"Computes average of n matrices and creates publication-ready plot with average map. \n\n"
|
|
191
|
+
"The input matrices must be supplied by the names of the output of previous 'Shift' runs as comma separated values.\n\n"
|
|
192
|
+
"A subsequent downstream processing after 'Shift' runs; thus, matrices must have equal lengths.\n\n"
|
|
193
|
+
"Example:\n"
|
|
194
|
+
" tmq average --mat apo,holo,bound --resr 1-300 --max 8 --out my_avg\n\n"
|
|
195
|
+
),
|
|
196
|
+
formatter_class=argparse.RawTextHelpFormatter
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
dehot_parser.add_argument("-m", "--mat", required=True, type=str,
|
|
200
|
+
help="Comma-separated list of matrix names, accepts only the name without extension")
|
|
201
|
+
dehot_parser.add_argument("-rr", "--resr", type=str, required=True,
|
|
202
|
+
help="Residue range of your protein in the form start-end (e.g., 1-300")
|
|
203
|
+
dehot_parser.add_argument("-ma", "--max", type=int, default=5, required=True,
|
|
204
|
+
help="Max shift value for color scaling, (default: 5)")
|
|
205
|
+
dehot_parser.add_argument("-o", "--out", type=str, required=True,
|
|
206
|
+
help="Basename for outputs")
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
print("")
|
|
210
|
+
args = parser.parse_args()
|
|
211
|
+
|
|
212
|
+
if args.command == "shift":
|
|
213
|
+
traj2pdb_cli(args)
|
|
214
|
+
pdb2csv_cli(args)
|
|
215
|
+
shift_cli(args)
|
|
216
|
+
trajmap_cli(args)
|
|
217
|
+
shift2graph_cli(args)
|
|
218
|
+
end_time = time.perf_counter()
|
|
219
|
+
total = end_time - start_time
|
|
220
|
+
print_final_message(total)
|
|
221
|
+
elif args.command == "hotspot":
|
|
222
|
+
traj2pdb_cli(args)
|
|
223
|
+
pdb2csv_cli(args)
|
|
224
|
+
trajmap_cli(args)
|
|
225
|
+
detect_shift_cli(args)
|
|
226
|
+
create_submatrices_cli(args)
|
|
227
|
+
run_hotspot_cli(args)
|
|
228
|
+
slice_shifts_cli(args)
|
|
229
|
+
run_hotspot_cli(args)
|
|
230
|
+
end_time = time.perf_counter()
|
|
231
|
+
total = end_time - start_time
|
|
232
|
+
print_final_message(total)
|
|
233
|
+
|
|
234
|
+
elif args.command == "diff":
|
|
235
|
+
diff_map_cli(args)
|
|
236
|
+
end_time = time.perf_counter()
|
|
237
|
+
total = end_time - start_time
|
|
238
|
+
print_final_message(total)
|
|
239
|
+
|
|
240
|
+
elif args.command == "average":
|
|
241
|
+
avg_trajmap_cli(args)
|
|
242
|
+
end_time = time.perf_counter()
|
|
243
|
+
total = end_time - start_time
|
|
244
|
+
print_final_message(total)
|
|
245
|
+
|
|
246
|
+
else:
|
|
247
|
+
parser.print_help()
|
|
248
|
+
print("")
|
|
249
|
+
print("Cite this as: " + Fore.BLUE + "SHEDOOMTC. (2026). TrajMapQuick: Towards Fast Trajectory Map Analysis and Visualization (v1.0). Zenodo. https://doi.org/10.5281/zenodo.20681061" + Style.RESET_ALL)
|
|
250
|
+
print("")
|
tmq/commands/__init__.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Parse input matrices, compute their element-wise average,
|
|
2
|
+
and save an averaged trajectory map PNG.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import time
|
|
6
|
+
from ..core.average_trajmap import avg_trajmap
|
|
7
|
+
import matplotlib
|
|
8
|
+
matplotlib.use("Agg")
|
|
9
|
+
import matplotlib.pyplot as plt
|
|
10
|
+
from ..utils.utils import ensure_csv_extension, ensure_png_extension, parse_range, load_matrix_4_diff_map, csv2matrix
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def avg_trajmap_cli(args):
|
|
14
|
+
start_time = time.perf_counter()
|
|
15
|
+
print("")
|
|
16
|
+
print("Plotting Average map...")
|
|
17
|
+
|
|
18
|
+
"""split the matrix argument to get list of matrices
|
|
19
|
+
"""
|
|
20
|
+
matrix_names = args.mat.split(",")
|
|
21
|
+
prefix = "_pdb2csv_"
|
|
22
|
+
matrices = [csv2matrix(ensure_csv_extension(name + prefix)) for name in matrix_names]
|
|
23
|
+
|
|
24
|
+
residue_start, residue_end = parse_range(args.resr)
|
|
25
|
+
|
|
26
|
+
"""pass the matrices to the core function
|
|
27
|
+
"""
|
|
28
|
+
fig = avg_trajmap(residue_start, residue_end, args.max, *matrices)
|
|
29
|
+
|
|
30
|
+
prefix1 = "_average_map_"
|
|
31
|
+
savename = ensure_png_extension(args.out + prefix1)
|
|
32
|
+
fig.savefig(savename, dpi=800, bbox_inches='tight')
|
|
33
|
+
print(f"Difference map saved to {savename}")
|
|
34
|
+
plt.close(fig)
|
|
35
|
+
total = time.perf_counter() - start_time
|
|
36
|
+
print(f"Time taken to plot Difference map: {total:.2f} seconds")
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Load a distance matrix, compute residue-range shifts across frames, and write a shift CSV.
|
|
2
|
+
"""
|
|
3
|
+
|
|
4
|
+
import time
|
|
5
|
+
from ..core.csv2shift import shift
|
|
6
|
+
from ..utils.utils import csv2matrix, ensure_csv_extension, parse_range
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def shift_cli(args):
|
|
10
|
+
start_time = time.perf_counter()
|
|
11
|
+
print("")
|
|
12
|
+
prefix = "_pdb2csv_"
|
|
13
|
+
file = ensure_csv_extension(args.out + prefix)
|
|
14
|
+
matrix = csv2matrix(file)
|
|
15
|
+
residue_start, residue_end = parse_range(args.resrs)
|
|
16
|
+
n_frames = matrix.shape[1]
|
|
17
|
+
print(f"Calculating shift for residues {residue_start} to {residue_end} "
|
|
18
|
+
f"across frames 0 to {n_frames - 1}...")
|
|
19
|
+
|
|
20
|
+
shifta = shift(matrix, residue_start, residue_end)
|
|
21
|
+
|
|
22
|
+
prefix2 = "_shift_"
|
|
23
|
+
savename = ensure_csv_extension(args.out + prefix2)
|
|
24
|
+
shifta.to_csv(savename, index=False)
|
|
25
|
+
print(f"Shift saved to {savename}")
|
|
26
|
+
total = time.perf_counter() - start_time
|
|
27
|
+
print(f"Time taken to calculate shift: {total:.2f} seconds")
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Load two matrices, render their difference heatmap (A−B), and save the figure PNG.
|
|
2
|
+
"""
|
|
3
|
+
|
|
4
|
+
import time
|
|
5
|
+
from ..core.diff2graph import diff_map
|
|
6
|
+
import matplotlib
|
|
7
|
+
matplotlib.use("Agg")
|
|
8
|
+
import matplotlib.pyplot as plt
|
|
9
|
+
from ..utils.utils import ensure_csv_extension, ensure_png_extension, parse_range, load_matrix_4_diff_map
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def diff_map_cli(args):
|
|
14
|
+
start_time = time.perf_counter()
|
|
15
|
+
print("")
|
|
16
|
+
print("Plotting Difference map...")
|
|
17
|
+
|
|
18
|
+
prefix = "_pdb2csv_"
|
|
19
|
+
file1 = ensure_csv_extension(args.mat1 + prefix)
|
|
20
|
+
file2 = ensure_csv_extension(args.mat2 + prefix)
|
|
21
|
+
|
|
22
|
+
A = load_matrix_4_diff_map(file1)
|
|
23
|
+
B = load_matrix_4_diff_map(file2)
|
|
24
|
+
|
|
25
|
+
residue_start, residue_end = parse_range(args.resr)
|
|
26
|
+
|
|
27
|
+
fig = diff_map(A, B, args.max, residue_start, residue_end)
|
|
28
|
+
|
|
29
|
+
prefix1 = "_diff_map_"
|
|
30
|
+
savename = ensure_png_extension(args.out + prefix1)
|
|
31
|
+
fig.savefig(savename, dpi=800, bbox_inches='tight')
|
|
32
|
+
print(f"Difference map saved to {savename}")
|
|
33
|
+
plt.close(fig)
|
|
34
|
+
total = time.perf_counter() - start_time
|
|
35
|
+
print(f"Time taken to plot Difference map: {total:.2f} seconds")
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""Run hotspot detection and save a summary hotspot-region plot PNG.
|
|
2
|
+
"""
|
|
3
|
+
|
|
4
|
+
import time
|
|
5
|
+
import matplotlib
|
|
6
|
+
matplotlib.use("Agg")
|
|
7
|
+
import matplotlib.pyplot as plt
|
|
8
|
+
from matplotlib.ticker import MultipleLocator
|
|
9
|
+
from ..core.hotspot import create_submatrices, detect_shifts, plot_hotspot_regions, plot_shift_regions, plot_slice_regions, slice_shifts
|
|
10
|
+
from ..utils.utils import csv2matrix, ensure_csv_extension, ensure_png_extension, parse_range, shift_to_dataframe
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def detect_shift_cli(args):
|
|
14
|
+
print("")
|
|
15
|
+
print("Detecting shift regions...")
|
|
16
|
+
prefix = "_pdb2csv_"
|
|
17
|
+
file = ensure_csv_extension(args.out + prefix)
|
|
18
|
+
matrix = csv2matrix(file)
|
|
19
|
+
mean_shift, smooth, regions = detect_shifts(
|
|
20
|
+
matrix=matrix,
|
|
21
|
+
window=args.window,
|
|
22
|
+
mindist=args.mindist,
|
|
23
|
+
hotspot=args.hot,)
|
|
24
|
+
return mean_shift, smooth, regions
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def create_submatrices_cli(args):
|
|
28
|
+
print("")
|
|
29
|
+
print("Extracting region submatrices...")
|
|
30
|
+
prefix = "_pdb2csv_"
|
|
31
|
+
file = ensure_csv_extension(args.out + prefix)
|
|
32
|
+
matrix = csv2matrix(file)
|
|
33
|
+
prefix1 = "_matrix_"
|
|
34
|
+
savematrix = ensure_csv_extension(args.out + prefix1)
|
|
35
|
+
matrix.to_csv(savematrix, index=False)
|
|
36
|
+
|
|
37
|
+
"""Call backend"""
|
|
38
|
+
submatrices, regions, mean_shift, smooth = create_submatrices(
|
|
39
|
+
matrix=matrix,
|
|
40
|
+
window=args.window,
|
|
41
|
+
mindist=args.mindist,
|
|
42
|
+
hotspot=args.hot)
|
|
43
|
+
return submatrices
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def slice_shifts_cli(args):
|
|
47
|
+
start_time = time.perf_counter()
|
|
48
|
+
print("")
|
|
49
|
+
print("Searching for hotspot regions and plotting individual shift graphs...")
|
|
50
|
+
prefix = "_pdb2csv_"
|
|
51
|
+
file = ensure_csv_extension(args.out + prefix)
|
|
52
|
+
matrix = csv2matrix(file)
|
|
53
|
+
|
|
54
|
+
"""Backend: detect"""
|
|
55
|
+
results = slice_shifts(
|
|
56
|
+
matrix=matrix,
|
|
57
|
+
window=args.window,
|
|
58
|
+
mindist=args.mindist,
|
|
59
|
+
hotspot=args.hot)
|
|
60
|
+
|
|
61
|
+
for start, end, shift_data in results:
|
|
62
|
+
fig = plot_slice_regions(shift_data, start, end)
|
|
63
|
+
savename = f"{args.out}_shift_{start}_{end}.png"
|
|
64
|
+
fig.savefig(savename, dpi=800, bbox_inches='tight')
|
|
65
|
+
plt.close(fig)
|
|
66
|
+
print(f"Hotspot region shift graph saved to {savename}")
|
|
67
|
+
total = time.perf_counter() - start_time
|
|
68
|
+
print(f"Time taken to search for hotspot regions: {total:.2f} seconds")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
"""Hotspot region detection and plotting
|
|
72
|
+
"""
|
|
73
|
+
def run_hotspot_cli(args):
|
|
74
|
+
start_time = time.perf_counter()
|
|
75
|
+
print("")
|
|
76
|
+
print("Detecting hotspot regions based on mean shift and plotting...")
|
|
77
|
+
mean_shift, smooth, regions = detect_shift_cli(args)
|
|
78
|
+
|
|
79
|
+
fig = plot_hotspot_regions(
|
|
80
|
+
mean_shift,
|
|
81
|
+
smooth,
|
|
82
|
+
regions,
|
|
83
|
+
title="Residue Shift Hotspots")
|
|
84
|
+
savename = f"{args.out}_shift_hotspots.png"
|
|
85
|
+
fig.savefig(savename, dpi=800, bbox_inches='tight')
|
|
86
|
+
plt.close(fig)
|
|
87
|
+
print(f"Hotspot region plot saved to {savename}")
|
|
88
|
+
total = time.perf_counter() - start_time
|
|
89
|
+
print(f"Time taken to detect hotspot regions: {total:.2f} seconds")
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Convert a multi-model PDB (produced from trajectories) into a residue×frame distance CSV.
|
|
2
|
+
"""
|
|
3
|
+
|
|
4
|
+
import time
|
|
5
|
+
from ..utils.utils import parse_range, ensure_csv_extension
|
|
6
|
+
from ..core.pdb2csv import pdb2csv
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def pdb2csv_cli(args):
|
|
10
|
+
start_time = time.perf_counter()
|
|
11
|
+
prefix = "_pdb2csv_"
|
|
12
|
+
prefix2 = "_traj2pdb_"
|
|
13
|
+
savename = ensure_csv_extension(args.out + prefix)
|
|
14
|
+
pdb_file = args.out + prefix2 + ".pdb"
|
|
15
|
+
start, end = parse_range(args.resr)
|
|
16
|
+
mode = args.cent
|
|
17
|
+
print("")
|
|
18
|
+
print("Converting PDB to CSV distance matrix...")
|
|
19
|
+
|
|
20
|
+
matrix= pdb2csv(
|
|
21
|
+
pdb_file=pdb_file,
|
|
22
|
+
residue_start=start,
|
|
23
|
+
residue_end=end,
|
|
24
|
+
mode=mode)
|
|
25
|
+
|
|
26
|
+
matrix.to_csv(savename)
|
|
27
|
+
print(f"Distance matrix saved to {savename}")
|
|
28
|
+
total = time.perf_counter() - start_time
|
|
29
|
+
print(f"Time taken to convert PDB to CSV: {total:.2f} seconds")
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Load a shift CSV, plot the time-series with rolling-average, and save a PNG graph.
|
|
2
|
+
"""
|
|
3
|
+
|
|
4
|
+
import time
|
|
5
|
+
import matplotlib
|
|
6
|
+
matplotlib.use("Agg")
|
|
7
|
+
import matplotlib.pyplot as plt
|
|
8
|
+
from ..core.shift2graph import shift2graph
|
|
9
|
+
from ..utils.utils import ensure_csv_extension, ensure_png_extension, shift_to_dataframe
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def shift2graph_cli(args):
|
|
13
|
+
start_time = time.perf_counter()
|
|
14
|
+
print("")
|
|
15
|
+
print("Plotting shift graph...")
|
|
16
|
+
prefix = "_shift_"
|
|
17
|
+
file = ensure_csv_extension(args.out + prefix)
|
|
18
|
+
prefix1 = "_shift_graph_"
|
|
19
|
+
savename = ensure_png_extension(args.out + prefix1)
|
|
20
|
+
df = shift_to_dataframe(file)
|
|
21
|
+
|
|
22
|
+
fig = shift2graph(df, args.resrs)
|
|
23
|
+
|
|
24
|
+
fig.savefig(savename, dpi=800, bbox_inches='tight')
|
|
25
|
+
print(f"Shift graph saved to {savename}")
|
|
26
|
+
plt.close(fig)
|
|
27
|
+
total = time.perf_counter() - start_time
|
|
28
|
+
print(f"Time taken to plot shift graph: {total:.2f} seconds")
|
|
29
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Load a residue×frame matrix, render a trajectory heatmap, and save the PNG figure.
|
|
2
|
+
"""
|
|
3
|
+
|
|
4
|
+
import time
|
|
5
|
+
from ..core.traj2pdb import traj2pdb
|
|
6
|
+
from ..utils.utils import ensure_pdb_extension
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def traj2pdb_cli(args):
|
|
10
|
+
start_time = time.perf_counter()
|
|
11
|
+
prefix = "_traj2pdb_"
|
|
12
|
+
savename = ensure_pdb_extension(args.out + prefix)
|
|
13
|
+
print("Loading trajectory...")
|
|
14
|
+
traj = traj2pdb(args.top, args.traj, args.str)
|
|
15
|
+
print("Selecting backbone...")
|
|
16
|
+
print("Aligning...")
|
|
17
|
+
print("Saving trajectory to", savename)
|
|
18
|
+
traj.save_pdb(savename)
|
|
19
|
+
end_time = time.perf_counter()
|
|
20
|
+
total = end_time - start_time
|
|
21
|
+
print(f"Time taken to convert trajectory to PDB: {total:.2f} seconds")
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Load a residue×frame matrix, render a trajectory heatmap, and save the PNG figure.
|
|
2
|
+
"""
|
|
3
|
+
|
|
4
|
+
import time
|
|
5
|
+
import matplotlib
|
|
6
|
+
matplotlib.use("Agg")
|
|
7
|
+
import matplotlib.pyplot as plt
|
|
8
|
+
from ..core.trajmap import trajmap
|
|
9
|
+
from ..utils.utils import csv2matrix, ensure_csv_extension, ensure_png_extension, parse_range
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def trajmap_cli(args):
|
|
13
|
+
start_time = time.perf_counter()
|
|
14
|
+
print("")
|
|
15
|
+
print("Plotting trajectory map...")
|
|
16
|
+
prefix = "_pdb2csv_"
|
|
17
|
+
file = ensure_csv_extension(args.out + prefix)
|
|
18
|
+
matrix = csv2matrix(file)
|
|
19
|
+
residue_start, residue_end = parse_range(args.resr)
|
|
20
|
+
prefix1 = "_trajmap_"
|
|
21
|
+
savename = ensure_png_extension(args.out + prefix1)
|
|
22
|
+
|
|
23
|
+
fig = trajmap(matrix, residue_start, residue_end, args.max)
|
|
24
|
+
|
|
25
|
+
fig.savefig(savename, dpi=800, bbox_inches='tight')
|
|
26
|
+
print(f"Trajectory map saved to {savename}")
|
|
27
|
+
plt.close(fig)
|
|
28
|
+
total = time.perf_counter() - start_time
|
|
29
|
+
print(f"Time taken to plot trajectory map: {total:.2f} seconds")
|
tmq/core/__init__.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
""" Compute an element-wise average of input matrices
|
|
2
|
+
and render a trajectory map figure
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import pandas as pd
|
|
7
|
+
import numpy as np
|
|
8
|
+
import matplotlib
|
|
9
|
+
matplotlib.use("Agg")
|
|
10
|
+
from ..core.trajmap import trajmap
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def avg_trajmap(residue_start, residue_end, vmax, *matrices):
|
|
15
|
+
"""
|
|
16
|
+
Take the element-wise average of two or more matrices.
|
|
17
|
+
All matrices must have the same shape.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
mats = [np.asarray(m) for m in matrices]
|
|
21
|
+
print("Loaded shapes:", [m.shape for m in mats])
|
|
22
|
+
|
|
23
|
+
shapes = {m.shape for m in mats}
|
|
24
|
+
if len(shapes) != 1:
|
|
25
|
+
raise ValueError(f"All matrices must have the same shape, got: {shapes}")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
avg_array = np.nanmean(mats, axis=0)
|
|
29
|
+
avg_array = np.nan_to_num(avg_array, nan=0.0)
|
|
30
|
+
|
|
31
|
+
matrix = pd.DataFrame(avg_array)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
fig = trajmap(matrix, residue_start, residue_end, vmax)
|
|
35
|
+
return fig
|
tmq/core/csv2shift.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
""" This computes shift in Armstrongs for
|
|
2
|
+
a given loop region of the protein
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
import pandas as pd
|
|
8
|
+
from ..utils.utils import matrix2shift
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def shift(matrix, residue_start, residue_end):
|
|
12
|
+
n_frames = matrix.shape[1]
|
|
13
|
+
start_frame = 0
|
|
14
|
+
end_frame = n_frames - 1
|
|
15
|
+
params = [residue_start, residue_end, start_frame, end_frame]
|
|
16
|
+
shift = matrix2shift(matrix, params)
|
|
17
|
+
return shift
|