imatpy 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
imatpy-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,369 @@
1
+ Metadata-Version: 2.1
2
+ Name: imatpy
3
+ Version: 0.1.0
4
+ Summary: "Python implementation of the Integrative Metabolic Analysis Tool (iMAT) algorithm for context specific metabolic modeling."
5
+ License: MIT
6
+ Author: Braden Griebel
7
+ Requires-Python: >3.9,<3.11
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Provides-Extra: cplex
12
+ Provides-Extra: gurobipy
13
+ Requires-Dist: cobra (>=0.27.0,<0.28.0)
14
+ Requires-Dist: cplex (==22.1.1.0) ; extra == "cplex"
15
+ Requires-Dist: gurobipy (>=10.0.3,<11.0.0) ; extra == "gurobipy"
16
+ Requires-Dist: numpy (>=1.26.0,<2.0.0)
17
+ Requires-Dist: optlang (>=1.7.0,<2.0.0)
18
+ Requires-Dist: pandas (>=1.0.0,<2.0.0)
19
+ Requires-Dist: scipy (>=1.11.3,<2.0.0)
20
+ Requires-Dist: sympy (>=1.12,<2.0)
21
+ Description-Content-Type: text/markdown
22
+
23
+ # Readme
24
+
25
+ <img src="./imatpy_logo.png" height="60" alt="logo" />
26
+
27
+ [![Documentation
28
+ Status](https://readthedocs.org/projects/imatpy/badge/?version=latest.png)](https://imatpy.readthedocs.io/en/latest/?badge=latest)
29
+ ![Tests](https://github.com/Braden-Griebel/imatpy/actions/workflows/tests.yml/badge.svg)
30
+
31
+ ## About
32
+
33
+ iMATpy is a python package implementing the iMAT algorithm for
34
+ integrating gene expression information with a genome scale metabolic
35
+ model, described in [(Shlomi T, et al. Network-based prediction of human
36
+ tissue-specific metabolism, Nat. Biotechnol., 2008, vol. 26 (pg.
37
+ 1003-1010))](https://www.nature.com/articles/nbt.1487).
38
+
39
+ ## Background
40
+
41
+ The iMAT algorithm takes a genome scale metabolic model (GSM), and gene
42
+ expression weights, then tries to find a feasible flux distribution
43
+ which maximizes the sum of reactions with high expression which have a
44
+ flux above `epsilon`, and reactions with low expression which have a
45
+ flux below `threshold`.
46
+
47
+ ## Installation
48
+
49
+ This package can be installed via pip
50
+
51
+ ``` python
52
+ pip install imatpy
53
+ ```
54
+
55
+ ## Solvers
56
+
57
+ In order to solve the optimization problems associated with iMAT, a
58
+ LP/MILP solver is required. By default this package uses the
59
+ [GLPK](https://www.gnu.org/software/glpk/) solver which is installed
60
+ automatically by COBRApy, but [Gurobi](https://www.gurobi.com/) and
61
+ [CPLEX](https://www.ibm.com/products/ilog-cplex-optimization-studio/cplex-optimizer).
62
+ Both Gurobi and CPLEX have free academic licenses available.
63
+
64
+ ## Workflow
65
+
66
+ The general workflow for using this package is as follows:
67
+
68
+ 1. Normalize gene expression data for sequencing depth and gene length
69
+ (TPM or RPKM both work well)
70
+ 2. Quantile normalize the gene expression data (for example with the
71
+ [`qnorm` package](https://pypi.org/project/qnorm/)) (This is
72
+ optional, but can help make the results less sensitive to
73
+ parameters)
74
+ 3. Combine gene expression values accross samples, for example by
75
+ taking the mean or median
76
+ 4. Convert the gene expression data into qualitative weights, of -1, 0,
77
+ or 1, where -1 represents low expression, 1 represents high
78
+ expression, and 0 represents all other genes. This can be done by
79
+ setting the bottom 15% of genes to -1, the top 15% of genes to 1,
80
+ and all other genes to 0. Other percentiles can be used, but 15% is
81
+ a decent starting point.
82
+ 5. Using the `parse_gpr` submodule, specifically the
83
+ `gene_to_rxn_weights` function, convert the gene weights into
84
+ reaction weights using the GPR rules in the model.
85
+ 6. Either generate a flux distribution with the iMAT algorithm, or
86
+ construct a new model with restrictions based on iMAT results.
87
+ - To generate a flux distribution, use the `imatpy.imat` submodule,
88
+ specifically the `imat` function. This function takes a model, and
89
+ a series of reaction weights, and returns a flux distribution
90
+ which maximizes the sum of reactions with high expression which
91
+ have a flux above `epsilon`, and reactions with low expression
92
+ which have a flux below `threshold`.
93
+ - To generate a model with restrictions based on the iMAT results,
94
+ use the `model_creation` submodule. It includes a variety of
95
+ different methods for generating models based on iMAT, with a
96
+ wrapper function `generate_model` for convinience.
97
+
98
+ ## Parse GPR
99
+
100
+ The `parse_gpr` submodule has functions for applying the
101
+ gene-protien-reaction (GPR) rules in a model to gene weights in order to
102
+ convert gene weights into reaction weights which can act as input to the
103
+ iMAT algorithm.
104
+
105
+ The input to this method is a pandas Series with the index being the
106
+ gene identifiers, and the values being the gene weights. The output is a
107
+ pandas Series with the index being the reaction identifiers, and the
108
+ values being the reaction weights. This method only handles a single
109
+ series, so the gene expression data must be processed into single
110
+ weights (with -1 representing lowly expressed genes, 1 representing
111
+ highly expressed genes, and 0 for all other genes).
112
+
113
+ Here is an example of how to use this method:
114
+
115
+ ``` python
116
+ # External imports
117
+ import pandas as pd
118
+
119
+ # iMATpy imports
120
+ from imatpy.model_utils import read_model
121
+ from imatpy.parse_gpr import gene_to_rxn_weights
122
+
123
+ # Read in the model
124
+ model = read_model("./tests/data/test_model.xml")
125
+
126
+ # Create a pandas Series representing gene expression weights
127
+ model_weights = pd.Series({
128
+ "g_A_imp": 1,
129
+ "g_B_imp": -1,
130
+ "g_C_imp": -1,
131
+ "g_F_exp": 0,
132
+ "g_G_exp": -1,
133
+ "g_H_exp": 0,
134
+ "g_A_B_D_E": 0,
135
+ "g_C_E_F": -1,
136
+ "g_C_H": 0,
137
+ "g_D_G": 1,
138
+ })
139
+
140
+ # Convert the gene weights into reaction weights
141
+ reaction_weights = gene_to_rxn_weights(model=model, gene_weights=model_weights)
142
+
143
+ # Print the reaction weights
144
+ print(reaction_weights)
145
+ ```
146
+
147
+ R_A_e_ex 0.0
148
+ R_B_e_ex 0.0
149
+ R_C_e_ex 0.0
150
+ R_F_e_ex 0.0
151
+ R_G_e_ex 0.0
152
+ R_H_e_ex 0.0
153
+ R_A_imp 1.0
154
+ R_B_imp -1.0
155
+ R_C_imp -1.0
156
+ R_F_exp 0.0
157
+ R_G_exp -1.0
158
+ R_H_exp 0.0
159
+ r_A_B_D_E 0.0
160
+ r_C_E_F -1.0
161
+ r_C_H 0.0
162
+ r_D_G 1.0
163
+ dtype: float64
164
+
165
+ ## iMAT Methods
166
+
167
+ The `imat` submodule contains functions for running the iMAT algorithm.
168
+ The main function is `imat`, which takes a model, and a series of
169
+ reaction weights, and returns a flux distribution which maximizes the
170
+ sum of reactions with high expression which have a flux above `epsilon`,
171
+ and reactions with low expression which have a flux below `threshold`.
172
+
173
+ Here is an example of how to use this method:
174
+
175
+ ``` python
176
+ # External imports
177
+ import pandas as pd
178
+
179
+ # iMATpy imports
180
+ from imatpy.model_utils import read_model
181
+ from imatpy.imat import imat
182
+
183
+ # Read in the model
184
+ model = read_model("./tests/data/test_model.xml")
185
+
186
+ # Read in the reaction weights
187
+ rxn_weights = pd.read_csv("./tests/data/test_model_reaction_weights.csv", index_col=0).squeeze()
188
+
189
+ # Run iMAT
190
+ imat_results = imat(model=model, rxn_weights=rxn_weights, epsilon=1, threshold=0.01)
191
+
192
+ # Print the imat objective
193
+ print(f"iMAT Objective: {imat_results.objective_value}")
194
+
195
+ # Print the imat flux distribution
196
+ print(f"iMAT Flux Distribution: \n{imat_results.fluxes}")
197
+ ```
198
+
199
+ iMAT Objective: 3.0
200
+ iMAT Flux Distribution:
201
+ R_A_e_ex -1.0
202
+ R_B_e_ex -1.0
203
+ R_C_e_ex -1.0
204
+ R_F_e_ex 1.0
205
+ R_G_e_ex 1.0
206
+ R_H_e_ex -0.0
207
+ R_A_imp 1.0
208
+ R_B_imp 1.0
209
+ R_C_imp 1.0
210
+ R_F_exp 1.0
211
+ R_G_exp 1.0
212
+ R_H_exp 0.0
213
+ r_A_B_D_E 1.0
214
+ r_C_E_F 1.0
215
+ r_C_H 0.0
216
+ r_D_G 1.0
217
+ Name: fluxes, dtype: float64
218
+
219
+ ## Model Creation
220
+
221
+ The `model_creation` submodule contains functions for creating new
222
+ models based on the results of iMAT. The main function is
223
+ `generate_model`, which takes a model, and a series of reaction weights,
224
+ and returns a new model with restrictions based on the iMAT results.
225
+
226
+ The available methods for creating a model based on an iMAT flux
227
+ distribution is:
228
+ - `imat_restrictions` Adds the binary variables and constraints used in
229
+ the iMAT algorithm, as well as an additional constraint ensuring that
230
+ the flux distribution is within tolerance of the optimal iMAT objective
231
+ value. This method stays closest to the iMAT objective, but the included
232
+ indicator (binary) variables mean that is unsuitable for sampling.
233
+
234
+ - `simple_bounds` Adds bounds on the reactions found to be “on”, and
235
+ “off” in iMAT. For all the highly expressed reactions found to be
236
+ “on”, the flux is constrained to be at least `epsilon`. For all the
237
+ lowly expressed reactions found to be “off”, the flux is constrained
238
+ to be below `threshold`.
239
+
240
+ - `subset` Removes reactions from the model which are found to be “off”.
241
+ For all the lowly expressed reactions found to be off, they are
242
+ constrained to have a flux below `threshold`.
243
+
244
+ - `fva` Finds bounds using an FVA like approach. A temporary model is
245
+ created in a simmilar way to the
246
+
247
+ - `imat_restrictions` method above, which includes the imat variables,
248
+ constraints, and which also constrains the flux distribution to be
249
+ near optimal for iMAT. The maximum and minimum fluxes allowed through
250
+ each reaction (while still maintaining the optimal iMAT objective) is
251
+ found. These values are used as the new reaction bounds. It should be
252
+ noted, that although the individual upper and lower bounds for the
253
+ reaction are achievable for each reation while being consistant with
254
+ the optimal iMAT objective, this doesn’t guarantee that the flux
255
+ distribution overall is consistant with the optimal iMAT objective.
256
+
257
+ - `milp` Uses a set of mixed integer linear programs to find whether a
258
+ reaction should be forced off, forward, or reverse. Each reaction in
259
+ turn is forced to be off, active in the forward direction, and active
260
+ in the reverse direction, and the iMAT objective is maximized. Whether
261
+ a reaction should be forced off, or active in either the forward or
262
+ reverse direction is then determined by which direction maximizes the
263
+ iMAT objective. Again, it should be noted that this doesn’t guarantee
264
+ that the iMAT objective is overall maximized by solutions to this
265
+ model.
266
+
267
+ Below is an example of how to generate a model with iMAT restrictions:
268
+
269
+ ``` python
270
+ # External imports
271
+ import pandas as pd
272
+
273
+ # iMATpy imports
274
+ from imatpy.model_utils import read_model
275
+ from imatpy.model_creation import generate_model
276
+
277
+ # Read in the model
278
+ model = read_model("./tests/data/test_model.xml")
279
+
280
+ # Read in the reaction weights
281
+ rxn_weights = pd.read_csv("./tests/data/test_model_reaction_weights.csv", index_col=0).squeeze()
282
+
283
+ # Generate a model with iMAT restrictions
284
+ imat_model = generate_model(model=model, rxn_weights=rxn_weights, method="fva", epsilon=1, threshold=0.01)
285
+
286
+ # This model can be used for sampling, finding optimal biomass generation, finding essential genes, etc.
287
+ optimal_biomass = imat_model.slim_optimize()
288
+
289
+ print(f"Optimal Biomass: {optimal_biomass}")
290
+ ```
291
+
292
+ Optimal Biomass: 50.0
293
+
294
+ ## Model Utils
295
+
296
+ The `model_utils` submodule contains several utility functions for
297
+ working with COBRApy models. Specifically, it contains functions for: -
298
+ Reading and writing models in various formats with a single function,
299
+ specifically `read_model`/`write_model`. - Determining if two models are
300
+ equivalent, using `model_eq`.
301
+
302
+ Here is an example of how to use the model IO methods:
303
+
304
+ ``` python
305
+ # iMATpy imports
306
+ from imatpy.model_utils import read_model, write_model, model_eq
307
+
308
+ # You can read in a model from a file
309
+ model = read_model("./tests/data/test_model.xml") # in SBML
310
+ model = read_model("./tests/data/test_model.json") # in JSON
311
+ model = read_model("./tests/data/test_model.yml") # in YAML
312
+ model = read_model("./tests/data/test_model.mat") # in Matlab
313
+
314
+ # You can also write a model to a file
315
+ write_model(model, "./tests/data/test_model.xml") # in SBML
316
+ write_model(model, "./tests/data/test_model.json") # in JSON
317
+ write_model(model, "./tests/data/test_model.yml") # in YAML
318
+ write_model(model, "./tests/data/test_model.mat") # in Matlab
319
+ ```
320
+
321
+ Here is an example of using the model comparison method:
322
+
323
+ ``` python
324
+ # iMATpy imports
325
+ from imatpy.model_utils import read_model, model_eq
326
+
327
+ # Read a model
328
+ model = read_model("./tests/data/test_model.xml")
329
+
330
+ # Create a copy of the model
331
+ model_copy = model.copy()
332
+
333
+ # Check that the models are equivalent
334
+ print(f"Models are equivalent: {model_eq(model, model_copy)}")
335
+
336
+ # Change the copy model
337
+ model_copy.reactions.get_by_id("r_A_B_D_E").lower_bound = -314
338
+
339
+ # Check that the models are no longer equivalent
340
+ print(f"Models are equivalent: {model_eq(model, model_copy)}")
341
+ ```
342
+
343
+ Models are equivalent: True
344
+ Models are equivalent: False
345
+
346
+ ## License
347
+
348
+ This package itself is relased under an MIT license. It makes use of
349
+ several libraries which are listed below:
350
+ - COBRApy: Released under the LGPL-2.0-or-later license see
351
+ [here](https://github.com/opencobra/cobrapy/blob/devel/LICENSE)
352
+ - Numpy: Released under the BSD-3-Clause license see
353
+ [here](https://github.com/numpy/numpy/blob/main/LICENSE.txt)
354
+ - Optlang: Released under the Apache-2.0 lisence see
355
+ [here](https://github.com/opencobra/optlang/blob/master/LICENSE)
356
+ - Pandas: Released under the BSD-3-Clause license see
357
+ [here](https://github.com/pandas-dev/pandas/blob/main/LICENSE)
358
+ - Scipy: Released under the BSD-3-Clause license see
359
+ [here](https://github.com/scipy/scipy/blob/main/LICENSE.txt)
360
+ - Sympy: Released under the BSD-3-Clause license see
361
+ [here](https://github.com/sympy/sympy/blob/master/LICENSE)
362
+
363
+ In addition, these libraries were used during developement:
364
+ - black: Used for autoformating
365
+ - jupyter: Used for rendering quarto documents - flake8: Used for
366
+ linting - pytest: Used for running unittests
367
+ - Sphinx: Used for generating documentation
368
+ - sphinx-rtd-theme: Used for formating the documentation
369
+