{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Growth media\n", "\n", "The availability of nutrients has a major impact on metabolic fluxes and `cobrapy` provides some helpers to manage the exchanges between the external environment and your metabolic model. In experimental settings the \"environment\" is usually constituted by the growth medium, ergo the concentrations of all metabolites and co-factors available to the modeled organism. However, constraint-based metabolic models only consider fluxes. Thus, you can not simply use concentrations since fluxes have the unit `mmol / [gDW h]` (concentration per gram dry weight of cells and hour). \n", "\n", "Also, you are setting an upper bound for the particular import flux and not the flux itself. There are some crude approximations. For instance, if you supply 1 mol of glucose every 24h to 1 gram of bacteria you might set the upper exchange flux for glucose to `1 mol / [1 gDW * 24 h]` since that is the nominal maximum that can be imported. There is no guarantee however that glucose will be consumed with that flux. Thus, the preferred data for exchange fluxes are direct flux measurements as the ones obtained from timecourse exa-metabolome measurements for instance. \n", "\n", "So how does that look in COBRApy? The current growth medium of a model is managed by the `medium` attribute. " ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Scaling...\n", " A: min|aij| = 1.000e+00 max|aij| = 1.000e+00 ratio = 1.000e+00\n", "Problem data seem to be well scaled\n" ] }, { "data": { "text/plain": [ "{'EX_co2_e': 1000.0,\n", " 'EX_glc__D_e': 10.0,\n", " 'EX_h_e': 1000.0,\n", " 'EX_h2o_e': 1000.0,\n", " 'EX_nh4_e': 1000.0,\n", " 'EX_o2_e': 1000.0,\n", " 'EX_pi_e': 1000.0}" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from cobra.io import load_model\n", "\n", "model = load_model(\"textbook\")\n", "model.medium" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This will return a dictionary that contains the upper flux bounds for all active exchange fluxes (the ones having non-zero flux bounds). Right now we see that we have enabled aerobic growth. You can modify a growth medium of a model by assigning a dictionary to `model.medium` that maps exchange reactions to their respective upper import bounds. For now let us enforce anaerobic growth by shutting off the oxygen import." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'EX_co2_e': 1000.0,\n", " 'EX_glc__D_e': 10.0,\n", " 'EX_h_e': 1000.0,\n", " 'EX_h2o_e': 1000.0,\n", " 'EX_nh4_e': 1000.0,\n", " 'EX_pi_e': 1000.0}" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "medium = model.medium\n", "medium[\"EX_o2_e\"] = 0.0\n", "model.medium = medium\n", "\n", "model.medium" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we can see oxygen import is now removed from the list of active exchanges and we can verify that this also leads to a lower growth rate." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.21166294973530736" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model.slim_optimize()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There is a small trap here. `model.medium` can not be assigned to directly. So the following will not work:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'EX_co2_e': 1000.0,\n", " 'EX_glc__D_e': 10.0,\n", " 'EX_h_e': 1000.0,\n", " 'EX_h2o_e': 1000.0,\n", " 'EX_nh4_e': 1000.0,\n", " 'EX_pi_e': 1000.0}" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model.medium[\"EX_co2_e\"] = 0.0\n", "model.medium" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As you can see `EX_co2_e` is not set to zero. This is because model.medium is just a copy of the current exchange fluxes. Assigning to it directly with `model.medium[...] = ...` will **not** change the model. You have to assign an entire dictionary with the changed import flux upper bounds:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'EX_glc__D_e': 10.0,\n", " 'EX_h_e': 1000.0,\n", " 'EX_h2o_e': 1000.0,\n", " 'EX_nh4_e': 1000.0,\n", " 'EX_pi_e': 1000.0}" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "medium = model.medium\n", "medium[\"EX_co2_e\"] = 0.0\n", "model.medium = medium\n", "\n", "model.medium # now it worked" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Setting the growth medium also connects to the context manager, so you can set a specific growth medium in a reversible manner." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.21166294973530736\n", "0.8739215069684102\n" ] }, { "data": { "text/plain": [ "{'EX_co2_e': 1000.0,\n", " 'EX_glc__D_e': 10.0,\n", " 'EX_h_e': 1000.0,\n", " 'EX_h2o_e': 1000.0,\n", " 'EX_nh4_e': 1000.0,\n", " 'EX_o2_e': 1000.0,\n", " 'EX_pi_e': 1000.0}" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model = load_model(\"textbook\")\n", "\n", "with model:\n", " medium = model.medium\n", " medium[\"EX_o2_e\"] = 0.0\n", " model.medium = medium\n", " print(model.slim_optimize())\n", "print(model.slim_optimize())\n", "model.medium" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So the medium change is only applied within the `with` block and reverted automatically." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Minimal media\n", "\n", "In some cases you might be interested in the smallest growth medium that can maintain a specific growth rate, the so called \"minimal medium\". For this we provide the function `minimal_medium` which by default obtains the medium with the lowest total import flux. This function needs two arguments: the model and the minimum growth rate (or other objective) the model has to achieve." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "EX_glc__D_e 10.000000\n", "EX_nh4_e 4.765319\n", "EX_o2_e 21.799493\n", "EX_pi_e 3.214895\n", "dtype: float64" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from cobra.medium import minimal_medium\n", "\n", "max_growth = model.slim_optimize()\n", "minimal_medium(model, max_growth)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So we see that growth is actually limited by glucose import.\n", "\n", "Alternatively you might be interested in a minimal medium with the smallest number of active imports. This can be achieved by using the `minimize_components` argument (note that this uses a MIP formulation and will therefore be much slower)." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "EX_glc__D_e 10.00000\n", "EX_nh4_e 0.54528\n", "EX_pi_e 0.36787\n", "dtype: float64" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "minimal_medium(model, 0.1, minimize_components=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When minimizing the number of import fluxes there may be many alternative solutions. To obtain several of those you can also pass a positive integer to `minimize_components` which will give you at most that many alternative solutions. Let us try that with our model and also use the `open_exchanges` argument which will assign a large upper bound to all import reactions in the model. The return type will be a `pandas.DataFrame`." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
012345
EX_fru_e0.000000308.829440.0000031.585960.0000000.000000
EX_glc__D_e0.0000000.00000308.829440.0000031.1571040.000000
EX_gln__L_e0.0000000.000000.000002.181120.00000018.848678
EX_glu__L_e277.5880566.108406.108400.000000.0000000.000000
EX_mal__L_e0.0000000.000000.000000.000000.0000001000.000000
EX_nh4_e0.0000000.000000.000000.000004.3622400.000000
EX_o2_e500.0000000.000000.000000.000000.0000000.000000
EX_pi_e46.9449762.942962.942962.942962.94296012.583458
\n", "
" ], "text/plain": [ " 0 1 2 3 4 \\\n", "EX_fru_e 0.000000 308.82944 0.00000 31.58596 0.000000 \n", "EX_glc__D_e 0.000000 0.00000 308.82944 0.00000 31.157104 \n", "EX_gln__L_e 0.000000 0.00000 0.00000 2.18112 0.000000 \n", "EX_glu__L_e 277.588056 6.10840 6.10840 0.00000 0.000000 \n", "EX_mal__L_e 0.000000 0.00000 0.00000 0.00000 0.000000 \n", "EX_nh4_e 0.000000 0.00000 0.00000 0.00000 4.362240 \n", "EX_o2_e 500.000000 0.00000 0.00000 0.00000 0.000000 \n", "EX_pi_e 46.944976 2.94296 2.94296 2.94296 2.942960 \n", "\n", " 5 \n", "EX_fru_e 0.000000 \n", "EX_glc__D_e 0.000000 \n", "EX_gln__L_e 18.848678 \n", "EX_glu__L_e 0.000000 \n", "EX_mal__L_e 1000.000000 \n", "EX_nh4_e 0.000000 \n", "EX_o2_e 0.000000 \n", "EX_pi_e 12.583458 " ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "minimal_medium(model, 0.8, minimize_components=8, open_exchanges=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So there are 4 alternative solutions in total. One aerobic and three anaerobic ones using different carbon sources." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Boundary reactions\n", "\n", "Apart from exchange reactions there are other types of boundary reactions such as demand or sink reactions. `cobrapy` uses various heuristics to identify those and they can be accessed by using the appropriate attribute.\n", "\n", "For exchange reactions:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[,\n", " ,\n", " ,\n", " ,\n", " ]" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ecoli = load_model(\"iJO1366\")\n", "ecoli.exchanges[0:5]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For demand reactions:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ]" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ecoli.demands" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For sink reactions:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ecoli.sinks" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "All boundary reactions (any reaction that consumes or introduces mass into the system) can be obtained with the `boundary` attribute:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ,\n", " ]" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ecoli.boundary[0:10]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.7.1" } }, "nbformat": 4, "nbformat_minor": 2 }