prstools 0.0.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.
- prstools-0.0.3/LICENSE +21 -0
- prstools-0.0.3/MANIFEST.in +5 -0
- prstools-0.0.3/PKG-INFO +44 -0
- prstools-0.0.3/README.md +9 -0
- prstools-0.0.3/prstools/__init__.py +40 -0
- prstools-0.0.3/prstools/_cmd.py +352 -0
- prstools-0.0.3/prstools/_ext_utils.py +337 -0
- prstools-0.0.3/prstools/_modidx.py +32 -0
- prstools-0.0.3/prstools/data/__init__.py +0 -0
- prstools-0.0.3/prstools/data/_example/__init__.py +0 -0
- prstools-0.0.3/prstools/data/_example/ldgm_1kg_pop/EUR/1kg_chr22_22004675_23374984.EUR.edgelist +21045 -0
- prstools-0.0.3/prstools/data/_example/ldgm_1kg_pop/EUR/1kg_chr22_30667654_32269392.EUR.edgelist +45229 -0
- prstools-0.0.3/prstools/data/_example/ldgm_1kg_pop/EUR/__init__.py +0 -0
- prstools-0.0.3/prstools/data/_example/ldgm_1kg_pop/__init__.py +0 -0
- prstools-0.0.3/prstools/data/_example/ldgm_1kg_pop/snplist/1kg_chr22_22004675_23374984.snplist +6156 -0
- prstools-0.0.3/prstools/data/_example/ldgm_1kg_pop/snplist/1kg_chr22_30667654_32269392.snplist +9652 -0
- prstools-0.0.3/prstools/data/_example/ldgm_1kg_pop/snplist/__init__.py +0 -0
- prstools-0.0.3/prstools/data/_example/ldref_1kg_pop/__init__.py +0 -0
- prstools-0.0.3/prstools/data/_example/ldref_1kg_pop/ldblk_1kg_chr22.hdf5 +0 -0
- prstools-0.0.3/prstools/data/_example/ldref_1kg_pop/snpinfo_1kg_hm3 +937 -0
- prstools-0.0.3/prstools/data/_example/sumstats.tsv +948 -0
- prstools-0.0.3/prstools/data/_example/target.bed +0 -0
- prstools-0.0.3/prstools/data/_example/target.bim +947 -0
- prstools-0.0.3/prstools/data/_example/target.fam +4275 -0
- prstools-0.0.3/prstools/data/defs/__init__.py +0 -0
- prstools-0.0.3/prstools/data/defs/regdef/__init__.py +0 -0
- prstools-0.0.3/prstools/data/defs/regdef/regions_1blk_shift=0.regdef.tsv +1704 -0
- prstools-0.0.3/prstools/data/defs/regdef/regions_2blk_shift=0.regdef.tsv +855 -0
- prstools-0.0.3/prstools/data/defs/regdef/regions_2blk_shift=1.regdef.tsv +872 -0
- prstools-0.0.3/prstools/data/defs/regdef/regions_3blk_shift=0.regdef.tsv +575 -0
- prstools-0.0.3/prstools/data/defs/regdef/regions_3blk_shift=1.regdef.tsv +583 -0
- prstools-0.0.3/prstools/data/defs/regdef/regions_3blk_shift=2.regdef.tsv +592 -0
- prstools-0.0.3/prstools/parse_genet.py +198 -0
- prstools-0.0.3/prstools/scores.py +185 -0
- prstools-0.0.3/prstools/utils.py +561 -0
- prstools-0.0.3/prstools.egg-info/PKG-INFO +44 -0
- prstools-0.0.3/prstools.egg-info/SOURCES.txt +43 -0
- prstools-0.0.3/prstools.egg-info/dependency_links.txt +1 -0
- prstools-0.0.3/prstools.egg-info/entry_points.txt +7 -0
- prstools-0.0.3/prstools.egg-info/not-zip-safe +1 -0
- prstools-0.0.3/prstools.egg-info/requires.txt +15 -0
- prstools-0.0.3/prstools.egg-info/top_level.txt +1 -0
- prstools-0.0.3/settings.ini +58 -0
- prstools-0.0.3/setup.cfg +4 -0
- prstools-0.0.3/setup.py +87 -0
prstools-0.0.3/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Menno Witteveen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
prstools-0.0.3/PKG-INFO
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: prstools
|
|
3
|
+
Version: 0.0.3
|
|
4
|
+
Summary: Convenient and powerfull Polygenic Risk Score creation.
|
|
5
|
+
Home-page: https://github.com/mennowitteveen/prstools
|
|
6
|
+
Author: Menno Witteveen et al.
|
|
7
|
+
Author-email: menno102@hotmail.com
|
|
8
|
+
License: MIT License
|
|
9
|
+
Keywords: PRS PGS polygenic genomics prediction genetics
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Natural Language :: English
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Requires-Python: >=3.6
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: pandas
|
|
23
|
+
Requires-Dist: matplotlib
|
|
24
|
+
Requires-Dist: numpy
|
|
25
|
+
Requires-Dist: scipy
|
|
26
|
+
Requires-Dist: tqdm
|
|
27
|
+
Requires-Dist: h5py
|
|
28
|
+
Requires-Dist: ipython
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: nbdev; extra == "dev"
|
|
31
|
+
Provides-Extra: full
|
|
32
|
+
Requires-Dist: mjwt; extra == "full"
|
|
33
|
+
Requires-Dist: pysnptools; extra == "full"
|
|
34
|
+
Requires-Dist: seaborn; extra == "full"
|
|
35
|
+
|
|
36
|
+
# prstools
|
|
37
|
+
|
|
38
|
+
<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->
|
|
39
|
+
|
|
40
|
+
`prstools` is software to create Polygenic Risk Scores (PRS) directly
|
|
41
|
+
from the commandline <br> (and optionally from inside python).
|
|
42
|
+
|
|
43
|
+
It contains various tools to make PRS generation easier. Installation
|
|
44
|
+
and running the demo example should not take more than 10 minutes.
|
prstools-0.0.3/README.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# prstools
|
|
2
|
+
|
|
3
|
+
<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->
|
|
4
|
+
|
|
5
|
+
`prstools` is software to create Polygenic Risk Scores (PRS) directly
|
|
6
|
+
from the commandline <br> (and optionally from inside python).
|
|
7
|
+
|
|
8
|
+
It contains various tools to make PRS generation easier. Installation
|
|
9
|
+
and running the demo example should not take more than 10 minutes.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
__version__ = "0.0.2"
|
|
2
|
+
_date = "18-02-2025"
|
|
3
|
+
# from . import *
|
|
4
|
+
|
|
5
|
+
# from . import models
|
|
6
|
+
# from . import loaders
|
|
7
|
+
# from . import utils
|
|
8
|
+
# from . import _cmd as cmd
|
|
9
|
+
|
|
10
|
+
# import .models
|
|
11
|
+
# from models import __
|
|
12
|
+
# from . import models.L2Pred
|
|
13
|
+
#
|
|
14
|
+
import importlib as _importlib # Import takes around 6 microseconds
|
|
15
|
+
|
|
16
|
+
# List of submodules to be included
|
|
17
|
+
_submodules = [
|
|
18
|
+
'_cmd',
|
|
19
|
+
'loaders',
|
|
20
|
+
'models',
|
|
21
|
+
'utils'
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
__all__ = _submodules + [
|
|
25
|
+
# 'LowLevelCallable',
|
|
26
|
+
# 'test',
|
|
27
|
+
# 'show_config',
|
|
28
|
+
'__version__',
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
def __dir__():
|
|
32
|
+
return __all__
|
|
33
|
+
|
|
34
|
+
def __getattr__(name):
|
|
35
|
+
if name in _submodules:
|
|
36
|
+
return _importlib.import_module(f'prstools.{name}')
|
|
37
|
+
try:
|
|
38
|
+
return globals()[name]
|
|
39
|
+
except KeyError:
|
|
40
|
+
raise AttributeError(f"Module 'prstools' has no attribute '{name}'")
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
import os, time, sys, argparse, json
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def set_cpu_envvars(cpus=1):
|
|
5
|
+
if cpus != -1: # disabling.
|
|
6
|
+
#MKL_NUM_THREADS=1 NUMEXPR_NUM_THREADS=1 OMP_NUM_THREADS=1 OPENBLAS_NUM_THREADS=1
|
|
7
|
+
print(f'Setting environmental variables to control number of cpus used (={cpus}).')
|
|
8
|
+
n_cores = cpus # Correction, this does do something, although its quite opaque
|
|
9
|
+
os.environ['OPENBLAS_NUM_THREADS'] = str(n_cores)
|
|
10
|
+
os.environ['MKL_NUM_THREADS'] = str(n_cores) # For Intel MKL
|
|
11
|
+
os.environ['OMP_NUM_THREADS'] = str(n_cores)
|
|
12
|
+
os.environ['NUMEXPR_NUM_THREADS'] = str(n_cores) # For NumExpr
|
|
13
|
+
# os.environ['OMP_DYNAMIC'] = 'FALSE'
|
|
14
|
+
# os.environ['OMP_THREAD_LIMIT'] = str(n_cores)
|
|
15
|
+
# os.environ['OMP_NESTED'] = 'FALSE'
|
|
16
|
+
# os.environ['OMP_PROC_BIND'] = 'TRUE'
|
|
17
|
+
else:
|
|
18
|
+
print('Skipping the setting of environmental variables')
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
##################################################### BEST IF THIS IS ALREADY DONE BY THE TIME THIS CODE RUNS ############
|
|
22
|
+
|
|
23
|
+
## CLI mechanics functionality:
|
|
24
|
+
def process_subparserkwgs(subparserkwg_lst):
|
|
25
|
+
from textwrap import dedent
|
|
26
|
+
for i, spkwg in enumerate(subparserkwg_lst):
|
|
27
|
+
if type(spkwg) is type({}): continue
|
|
28
|
+
elif 'PRSTCLI' in str(getattr(spkwg,'__bases__','')):
|
|
29
|
+
new_spkwg = spkwg._get_cli_spkwg()
|
|
30
|
+
subparserkwg_lst[i] = new_spkwg
|
|
31
|
+
elif 'BasePred' in str(getattr(spkwg,'__bases__','')):
|
|
32
|
+
from .utils import retrieve_pkwargs
|
|
33
|
+
doc = dedent(spkwg.__doc__)
|
|
34
|
+
new_spkwg = dict(
|
|
35
|
+
cmdname = spkwg.__name__.lower(), #command name
|
|
36
|
+
clsname = spkwg.__name__, #class name
|
|
37
|
+
description= doc,
|
|
38
|
+
help = doc.split('\n')[0],
|
|
39
|
+
epilog = spkwg._get_cli_epilog(),
|
|
40
|
+
module = spkwg.__module__,
|
|
41
|
+
pkwargs = retrieve_pkwargs(spkwg),
|
|
42
|
+
subtype = 'BasePred'
|
|
43
|
+
)
|
|
44
|
+
subparserkwg_lst[i] = new_spkwg
|
|
45
|
+
else:
|
|
46
|
+
print(str(getattr(spkwg,'__bases__','')))
|
|
47
|
+
raise NotImplementedError('Contact dev.')
|
|
48
|
+
return subparserkwg_lst
|
|
49
|
+
def retrieve_classmethod(*, clsname, methodname, modulename='prstools.models'):
|
|
50
|
+
#models = importlib.reload(models)
|
|
51
|
+
def pipefun(*args,**kwargs):
|
|
52
|
+
import importlib
|
|
53
|
+
cls = getattr(importlib.import_module(modulename), clsname)
|
|
54
|
+
return getattr(cls,methodname)(*args,**kwargs)
|
|
55
|
+
return pipefun
|
|
56
|
+
def process_argkwargs(kwargs, setverbosetrue=False):
|
|
57
|
+
kwargs = kwargs.copy()
|
|
58
|
+
kwargs['help'] = argparse.SUPPRESS if kwargs.get('help', None) is None else kwargs['help']
|
|
59
|
+
if kwargs.get('type',None) is bool:
|
|
60
|
+
if not kwargs['default']:
|
|
61
|
+
kwargs.pop('type')
|
|
62
|
+
kwargs['action']='store_true'
|
|
63
|
+
kwargs['default'] = argparse.SUPPRESS
|
|
64
|
+
if setverbosetrue:
|
|
65
|
+
raise NotImplementedError()
|
|
66
|
+
if 'default' in kwargs and kwargs['default'] == 'SUPPRESS':
|
|
67
|
+
kwargs['default'] = argparse.SUPPRESS
|
|
68
|
+
if (kwargs['help'] != argparse.SUPPRESS):
|
|
69
|
+
if not (kwargs.get('default', 'idontexist') in ['idontexist', argparse.SUPPRESS]):
|
|
70
|
+
kwargs['help'] += f" (default: {kwargs.pop('default')})"
|
|
71
|
+
if 'required' in kwargs:
|
|
72
|
+
if kwargs['required'] is True:
|
|
73
|
+
kwargs['help'] = kwargs['help'] + ' (required)'
|
|
74
|
+
# kwargs['help'] = '* '+kwargs['help'] + format_bold(' (required)')
|
|
75
|
+
return kwargs
|
|
76
|
+
def format_color(text, color_code): return f"\033[{color_code}m{text}\033[0m"
|
|
77
|
+
def format_bold(text): return f"\033[1m{text}\033[0m"
|
|
78
|
+
##################################################### BEST IF THIS IS ALREADY DONE BY THE TIME THIS CODE RUNS ############
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
## Formatting functionality:
|
|
83
|
+
class CustomArgumentParser(argparse.ArgumentParser):
|
|
84
|
+
|
|
85
|
+
def format_usage(self):
|
|
86
|
+
usage = super().format_usage()
|
|
87
|
+
return self.usage_optionals_formattingx(usage)
|
|
88
|
+
def format_help(self):
|
|
89
|
+
string = super().format_help()
|
|
90
|
+
string = self.usage_optionals_formattingx(string)
|
|
91
|
+
return string.replace('usage:','\nUsage:\n')
|
|
92
|
+
|
|
93
|
+
def usage_optionals_formattingx(self, string):
|
|
94
|
+
# print(string.find('\n'))
|
|
95
|
+
# loc = max(string.find('[-h]'), 0)
|
|
96
|
+
# print(loc*'-')
|
|
97
|
+
string = string.replace('] [',' ')
|
|
98
|
+
# string = string.replace('> [','>\n'+loc*'-'+'[')
|
|
99
|
+
return string
|
|
100
|
+
class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter,argparse.RawDescriptionHelpFormatter): #, argparse.RawDescriptionHelpFormatter):
|
|
101
|
+
def __init__(self, prog, indent_increment=1, max_help_position=60, width=None, minwidth=0):
|
|
102
|
+
if not width:
|
|
103
|
+
import shutil # Width processing
|
|
104
|
+
width = shutil.get_terminal_size().columns-2
|
|
105
|
+
width = max(width, minwidth)
|
|
106
|
+
_excl_lst = ['self', 'kwg_dt','_excl_lst','CustomFormatter','__class__','minwidth', 'shutil']
|
|
107
|
+
kwg_dt = {key: item for key, item in locals().items() if not (key in _excl_lst)}
|
|
108
|
+
super(CustomFormatter, self).__init__(**kwg_dt) #prog, indent_increment=indent_increment, max_help_position=max_help_position, width=width)
|
|
109
|
+
|
|
110
|
+
def _get_default_metavar_for_optional(self, action):
|
|
111
|
+
return '<'+action.dest+'>' #.upper()
|
|
112
|
+
|
|
113
|
+
def _format_action_invocation(self, action):
|
|
114
|
+
if not action.option_strings:
|
|
115
|
+
metavar, = self._metavar_formatter(action, action.dest)(1)
|
|
116
|
+
return metavar
|
|
117
|
+
else:
|
|
118
|
+
parts = []
|
|
119
|
+
if action.nargs == 0:
|
|
120
|
+
parts.extend(action.option_strings)
|
|
121
|
+
else:
|
|
122
|
+
default = '<'+action.dest+'>'#.upper()
|
|
123
|
+
args_string = self._format_args(action, default)
|
|
124
|
+
parts.extend(action.option_strings)
|
|
125
|
+
parts = parts[::-1]
|
|
126
|
+
parts[-1] += ' %s' % args_string
|
|
127
|
+
# if parts[-1] in ['']
|
|
128
|
+
# if action.required: return '\b\b* '+', '.join(parts)
|
|
129
|
+
return ', '.join(parts)
|
|
130
|
+
|
|
131
|
+
def parse_args(argv=None, description="Convenient and powerfull Polygenic Risk Score creation. \n\'prst\' is a commandline shorthand for \'prstools\'",
|
|
132
|
+
subparserkwg_lst=None, basecmd='prstools', return_spkwg=False, reload=False):
|
|
133
|
+
|
|
134
|
+
# Prepare parsing params:
|
|
135
|
+
if argv is None: argv=sys.argv[1:]; basecmd=sys.argv[0]
|
|
136
|
+
#from prstools.models import L2Pred, PRSCS
|
|
137
|
+
#subparserkwg_lst = [L2Pred, PRSCS]
|
|
138
|
+
if subparserkwg_lst is None:
|
|
139
|
+
if reload: import importlib; from prstools import _parser_vars; importlib.reload(_parser_vars)
|
|
140
|
+
from prstools._parser_vars import subparserkwg_lst
|
|
141
|
+
else:
|
|
142
|
+
subparserkwg_lst=process_subparserkwgs(subparserkwg_lst)
|
|
143
|
+
# subparserkwg_lst contains the information to construct parsers
|
|
144
|
+
# This is generated from model code by the developer and saved
|
|
145
|
+
|
|
146
|
+
# Construct Parser:
|
|
147
|
+
parser = CustomArgumentParser(
|
|
148
|
+
description=description,
|
|
149
|
+
argument_default=argparse.SUPPRESS,
|
|
150
|
+
add_help=False,
|
|
151
|
+
formatter_class=CustomFormatter
|
|
152
|
+
)
|
|
153
|
+
general_group = parser.add_argument_group('General Options')
|
|
154
|
+
parser.add_argument('-h', '--help', action='help', default=argparse.SUPPRESS, help=argparse.SUPPRESS) # , help='Show help')
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
if return_spkwg: return subparserkwg_lst
|
|
158
|
+
|
|
159
|
+
def prscsx_linkfun(**kwg): from prstools.PRScsx.PRScsx import main; sys.argv = sys.argv[1:]; main()
|
|
160
|
+
def prscs_linkfun(**kwg): from prstools.PRScs.PRScs import main; sys.argv = sys.argv[1:]; main()
|
|
161
|
+
xtr = dict(subtype='external')
|
|
162
|
+
ext_lst = [dict(cmdname='prscsx',help="PRS-CSx (original): A cross-population polygenic prediction method with continuous shrinkage "
|
|
163
|
+
"(CS) priors trained with multiple GWAS summary statistics.",func=prscsx_linkfun, **xtr),
|
|
164
|
+
dict(cmdname='prscs',help="PRS-CS (original): A polygenic prediction method with continuous shrinkage (CS) priors trained with GWAS summary statistics.", func=prscs_linkfun, **xtr)]
|
|
165
|
+
subparserkwg_lst += ext_lst
|
|
166
|
+
|
|
167
|
+
# Add Subparser structure:
|
|
168
|
+
subparser = parser.add_subparsers(title="Models & Utility Commands", dest="command", metavar='<command>'+' \b'*2, help="") #trick: +' \b'*0
|
|
169
|
+
extcmds = []; prc = process_argkwargs
|
|
170
|
+
for i, spkwg in enumerate(subparserkwg_lst):
|
|
171
|
+
if spkwg['subtype'] == 'BasePred':
|
|
172
|
+
# Create Model parser and add basic help:
|
|
173
|
+
model_parser = subparser.add_parser(spkwg['cmdname'], help=spkwg['help'],
|
|
174
|
+
description=spkwg['description'],
|
|
175
|
+
epilog=spkwg['epilog'],
|
|
176
|
+
formatter_class=CustomFormatter,
|
|
177
|
+
argument_default=argparse.SUPPRESS,
|
|
178
|
+
add_help=False)
|
|
179
|
+
|
|
180
|
+
modelgeneral_group = model_parser.add_argument_group('General Options')
|
|
181
|
+
modelgeneral_group.add_argument('-h', '--help', action='help', help='Show this help message and exit.') #default=argparse.SUPPRESS
|
|
182
|
+
# WARNING!: there is still something wrong with the default of this --cpus cli argument, it does not seem to get pushed into the setting of the number of cores function.
|
|
183
|
+
modelgeneral_group.add_argument('--cpus', '-c', **prc(dict(metavar='<number-of-cpus>', default=-1, type=int, help='The number of cpus to use. This will generate environmental variables inside \
|
|
184
|
+
of the python session, which will control the number of used cores. Functionality can be turned-off completely, by setting it to -1.\
|
|
185
|
+
(devnote: for default=1 some things have to be modified) ')))
|
|
186
|
+
|
|
187
|
+
# Add data related kwargs:
|
|
188
|
+
data_group = model_parser.add_argument_group('Data Arguments (first 5 required)')
|
|
189
|
+
data_group.add_argument("--ref","--ref_dir","-r",
|
|
190
|
+
**prc(dict(required=True, metavar='<dir/refcode>',
|
|
191
|
+
help="Path to the directory that contains the LD reference panel. You can download this reference data "
|
|
192
|
+
f"manually with \'{basecmd} downloadref\'. Soon it will be possible to automatically download it on the fly.")))
|
|
193
|
+
data_group.add_argument("--target", "--bim_prefix", "-t",
|
|
194
|
+
**prc(dict(required=True, metavar='<bim-prefix>',
|
|
195
|
+
help="Specify the directory and prefix of the bim file for the target dataset.")))
|
|
196
|
+
data_group.add_argument("--sst","--sst_file","-s", **prc(dict(required=True, metavar='<file>',
|
|
197
|
+
help="The summary statistics file from which the model will be created. The file should contain columns: SNP, A1, A2, BETA or OR, P or SE information. "
|
|
198
|
+
"At the moment, the file is assumed to be tab-seperated, if you like other formats please let devs know."
|
|
199
|
+
f"Alternative column names can be specified with --columns (more info below). SNP column should contain rsid\'s. "
|
|
200
|
+
f"See {format_color('https://tinyurl.com/sstxampl','34')} for an example.")))
|
|
201
|
+
data_group.add_argument("--out","--out_dir","-o",
|
|
202
|
+
**prc(dict(required=True, metavar='<dir+prefix>',
|
|
203
|
+
help="Output prefix for the results (variant weights). This should be a combination of the desired output dir and file prefix.")))
|
|
204
|
+
data_group.add_argument("--n_gwas","-n",
|
|
205
|
+
**prc(dict(required=False, type=int, metavar='<num>', default=None,
|
|
206
|
+
help="Sample size of the GWAS. Not required if sumstat has a 'N' column.")))
|
|
207
|
+
data_group.add_argument("--chrom", #lambda x: x.split(',')
|
|
208
|
+
type=str, metavar='<chroms>', default='all',
|
|
209
|
+
help="Optional: Select specific chromosome to work with. You can specify a specific chromosome as e.g. \"--chrom 3\". All chromosomes are used by default.")
|
|
210
|
+
data_group.add_argument("--colmap", #lambda x: x.split(',')
|
|
211
|
+
type=str, metavar='<alternative_colnames>',
|
|
212
|
+
help="Optional: Allows one to specify an alterative column name for columns SNP,A1,A2,BETA,OR,P,SE,N (in that order). "
|
|
213
|
+
"Forinstance \"--colmap rsid,a1,a2,beta_gwas,,pvalue,beta_standard_error,\" (OR & N are excluded in this example). "
|
|
214
|
+
"When the command is run a quick this_column -> that_column conversion table will be shown. "
|
|
215
|
+
"Additionaly prstools has many internal checks to make sure a good PRS will be generated! ")
|
|
216
|
+
|
|
217
|
+
# Add model-related arguments (hyper parameters and such):
|
|
218
|
+
modelargs_group = model_parser.add_argument_group('Model Arguments (all optional)')
|
|
219
|
+
for argname, item in spkwg['pkwargs'].items():
|
|
220
|
+
# if argname == 'n_iter':ergerg
|
|
221
|
+
#cargs, ckwargs = process_pkwargs(item) << -- underconstruction, need 2 add verbose=True
|
|
222
|
+
modelargs_group.add_argument(*item['args'], **process_argkwargs(item['kwargs']))
|
|
223
|
+
# Below 'func' contains a delayed import of a classmethod that can run the full method from arg
|
|
224
|
+
# This means the import (which can be slow) will take place only when run, leading to big speedups
|
|
225
|
+
# and a snappy cmdline tool, which is nice for users. In case the model is PRSCS2 it in effect says:
|
|
226
|
+
# .. .set_defaults(func=PRSCS2.run_from_cli_params_thiswholenamecouldchange_imasocalledclassmethod, .. etc
|
|
227
|
+
func = retrieve_classmethod(clsname=spkwg['clsname'], methodname='from_cli_params_and_run')
|
|
228
|
+
model_parser.set_defaults(func=func, pkwargs=spkwg['pkwargs'], model_parser=model_parser)
|
|
229
|
+
elif spkwg['subtype'] == 'function':
|
|
230
|
+
funct_parser = subparser.add_parser(spkwg['cmdname'], help=spkwg['help'],
|
|
231
|
+
description=spkwg['description'],
|
|
232
|
+
formatter_class=CustomFormatter,
|
|
233
|
+
argument_default=argparse.SUPPRESS,
|
|
234
|
+
add_help=False)
|
|
235
|
+
general_group = funct_parser.add_argument_group('Options')
|
|
236
|
+
general_group.add_argument('-h', '--help', action='help', help='Show this help message and exit.')
|
|
237
|
+
for argname, item in spkwg['pkwargs'].items():
|
|
238
|
+
general_group.add_argument(*item['args'], **process_argkwargs(item['kwargs']))
|
|
239
|
+
func = globals()[spkwg['cmdname']]
|
|
240
|
+
funct_parser.set_defaults(func=func)
|
|
241
|
+
elif spkwg['subtype'] == 'external':
|
|
242
|
+
linked_parser = subparser.add_parser(spkwg['cmdname'], help=spkwg['help'], description='unneeded', add_help=False) #, description='descption prscx')
|
|
243
|
+
linked_parser.set_defaults(func=spkwg['func'])
|
|
244
|
+
extcmds+=[spkwg['cmdname']]
|
|
245
|
+
elif spkwg['subtype'] == 'PRSTCLI':
|
|
246
|
+
subcmd_parser = subparser.add_parser(spkwg['cmdname'], help=spkwg['help'],
|
|
247
|
+
description=spkwg['description'],
|
|
248
|
+
epilog=spkwg['epilog'],
|
|
249
|
+
formatter_class=CustomFormatter,
|
|
250
|
+
argument_default=argparse.SUPPRESS,
|
|
251
|
+
add_help=False)
|
|
252
|
+
|
|
253
|
+
# Add groups and respective arguments:
|
|
254
|
+
for grpname, grpkwg in spkwg['groups'].items():
|
|
255
|
+
cur_group = subcmd_parser.add_argument_group(grpkwg['grpheader'])
|
|
256
|
+
for argname, item in grpkwg['pkwargs'].items():
|
|
257
|
+
cur_group.add_argument(*item['args'], **process_argkwargs(item['kwargs']))
|
|
258
|
+
|
|
259
|
+
# Set func to be linked to all the args:
|
|
260
|
+
func = retrieve_classmethod(modulename=spkwg['modulename'], clsname=spkwg['clsname'], methodname='from_cli_params_and_run')
|
|
261
|
+
subcmd_parser.set_defaults(func=func) # Yes it needs to b
|
|
262
|
+
else:
|
|
263
|
+
raise Exception('Subparser subtype not recognized, Contact dev.')
|
|
264
|
+
|
|
265
|
+
# Commence actual parsing:
|
|
266
|
+
if len(argv)<2: argv+=['-h']
|
|
267
|
+
knargs, _ = parser.parse_known_args(argv)
|
|
268
|
+
if knargs.command in extcmds:
|
|
269
|
+
return knargs
|
|
270
|
+
else:
|
|
271
|
+
args = parser.parse_args(argv)
|
|
272
|
+
return args
|
|
273
|
+
# import json
|
|
274
|
+
def main(argv=None):
|
|
275
|
+
|
|
276
|
+
if argv is None: argv=sys.argv[1:]
|
|
277
|
+
args = parse_args(argv)
|
|
278
|
+
display_info = True if 'pkwargs' in args else False
|
|
279
|
+
from prstools import __version__, _date# as version, date
|
|
280
|
+
timestampfmt = "%a, %d %b %Y %H:%M:%S %z"
|
|
281
|
+
if display_info:
|
|
282
|
+
param_dt = vars(args)
|
|
283
|
+
topstr = '\n'.join([
|
|
284
|
+
f'PRSTOOLS v{__version__} ({_date})',
|
|
285
|
+
f'Running command: {args.command}',
|
|
286
|
+
f'Options in effect:'
|
|
287
|
+
])
|
|
288
|
+
print(topstr)
|
|
289
|
+
for act in args.model_parser._actions:
|
|
290
|
+
key = act.dest
|
|
291
|
+
if not key in param_dt: continue
|
|
292
|
+
item = param_dt[key]
|
|
293
|
+
fun = lambda: item is args.pkwargs[key]['kwargs'].get('default',None)
|
|
294
|
+
cond0 = fun() if key in args.pkwargs else False
|
|
295
|
+
if cond0 or key in ['func','pkwargs','command','model_parser']: continue
|
|
296
|
+
pitem = item if type(item) is not bool else ''
|
|
297
|
+
print(' --%s %s' % (key, pitem))
|
|
298
|
+
print()
|
|
299
|
+
|
|
300
|
+
args_dt = vars(args)
|
|
301
|
+
# Need to happen here because it needs to happen before numpy/scipy is imported:
|
|
302
|
+
if 'cpus' in args_dt: set_cpu_envvars(**{key:item for key, item in args_dt.items() if key=='cpus'})
|
|
303
|
+
# Initialize logs and grab certain parts:
|
|
304
|
+
from prstools.utils import get_prstlogs; import pandas as pd; import socket
|
|
305
|
+
start = pd.Timestamp.now(); hostname = socket.gethostname(); cwd=os.getcwd()
|
|
306
|
+
prstlogs = get_prstlogs()
|
|
307
|
+
prstlogs['__version__'] = __version__
|
|
308
|
+
prstlogs['times']['start'] = start
|
|
309
|
+
prstlogs['cwd'] = cwd
|
|
310
|
+
prstlogs['hostname'] = hostname
|
|
311
|
+
prstlogs['argv'] = argv
|
|
312
|
+
#prstlogs['args_dt'] = args_dt
|
|
313
|
+
if display_info:
|
|
314
|
+
envstr = '\n'.join([
|
|
315
|
+
f'Hostname: {hostname}',
|
|
316
|
+
f'Working directory: {cwd}',
|
|
317
|
+
f'Start time: {start.strftime(timestampfmt)}',
|
|
318
|
+
f'']) #Just empty line for spacing
|
|
319
|
+
print(envstr)
|
|
320
|
+
|
|
321
|
+
# Run the actual task:
|
|
322
|
+
result = args.func(**args_dt)
|
|
323
|
+
|
|
324
|
+
# Some post main-task things:
|
|
325
|
+
stop = pd.Timestamp.now(); prstlogs['times']['stop'] = stop; prstlogs.finish()
|
|
326
|
+
if display_info: print(f'End time: {stop.strftime(timestampfmt)}',)
|
|
327
|
+
# add return functionality later
|
|
328
|
+
|
|
329
|
+
if '_isdevenv_prstools' in locals() or '--dev' in sys.argv:
|
|
330
|
+
|
|
331
|
+
if 'In' in locals():
|
|
332
|
+
with open('../prstools/_cmd.py', 'w') as f: f.write(In[-1])
|
|
333
|
+
print('Written to:', f.name);
|
|
334
|
+
|
|
335
|
+
from prstools import models, utils; import importlib
|
|
336
|
+
importlib.reload(models); importlib.reload(utils)
|
|
337
|
+
|
|
338
|
+
try:
|
|
339
|
+
from prstools.models import XPRS, PRSCS2, SPRSCS, PredPRS, Dentist, SNPFilter
|
|
340
|
+
from prstools.utils import DownloadUtil, store_argparse_dicts , Combine
|
|
341
|
+
store_argparse_dicts([DownloadUtil, Combine,
|
|
342
|
+
XPRS, PRSCS2, SPRSCS, PredPRS, Dentist, SNPFilter
|
|
343
|
+
])
|
|
344
|
+
print('Saved new argparse dict. (mind: dont forget the suppress mechanism, this is something in the argparse-dict processing)')
|
|
345
|
+
except Exception as e:
|
|
346
|
+
print(e, 'Import issue.'); raise e
|
|
347
|
+
|
|
348
|
+
if 'In' in locals():
|
|
349
|
+
get_ipython().system('time python ../prstools/_cmd.py | tail -1 #l2pred # afster a normal pip install, !time prst seems to have parity with this faster approach.')
|
|
350
|
+
else:
|
|
351
|
+
if __name__ == '__main__':
|
|
352
|
+
main()
|