{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# MICOM Batch API\n",
"\n",
"The basic unit of analysis in MICOM is called a \"Batch\". It is ambiguous on purpose an can mean the following things:\n",
"\n",
"- a single microbial community (like a batch of microbes, or a batch culture)\n",
"- a data set containing multiple microbial communities/samples (batch/group of samples)\n",
"\n",
"Those are managed by the [Batch](autoapi/micom/batch/batch/index.html#micom.batch.batch.Batch) class which contains all necessary tools to simulate those communities. It is the recommended entry point for MICOM as tries to strike a good balance between sensible defaults and flexibility in your analysis.\n",
"\n",
"A batch follows this lifecycle:\n",
"\n",
"1. Create a [Batch](autoapi/micom/batch/batch/index.html#micom.batch.batch.Batch) from a taxonomy table, a growth medium, and either a model database or model files.\n",
"2. Call [build()](autoapi/micom/batch/batch/index.html#micom.batch.batch.Batch.build) to assemble one community model per sample and write a manifest.\n",
"3. Call [grow()](autoapi/micom/batch/batch/index.html#micom.batch.batch.Batch.grow) to simulate growth, then inspect the returned `GrowthResults`.\n",
"4. Use [tradeoff()](autoapi/micom/batch/batch/index.html#micom.batch.batch.Batch.tradeoff), [minimal_medium()](autoapi/micom/batch/batch/index.html#micom.batch.batch.Batch.minimal_medium), or [complete_medium()](autoapi/micom/batch/batch/index.html#micom.batch.batch.Batch.complete_medium) for follow-up analyses.\n",
"\n",
"Each batch comes with a coupled [Configuration](autoapi/micom/batch/configuration/index.html#micom.batch.configuration.Configuration) object which controls all details of the functions in the batch and that can be exported and saved to reproduce analyses in the future.\n",
"\n",
"Like mentioned above a [Batch](autoapi/micom/batch/batch/index.html#micom.batch.batch.Batch) requires the following:\n",
"\n",
"1. A table of taxon/microbe abundances.\n",
"2. \\[optional\\] a growth medium/environment\n",
"3. \\[optional\\] a model database to link taxa to metabolic models\n",
"\n",
"So let's go through those.\n",
"\n",
"## Building community models\n",
"\n",
"### Taxon abundances\n",
"\n",
"The first thing we need is a table of taxon abundances. As mentioned before this a table containing taxa and abundances. Best to look at an example first."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" id | \n",
" genus | \n",
" species | \n",
" strain | \n",
" reactions | \n",
" metabolites | \n",
" abundance | \n",
" sample_id | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" strain_a | \n",
" Escherichia | \n",
" Escherichia coli | \n",
" strain a | \n",
" 95 | \n",
" 72 | \n",
" 764 | \n",
" sample_1 | \n",
"
\n",
" \n",
" | 1 | \n",
" strain_b | \n",
" Escherichia | \n",
" Escherichia coli | \n",
" strain b | \n",
" 95 | \n",
" 72 | \n",
" 783 | \n",
" sample_1 | \n",
"
\n",
" \n",
" | 2 | \n",
" strain_c | \n",
" Escherichia | \n",
" Escherichia coli | \n",
" strain c | \n",
" 95 | \n",
" 72 | \n",
" 154 | \n",
" sample_1 | \n",
"
\n",
" \n",
" | 3 | \n",
" strain_d | \n",
" Escherichia | \n",
" Escherichia coli | \n",
" strain d | \n",
" 95 | \n",
" 72 | \n",
" 98 | \n",
" sample_1 | \n",
"
\n",
" \n",
" | 4 | \n",
" strain_a | \n",
" Escherichia | \n",
" Escherichia coli | \n",
" strain a | \n",
" 95 | \n",
" 72 | \n",
" 86 | \n",
" sample_2 | \n",
"
\n",
" \n",
" | 5 | \n",
" strain_b | \n",
" Escherichia | \n",
" Escherichia coli | \n",
" strain b | \n",
" 95 | \n",
" 72 | \n",
" 212 | \n",
" sample_2 | \n",
"
\n",
" \n",
" | 6 | \n",
" strain_c | \n",
" Escherichia | \n",
" Escherichia coli | \n",
" strain c | \n",
" 95 | \n",
" 72 | \n",
" 518 | \n",
" sample_2 | \n",
"
\n",
" \n",
" | 7 | \n",
" strain_d | \n",
" Escherichia | \n",
" Escherichia coli | \n",
" strain d | \n",
" 95 | \n",
" 72 | \n",
" 261 | \n",
" sample_2 | \n",
"
\n",
" \n",
" | 8 | \n",
" strain_a | \n",
" Escherichia | \n",
" Escherichia coli | \n",
" strain a | \n",
" 95 | \n",
" 72 | \n",
" 12 | \n",
" sample_3 | \n",
"
\n",
" \n",
" | 9 | \n",
" strain_b | \n",
" Escherichia | \n",
" Escherichia coli | \n",
" strain b | \n",
" 95 | \n",
" 72 | \n",
" 170 | \n",
" sample_3 | \n",
"
\n",
" \n",
" | 10 | \n",
" strain_c | \n",
" Escherichia | \n",
" Escherichia coli | \n",
" strain c | \n",
" 95 | \n",
" 72 | \n",
" 51 | \n",
" sample_3 | \n",
"
\n",
" \n",
" | 11 | \n",
" strain_d | \n",
" Escherichia | \n",
" Escherichia coli | \n",
" strain d | \n",
" 95 | \n",
" 72 | \n",
" 799 | \n",
" sample_3 | \n",
"
\n",
" \n",
" | 12 | \n",
" strain_a | \n",
" Escherichia | \n",
" Escherichia coli | \n",
" strain a | \n",
" 95 | \n",
" 72 | \n",
" 878 | \n",
" sample_4 | \n",
"
\n",
" \n",
" | 13 | \n",
" strain_b | \n",
" Escherichia | \n",
" Escherichia coli | \n",
" strain b | \n",
" 95 | \n",
" 72 | \n",
" 996 | \n",
" sample_4 | \n",
"
\n",
" \n",
" | 14 | \n",
" strain_c | \n",
" Escherichia | \n",
" Escherichia coli | \n",
" strain c | \n",
" 95 | \n",
" 72 | \n",
" 156 | \n",
" sample_4 | \n",
"
\n",
" \n",
" | 15 | \n",
" strain_d | \n",
" Escherichia | \n",
" Escherichia coli | \n",
" strain d | \n",
" 95 | \n",
" 72 | \n",
" 150 | \n",
" sample_4 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id genus species strain reactions metabolites \\\n",
"0 strain_a Escherichia Escherichia coli strain a 95 72 \n",
"1 strain_b Escherichia Escherichia coli strain b 95 72 \n",
"2 strain_c Escherichia Escherichia coli strain c 95 72 \n",
"3 strain_d Escherichia Escherichia coli strain d 95 72 \n",
"4 strain_a Escherichia Escherichia coli strain a 95 72 \n",
"5 strain_b Escherichia Escherichia coli strain b 95 72 \n",
"6 strain_c Escherichia Escherichia coli strain c 95 72 \n",
"7 strain_d Escherichia Escherichia coli strain d 95 72 \n",
"8 strain_a Escherichia Escherichia coli strain a 95 72 \n",
"9 strain_b Escherichia Escherichia coli strain b 95 72 \n",
"10 strain_c Escherichia Escherichia coli strain c 95 72 \n",
"11 strain_d Escherichia Escherichia coli strain d 95 72 \n",
"12 strain_a Escherichia Escherichia coli strain a 95 72 \n",
"13 strain_b Escherichia Escherichia coli strain b 95 72 \n",
"14 strain_c Escherichia Escherichia coli strain c 95 72 \n",
"15 strain_d Escherichia Escherichia coli strain d 95 72 \n",
"\n",
" abundance sample_id \n",
"0 764 sample_1 \n",
"1 783 sample_1 \n",
"2 154 sample_1 \n",
"3 98 sample_1 \n",
"4 86 sample_2 \n",
"5 212 sample_2 \n",
"6 518 sample_2 \n",
"7 261 sample_2 \n",
"8 12 sample_3 \n",
"9 170 sample_3 \n",
"10 51 sample_3 \n",
"11 799 sample_3 \n",
"12 878 sample_4 \n",
"13 996 sample_4 \n",
"14 156 sample_4 \n",
"15 150 sample_4 "
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from micom.data import test_data\n",
"\n",
"data = test_data()\n",
"data"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The table may contain additional taxonomy ranks. MICOM uses every supplied rank to make database matching more stringent. For example, supplying both `genus` and `species` requires a model to match both ranks. Omit a rank when that annotation is unreliable.\n",
"\n",
"The required columns are `id`, `sample_id`, `abundance`, and the taxonomy rank used by the model database. In this example, the database is strain-level, so the table includes `strain`. The optional `genus` and `species` columns further constrain matching.\n",
"\n",
"Apart from the required columns you can add any other columns to the table that you like. For instance, metadata for the samples, cohort subgroups, notes, etc. Here we have two additional columns tracking the number of metabolites and reactions for each model. If you only want to analyze a single sample the sample_id columns would be the same for each taxon. \n",
"\n",
"## The growth medium\n",
"\n",
"A medium must contain `reaction` and `flux` columns. Add `sample_id` when different samples need different media; without it, MICOM applies the same medium to every sample."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" reaction | \n",
" flux | \n",
" metabolite | \n",
"
\n",
" \n",
" | reaction | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" | EX_glc__D_m | \n",
" EX_glc__D_m | \n",
" 10.000000 | \n",
" glc__D_m | \n",
"
\n",
" \n",
" | EX_nh4_m | \n",
" EX_nh4_m | \n",
" 4.362240 | \n",
" nh4_m | \n",
"
\n",
" \n",
" | EX_o2_m | \n",
" EX_o2_m | \n",
" 18.579253 | \n",
" o2_m | \n",
"
\n",
" \n",
" | EX_pi_m | \n",
" EX_pi_m | \n",
" 2.942960 | \n",
" pi_m | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" reaction flux metabolite\n",
"reaction \n",
"EX_glc__D_m EX_glc__D_m 10.000000 glc__D_m\n",
"EX_nh4_m EX_nh4_m 4.362240 nh4_m\n",
"EX_o2_m EX_o2_m 18.579253 o2_m\n",
"EX_pi_m EX_pi_m 2.942960 pi_m"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from micom.data import test_medium\n",
"from micom.qiime_formats import load_qiime_medium\n",
"\n",
"medium = load_qiime_medium(test_medium)\n",
"medium"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Building community models\n",
"\n",
"To build one community model for each sample, provide an abundance/taxonomy table and a model database. MICOM databases can be downloaded from the [MICOM Zenodo record](https://doi.org/10.5281/zenodo.3755182), or you can provide your own database. A database is optional when every row in the taxonomy table includes a `file` column pointing to an individual model.\n",
"\n",
"The `Batch` constructor validates the taxonomy and medium immediately. This makes input errors visible before the more expensive build step."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/html": [
"Batch [mercer_proteus]\n",
"\n",
"| 4 samples | 4 taxa |
\n",
"| model DB | ✅ | strain_models.qza |
\n",
"| medium | ✅ | 4 compounds, total flux = 35.88 mmol/(gDW·h) |
\n",
"| build | ❌ | \n",
"
| simulated | ❌ |
| tradeoffs | ❌ | \n",
"
\n"
],
"text/plain": [
""
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from micom import Batch\n",
"from micom.data import test_medium, test_db\n",
"\n",
"batch = Batch(\n",
" taxonomy=data,\n",
" medium=test_medium,\n",
" model_db=test_db,\n",
")\n",
"batch"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"[cutoff](autoapi/micom/batch/configuration/index.html#micom.batch.configuration.Configuration.build) and [threads](autoapi/micom/batch/configuration/index.html#micom.batch.configuration.Configuration.threads) are configured on `batch.config` rather than passed to [Batch.build()](autoapi/micom/batch/batch/index.html#micom.batch.batch.Batch.build) directly. The default cutoff keeps taxa representing at least 0.01% of a sample. The build workflow is parallelized using `batch.config.threads`; set `batch.config.build.force_rebuild = True` when existing pickle files should be replaced.\n",
"\n",
"The [build()](autoapi/micom/batch/batch/index.html#micom.batch.batch.Batch.build) workflow returns a manifest and stores it on `batch.build_manifest`. It also sets `batch.out_folder`, which later workflows use to locate the community models."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "c4927883c7e94c92b31eaaff2e09d4a0",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Output()"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"\n"
],
"text/plain": []
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"Batch [mercer_proteus]\n",
"\n",
"| 4 samples | 4 taxa |
\n",
"| model DB | ✅ | strain_models.qza |
\n",
"| medium | ✅ | 4 compounds, total flux = 35.88 mmol/(gDW·h) |
\n",
"| build | ✅ | \n",
"found 100.00 ± 0.00% of abundance |
\n",
"| simulated | ❌ |
| tradeoffs | ❌ | \n",
"
\n"
],
"text/plain": [
""
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"manifest = batch.build(\"models\")\n",
"batch"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This will propagate information from your input table as well as give you metrics on how well the samples were matched to the database. Our database only include models for the first 3 *E. coli* species so you see the workflow could only match 3/4 taxa for each sample. Probably the most important column is the `found_abundance_fraction`. This one tells which fraction of the sample abundance was matched to the database. You usually want this column to be above 0.5 so the majority of the sample is matched. A value of 1.0 would be perfect but is usually hard to achieve. Values around 0.8 are usually pretty good.\n",
"\n",
"The `file` column denotes the filename for the built community within the folder specified as `out_folder` before. You can use the `load_pickle` function to read individual models and run custom analyses. "
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"400\n"
]
}
],
"source": [
"from micom import load_pickle\n",
"\n",
"com = load_pickle(\"models/sample_1.pickle\")\n",
"print(len(com.reactions))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Simulating growth\n",
"\n",
"After [build()](autoapi/micom/batch/batch/index.html#micom.batch.batch.Batch.build) has completed, [grow()](autoapi/micom/batch/batch/index.html#micom.batch.batch.Batch.grow) simulates each community using `batch.medium` and the simulation settings in `batch.config`. The default strategy is cooperative tradeoff. A medium describes which external metabolites can be imported and their maximum fluxes; it can come from a DataFrame, CSV file, or Qiime 2 artifact.\n",
"\n",
"A medium must contain `reaction` and `flux` columns. Add `sample_id` when different samples need different media; without it, MICOM applies the same medium to every sample."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" reaction | \n",
" flux | \n",
" metabolite | \n",
"
\n",
" \n",
" | reaction | \n",
" | \n",
" | \n",
" | \n",
"
\n",
" \n",
" \n",
" \n",
" | EX_glc__D_m | \n",
" EX_glc__D_m | \n",
" 10.000000 | \n",
" glc__D_m | \n",
"
\n",
" \n",
" | EX_nh4_m | \n",
" EX_nh4_m | \n",
" 4.362240 | \n",
" nh4_m | \n",
"
\n",
" \n",
" | EX_o2_m | \n",
" EX_o2_m | \n",
" 18.579253 | \n",
" o2_m | \n",
"
\n",
" \n",
" | EX_pi_m | \n",
" EX_pi_m | \n",
" 2.942960 | \n",
" pi_m | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" reaction flux metabolite\n",
"reaction \n",
"EX_glc__D_m EX_glc__D_m 10.000000 glc__D_m\n",
"EX_nh4_m EX_nh4_m 4.362240 nh4_m\n",
"EX_o2_m EX_o2_m 18.579253 o2_m\n",
"EX_pi_m EX_pi_m 2.942960 pi_m"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from micom.data import test_medium\n",
"from micom.qiime_formats import load_qiime_medium\n",
"\n",
"medium = load_qiime_medium(test_medium)\n",
"medium"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The growth medium is represented as a DataFrame with `reaction` and `flux` columns. The `flux` value is the upper bound for import, usually in mmol/gDW/h.\n",
"\n",
"The `tradeoff` setting controls how much community growth is preserved while individual growth is optimized. It must be between 0 and 1: `1.0` preserves maximum community growth, while smaller values allow more individual optimization. The default value is read from `batch.config.simulation.tradeoff`."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "f51ed7f349f64575b183b8b37c95c269",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Output()"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"\n"
],
"text/plain": []
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"Batch [mercer_proteus]\n",
"\n",
"| 4 samples | 4 taxa |
\n",
"| model DB | ✅ | strain_models.qza |
\n",
"| medium | ✅ | 4 compounds, total flux = 35.88 mmol/(gDW·h) |
\n",
"| build | ✅ | \n",
"found 100.00 ± 0.00% of abundance |
\n",
"| simulated | ✅ | μᵢ = 0.25 ± 0.20 1/h |
\n",
"| tradeoffs | ❌ | \n",
"
\n"
],
"text/plain": [
""
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"results = batch.grow()\n",
"batch"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"[grow()](autoapi/micom/batch/batch/index.html#micom.batch.batch.Batch.grow) returns a `GrowthResults` object with three DataFrames: `growth_rates`, `exchanges`, and `annotations`. The same object is stored in `batch.results`, so it remains available for later analysis and visualization. The `has_results` property reports whether growth has been simulated."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Choosing a tradeoff parameter\n",
"\n",
"Results depend strongly on the tradeoff parameter. Even though values between 0.3-0.6 usually work well we recommend to run a tradeoff analysis to choose the best parameters for your data set and protocol. If you have already analyzed many samples in your lab and found a particular value to work well in general you may just use that but you should at least run this analysis once. In [our paper](https://doi.org/10.1128/mSystems.00606-19) we found that tradeoff best reproducing *in vivo* growth rates is the largest tradeoff that allows the majority of the bacteria to grow. Thus, the best tradeoff value is the value providing the best compromise between individual and cooperative growth. \n",
"\n",
"The `tradeoff` workflow will run growth simulations with several tradeoff values and return the results. "
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "0dcd0692f561460c8bb2da993b934132",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Output()"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"\n"
],
"text/plain": []
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"Batch [mercer_proteus]\n",
"\n",
"| 4 samples | 4 taxa |
\n",
"| model DB | ✅ | strain_models.qza |
\n",
"| medium | ✅ | 4 compounds, total flux = 35.88 mmol/(gDW·h) |
\n",
"| build | ✅ | \n",
"found 100.00 ± 0.00% of abundance |
\n",
"| simulated | ✅ | μᵢ = 0.25 ± 0.20 1/h |
\n",
"| tradeoffs | ✅ | \n",
"growing fraction: 100.00 - 100.00% |
\n",
"
\n"
],
"text/plain": [
""
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tradeoff = batch.tradeoff()\n",
"batch"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As we see it returns growth rates for each taxon in each sample for various tradeoff values. There is also a tradeoff value of `NaN` which means optimization of the pure community growth rate without regularization which usually has very bad performance and is provided as a reference. To choose a good value we can count how many of the taxa can grow (growth rate > 1e-6) on average for each of the tradeoff values across all samples."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/tmp/ipykernel_202114/632618865.py:1: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.\n",
" tradeoff.groupby(\"tradeoff\", dropna=False).apply(\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" tradeoff | \n",
" 0 | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 0.1 | \n",
" 16 | \n",
"
\n",
" \n",
" | 1 | \n",
" 0.2 | \n",
" 16 | \n",
"
\n",
" \n",
" | 2 | \n",
" 0.3 | \n",
" 16 | \n",
"
\n",
" \n",
" | 3 | \n",
" 0.4 | \n",
" 16 | \n",
"
\n",
" \n",
" | 4 | \n",
" 0.5 | \n",
" 16 | \n",
"
\n",
" \n",
" | 5 | \n",
" 0.6 | \n",
" 16 | \n",
"
\n",
" \n",
" | 6 | \n",
" 0.7 | \n",
" 16 | \n",
"
\n",
" \n",
" | 7 | \n",
" 0.8 | \n",
" 16 | \n",
"
\n",
" \n",
" | 8 | \n",
" 0.9 | \n",
" 16 | \n",
"
\n",
" \n",
" | 9 | \n",
" 1.0 | \n",
" 16 | \n",
"
\n",
" \n",
" | 10 | \n",
" NaN | \n",
" 11 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" tradeoff 0\n",
"0 0.1 16\n",
"1 0.2 16\n",
"2 0.3 16\n",
"3 0.4 16\n",
"4 0.5 16\n",
"5 0.6 16\n",
"6 0.7 16\n",
"7 0.8 16\n",
"8 0.9 16\n",
"9 1.0 16\n",
"10 NaN 11"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tradeoff.groupby(\"tradeoff\", dropna=False).apply(\n",
" lambda df: (df.growth_rate > 1e-6).sum()).reset_index()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here all taxa can grow for every tested tradeoff because the example medium provides excess nutrients. For real data, the fraction of growing taxa often declines as the tradeoff increases. The [`plot_tradeoff`](viz.html) visualization can show this relationship in more detail."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Finding and completing growth media\n",
"\n",
"[minimal_medium()](autoapi/micom/batch/batch/index.html#micom.batch.batch.Batch.minimal_medium) finds a medium that enables the requested community and taxon growth rates while minimizing a chosen criterion. It starts from the full set of possible imports.\n",
"\n",
"[complete_medium()](autoapi/micom/batch/batch/index.html#micom.batch.batch.Batch.complete_medium) instead augments an existing medium for the built communities. Use it when you have a plausible starting medium and want MICOM to add only the imports required to meet the growth targets. The two methods account for different scopes: [minimal_medium()](autoapi/micom/batch/batch/index.html#micom.batch.batch.Batch.minimal_medium) searches from scratch, while [complete_medium()](autoapi/micom/batch/batch/index.html#micom.batch.batch.Batch.complete_medium) preserves the supplied medium."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" reaction | \n",
" flux | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" EX_glc__D_m | \n",
" 10 | \n",
"
\n",
" \n",
" | 1 | \n",
" EX_o2_m | \n",
" 20 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" reaction flux\n",
"0 EX_glc__D_m 10\n",
"1 EX_o2_m 20"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import pandas as pd\n",
"\n",
"candidate_medium = pd.DataFrame({\"reaction\": [\"EX_glc__D_m\", \"EX_o2_m\"], \"flux\": [10, 20]})\n",
"candidate_medium"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can now ask MICOM to complete this medium by adding the smallest amount of overall flux so that all taxa in the database can grow with a growth rate off at least 0.1 1/h. "
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "b048f0a59b634a1d9958969f33b7b62a",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Output()"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"\n"
],
"text/plain": []
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" reaction | \n",
" metabolite | \n",
" description | \n",
" flux | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" EX_glc__D_m | \n",
" glc__D_m | \n",
" D-Glucose | \n",
" 10.00000 | \n",
"
\n",
" \n",
" | 1 | \n",
" EX_nh4_m | \n",
" nh4_m | \n",
" Ammonium | \n",
" 0.54528 | \n",
"
\n",
" \n",
" | 2 | \n",
" EX_o2_m | \n",
" o2_m | \n",
" O2 | \n",
" 20.00000 | \n",
"
\n",
" \n",
" | 3 | \n",
" EX_pi_m | \n",
" pi_m | \n",
" Phosphate | \n",
" 0.36787 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" reaction metabolite description flux\n",
"0 EX_glc__D_m glc__D_m D-Glucose 10.00000\n",
"1 EX_nh4_m nh4_m Ammonium 0.54528\n",
"2 EX_o2_m o2_m O2 20.00000\n",
"3 EX_pi_m pi_m Phosphate 0.36787"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"batch.complete_medium(community_growth=0.1, taxa_growth=0.01, medium=candidate_medium)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So we see that we can achieve growth by adding import for phosphate and ammonium."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "micom (3.14.7)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.14.7"
}
},
"nbformat": 4,
"nbformat_minor": 4
}