jsrc 0.2.2__tar.gz → 0.2.3__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.
- {jsrc-0.2.2/src/jsrc.egg-info → jsrc-0.2.3}/PKG-INFO +1 -1
- {jsrc-0.2.2 → jsrc-0.2.3}/pyproject.toml +1 -1
- jsrc-0.2.3/src/jsrc/analyze/__init__.py +41 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/cli.py +78 -32
- jsrc-0.2.3/src/jsrc/grn/__init__.py +36 -0
- jsrc-0.2.3/src/jsrc/gs/__init__.py +36 -0
- jsrc-0.2.3/src/jsrc/job/__init__.py +38 -0
- jsrc-0.2.3/src/jsrc/plot/__init__.py +42 -0
- jsrc-0.2.3/src/jsrc/plot/heart.py +82 -0
- jsrc-0.2.3/src/jsrc/seq/__init__.py +41 -0
- jsrc-0.2.3/src/jsrc/vision/__init__.py +40 -0
- {jsrc-0.2.2 → jsrc-0.2.3/src/jsrc.egg-info}/PKG-INFO +1 -1
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_cli_module_flows.py +56 -0
- jsrc-0.2.2/src/jsrc/analyze/__init__.py +0 -16
- jsrc-0.2.2/src/jsrc/grn/__init__.py +0 -15
- jsrc-0.2.2/src/jsrc/gs/__init__.py +0 -15
- jsrc-0.2.2/src/jsrc/job/__init__.py +0 -17
- jsrc-0.2.2/src/jsrc/plot/__init__.py +0 -29
- jsrc-0.2.2/src/jsrc/plot/heart.py +0 -37
- jsrc-0.2.2/src/jsrc/seq/__init__.py +0 -31
- jsrc-0.2.2/src/jsrc/vision/__init__.py +0 -15
- {jsrc-0.2.2 → jsrc-0.2.3}/LICENSE +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/README.md +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/setup.cfg +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/__init__.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/analyze/bootstrap_phylo.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/analyze/core.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/analyze/motif.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/analyze/msa_consensus.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/analyze/phylo.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/analyze/qc.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/analyze/snpindel.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/core.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/grn/anno2json.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/grn/build.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/grn/centrality.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/grn/core.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/grn/net2json.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/grn/serve.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/grn/sources/index.html +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/grn/sources/script.js +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/grn/sources/style.css +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/gs/build.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/gs/split.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/gs/train.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/job/core.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/job/gc.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/job/history.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/job/kill.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/job/logs.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/job/ls.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/job/show.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/job/submit.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/plot/chromosome.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/plot/circoslite.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/plot/cis.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/plot/core.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/plot/domain.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/plot/dotplot.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/plot/exon.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/plot/gene.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/plot/rose.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/seq/codon.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/seq/core.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/seq/digest.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/seq/extract.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/seq/fetch.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/seq/kmer.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/seq/promoter.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/seq/qc.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/seq/rename.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/seq/translate.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/seq/window.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/vision/core.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/vision/efd.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/vision/extract.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc/vision/traits.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc.egg-info/SOURCES.txt +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc.egg-info/dependency_links.txt +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc.egg-info/entry_points.txt +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc.egg-info/requires.txt +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/src/jsrc.egg-info/top_level.txt +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_analyze_extra.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_analyze_phylo.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_cli_error_behavior.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_grn_conversion.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_gs_train.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_job_core.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_job_portability.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_plot_commands.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_plot_core.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_progress.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_seq_codon_kmer.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_seq_core.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_seq_digest.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_seq_extract.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_seq_fetch.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_seq_promoter.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_seq_qc.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_seq_rename.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_seq_translate.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_seq_window.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_vision_efd.py +0 -0
- {jsrc-0.2.2 → jsrc-0.2.3}/tests/test_vision_extract.py +0 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
_SUBCOMMANDS: dict[str, tuple[str, str]] = {
|
|
5
|
+
"phylo": ("jsrc.analyze.phylo", "Build phylogenetic trees"),
|
|
6
|
+
"motif": ("jsrc.analyze.motif", "Motif discovery and reporting"),
|
|
7
|
+
"qc": ("jsrc.analyze.qc", "Alignment/sequence QC"),
|
|
8
|
+
"msa_consensus": ("jsrc.analyze.msa_consensus", "MSA consensus statistics"),
|
|
9
|
+
"snpindel": ("jsrc.analyze.snpindel", "SNP/INDEL analysis from alignments"),
|
|
10
|
+
"bootstrap_phylo": ("jsrc.analyze.bootstrap_phylo", "Bootstrap phylogeny support"),
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _register_stub_subcommands(subparsers: Any) -> None:
|
|
15
|
+
for name, (_, help_text) in _SUBCOMMANDS.items():
|
|
16
|
+
subparsers.add_parser(name, help=help_text)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _register_selected_subcommand(subparsers: Any, selected: str) -> bool:
|
|
20
|
+
module_path, _ = _SUBCOMMANDS.get(selected, ("", ""))
|
|
21
|
+
if not module_path:
|
|
22
|
+
return False
|
|
23
|
+
mod = importlib.import_module(module_path)
|
|
24
|
+
reg = getattr(mod, "register", None)
|
|
25
|
+
if reg is None:
|
|
26
|
+
raise AttributeError(f"{module_path}: missing register")
|
|
27
|
+
reg(subparsers)
|
|
28
|
+
return True
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def register_subparser(
|
|
32
|
+
subparsers: Any, selected_subcommand: str | None = None
|
|
33
|
+
) -> None:
|
|
34
|
+
analyze_parser = subparsers.add_parser("analyze", help="Analysis tools")
|
|
35
|
+
analyze_sub = analyze_parser.add_subparsers(dest="analyze_cmd")
|
|
36
|
+
analyze_parser.set_defaults(_group_parser=analyze_parser)
|
|
37
|
+
if selected_subcommand and _register_selected_subcommand(
|
|
38
|
+
analyze_sub, selected_subcommand
|
|
39
|
+
):
|
|
40
|
+
return
|
|
41
|
+
_register_stub_subcommands(analyze_sub)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import argparse
|
|
2
2
|
import importlib
|
|
3
|
+
import inspect
|
|
3
4
|
import logging
|
|
4
5
|
import os
|
|
5
6
|
import sys
|
|
@@ -24,6 +25,16 @@ MODULES = {
|
|
|
24
25
|
"job": "jsrc.job",
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
MODULE_HELP = {
|
|
29
|
+
"seq": "Sequence tools",
|
|
30
|
+
"plot": "Visualization",
|
|
31
|
+
"analyze": "Analysis workflows",
|
|
32
|
+
"gs": "Genomic selection",
|
|
33
|
+
"grn": "GRN tools",
|
|
34
|
+
"vision": "Image analysis",
|
|
35
|
+
"job": "Background jobs",
|
|
36
|
+
}
|
|
37
|
+
|
|
27
38
|
|
|
28
39
|
def _iter_enabled_modules() -> list[str]:
|
|
29
40
|
only = [x.strip() for x in os.getenv("JSRC_MODULES", "").split(",") if x.strip()]
|
|
@@ -34,31 +45,7 @@ def _iter_enabled_modules() -> list[str]:
|
|
|
34
45
|
return [n for n in names if n in MODULES and n not in disabled]
|
|
35
46
|
|
|
36
47
|
|
|
37
|
-
def
|
|
38
|
-
subparsers: argparse.Action, *, debug: bool = False
|
|
39
|
-
) -> tuple[list[str], list[str]]:
|
|
40
|
-
loaded: list[str] = []
|
|
41
|
-
errors: list[str] = []
|
|
42
|
-
for name in _iter_enabled_modules():
|
|
43
|
-
try:
|
|
44
|
-
mod = importlib.import_module(MODULES[name])
|
|
45
|
-
reg = getattr(mod, "register_subparser", None)
|
|
46
|
-
if reg is None:
|
|
47
|
-
errors.append(f"{name}: missing register_subparser")
|
|
48
|
-
continue
|
|
49
|
-
reg(subparsers)
|
|
50
|
-
loaded.append(name)
|
|
51
|
-
except (ImportError, AttributeError) as exc:
|
|
52
|
-
if debug:
|
|
53
|
-
raise
|
|
54
|
-
errors.append(f"{name}: {exc}")
|
|
55
|
-
return loaded, errors
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def main() -> None:
|
|
59
|
-
debug_mode = "--debug" in sys.argv[1:]
|
|
60
|
-
verbose = "--verbose" in sys.argv[1:] or debug_mode
|
|
61
|
-
setup_logging(verbose=verbose)
|
|
48
|
+
def _build_base_parser() -> argparse.ArgumentParser:
|
|
62
49
|
parser = argparse.ArgumentParser(
|
|
63
50
|
prog="jsrc", description="General-purpose bioinformatics and data toolkit"
|
|
64
51
|
)
|
|
@@ -69,17 +56,76 @@ def main() -> None:
|
|
|
69
56
|
action="store_true",
|
|
70
57
|
help="Show traceback for module loading and runtime errors",
|
|
71
58
|
)
|
|
72
|
-
|
|
59
|
+
return parser
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _register_stub_modules(
|
|
63
|
+
subparsers: argparse.Action, enabled_modules: list[str]
|
|
64
|
+
) -> None:
|
|
65
|
+
for name in enabled_modules:
|
|
66
|
+
subparsers.add_parser(name, help=MODULE_HELP.get(name, f"{name} module"))
|
|
73
67
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
68
|
+
|
|
69
|
+
def _register_one_module(
|
|
70
|
+
subparsers: argparse.Action,
|
|
71
|
+
module_name: str,
|
|
72
|
+
*,
|
|
73
|
+
selected_subcommand: str | None = None,
|
|
74
|
+
debug: bool = False,
|
|
75
|
+
) -> bool:
|
|
76
|
+
try:
|
|
77
|
+
mod = importlib.import_module(MODULES[module_name])
|
|
78
|
+
reg = getattr(mod, "register_subparser", None)
|
|
79
|
+
if reg is None:
|
|
80
|
+
raise AttributeError("missing register_subparser")
|
|
81
|
+
params = inspect.signature(reg).parameters
|
|
82
|
+
if "selected_subcommand" in params:
|
|
83
|
+
reg(subparsers, selected_subcommand=selected_subcommand)
|
|
84
|
+
else:
|
|
85
|
+
reg(subparsers)
|
|
86
|
+
return True
|
|
87
|
+
except (ImportError, AttributeError) as exc:
|
|
88
|
+
if debug:
|
|
89
|
+
raise
|
|
90
|
+
logging.error("Error: failed to load module '%s': %s", module_name, exc)
|
|
91
|
+
return False
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _probe_route(argv: list[str]) -> tuple[str | None, str | None]:
|
|
95
|
+
probe = argparse.ArgumentParser(add_help=False)
|
|
96
|
+
probe.add_argument("--verbose", action="store_true")
|
|
97
|
+
probe.add_argument("--debug", action="store_true")
|
|
98
|
+
probe.add_argument("-v", "--version", action="store_true")
|
|
99
|
+
probe.add_argument("command", nargs="?")
|
|
100
|
+
probe.add_argument("subcommand", nargs="?")
|
|
101
|
+
args, _ = probe.parse_known_args(argv)
|
|
102
|
+
return args.command, args.subcommand
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def main() -> None:
|
|
106
|
+
argv = sys.argv[1:]
|
|
107
|
+
debug_mode = "--debug" in argv
|
|
108
|
+
verbose = "--verbose" in sys.argv[1:] or debug_mode
|
|
109
|
+
setup_logging(verbose=verbose)
|
|
110
|
+
enabled_modules = _iter_enabled_modules()
|
|
111
|
+
if not enabled_modules:
|
|
80
112
|
logging.error("no module loaded")
|
|
81
113
|
sys.exit(2)
|
|
82
114
|
|
|
115
|
+
requested_module, requested_subcommand = _probe_route(argv)
|
|
116
|
+
parser = _build_base_parser()
|
|
117
|
+
subparsers = parser.add_subparsers(dest="command", help="Available modules")
|
|
118
|
+
if requested_module and requested_module in enabled_modules:
|
|
119
|
+
if not _register_one_module(
|
|
120
|
+
subparsers,
|
|
121
|
+
requested_module,
|
|
122
|
+
selected_subcommand=requested_subcommand,
|
|
123
|
+
debug=debug_mode,
|
|
124
|
+
):
|
|
125
|
+
sys.exit(2)
|
|
126
|
+
else:
|
|
127
|
+
_register_stub_modules(subparsers, enabled_modules)
|
|
128
|
+
|
|
83
129
|
args = parser.parse_args()
|
|
84
130
|
if not args.command:
|
|
85
131
|
parser.print_help()
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
_SUBCOMMANDS: dict[str, tuple[str, str]] = {
|
|
5
|
+
"build": ("jsrc.grn.build", "Build GRN viewer package"),
|
|
6
|
+
"net2json": ("jsrc.grn.net2json", "Convert GRN edge table to grn.json"),
|
|
7
|
+
"anno2json": ("jsrc.grn.anno2json", "Convert annotation table to annotation.json"),
|
|
8
|
+
"serve": ("jsrc.grn.serve", "Start GRN viewer service"),
|
|
9
|
+
"centrality": ("jsrc.grn.centrality", "Compute GRN centrality metrics"),
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _register_stub_subcommands(subparsers: Any) -> None:
|
|
14
|
+
for name, (_, help_text) in _SUBCOMMANDS.items():
|
|
15
|
+
subparsers.add_parser(name, help=help_text)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _register_selected_subcommand(subparsers: Any, selected: str) -> bool:
|
|
19
|
+
module_path, _ = _SUBCOMMANDS.get(selected, ("", ""))
|
|
20
|
+
if not module_path:
|
|
21
|
+
return False
|
|
22
|
+
mod = importlib.import_module(module_path)
|
|
23
|
+
reg = getattr(mod, "register", None)
|
|
24
|
+
if reg is None:
|
|
25
|
+
raise AttributeError(f"{module_path}: missing register")
|
|
26
|
+
reg(subparsers)
|
|
27
|
+
return True
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def register_subparser(subparsers: Any, selected_subcommand: str | None = None) -> None:
|
|
31
|
+
grn_parser = subparsers.add_parser("grn", help="GRN conversion and local viewer")
|
|
32
|
+
grn_sub = grn_parser.add_subparsers(dest="grn_cmd")
|
|
33
|
+
grn_parser.set_defaults(_group_parser=grn_parser)
|
|
34
|
+
if selected_subcommand and _register_selected_subcommand(grn_sub, selected_subcommand):
|
|
35
|
+
return
|
|
36
|
+
_register_stub_subcommands(grn_sub)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
_SUBCOMMANDS: dict[str, tuple[str, str]] = {
|
|
5
|
+
"build": ("jsrc.gs.build", "Build genomic selection datasets"),
|
|
6
|
+
"split": ("jsrc.gs.split", "Split GS datasets into folds"),
|
|
7
|
+
"train": ("jsrc.gs.train", "Train and evaluate GS models"),
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _register_stub_subcommands(subparsers: Any) -> None:
|
|
12
|
+
for name, (_, help_text) in _SUBCOMMANDS.items():
|
|
13
|
+
subparsers.add_parser(name, help=help_text)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _register_selected_subcommand(subparsers: Any, selected: str) -> bool:
|
|
17
|
+
module_path, _ = _SUBCOMMANDS.get(selected, ("", ""))
|
|
18
|
+
if not module_path:
|
|
19
|
+
return False
|
|
20
|
+
mod = importlib.import_module(module_path)
|
|
21
|
+
reg = getattr(mod, "register", None)
|
|
22
|
+
if reg is None:
|
|
23
|
+
raise AttributeError(f"{module_path}: missing register")
|
|
24
|
+
reg(subparsers)
|
|
25
|
+
return True
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def register_subparser(subparsers: Any, selected_subcommand: str | None = None) -> None:
|
|
29
|
+
gs_parser = subparsers.add_parser(
|
|
30
|
+
"gs", help="Genomic selection dataset and model workflows"
|
|
31
|
+
)
|
|
32
|
+
gs_sub = gs_parser.add_subparsers(dest="gs_cmd")
|
|
33
|
+
gs_parser.set_defaults(_group_parser=gs_parser)
|
|
34
|
+
if selected_subcommand and _register_selected_subcommand(gs_sub, selected_subcommand):
|
|
35
|
+
return
|
|
36
|
+
_register_stub_subcommands(gs_sub)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
_SUBCOMMANDS: dict[str, tuple[str, str]] = {
|
|
5
|
+
"submit": ("jsrc.job.submit", "Submit a background job"),
|
|
6
|
+
"ls": ("jsrc.job.ls", "List jobs"),
|
|
7
|
+
"show": ("jsrc.job.show", "Show one job"),
|
|
8
|
+
"logs": ("jsrc.job.logs", "Show job logs"),
|
|
9
|
+
"kill": ("jsrc.job.kill", "Terminate a running job"),
|
|
10
|
+
"history": ("jsrc.job.history", "Show job history"),
|
|
11
|
+
"gc": ("jsrc.job.gc", "Garbage-collect old job artifacts"),
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _register_stub_subcommands(subparsers: Any) -> None:
|
|
16
|
+
for name, (_, help_text) in _SUBCOMMANDS.items():
|
|
17
|
+
subparsers.add_parser(name, help=help_text)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _register_selected_subcommand(subparsers: Any, selected: str) -> bool:
|
|
21
|
+
module_path, _ = _SUBCOMMANDS.get(selected, ("", ""))
|
|
22
|
+
if not module_path:
|
|
23
|
+
return False
|
|
24
|
+
mod = importlib.import_module(module_path)
|
|
25
|
+
reg = getattr(mod, "register", None)
|
|
26
|
+
if reg is None:
|
|
27
|
+
raise AttributeError(f"{module_path}: missing register")
|
|
28
|
+
reg(subparsers)
|
|
29
|
+
return True
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def register_subparser(subparsers: Any, selected_subcommand: str | None = None) -> None:
|
|
33
|
+
job_parser = subparsers.add_parser("job", help="Track and manage background jobs")
|
|
34
|
+
job_sub = job_parser.add_subparsers(dest="job_cmd")
|
|
35
|
+
job_parser.set_defaults(_group_parser=job_parser)
|
|
36
|
+
if selected_subcommand and _register_selected_subcommand(job_sub, selected_subcommand):
|
|
37
|
+
return
|
|
38
|
+
_register_stub_subcommands(job_sub)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
_SUBCOMMANDS: dict[str, tuple[str, str]] = {
|
|
5
|
+
"gene": ("jsrc.plot.gene", "Plot gene structure diagram"),
|
|
6
|
+
"exon": ("jsrc.plot.exon", "Plot exon structure diagram"),
|
|
7
|
+
"chromosome": ("jsrc.plot.chromosome", "Plot chromosome map"),
|
|
8
|
+
"domain": ("jsrc.plot.domain", "Plot protein domain architecture"),
|
|
9
|
+
"cis": ("jsrc.plot.cis", "Plot cis-regulatory elements"),
|
|
10
|
+
"heart": ("jsrc.plot.heart", "Plot heart curve"),
|
|
11
|
+
"rose": ("jsrc.plot.rose", "Plot 3D rose model"),
|
|
12
|
+
"dotplot": ("jsrc.plot.dotplot", "Sequence dotplot by exact k-mer matches"),
|
|
13
|
+
"circoslite": ("jsrc.plot.circoslite", "Simple circular tracks for genome stats"),
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _register_stub_subcommands(subparsers: Any) -> None:
|
|
18
|
+
for name, (_, help_text) in _SUBCOMMANDS.items():
|
|
19
|
+
subparsers.add_parser(name, help=help_text)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _register_selected_subcommand(subparsers: Any, selected: str) -> bool:
|
|
23
|
+
module_path, _ = _SUBCOMMANDS.get(selected, ("", ""))
|
|
24
|
+
if not module_path:
|
|
25
|
+
return False
|
|
26
|
+
mod = importlib.import_module(module_path)
|
|
27
|
+
reg = getattr(mod, "register", None)
|
|
28
|
+
if reg is None:
|
|
29
|
+
raise AttributeError(f"{module_path}: missing register")
|
|
30
|
+
reg(subparsers)
|
|
31
|
+
return True
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def register_subparser(
|
|
35
|
+
subparsers: Any, selected_subcommand: str | None = None
|
|
36
|
+
) -> None:
|
|
37
|
+
plot_parser = subparsers.add_parser("plot", help="Visualization")
|
|
38
|
+
plot_sub = plot_parser.add_subparsers(dest="plot_cmd")
|
|
39
|
+
plot_parser.set_defaults(_group_parser=plot_parser)
|
|
40
|
+
if selected_subcommand and _register_selected_subcommand(plot_sub, selected_subcommand):
|
|
41
|
+
return
|
|
42
|
+
_register_stub_subcommands(plot_sub)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
from argparse import Namespace
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _load_interactive_pyplot() -> Any:
|
|
10
|
+
try:
|
|
11
|
+
import matplotlib
|
|
12
|
+
except ImportError as exc:
|
|
13
|
+
raise SystemExit(
|
|
14
|
+
"matplotlib is required for this command. Install it with: pip install matplotlib"
|
|
15
|
+
) from exc
|
|
16
|
+
|
|
17
|
+
env_backend = os.getenv("MPLBACKEND", "").strip()
|
|
18
|
+
if env_backend:
|
|
19
|
+
import matplotlib.pyplot as plt
|
|
20
|
+
|
|
21
|
+
if "agg" in matplotlib.get_backend().lower():
|
|
22
|
+
raise SystemExit(
|
|
23
|
+
"jsrc plot heart requires an interactive matplotlib backend. "
|
|
24
|
+
"Current MPLBACKEND is non-interactive."
|
|
25
|
+
)
|
|
26
|
+
return plt
|
|
27
|
+
|
|
28
|
+
if sys.platform.startswith("linux") and not (
|
|
29
|
+
os.getenv("DISPLAY") or os.getenv("WAYLAND_DISPLAY")
|
|
30
|
+
):
|
|
31
|
+
raise SystemExit(
|
|
32
|
+
"No graphical display detected. Set DISPLAY/WAYLAND_DISPLAY or run in a desktop session."
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
for backend in ("TkAgg", "QtAgg", "Qt5Agg", "GTK3Agg", "WXAgg", "MacOSX"):
|
|
36
|
+
try:
|
|
37
|
+
matplotlib.use(backend, force=True)
|
|
38
|
+
import matplotlib.pyplot as plt
|
|
39
|
+
|
|
40
|
+
if "agg" not in matplotlib.get_backend().lower():
|
|
41
|
+
return plt
|
|
42
|
+
except (ImportError, ValueError):
|
|
43
|
+
continue
|
|
44
|
+
|
|
45
|
+
raise SystemExit(
|
|
46
|
+
"No interactive matplotlib backend is available. "
|
|
47
|
+
"Install a GUI backend (for example python3-tk or PyQt6)."
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def cmd(args: Namespace) -> None:
|
|
52
|
+
plt = _load_interactive_pyplot()
|
|
53
|
+
x = np.arange(-1.8, 1.8, 0.005)
|
|
54
|
+
|
|
55
|
+
plt.figure(figsize=(12, 10))
|
|
56
|
+
plt.grid(True)
|
|
57
|
+
plt.axis([-3, 3, -2, 4])
|
|
58
|
+
|
|
59
|
+
plt.text(
|
|
60
|
+
0,
|
|
61
|
+
3.3,
|
|
62
|
+
r"$f(x)=x^{\frac{2}{3}}+0.9(3.3-x^2)^{\frac{1}{2}}\sin(\alpha\pi x)$",
|
|
63
|
+
fontsize=28,
|
|
64
|
+
ha="center",
|
|
65
|
+
)
|
|
66
|
+
txt = plt.text(-0.35, 2.9, "", fontsize=26, ha="left")
|
|
67
|
+
(line,) = plt.plot([], [], linewidth=3.5, color="#CD5555")
|
|
68
|
+
|
|
69
|
+
for alpha in np.arange(1, 20.01, 0.01):
|
|
70
|
+
y = np.cbrt(x**2) + 0.9 * np.sqrt(np.clip(3.3 - x**2, 0, None)) * np.sin(
|
|
71
|
+
alpha * np.pi * x
|
|
72
|
+
)
|
|
73
|
+
line.set_data(x, y)
|
|
74
|
+
txt.set_text(rf"$\alpha={alpha:.2f}$")
|
|
75
|
+
plt.pause(0.003)
|
|
76
|
+
|
|
77
|
+
plt.show()
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def register(subparsers: Any) -> None:
|
|
81
|
+
p = subparsers.add_parser("heart", help="Plot heart curve")
|
|
82
|
+
p.set_defaults(func=cmd)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
_SUBCOMMANDS: dict[str, tuple[str, str]] = {
|
|
5
|
+
"extract": ("jsrc.seq.extract", "Extract sequences by IDs"),
|
|
6
|
+
"fetch": ("jsrc.seq.fetch", "Fetch sequences from remote databases"),
|
|
7
|
+
"digest": ("jsrc.seq.digest", "Simulate restriction enzyme digestion"),
|
|
8
|
+
"rename": ("jsrc.seq.rename", "Rename FASTA headers"),
|
|
9
|
+
"translate": ("jsrc.seq.translate", "Translate CDS/DNA to protein"),
|
|
10
|
+
"promoter": ("jsrc.seq.promoter", "Extract promoter sequences"),
|
|
11
|
+
"qc": ("jsrc.seq.qc", "Sequence quality statistics"),
|
|
12
|
+
"codon": ("jsrc.seq.codon", "Codon usage analysis"),
|
|
13
|
+
"kmer": ("jsrc.seq.kmer", "Count k-mer frequencies"),
|
|
14
|
+
"window": ("jsrc.seq.window", "Sliding-window sequence statistics"),
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _register_stub_subcommands(subparsers: Any) -> None:
|
|
19
|
+
for name, (_, help_text) in _SUBCOMMANDS.items():
|
|
20
|
+
subparsers.add_parser(name, help=help_text)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _register_selected_subcommand(subparsers: Any, selected: str) -> bool:
|
|
24
|
+
module_path, _ = _SUBCOMMANDS.get(selected, ("", ""))
|
|
25
|
+
if not module_path:
|
|
26
|
+
return False
|
|
27
|
+
mod = importlib.import_module(module_path)
|
|
28
|
+
reg = getattr(mod, "register", None)
|
|
29
|
+
if reg is None:
|
|
30
|
+
raise AttributeError(f"{module_path}: missing register")
|
|
31
|
+
reg(subparsers)
|
|
32
|
+
return True
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def register_subparser(subparsers: Any, selected_subcommand: str | None = None) -> None:
|
|
36
|
+
seq_parser = subparsers.add_parser("seq", help="Sequence operations")
|
|
37
|
+
seq_sub = seq_parser.add_subparsers(dest="seq_cmd")
|
|
38
|
+
seq_parser.set_defaults(_group_parser=seq_parser)
|
|
39
|
+
if selected_subcommand and _register_selected_subcommand(seq_sub, selected_subcommand):
|
|
40
|
+
return
|
|
41
|
+
_register_stub_subcommands(seq_sub)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
_SUBCOMMANDS: dict[str, tuple[str, str]] = {
|
|
5
|
+
"extract": ("jsrc.vision.extract", "Extract objects from images"),
|
|
6
|
+
"efd": ("jsrc.vision.efd", "Elliptic Fourier descriptor analysis"),
|
|
7
|
+
"traits": ("jsrc.vision.traits", "Measure morphology traits"),
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _register_stub_subcommands(subparsers: Any) -> None:
|
|
12
|
+
for name, (_, help_text) in _SUBCOMMANDS.items():
|
|
13
|
+
subparsers.add_parser(name, help=help_text)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _register_selected_subcommand(subparsers: Any, selected: str) -> bool:
|
|
17
|
+
module_path, _ = _SUBCOMMANDS.get(selected, ("", ""))
|
|
18
|
+
if not module_path:
|
|
19
|
+
return False
|
|
20
|
+
mod = importlib.import_module(module_path)
|
|
21
|
+
reg = getattr(mod, "register", None)
|
|
22
|
+
if reg is None:
|
|
23
|
+
raise AttributeError(f"{module_path}: missing register")
|
|
24
|
+
reg(subparsers)
|
|
25
|
+
return True
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def register_subparser(
|
|
29
|
+
subparsers: Any, selected_subcommand: str | None = None
|
|
30
|
+
) -> None:
|
|
31
|
+
vision_parser = subparsers.add_parser(
|
|
32
|
+
"vision", help="Image recognition and shape descriptors"
|
|
33
|
+
)
|
|
34
|
+
vision_sub = vision_parser.add_subparsers(dest="vision_cmd")
|
|
35
|
+
vision_parser.set_defaults(_group_parser=vision_parser)
|
|
36
|
+
if selected_subcommand and _register_selected_subcommand(
|
|
37
|
+
vision_sub, selected_subcommand
|
|
38
|
+
):
|
|
39
|
+
return
|
|
40
|
+
_register_stub_subcommands(vision_sub)
|
|
@@ -42,6 +42,62 @@ def test_cli_debug_mode_raises_original_exception(monkeypatch):
|
|
|
42
42
|
cli.main()
|
|
43
43
|
|
|
44
44
|
|
|
45
|
+
def test_cli_plot_help_imports_only_plot_module(monkeypatch):
|
|
46
|
+
imported: list[str] = []
|
|
47
|
+
real_import = cli.importlib.import_module
|
|
48
|
+
|
|
49
|
+
def _spy(name: str):
|
|
50
|
+
imported.append(name)
|
|
51
|
+
return real_import(name)
|
|
52
|
+
|
|
53
|
+
monkeypatch.setattr(cli.importlib, "import_module", _spy)
|
|
54
|
+
monkeypatch.setattr(sys, "argv", ["jsrc", "plot", "-h"])
|
|
55
|
+
with pytest.raises(SystemExit) as exc:
|
|
56
|
+
cli.main()
|
|
57
|
+
assert exc.value.code == 0
|
|
58
|
+
assert imported == ["jsrc.plot"]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_cli_root_help_does_not_import_modules(monkeypatch):
|
|
62
|
+
imported: list[str] = []
|
|
63
|
+
real_import = cli.importlib.import_module
|
|
64
|
+
|
|
65
|
+
def _spy(name: str):
|
|
66
|
+
imported.append(name)
|
|
67
|
+
return real_import(name)
|
|
68
|
+
|
|
69
|
+
monkeypatch.setattr(cli.importlib, "import_module", _spy)
|
|
70
|
+
monkeypatch.setattr(sys, "argv", ["jsrc", "-h"])
|
|
71
|
+
with pytest.raises(SystemExit) as exc:
|
|
72
|
+
cli.main()
|
|
73
|
+
assert exc.value.code == 0
|
|
74
|
+
assert imported == []
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@pytest.mark.parametrize(
|
|
78
|
+
("argv", "expected_imports"),
|
|
79
|
+
[
|
|
80
|
+
(["jsrc", "plot", "heart", "-h"], ["jsrc.plot", "jsrc.plot.heart"]),
|
|
81
|
+
(["jsrc", "seq", "window", "-h"], ["jsrc.seq", "jsrc.seq.window"]),
|
|
82
|
+
(["jsrc", "grn", "centrality", "-h"], ["jsrc.grn", "jsrc.grn.centrality"]),
|
|
83
|
+
],
|
|
84
|
+
)
|
|
85
|
+
def test_cli_imports_only_selected_subcommand(monkeypatch, argv, expected_imports):
|
|
86
|
+
imported: list[str] = []
|
|
87
|
+
real_import = cli.importlib.import_module
|
|
88
|
+
|
|
89
|
+
def _spy(name: str):
|
|
90
|
+
imported.append(name)
|
|
91
|
+
return real_import(name)
|
|
92
|
+
|
|
93
|
+
monkeypatch.setattr(cli.importlib, "import_module", _spy)
|
|
94
|
+
monkeypatch.setattr(sys, "argv", argv)
|
|
95
|
+
with pytest.raises(SystemExit) as exc:
|
|
96
|
+
cli.main()
|
|
97
|
+
assert exc.value.code == 0
|
|
98
|
+
assert imported == expected_imports
|
|
99
|
+
|
|
100
|
+
|
|
45
101
|
def test_job_submit_and_list_flow(tmp_path, capsys, monkeypatch):
|
|
46
102
|
monkeypatch.setenv("XDG_DATA_HOME", str(tmp_path / "xdg"))
|
|
47
103
|
monkeypatch.setenv("JSRC_JOBS_FILE", str(tmp_path / "jobs.tsv"))
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
from typing import Any
|
|
2
|
-
|
|
3
|
-
from jsrc.analyze import bootstrap_phylo, motif, msa_consensus, phylo, qc, snpindel
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def register_subparser(subparsers: Any) -> None:
|
|
7
|
-
analyze_parser = subparsers.add_parser("analyze", help="Analysis tools")
|
|
8
|
-
analyze_sub = analyze_parser.add_subparsers(dest="analyze_cmd")
|
|
9
|
-
analyze_parser.set_defaults(_group_parser=analyze_parser)
|
|
10
|
-
|
|
11
|
-
phylo.register(analyze_sub)
|
|
12
|
-
motif.register(analyze_sub)
|
|
13
|
-
qc.register(analyze_sub)
|
|
14
|
-
msa_consensus.register(analyze_sub)
|
|
15
|
-
snpindel.register(analyze_sub)
|
|
16
|
-
bootstrap_phylo.register(analyze_sub)
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
from typing import Any
|
|
2
|
-
|
|
3
|
-
from jsrc.grn import anno2json, build, centrality, net2json, serve
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def register_subparser(subparsers: Any) -> None:
|
|
7
|
-
grn_parser = subparsers.add_parser("grn", help="GRN conversion and local viewer")
|
|
8
|
-
grn_sub = grn_parser.add_subparsers(dest="grn_cmd")
|
|
9
|
-
grn_parser.set_defaults(_group_parser=grn_parser)
|
|
10
|
-
|
|
11
|
-
build.register(grn_sub)
|
|
12
|
-
net2json.register(grn_sub)
|
|
13
|
-
anno2json.register(grn_sub)
|
|
14
|
-
serve.register(grn_sub)
|
|
15
|
-
centrality.register(grn_sub)
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
from typing import Any
|
|
2
|
-
|
|
3
|
-
from jsrc.gs import build, split, train
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def register_subparser(subparsers: Any) -> None:
|
|
7
|
-
gs_parser = subparsers.add_parser(
|
|
8
|
-
"gs", help="Genomic selection dataset and model workflows"
|
|
9
|
-
)
|
|
10
|
-
gs_sub = gs_parser.add_subparsers(dest="gs_cmd")
|
|
11
|
-
gs_parser.set_defaults(_group_parser=gs_parser)
|
|
12
|
-
|
|
13
|
-
build.register(gs_sub)
|
|
14
|
-
split.register(gs_sub)
|
|
15
|
-
train.register(gs_sub)
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
from typing import Any
|
|
2
|
-
|
|
3
|
-
from jsrc.job import gc, history, kill, logs, ls, show, submit
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def register_subparser(subparsers: Any) -> None:
|
|
7
|
-
job_parser = subparsers.add_parser("job", help="Track and manage background jobs")
|
|
8
|
-
job_sub = job_parser.add_subparsers(dest="job_cmd")
|
|
9
|
-
job_parser.set_defaults(_group_parser=job_parser)
|
|
10
|
-
|
|
11
|
-
submit.register(job_sub)
|
|
12
|
-
ls.register(job_sub)
|
|
13
|
-
show.register(job_sub)
|
|
14
|
-
logs.register(job_sub)
|
|
15
|
-
kill.register(job_sub)
|
|
16
|
-
history.register(job_sub)
|
|
17
|
-
gc.register(job_sub)
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
from typing import Any
|
|
2
|
-
|
|
3
|
-
from jsrc.plot import (
|
|
4
|
-
chromosome,
|
|
5
|
-
circoslite,
|
|
6
|
-
cis,
|
|
7
|
-
domain,
|
|
8
|
-
dotplot,
|
|
9
|
-
exon,
|
|
10
|
-
gene,
|
|
11
|
-
heart,
|
|
12
|
-
rose,
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def register_subparser(subparsers: Any) -> None:
|
|
17
|
-
plot_parser = subparsers.add_parser("plot", help="Visualization")
|
|
18
|
-
plot_sub = plot_parser.add_subparsers(dest="plot_cmd")
|
|
19
|
-
plot_parser.set_defaults(_group_parser=plot_parser)
|
|
20
|
-
|
|
21
|
-
gene.register(plot_sub)
|
|
22
|
-
exon.register(plot_sub)
|
|
23
|
-
chromosome.register(plot_sub)
|
|
24
|
-
domain.register(plot_sub)
|
|
25
|
-
cis.register(plot_sub)
|
|
26
|
-
heart.register(plot_sub)
|
|
27
|
-
rose.register(plot_sub)
|
|
28
|
-
dotplot.register(plot_sub)
|
|
29
|
-
circoslite.register(plot_sub)
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
import matplotlib.pyplot as plt
|
|
3
|
-
from argparse import Namespace
|
|
4
|
-
from typing import Any
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def cmd(args: Namespace) -> None:
|
|
8
|
-
x = np.arange(-1.8, 1.8, 0.005)
|
|
9
|
-
|
|
10
|
-
plt.figure(figsize=(12, 10))
|
|
11
|
-
plt.grid(True)
|
|
12
|
-
plt.axis([-3, 3, -2, 4])
|
|
13
|
-
|
|
14
|
-
plt.text(
|
|
15
|
-
0,
|
|
16
|
-
3.3,
|
|
17
|
-
r"$f(x)=x^{\frac{2}{3}}+0.9(3.3-x^2)^{\frac{1}{2}}\sin(\alpha\pi x)$",
|
|
18
|
-
fontsize=28,
|
|
19
|
-
ha="center",
|
|
20
|
-
)
|
|
21
|
-
txt = plt.text(-0.35, 2.9, "", fontsize=26, ha="left")
|
|
22
|
-
(line,) = plt.plot([], [], linewidth=3.5, color="#CD5555")
|
|
23
|
-
|
|
24
|
-
for alpha in np.arange(1, 20.01, 0.01):
|
|
25
|
-
y = np.cbrt(x**2) + 0.9 * np.sqrt(np.clip(3.3 - x**2, 0, None)) * np.sin(
|
|
26
|
-
alpha * np.pi * x
|
|
27
|
-
)
|
|
28
|
-
line.set_data(x, y)
|
|
29
|
-
txt.set_text(rf"$\alpha={alpha:.2f}$")
|
|
30
|
-
plt.pause(0.003)
|
|
31
|
-
|
|
32
|
-
plt.show()
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def register(subparsers: Any) -> None:
|
|
36
|
-
p = subparsers.add_parser("heart", help="Plot heart curve")
|
|
37
|
-
p.set_defaults(func=cmd)
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
from typing import Any
|
|
2
|
-
|
|
3
|
-
from jsrc.seq import (
|
|
4
|
-
codon,
|
|
5
|
-
digest,
|
|
6
|
-
extract,
|
|
7
|
-
fetch,
|
|
8
|
-
kmer,
|
|
9
|
-
promoter,
|
|
10
|
-
qc,
|
|
11
|
-
rename,
|
|
12
|
-
translate,
|
|
13
|
-
window,
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def register_subparser(subparsers: Any) -> None:
|
|
18
|
-
seq_parser = subparsers.add_parser("seq", help="Sequence operations")
|
|
19
|
-
seq_sub = seq_parser.add_subparsers(dest="seq_cmd")
|
|
20
|
-
seq_parser.set_defaults(_group_parser=seq_parser)
|
|
21
|
-
|
|
22
|
-
extract.register(seq_sub)
|
|
23
|
-
fetch.register(seq_sub)
|
|
24
|
-
digest.register(seq_sub)
|
|
25
|
-
rename.register(seq_sub)
|
|
26
|
-
translate.register(seq_sub)
|
|
27
|
-
promoter.register(seq_sub)
|
|
28
|
-
qc.register(seq_sub)
|
|
29
|
-
codon.register(seq_sub)
|
|
30
|
-
kmer.register(seq_sub)
|
|
31
|
-
window.register(seq_sub)
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
from typing import Any
|
|
2
|
-
|
|
3
|
-
from jsrc.vision import efd, extract, traits
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def register_subparser(subparsers: Any) -> None:
|
|
7
|
-
vision_parser = subparsers.add_parser(
|
|
8
|
-
"vision", help="Image recognition and shape descriptors"
|
|
9
|
-
)
|
|
10
|
-
vision_sub = vision_parser.add_subparsers(dest="vision_cmd")
|
|
11
|
-
vision_parser.set_defaults(_group_parser=vision_parser)
|
|
12
|
-
|
|
13
|
-
extract.register(vision_sub)
|
|
14
|
-
efd.register(vision_sub)
|
|
15
|
-
traits.register(vision_sub)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|