Claude Skill

alterlab-cobrapy

Build and analyze genome-scale constraint-based metabolic models with COBRApy — flux balance analysis (FBA), flux variability analysis (FVA), gene and reaction knockouts, flux sampling, and SBML model I/O. Use when simulating metabolic networks, predicting growth or knockout phen

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download alterlab-ieu-alterlab-academic-skills-skills_bioinformatics_alterlab-cobrapy-e4836c0.zip · 19 KB
Part of alterlab-ieu/alterlab-academic-skills — 94 skills

Install

skills CLI npx skills add https://github.com/AlterLab-IEU/AlterLab-Academic-Skills/tree/main/skills/bioinformatics/alterlab-cobrapy
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install alterlab-ieu-alterlab-academic-skills@llmmart
Git git clone https://github.com/AlterLab-IEU/AlterLab-Academic-Skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole alterlab-ieu/alterlab-academic-skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

COBRApy - Constraint-Based Reconstruction and Analysis

Overview

COBRApy is a Python library for constraint-based reconstruction and analysis (COBRA) of metabolic models, essential for systems biology research. Work with genome-scale metabolic models, perform computational simulations of cellular metabolism, conduct metabolic engineering analyses, and predict phenotypic behaviors.

When to Use This Skill

Use this skill when the user wants to:

  • Load a genome-scale metabolic model (SBML/JSON/YAML) and simulate growth with FBA/pFBA.
  • Predict knockout phenotypes, essential genes, or minimal media.
  • Explore flux space with FVA, flux sampling, or production envelopes.
  • Build, gapfill, or curate a constraint-based model.

Does NOT Trigger

Scenario Use Instead
Looking up a pathway or reaction annotation rather than simulating alterlab-kegg, alterlab-reactome
Enzyme kinetic parameters (kcat, Km) for a reaction alterlab-brenda
Graph analysis of the metabolic network (centrality, communities) rather than flux alterlab-networkx
Metabolomics measurements and their identification alterlab-metabolomics-wb, alterlab-hmdb
Multi-objective optimization that is not a flux-balance problem alterlab-pymoo

Installation and Requirements

uv pip install cobra              # 0.32.x as of 2026-09
uv pip install 'cobra[array]'     # scipy extra, for array-based model handling
uv pip install 'cobra[chrr]'      # hopsy, enables the fast CHRR sampler

Requirements: depends on optlang and a solver — GLPK ships by default via swiglpk, while CPLEX and Gurobi are optional and considerably faster on genome-scale models. pandas is a hard dependency (pinned < 3); matplotlib/seaborn only for plots. Flux sampling and parallel deletions use multiprocessing, so guard scripts with if __name__ == "__main__": on Windows/macOS spawn.

Bundled model names. load_model only recognizes three bundled aliases: "textbook" (the E. coli core model, e_coli_core), "iJO1366" (full E. coli genome-scale), and "salmonella". Any other identifier (e.g. "ecoli", "e_coli_core") is not a bundled alias and triggers a remote lookup against BiGG/BioModels, which requires network access and may fail. Use read_sbml_model("path.xml") for your own models.

Core Capabilities

COBRApy provides comprehensive tools organized into several key areas:

1. Model Management

Load existing models from repositories or files:

from cobra.io import load_model

# Load bundled test models
model = load_model("textbook")  # E. coli core model
model = load_model("iJO1366")   # Full E. coli genome-scale model (BiGG)
model = load_model("salmonella")

# Load from files
from cobra.io import read_sbml_model, load_json_model, load_yaml_model
model = read_sbml_model("path/to/model.xml")
model = load_json_model("path/to/model.json")
model = load_yaml_model("path/to/model.yml")

Save models in various formats:

from cobra.io import write_sbml_model, save_json_model, save_yaml_model
write_sbml_model(model, "output.xml")  # Preferred format
save_json_model(model, "output.json")  # For Escher compatibility
save_yaml_model(model, "output.yml")   # Human-readable

2. Model Structure and Components

Access and inspect model components:

# Access components
model.reactions      # DictList of all reactions
model.metabolites    # DictList of all metabolites
model.genes          # DictList of all genes

# Get specific items by ID or index
reaction = model.reactions.get_by_id("PFK")
metabolite = model.metabolites[0]

# Inspect properties
print(reaction.reaction)        # Stoichiometric equation
print(reaction.bounds)          # Flux constraints
print(reaction.gene_reaction_rule)  # GPR logic
print(metabolite.formula)       # Chemical formula
print(metabolite.compartment)   # Cellular location

3. Flux Balance Analysis (FBA)

Perform standard FBA simulation:

# Basic optimization
solution = model.optimize()
print(f"Objective value: {solution.objective_value}")
print(f"Status: {solution.status}")

# Access fluxes
print(solution.fluxes["PFK"])
print(solution.fluxes.head())

# Fast optimization (objective value only)
objective_value = model.slim_optimize()

# Change objective
model.objective = "ATPM"
solution = model.optimize()

Parsimonious FBA (minimize total flux):

from cobra.flux_analysis import pfba
solution = pfba(model)

Geometric FBA (find central solution):

from cobra.flux_analysis import geometric_fba
solution = geometric_fba(model)

4. Flux Variability Analysis (FVA)

Determine flux ranges for all reactions:

from cobra.flux_analysis import flux_variability_analysis

# Standard FVA
fva_result = flux_variability_analysis(model)

# FVA at 90% optimality
fva_result = flux_variability_analysis(model, fraction_of_optimum=0.9)

# Loopless FVA (eliminates thermodynamically infeasible loops)
fva_result = flux_variability_analysis(model, loopless=True)

# FVA for specific reactions
fva_result = flux_variability_analysis(
    model,
    reaction_list=["PFK", "FBA", "PGI"]
)

5. Gene and Reaction Deletion Studies

Perform knockout analyses:

from cobra.flux_analysis import (
    single_gene_deletion,
    single_reaction_deletion,
    double_gene_deletion,
    double_reaction_deletion
)

# Single deletions
gene_results = single_gene_deletion(model)
reaction_results = single_reaction_deletion(model)

# Double deletions (uses multiprocessing)
double_gene_results = double_gene_deletion(
    model,
    processes=4  # Number of CPU cores
)

# Manual knockout using context manager
with model:
    model.genes.get_by_id("b0008").knock_out()
    solution = model.optimize()
    print(f"Growth after knockout: {solution.objective_value}")
# Model automatically reverts after context exit

6. Growth Media and Minimal Media

Manage growth medium:

# View current medium
print(model.medium)

# Modify medium (must reassign entire dict)
medium = model.medium
medium["EX_glc__D_e"] = 10.0  # Set glucose uptake
medium["EX_o2_e"] = 0.0       # Anaerobic conditions
model.medium = medium

# Calculate minimal media
from cobra.medium import minimal_medium

# Minimize total import flux
min_medium = minimal_medium(model, minimize_components=False)

# Minimize number of components (uses MILP, slower)
min_medium = minimal_medium(
    model,
    minimize_components=True,
    open_exchanges=True
)

7. Flux Sampling

Sample the feasible flux space:

from cobra.sampling import sample

# method defaults to "auto" in current cobrapy; the three options are:
#   "chrr"  - coordinate hit-and-run with rounding, via the C++ hopsy library
#             (install with cobra[chrr]); usually the fastest and best-mixing
#   "optgp" - parallel, wants large n (>1000) to be efficient
#   "achr"  - artificial centering hit-and-run, better for small n
samples = sample(model, n=1000)                              # auto
samples = sample(model, n=1000, method="optgp", processes=4)  # explicit OptGP
samples = sample(model, n=1000, method="achr")

# Validate samples
from cobra.sampling import OptGPSampler
sampler = OptGPSampler(model, processes=4)
sampler.sample(1000)
validation = sampler.validate(sampler.samples)
print(validation.value_counts())  # Should be all 'v' for valid

8. Production Envelopes

Calculate phenotype phase planes:

from cobra.flux_analysis import production_envelope

# Standard production envelope
envelope = production_envelope(
    model,
    reactions=["EX_glc__D_e", "EX_o2_e"],
    objective="EX_ac_e"  # Acetate production
)

# With carbon yield
envelope = production_envelope(
    model,
    reactions=["EX_glc__D_e", "EX_o2_e"],
    carbon_sources="EX_glc__D_e"
)

# Visualize (use matplotlib or pandas plotting)
import matplotlib.pyplot as plt
envelope.plot(x="EX_glc__D_e", y="EX_o2_e", kind="scatter")
plt.show()

9. Gapfilling

Add reactions to make models feasible:

import cobra
from cobra.flux_analysis import gapfill

# Build a universal model of candidate reactions to draw from.
# In practice, load a curated reaction database (e.g. the BiGG
# universal reactions JSON via load_json_model) or assemble reactions
# into an empty cobra.Model — there is no load_model("universal").
universal = cobra.Model("universal_reactions")
# ...populate `universal` with candidate cobra.Reaction objects...

with model:
    # Create a gap for demonstration
    model.remove_reactions([model.reactions.PGI])

    # Find the minimal set of reactions from `universal` to restore feasibility
    solution = gapfill(model, universal, demand_reactions=False)
    for reaction in solution[0]:
        print(reaction.id)

Note: gapfill returns a list of reaction lists (one per iteration when iterations > 1), so iterate solution[0] rather than printing solution directly.

10. Model Building

Build models from scratch:

from cobra import Model, Reaction, Metabolite

# Create model
model = Model("my_model")

# Create metabolites
atp_c = Metabolite("atp_c", formula="C10H12N5O13P3",
                   name="ATP", compartment="c")
adp_c = Metabolite("adp_c", formula="C10H12N5O10P2",
                   name="ADP", compartment="c")
pi_c = Metabolite("pi_c", formula="HO4P",
                  name="Phosphate", compartment="c")

# Create reaction
reaction = Reaction("ATPASE")
reaction.name = "ATP hydrolysis"
reaction.subsystem = "Energy"
reaction.lower_bound = 0.0
reaction.upper_bound = 1000.0

# Add metabolites with stoichiometry
reaction.add_metabolites({
    atp_c: -1.0,
    adp_c: 1.0,
    pi_c: 1.0
})

# Add gene-reaction rule
reaction.gene_reaction_rule = "(gene1 and gene2) or gene3"

# Add to model
model.add_reactions([reaction])

# Add boundary reactions
model.add_boundary(atp_c, type="exchange")
model.add_boundary(adp_c, type="demand")

# Set objective
model.objective = "ATPASE"

Common Workflows

Workflow 1: Load Model and Predict Growth

from cobra.io import load_model

# Load model
model = load_model("iJO1366")

# Run FBA
solution = model.optimize()
print(f"Growth rate: {solution.objective_value:.3f} /h")

# Show active pathways
print(solution.fluxes[solution.fluxes.abs() > 1e-6])

Workflow 2: Gene Knockout Screen

from cobra.io import load_model
from cobra.flux_analysis import single_gene_deletion

# Load model
model = load_model("iJO1366")

# Perform single gene deletions
results = single_gene_deletion(model)

# Find essential genes (growth < threshold)
essential_genes = results[results["growth"] < 0.01]
print(f"Found {len(essential_genes)} essential genes")

# Find genes with minimal impact
neutral_genes = results[results["growth"] > 0.9 * solution.objective_value]

Workflow 3: Media Optimization

from cobra.io import load_model
from cobra.medium import minimal_medium

# Load model
model = load_model("iJO1366")

# Calculate minimal medium for 50% of max growth
target_growth = model.slim_optimize() * 0.5
min_medium = minimal_medium(
    model,
    target_growth,
    minimize_components=True
)

print(f"Minimal medium components: {len(min_medium)}")
print(min_medium)

Workflow 4: Flux Uncertainty Analysis

from cobra.io import load_model
from cobra.flux_analysis import flux_variability_analysis
from cobra.sampling import sample

# Load model
model = load_model("iJO1366")

# First check flux ranges at optimality
fva = flux_variability_analysis(model, fraction_of_optimum=1.0)

# For reactions with large ranges, sample to understand distribution
samples = sample(model, n=1000)

# Analyze specific reaction
reaction_id = "PFK"
import matplotlib.pyplot as plt
samples[reaction_id].hist(bins=50)
plt.xlabel(f"Flux through {reaction_id}")
plt.ylabel("Frequency")
plt.show()

Workflow 5: Context Manager for Temporary Changes

Use context managers to make temporary modifications:

# Model remains unchanged outside context
with model:
    # Temporarily change objective
    model.objective = "ATPM"

    # Temporarily modify bounds
    model.reactions.EX_glc__D_e.lower_bound = -5.0

    # Temporarily knock out genes
    model.genes.b0008.knock_out()

    # Optimize with changes
    solution = model.optimize()
    print(f"Modified growth: {solution.objective_value}")

# All changes automatically reverted
solution = model.optimize()
print(f"Original growth: {solution.objective_value}")

Key Concepts

DictList Objects

Models use DictList objects for reactions, metabolites, and genes - behaving like both lists and dictionaries:

# Access by index
first_reaction = model.reactions[0]

# Access by ID
pfk = model.reactions.get_by_id("PFK")

# Query methods
atp_reactions = model.reactions.query("atp")

Flux Constraints

Reaction bounds define feasible flux ranges:

  • Irreversible: lower_bound = 0, upper_bound > 0
  • Reversible: lower_bound < 0, upper_bound > 0
  • Set both bounds simultaneously with .bounds to avoid inconsistencies

Gene-Reaction Rules (GPR)

Boolean logic linking genes to reactions:

# AND logic (both required)
reaction.gene_reaction_rule = "gene1 and gene2"

# OR logic (either sufficient)
reaction.gene_reaction_rule = "gene1 or gene2"

# Complex logic
reaction.gene_reaction_rule = "(gene1 and gene2) or (gene3 and gene4)"

Exchange Reactions

Special reactions representing metabolite import/export:

  • Named with prefix EX_ by convention
  • Positive flux = secretion, negative flux = uptake
  • Managed through model.medium dictionary

Best Practices

  1. Use context managers for temporary modifications to avoid state management issues
  2. Validate models before analysis using model.slim_optimize() to ensure feasibility
  3. Check solution status after optimization - optimal indicates successful solve
  4. Use loopless FVA when thermodynamic feasibility matters
  5. Set fraction_of_optimum appropriately in FVA to explore suboptimal space
  6. Parallelize computationally expensive operations (sampling, double deletions)
  7. Prefer SBML format for model exchange and long-term storage
  8. Use slim_optimize() when only objective value needed for performance
  9. Validate flux samples to ensure numerical stability

Troubleshooting

Infeasible solutions: Check medium constraints, reaction bounds, and model consistency Slow optimization: Try different solvers (GLPK, CPLEX, Gurobi) via model.solver Unbounded solutions: Verify exchange reactions have appropriate upper bounds Import errors: Ensure correct file format and valid SBML identifiers

References

For detailed workflows and API patterns, refer to:

  • references/workflows.md - Comprehensive step-by-step workflow examples
  • references/api_quick_reference.md - Common function signatures and patterns

Official documentation: https://cobrapy.readthedocs.io/en/latest/

Part of the AlterLab Academic Skills suite.

Files (alterlab-academic-skills)
  • evals
    • evals.json 5.5 KB
      {
        "skill": "alterlab-cobrapy",
        "evals": [
          {
            "id": "fba-growth-prediction",
            "prompt": "I have the E. coli iJO1366 genome-scale model as an SBML file. I want to run flux balance analysis to predict the growth rate and see which pathways carry flux at the optimum.",
            "expected_output": "Invokes alterlab-cobrapy. Loads the model with read_sbml_model (or load_model('iJO1366')), calls model.optimize(), reports solution.objective_value as the growth rate and solution.status, and inspects the active fluxes (e.g. solution.fluxes where abs > 1e-6).",
            "assertions": [
              { "type": "should_trigger", "value": true },
              { "type": "output_contains", "value": "optimize" },
              { "type": "behavior", "value": "Runs FBA via model.optimize() and reports the objective value as growth rate." }
            ]
          },
          {
            "id": "single-gene-deletion-essential",
            "prompt": "Using my SBML metabolic model, I want to do a single gene knockout screen to find the essential genes whose deletion abolishes growth.",
            "expected_output": "Invokes alterlab-cobrapy. Uses single_gene_deletion from cobra.flux_analysis, filters the results where growth falls below a threshold (e.g. < 0.01) to identify essential genes, and may mention the context-manager knock_out() pattern for individual genes.",
            "assertions": [
              { "type": "should_trigger", "value": true },
              { "type": "output_contains", "value": "single_gene_deletion" },
              { "type": "behavior", "value": "Identifies essential genes by thresholding growth from a deletion screen." }
            ]
          },
          {
            "id": "fva-flux-variability",
            "prompt": "I want to know the feasible flux ranges for my reactions at 90% of optimal growth, and I need to eliminate thermodynamically infeasible loops from the result.",
            "expected_output": "Invokes alterlab-cobrapy. Runs flux_variability_analysis from cobra.flux_analysis with fraction_of_optimum=0.9 and loopless=True to get minimum/maximum flux per reaction without infeasible cycles.",
            "assertions": [
              { "type": "should_trigger", "value": true },
              { "type": "output_contains", "value": "flux_variability_analysis" },
              { "type": "behavior", "value": "Uses fraction_of_optimum and loopless to bound flux ranges." }
            ]
          },
          {
            "id": "minimal-media-anaerobic",
            "prompt": "I need to compute the minimal medium that still supports growth for my model, and then re-run the simulation under anaerobic conditions by shutting off oxygen uptake.",
            "expected_output": "Invokes alterlab-cobrapy. Uses minimal_medium from cobra.medium to find the minimal component set, and modifies model.medium (reassigning the whole dict) to set EX_o2_e to 0 for anaerobic conditions before re-optimizing.",
            "assertions": [
              { "type": "should_trigger", "value": true },
              { "type": "output_contains", "value": "minimal_medium" },
              { "type": "behavior", "value": "Computes minimal medium and edits model.medium to model anaerobic growth." }
            ]
          },
          {
            "id": "flux-sampling-distribution",
            "prompt": "I want to sample 1000 points from the feasible flux space of my model to understand the flux distribution through PFK, using parallel processing.",
            "expected_output": "Invokes alterlab-cobrapy. Uses sample from cobra.sampling (OptGP method with processes for parallelism) to draw samples, then inspects the distribution for the target reaction (e.g. a histogram of samples['PFK']).",
            "assertions": [
              { "type": "should_trigger", "value": true },
              { "type": "output_contains", "value": "sample" },
              { "type": "behavior", "value": "Uses cobra.sampling.sample (OptGP/ACHR) to characterize the flux distribution." }
            ]
          },
          {
            "id": "near-miss-pydeseq2",
            "prompt": "I have a counts matrix from a bulk RNA-seq experiment and want to find genes that are differentially expressed between knockout and wild-type samples.",
            "expected_output": "Does NOT invoke this skill; defers to alterlab-pydeseq2. The user wants statistical differential gene expression on RNA-seq counts, not constraint-based metabolic flux simulation on a genome-scale model.",
            "assertions": [
              { "type": "should_not_trigger", "value": true },
              { "type": "output_contains", "value": "alterlab-pydeseq2" }
            ]
          },
          {
            "id": "near-miss-arboreto",
            "prompt": "From my expression matrix I want to infer the gene regulatory network linking transcription factors to their target genes.",
            "expected_output": "Does NOT invoke this skill; defers to alterlab-arboreto. The user wants TF-target regulatory network inference (GRNBoost2/GENIE3) from expression data, not stoichiometric flux analysis of a metabolic network.",
            "assertions": [
              { "type": "should_not_trigger", "value": true },
              { "type": "output_contains", "value": "alterlab-arboreto" }
            ]
          },
          {
            "id": "near-miss-brenda",
            "prompt": "What are the measured kcat and Km values of E. coli phosphofructokinase for fructose-6-phosphate? I need literature kinetic constants, not a simulation.",
            "expected_output": "Does NOT invoke this skill; defers to alterlab-brenda. The user wants curated enzyme kinetic parameters (kcat, Km) from the literature, which BRENDA provides; COBRApy runs steady-state constraint-based simulations and does not look up kinetic constants.",
            "assertions": [
              { "type": "should_not_trigger", "value": true },
              { "type": "output_contains", "value": "alterlab-brenda" }
            ]
          }
        ]
      }
      
  • references
    • api_quick_reference.md 16.4 KB
      # COBRApy API Quick Reference
      
      This document provides quick reference for common COBRApy functions, signatures, and usage patterns.
      
      ## Model I/O
      
      ### Loading Models
      
      ```python
      from cobra.io import load_model, read_sbml_model, load_json_model, load_yaml_model, load_matlab_model
      
      # Bundled test models (only these three aliases are bundled)
      model = load_model("textbook")   # E. coli core metabolism (e_coli_core)
      model = load_model("iJO1366")    # Full E. coli genome-scale model
      model = load_model("salmonella") # Salmonella LT2
      # NOTE: any other id (e.g. "ecoli") is NOT bundled and falls through to a
      # remote BiGG/BioModels lookup (needs network access).
      
      # From files
      model = read_sbml_model(filename, f_replace={}, **kwargs)
      model = load_json_model(filename)
      model = load_yaml_model(filename)
      model = load_matlab_model(filename, variable_name=None)
      ```
      
      ### Saving Models
      
      ```python
      from cobra.io import write_sbml_model, save_json_model, save_yaml_model, save_matlab_model
      
      write_sbml_model(model, filename, f_replace={}, **kwargs)
      save_json_model(model, filename, pretty=False, **kwargs)
      save_yaml_model(model, filename, **kwargs)
      save_matlab_model(model, filename, **kwargs)
      ```
      
      ## Model Structure
      
      ### Core Classes
      
      ```python
      from cobra import Model, Reaction, Metabolite, Gene
      
      # Create model
      model = Model(id_or_model=None, name=None)
      
      # Create metabolite
      metabolite = Metabolite(
          id=None,
          formula=None,
          name="",
          charge=None,
          compartment=None
      )
      
      # Create reaction
      reaction = Reaction(
          id=None,
          name="",
          subsystem="",
          lower_bound=0.0,
          upper_bound=None
      )
      
      # Create gene
      gene = Gene(id=None, name="", functional=True)
      ```
      
      ### Model Attributes
      
      ```python
      # Component access (DictList objects)
      model.reactions       # DictList of Reaction objects
      model.metabolites     # DictList of Metabolite objects
      model.genes          # DictList of Gene objects
      
      # Special reaction lists
      model.exchanges      # Exchange reactions (external transport)
      model.demands        # Demand reactions (metabolite sinks)
      model.sinks          # Sink reactions
      model.boundary       # All boundary reactions
      
      # Model properties
      model.objective      # Current objective (read/write)
      model.objective_direction  # "max" or "min"
      model.medium         # Growth medium (dict of exchange: bound)
      model.solver         # Optimization solver
      ```
      
      ### DictList Methods
      
      ```python
      # Access by index
      item = model.reactions[0]
      
      # Access by ID
      item = model.reactions.get_by_id("PFK")
      
      # Query by string (substring match)
      items = model.reactions.query("atp")      # Case-insensitive search
      items = model.reactions.query(lambda x: x.subsystem == "Glycolysis")
      
      # List comprehension
      items = [r for r in model.reactions if r.lower_bound < 0]
      
      # Check membership
      "PFK" in model.reactions
      ```
      
      ## Optimization
      
      ### Basic Optimization
      
      ```python
      # Full optimization (returns Solution object)
      solution = model.optimize()
      
      # Attributes of Solution
      solution.objective_value   # Objective function value
      solution.status           # Optimization status ("optimal", "infeasible", etc.)
      solution.fluxes          # Pandas Series of reaction fluxes
      solution.shadow_prices   # Pandas Series of metabolite shadow prices
      solution.reduced_costs   # Pandas Series of reduced costs
      
      # Fast optimization (returns float only)
      objective_value = model.slim_optimize()
      
      # Change objective
      model.objective = "ATPM"
      model.objective = model.reactions.ATPM
      model.objective = {model.reactions.ATPM: 1.0}
      
      # Change optimization direction
      model.objective_direction = "max"  # or "min"
      ```
      
      ### Solver Configuration
      
      ```python
      # Check available solvers
      from cobra.util.solver import solvers
      print(solvers)
      
      # Change solver
      model.solver = "glpk"  # or "cplex", "gurobi", etc.
      
      # Solver-specific configuration
      model.solver.configuration.timeout = 60  # seconds
      model.solver.configuration.verbosity = 1
      model.solver.configuration.tolerances.feasibility = 1e-9
      ```
      
      ## Flux Analysis
      
      ### Flux Balance Analysis (FBA)
      
      ```python
      from cobra.flux_analysis import pfba, geometric_fba
      
      # Parsimonious FBA
      solution = pfba(model, fraction_of_optimum=1.0, **kwargs)
      
      # Geometric FBA
      solution = geometric_fba(model, epsilon=1e-06, max_tries=200)
      ```
      
      ### Flux Variability Analysis (FVA)
      
      ```python
      from cobra.flux_analysis import flux_variability_analysis
      
      fva_result = flux_variability_analysis(
          model,
          reaction_list=None,        # List of reaction IDs or None for all
          loopless=False,            # Eliminate thermodynamically infeasible loops
          fraction_of_optimum=1.0,   # Optimality fraction (0.0-1.0)
          pfba_factor=None,          # Optional pFBA constraint
          processes=1                # Number of parallel processes
      )
      
      # Returns DataFrame with columns: minimum, maximum
      ```
      
      ### Gene and Reaction Deletions
      
      ```python
      from cobra.flux_analysis import (
          single_gene_deletion,
          single_reaction_deletion,
          double_gene_deletion,
          double_reaction_deletion
      )
      
      # Single deletions
      results = single_gene_deletion(
          model,
          gene_list=None,     # None for all genes
          processes=1,
          **kwargs
      )
      
      results = single_reaction_deletion(
          model,
          reaction_list=None,  # None for all reactions
          processes=1,
          **kwargs
      )
      
      # Double deletions
      results = double_gene_deletion(
          model,
          gene_list1=None,
          gene_list2=None,
          processes=1,
          **kwargs
      )
      
      results = double_reaction_deletion(
          model,
          reaction_list1=None,
          reaction_list2=None,
          processes=1,
          **kwargs
      )
      
      # Returns DataFrame with columns: ids, growth, status
      # For double deletions, index is MultiIndex of gene/reaction pairs
      ```
      
      ### Flux Sampling
      
      ```python
      from cobra.sampling import sample, OptGPSampler, ACHRSampler
      
      # Simple interface
      samples = sample(
          model,
          n,                  # Number of samples
          method="optgp",     # default "auto"; also "achr" or "chrr" (needs cobra[chrr])
          thinning=100,       # Thinning factor (sample every n iterations)
          processes=1,        # Parallel processes (OptGP only)
          seed=None          # Random seed
      )
      
      # Advanced interface with sampler objects
      sampler = OptGPSampler(model, processes=4, thinning=100)
      sampler = ACHRSampler(model, thinning=100)
      
      # Generate samples
      samples = sampler.sample(n)
      
      # Validate samples
      validation = sampler.validate(sampler.samples)
      # Returns array of 'v' (valid), 'l' (lower bound violation),
      # 'u' (upper bound violation), 'e' (equality violation)
      
      # Batch sampling
      sampler.batch(n_samples, n_batches)
      ```
      
      ### Production Envelopes
      
      ```python
      from cobra.flux_analysis import production_envelope
      
      envelope = production_envelope(
          model,
          reactions,              # List of 1-2 reaction IDs
          objective=None,         # Objective reaction ID (None uses model objective)
          carbon_sources=None,    # Carbon source for yield calculation
          points=20,              # Number of points to calculate
          threshold=0.01          # Minimum objective value threshold
      )
      
      # Returns DataFrame with columns:
      # - First reaction flux
      # - Second reaction flux (if provided)
      # - objective_minimum, objective_maximum
      # - carbon_yield_minimum, carbon_yield_maximum (if carbon source specified)
      # - mass_yield_minimum, mass_yield_maximum
      ```
      
      ### Gapfilling
      
      ```python
      from cobra.flux_analysis import gapfill
      
      # Basic gapfilling
      solution = gapfill(
          model,
          universal=None,         # Universal model with candidate reactions
          lower_bound=0.05,       # Minimum objective flux
          penalties=None,         # Dict of reaction: penalty
          demand_reactions=True,  # Add demand reactions if needed
          exchange_reactions=False,
          iterations=1
      )
      
      # Returns a LIST OF LISTS: one inner list of cobra.Reaction objects per
      # iteration. Iterate solution[0] for the first solution set.
      for reaction in solution[0]:
          print(reaction.id)
      
      # Multiple alternative solutions in one call
      solutions = gapfill(model, universal, iterations=5)
      for i, reaction_set in enumerate(solutions):
          print(f"Solution {i}: {[r.id for r in reaction_set]}")
      ```
      
      ### Other Analysis Methods
      
      ```python
      from cobra.flux_analysis import (
          find_blocked_reactions,
          find_essential_genes,
          find_essential_reactions
      )
      
      # Blocked reactions (cannot carry flux)
      blocked = find_blocked_reactions(
          model,
          reaction_list=None,
          zero_cutoff=1e-9,
          open_exchanges=False
      )
      
      # Essential genes/reactions
      essential_genes = find_essential_genes(model, threshold=0.01)
      essential_reactions = find_essential_reactions(model, threshold=0.01)
      ```
      
      ## Media and Boundary Conditions
      
      ### Medium Management
      
      ```python
      # Get current medium (returns dict)
      medium = model.medium
      
      # Set medium (must reassign entire dict)
      medium = model.medium
      medium["EX_glc__D_e"] = 10.0
      medium["EX_o2_e"] = 20.0
      model.medium = medium
      
      # Alternative: individual modification
      with model:
          model.reactions.EX_glc__D_e.lower_bound = -10.0
      ```
      
      ### Minimal Media
      
      ```python
      from cobra.medium import minimal_medium
      
      # Parameter order matters if you call positionally:
      min_medium = minimal_medium(
          model,
          min_objective_value=0.1,   # Minimum objective (growth) value
          exports=False,             # Allow secretion fluxes in the result
          minimize_components=False, # If True/int, minimize component COUNT via MILP (slower)
          open_exchanges=False,      # Open all exchanges before optimization
      )
      
      # Returns a pandas.Series of required import fluxes (or a DataFrame when
      # minimize_components is an int requesting multiple solutions; None if infeasible)
      ```
      
      ### Boundary Reactions
      
      ```python
      # Add boundary reaction
      model.add_boundary(
          metabolite,
          type="exchange",    # or "demand", "sink"
          reaction_id=None,   # Auto-generated if None
          lb=None,
          ub=None,
          sbo_term=None
      )
      
      # Access boundary reactions
      exchanges = model.exchanges     # System boundary
      demands = model.demands         # Intracellular removal
      sinks = model.sinks            # Intracellular exchange
      boundaries = model.boundary    # All boundary reactions
      ```
      
      ## Model Manipulation
      
      ### Adding Components
      
      ```python
      # Add reactions (always plural; pass a list even for one reaction)
      model.add_reactions([reaction1, reaction2, ...])
      model.add_reactions([reaction])
      
      # Add metabolites
      reaction.add_metabolites({
          metabolite1: -1.0,  # Consumed (negative stoichiometry)
          metabolite2: 1.0    # Produced (positive stoichiometry)
      })
      
      # Add metabolites to model
      model.add_metabolites([metabolite1, metabolite2, ...])
      
      # Genes are created automatically when you set a reaction's
      # gene_reaction_rule, so there is rarely a need to add Gene objects
      # directly. To register genes explicitly, set the GPR:
      reaction.gene_reaction_rule = "gene1 and gene2"  # creates Gene objects in model.genes
      ```
      
      ### Removing Components
      
      ```python
      # Remove reactions
      model.remove_reactions([reaction1, reaction2, ...])
      model.remove_reactions(["PFK", "FBA"])
      
      # Remove metabolites (removes from reactions too)
      model.remove_metabolites([metabolite1, metabolite2, ...])
      
      # Remove genes (usually via gene_reaction_rule)
      model.genes.remove(gene)
      ```
      
      ### Modifying Reactions
      
      ```python
      # Set bounds
      reaction.bounds = (lower, upper)
      reaction.lower_bound = 0.0
      reaction.upper_bound = 1000.0
      
      # Modify stoichiometry
      reaction.add_metabolites({metabolite: 1.0})
      reaction.subtract_metabolites({metabolite: 1.0})
      
      # Change gene-reaction rule
      reaction.gene_reaction_rule = "(gene1 and gene2) or gene3"
      
      # Knock out
      reaction.knock_out()
      gene.knock_out()
      ```
      
      ### Model Copying
      
      ```python
      # Deep copy (independent model)
      model_copy = model.copy()
      
      # Copy specific reactions
      new_model = Model("subset")
      reactions_to_copy = [model.reactions.PFK, model.reactions.FBA]
      new_model.add_reactions(reactions_to_copy)
      ```
      
      ## Context Management
      
      Use context managers for temporary modifications:
      
      ```python
      # Changes automatically revert after with block
      with model:
          model.objective = "ATPM"
          model.reactions.EX_glc__D_e.lower_bound = -5.0
          model.genes.b0008.knock_out()
          solution = model.optimize()
      
      # Model state restored here
      
      # Multiple nested contexts
      with model:
          model.objective = "ATPM"
          with model:
              model.genes.b0008.knock_out()
              # Both modifications active
          # Only objective change active
      
      # Context management with reactions
      with model:
          model.reactions.PFK.knock_out()
          # Equivalent to: reaction.lower_bound = reaction.upper_bound = 0
      ```
      
      ## Reaction and Metabolite Properties
      
      ### Reaction Attributes
      
      ```python
      reaction.id                      # Unique identifier
      reaction.name                    # Human-readable name
      reaction.subsystem               # Pathway/subsystem
      reaction.bounds                  # (lower_bound, upper_bound)
      reaction.lower_bound
      reaction.upper_bound
      reaction.reversibility          # Boolean (lower_bound < 0)
      reaction.gene_reaction_rule     # GPR string
      reaction.genes                  # Set of associated Gene objects
      reaction.metabolites            # Dict of {metabolite: stoichiometry}
      
      # Methods
      reaction.reaction               # Stoichiometric equation string
      reaction.build_reaction_string() # Same as above
      reaction.check_mass_balance()   # Returns imbalances or empty dict
      reaction.get_coefficient(metabolite_id)
      reaction.add_metabolites({metabolite: coeff})
      reaction.subtract_metabolites({metabolite: coeff})
      reaction.knock_out()
      ```
      
      ### Metabolite Attributes
      
      ```python
      metabolite.id                   # Unique identifier
      metabolite.name                 # Human-readable name
      metabolite.formula              # Chemical formula
      metabolite.charge               # Charge
      metabolite.compartment          # Compartment ID
      metabolite.reactions            # FrozenSet of associated reactions
      
      # Methods
      metabolite.summary()            # Print production/consumption
      metabolite.copy()
      ```
      
      ### Gene Attributes
      
      ```python
      gene.id                         # Unique identifier
      gene.name                       # Human-readable name
      gene.functional                 # Boolean activity status
      gene.reactions                  # FrozenSet of associated reactions
      
      # Methods
      gene.knock_out()
      ```
      
      ## Model Validation
      
      ### Consistency Checking
      
      ```python
      from cobra.manipulation import check_mass_balance, check_metabolite_compartment_formula
      
      # Check all reactions for mass balance
      unbalanced = {}
      for reaction in model.reactions:
          balance = reaction.check_mass_balance()
          if balance:
              unbalanced[reaction.id] = balance
      
      # Check metabolite formulas are valid
      check_metabolite_compartment_formula(model)
      ```
      
      ### Model Statistics
      
      ```python
      # Basic stats
      print(f"Reactions: {len(model.reactions)}")
      print(f"Metabolites: {len(model.metabolites)}")
      print(f"Genes: {len(model.genes)}")
      
      # Advanced stats
      print(f"Exchanges: {len(model.exchanges)}")
      print(f"Demands: {len(model.demands)}")
      
      # Blocked reactions
      from cobra.flux_analysis import find_blocked_reactions
      blocked = find_blocked_reactions(model)
      print(f"Blocked reactions: {len(blocked)}")
      
      # Essential genes
      from cobra.flux_analysis import find_essential_genes
      essential = find_essential_genes(model)
      print(f"Essential genes: {len(essential)}")
      ```
      
      ## Summary Methods
      
      ```python
      # Model summary
      model.summary()                  # Overall model info
      
      # Metabolite summary
      model.metabolites.atp_c.summary()
      
      # Reaction summary
      model.reactions.PFK.summary()
      
      # Summary with FVA
      model.summary(fva=0.95)         # Include FVA at 95% optimality
      ```
      
      ## Common Patterns
      
      ### Batch Analysis Pattern
      
      ```python
      results = []
      for condition in conditions:
          with model:
              # Apply condition
              setup_condition(model, condition)
      
              # Analyze
              solution = model.optimize()
      
              # Store result
              results.append({
                  "condition": condition,
                  "growth": solution.objective_value,
                  "status": solution.status
              })
      
      df = pd.DataFrame(results)
      ```
      
      ### Systematic Knockout Pattern
      
      ```python
      knockout_results = []
      for gene in model.genes:
          with model:
              gene.knock_out()
      
              solution = model.optimize()
      
              knockout_results.append({
                  "gene": gene.id,
                  "growth": solution.objective_value if solution.status == "optimal" else 0,
                  "status": solution.status
              })
      
      df = pd.DataFrame(knockout_results)
      ```
      
      ### Parameter Scan Pattern
      
      ```python
      parameter_values = np.linspace(0, 20, 21)
      results = []
      
      for value in parameter_values:
          with model:
              model.reactions.EX_glc__D_e.lower_bound = -value
      
              solution = model.optimize()
      
              results.append({
                  "glucose_uptake": value,
                  "growth": solution.objective_value,
                  "acetate_secretion": solution.fluxes["EX_ac_e"]
              })
      
      df = pd.DataFrame(results)
      ```
      
      This quick reference covers the most commonly used COBRApy functions and patterns. For complete API documentation, see https://cobrapy.readthedocs.io/
      
    • workflows.md 21.3 KB
      # COBRApy Comprehensive Workflows
      
      This document provides detailed step-by-step workflows for common COBRApy tasks in metabolic modeling.
      
      ## Workflow 1: Complete Knockout Study with Visualization
      
      This workflow demonstrates how to perform a comprehensive gene knockout study and visualize the results.
      
      ```python
      import pandas as pd
      import matplotlib.pyplot as plt
      from cobra.io import load_model
      from cobra.flux_analysis import single_gene_deletion, double_gene_deletion
      
      # Step 1: Load model
      model = load_model("textbook")  # E. coli core model (bundled, runs offline)
      print(f"Loaded model: {model.id}")
      print(f"Model contains {len(model.reactions)} reactions, {len(model.metabolites)} metabolites, {len(model.genes)} genes")
      
      # Step 2: Get baseline growth rate
      baseline = model.slim_optimize()
      print(f"Baseline growth rate: {baseline:.3f} /h")
      
      # Step 3: Perform single gene deletions
      print("Performing single gene deletions...")
      single_results = single_gene_deletion(model)
      
      # Step 4: Classify genes by impact
      essential_genes = single_results[single_results["growth"] < 0.01]
      severely_impaired = single_results[(single_results["growth"] >= 0.01) &
                                         (single_results["growth"] < 0.5 * baseline)]
      moderately_impaired = single_results[(single_results["growth"] >= 0.5 * baseline) &
                                           (single_results["growth"] < 0.9 * baseline)]
      neutral_genes = single_results[single_results["growth"] >= 0.9 * baseline]
      
      print(f"\nSingle Deletion Results:")
      print(f"  Essential genes: {len(essential_genes)}")
      print(f"  Severely impaired: {len(severely_impaired)}")
      print(f"  Moderately impaired: {len(moderately_impaired)}")
      print(f"  Neutral genes: {len(neutral_genes)}")
      
      # Step 5: Visualize distribution
      fig, ax = plt.subplots(figsize=(10, 6))
      single_results["growth"].hist(bins=50, ax=ax)
      ax.axvline(baseline, color='r', linestyle='--', label='Baseline')
      ax.set_xlabel("Growth rate (/h)")
      ax.set_ylabel("Number of genes")
      ax.set_title("Distribution of Growth Rates After Single Gene Deletions")
      ax.legend()
      plt.tight_layout()
      plt.savefig("single_deletion_distribution.png", dpi=300)
      
      # Step 6: Identify gene pairs for double deletions
      # Focus on non-essential genes to find synthetic lethals
      target_genes = single_results[single_results["growth"] >= 0.5 * baseline].index.tolist()
      target_genes = [list(gene)[0] for gene in target_genes[:50]]  # Limit for performance
      
      print(f"\nPerforming double deletions on {len(target_genes)} genes...")
      double_results = double_gene_deletion(
          model,
          gene_list1=target_genes,
          processes=4
      )
      
      # Step 7: Find synthetic lethal pairs
      synthetic_lethals = double_results[
          (double_results["growth"] < 0.01) &
          (single_results.loc[double_results.index.get_level_values(0)]["growth"].values >= 0.5 * baseline) &
          (single_results.loc[double_results.index.get_level_values(1)]["growth"].values >= 0.5 * baseline)
      ]
      
      print(f"Found {len(synthetic_lethals)} synthetic lethal gene pairs")
      print("\nTop 10 synthetic lethal pairs:")
      print(synthetic_lethals.head(10))
      
      # Step 8: Export results
      single_results.to_csv("single_gene_deletions.csv")
      double_results.to_csv("double_gene_deletions.csv")
      synthetic_lethals.to_csv("synthetic_lethals.csv")
      ```
      
      ## Workflow 2: Media Design and Optimization
      
      This workflow shows how to systematically design growth media and find minimal media compositions.
      
      ```python
      from cobra.io import load_model
      from cobra.medium import minimal_medium
      import pandas as pd
      
      # Step 1: Load model and check current medium
      model = load_model("textbook")  # E. coli core model (bundled, runs offline)
      current_medium = model.medium
      print("Current medium composition:")
      for exchange, bound in current_medium.items():
          metabolite_id = exchange.replace("EX_", "").replace("_e", "")
          print(f"  {metabolite_id}: {bound:.2f} mmol/gDW/h")
      
      # Step 2: Get baseline growth
      baseline_growth = model.slim_optimize()
      print(f"\nBaseline growth rate: {baseline_growth:.3f} /h")
      
      # Step 3: Calculate minimal medium for different growth targets
      growth_targets = [0.25, 0.5, 0.75, 1.0]
      minimal_media = {}
      
      for fraction in growth_targets:
          target_growth = baseline_growth * fraction
          print(f"\nCalculating minimal medium for {fraction*100:.0f}% growth ({target_growth:.3f} /h)...")
      
          min_medium = minimal_medium(
              model,
              target_growth,
              minimize_components=True,
              open_exchanges=True
          )
      
          minimal_media[fraction] = min_medium
          print(f"  Required components: {len(min_medium)}")
          print(f"  Components: {list(min_medium.index)}")
      
      # Step 4: Compare media compositions
      media_df = pd.DataFrame(minimal_media).fillna(0)
      media_df.to_csv("minimal_media_comparison.csv")
      
      # Step 5: Test aerobic vs anaerobic conditions
      print("\n--- Aerobic vs Anaerobic Comparison ---")
      
      # Aerobic
      model_aerobic = model.copy()
      aerobic_growth = model_aerobic.slim_optimize()
      aerobic_medium = minimal_medium(model_aerobic, aerobic_growth * 0.9, minimize_components=True)
      
      # Anaerobic
      model_anaerobic = model.copy()
      medium_anaerobic = model_anaerobic.medium
      medium_anaerobic["EX_o2_e"] = 0.0
      model_anaerobic.medium = medium_anaerobic
      anaerobic_growth = model_anaerobic.slim_optimize()
      anaerobic_medium = minimal_medium(model_anaerobic, anaerobic_growth * 0.9, minimize_components=True)
      
      print(f"Aerobic growth: {aerobic_growth:.3f} /h (requires {len(aerobic_medium)} components)")
      print(f"Anaerobic growth: {anaerobic_growth:.3f} /h (requires {len(anaerobic_medium)} components)")
      
      # Step 6: Identify unique requirements
      aerobic_only = set(aerobic_medium.index) - set(anaerobic_medium.index)
      anaerobic_only = set(anaerobic_medium.index) - set(aerobic_medium.index)
      shared = set(aerobic_medium.index) & set(anaerobic_medium.index)
      
      print(f"\nShared components: {len(shared)}")
      print(f"Aerobic-only: {aerobic_only}")
      print(f"Anaerobic-only: {anaerobic_only}")
      
      # Step 7: Test custom medium
      print("\n--- Testing Custom Medium ---")
      custom_medium = {
          "EX_glc__D_e": 10.0,  # Glucose
          "EX_o2_e": 20.0,       # Oxygen
          "EX_nh4_e": 5.0,       # Ammonium
          "EX_pi_e": 5.0,        # Phosphate
          "EX_so4_e": 1.0,       # Sulfate
      }
      
      with model:
          model.medium = custom_medium
          custom_growth = model.optimize().objective_value
          print(f"Growth on custom medium: {custom_growth:.3f} /h")
      
          # Check which nutrients are limiting
          for exchange in custom_medium:
              with model:
                  # Double the uptake rate
                  medium_test = model.medium
                  medium_test[exchange] *= 2
                  model.medium = medium_test
                  test_growth = model.optimize().objective_value
                  improvement = (test_growth - custom_growth) / custom_growth * 100
                  if improvement > 1:
                      print(f"  {exchange}: +{improvement:.1f}% growth when doubled (LIMITING)")
      ```
      
      ## Workflow 3: Flux Space Exploration with Sampling
      
      This workflow demonstrates comprehensive flux space analysis using FVA and sampling.
      
      ```python
      from cobra.io import load_model
      from cobra.flux_analysis import flux_variability_analysis
      from cobra.sampling import sample
      import pandas as pd
      import matplotlib.pyplot as plt
      import seaborn as sns
      
      # Step 1: Load model
      model = load_model("textbook")  # E. coli core model (bundled, runs offline)
      baseline = model.slim_optimize()
      print(f"Baseline growth: {baseline:.3f} /h")
      
      # Step 2: Perform FVA at optimal growth
      print("\nPerforming FVA at optimal growth...")
      fva_optimal = flux_variability_analysis(model, fraction_of_optimum=1.0)
      
      # Step 3: Identify reactions with flexibility
      fva_optimal["range"] = fva_optimal["maximum"] - fva_optimal["minimum"]
      fva_optimal["relative_range"] = fva_optimal["range"] / (fva_optimal["maximum"].abs() + 1e-9)
      
      flexible_reactions = fva_optimal[fva_optimal["range"] > 1.0].sort_values("range", ascending=False)
      print(f"\nFound {len(flexible_reactions)} reactions with >1.0 mmol/gDW/h flexibility")
      print("\nTop 10 most flexible reactions:")
      print(flexible_reactions.head(10)[["minimum", "maximum", "range"]])
      
      # Step 4: Perform FVA at suboptimal growth (90%)
      print("\nPerforming FVA at 90% optimal growth...")
      fva_suboptimal = flux_variability_analysis(model, fraction_of_optimum=0.9)
      fva_suboptimal["range"] = fva_suboptimal["maximum"] - fva_suboptimal["minimum"]
      
      # Step 5: Compare flexibility at different optimality levels
      comparison = pd.DataFrame({
          "range_100": fva_optimal["range"],
          "range_90": fva_suboptimal["range"]
      })
      comparison["range_increase"] = comparison["range_90"] - comparison["range_100"]
      
      print("\nReactions with largest increase in flexibility at suboptimality:")
      print(comparison.sort_values("range_increase", ascending=False).head(10))
      
      # Step 6: Perform flux sampling
      print("\nPerforming flux sampling (1000 samples)...")
      samples = sample(model, n=1000, method="optgp", processes=4)  # or leave method="auto"
      
      # Step 7: Analyze sampling results for key reactions
      key_reactions = ["PFK", "FBA", "TPI", "GAPD", "PGK", "PGM", "ENO", "PYK"]
      available_key_reactions = [r for r in key_reactions if r in samples.columns]
      
      if available_key_reactions:
          fig, axes = plt.subplots(2, 4, figsize=(16, 8))
          axes = axes.flatten()
      
          for idx, reaction_id in enumerate(available_key_reactions[:8]):
              ax = axes[idx]
              samples[reaction_id].hist(bins=30, ax=ax, alpha=0.7)
      
              # Overlay FVA bounds
              fva_min = fva_optimal.loc[reaction_id, "minimum"]
              fva_max = fva_optimal.loc[reaction_id, "maximum"]
              ax.axvline(fva_min, color='r', linestyle='--', label='FVA min')
              ax.axvline(fva_max, color='r', linestyle='--', label='FVA max')
      
              ax.set_xlabel("Flux (mmol/gDW/h)")
              ax.set_ylabel("Frequency")
              ax.set_title(reaction_id)
              if idx == 0:
                  ax.legend()
      
          plt.tight_layout()
          plt.savefig("flux_distributions.png", dpi=300)
      
      # Step 8: Calculate correlation between reactions
      print("\nCalculating flux correlations...")
      correlation_matrix = samples[available_key_reactions].corr()
      
      fig, ax = plt.subplots(figsize=(10, 8))
      sns.heatmap(correlation_matrix, annot=True, fmt=".2f", cmap="coolwarm",
                  center=0, ax=ax, square=True)
      ax.set_title("Flux Correlations Between Key Glycolysis Reactions")
      plt.tight_layout()
      plt.savefig("flux_correlations.png", dpi=300)
      
      # Step 9: Identify reaction modules (highly correlated groups)
      print("\nHighly correlated reaction pairs (|r| > 0.9):")
      for i in range(len(correlation_matrix)):
          for j in range(i+1, len(correlation_matrix)):
              corr = correlation_matrix.iloc[i, j]
              if abs(corr) > 0.9:
                  print(f"  {correlation_matrix.index[i]} <-> {correlation_matrix.columns[j]}: {corr:.3f}")
      
      # Step 10: Export all results
      fva_optimal.to_csv("fva_optimal.csv")
      fva_suboptimal.to_csv("fva_suboptimal.csv")
      samples.to_csv("flux_samples.csv")
      correlation_matrix.to_csv("flux_correlations.csv")
      ```
      
      ## Workflow 4: Production Strain Design
      
      This workflow demonstrates how to design a production strain for a target metabolite.
      
      ```python
      from cobra.io import load_model
      from cobra.flux_analysis import (
          production_envelope,
          flux_variability_analysis,
          single_gene_deletion
      )
      import pandas as pd
      import matplotlib.pyplot as plt
      
      # Step 1: Define production target
      TARGET_METABOLITE = "EX_ac_e"  # Acetate production
      CARBON_SOURCE = "EX_glc__D_e"  # Glucose uptake
      
      # Step 2: Load model
      model = load_model("textbook")  # E. coli core model (bundled, runs offline)
      print(f"Designing strain for {TARGET_METABOLITE} production")
      
      # Step 3: Calculate baseline production envelope
      print("\nCalculating production envelope...")
      envelope = production_envelope(
          model,
          reactions=[CARBON_SOURCE, TARGET_METABOLITE],
          carbon_sources=CARBON_SOURCE
      )
      
      # Visualize production envelope
      fig, ax = plt.subplots(figsize=(10, 6))
      ax.plot(envelope[CARBON_SOURCE], envelope["mass_yield_maximum"], 'b-', label='Max yield')
      ax.plot(envelope[CARBON_SOURCE], envelope["mass_yield_minimum"], 'r-', label='Min yield')
      ax.set_xlabel(f"Glucose uptake (mmol/gDW/h)")
      ax.set_ylabel(f"Acetate yield")
      ax.set_title("Wild-type Production Envelope")
      ax.legend()
      ax.grid(True, alpha=0.3)
      plt.tight_layout()
      plt.savefig("production_envelope_wildtype.png", dpi=300)
      
      # Step 4: Maximize production while maintaining growth
      print("\nOptimizing for production...")
      
      BIOMASS = "BIOMASS_Ecoli_core_w_GAM"  # biomass reaction id in the textbook model
      
      # Record max growth before re-tasking the objective
      max_growth = model.slim_optimize()
      MIN_GROWTH = 0.1 * max_growth  # require at least 10% of max growth
      
      # Permanently constrain growth and switch the objective to product formation.
      # (These are deliberate model changes that persist through the knockout screen
      # below; use `with model:` instead if you want them to revert.)
      model.reactions.get_by_id(BIOMASS).lower_bound = MIN_GROWTH
      model.objective = TARGET_METABOLITE
      model.objective_direction = "max"
      
      production_solution = model.optimize()
      max_production = production_solution.objective_value
      print(f"Maximum production: {max_production:.3f} mmol/gDW/h")
      print(f"Growth rate: {production_solution.fluxes[BIOMASS]:.3f} /h")
      
      # Step 5: Identify beneficial gene knockouts
      print("\nScreening for beneficial knockouts...")
      # The growth constraint and product objective from Step 4 are still in effect.
      
      knockout_results = []
      for gene in model.genes:
          with model:
              gene.knock_out()
              try:
                  solution = model.optimize()
                  if solution.status == "optimal":
                      production = solution.objective_value
                      growth = solution.fluxes["BIOMASS_Ecoli_core_w_GAM"]
      
                      if production > max_production * 1.05:  # >5% improvement
                          knockout_results.append({
                              "gene": gene.id,
                              "production": production,
                              "growth": growth,
                              "improvement": (production / max_production - 1) * 100
                          })
              except:
                  continue
      
      knockout_df = pd.DataFrame(knockout_results)
      if len(knockout_df) > 0:
          knockout_df = knockout_df.sort_values("improvement", ascending=False)
          print(f"\nFound {len(knockout_df)} beneficial knockouts:")
          print(knockout_df.head(10))
          knockout_df.to_csv("beneficial_knockouts.csv", index=False)
      else:
          print("No beneficial single knockouts found")
      
      # Step 6: Test combination of best knockouts
      if len(knockout_df) > 0:
          print("\nTesting knockout combinations...")
          top_genes = knockout_df.head(3)["gene"].tolist()
      
          with model:
              for gene_id in top_genes:
                  model.genes.get_by_id(gene_id).knock_out()
      
              solution = model.optimize()
              if solution.status == "optimal":
                  combined_production = solution.objective_value
                  combined_growth = solution.fluxes["BIOMASS_Ecoli_core_w_GAM"]
                  combined_improvement = (combined_production / max_production - 1) * 100
      
                  print(f"\nCombined knockout results:")
                  print(f"  Genes: {', '.join(top_genes)}")
                  print(f"  Production: {combined_production:.3f} mmol/gDW/h")
                  print(f"  Growth: {combined_growth:.3f} /h")
                  print(f"  Improvement: {combined_improvement:.1f}%")
      
      # Step 7: Analyze flux distribution in production strain
      if len(knockout_df) > 0:
          best_gene = knockout_df.iloc[0]["gene"]
      
          with model:
              model.genes.get_by_id(best_gene).knock_out()
              solution = model.optimize()
      
              # Get active pathways
              active_fluxes = solution.fluxes[solution.fluxes.abs() > 0.1]
              active_fluxes.to_csv(f"production_strain_fluxes_{best_gene}_knockout.csv")
      
              print(f"\nActive reactions in production strain: {len(active_fluxes)}")
      ```
      
      ## Workflow 5: Model Validation and Debugging
      
      This workflow shows systematic approaches to validate and debug metabolic models.
      
      ```python
      from cobra.io import load_model, read_sbml_model
      from cobra.flux_analysis import flux_variability_analysis
      import pandas as pd
      
      # Step 1: Load model
      model = load_model("textbook")  # E. coli core; or read_sbml_model("your_model.xml")
      print(f"Model: {model.id}")
      print(f"Reactions: {len(model.reactions)}")
      print(f"Metabolites: {len(model.metabolites)}")
      print(f"Genes: {len(model.genes)}")
      
      # Step 2: Check model feasibility
      print("\n--- Feasibility Check ---")
      try:
          objective_value = model.slim_optimize()
          print(f"Model is feasible (objective: {objective_value:.3f})")
      except:
          print("Model is INFEASIBLE")
          print("Troubleshooting steps:")
      
          # Check for blocked reactions
          from cobra.flux_analysis import find_blocked_reactions
          blocked = find_blocked_reactions(model)
          print(f"  Blocked reactions: {len(blocked)}")
          if len(blocked) > 0:
              print(f"  First 10 blocked: {list(blocked)[:10]}")
      
          # Check medium
          print(f"\n  Current medium: {model.medium}")
      
          # Try opening all exchanges
          for reaction in model.exchanges:
              reaction.lower_bound = -1000
      
          try:
              objective_value = model.slim_optimize()
              print(f"\n  Model feasible with open exchanges (objective: {objective_value:.3f})")
              print("  Issue: Medium constraints too restrictive")
          except:
              print("\n  Model still infeasible with open exchanges")
              print("  Issue: Structural problem (missing reactions, mass imbalance, etc.)")
      
      # Step 3: Check mass and charge balance
      print("\n--- Mass and Charge Balance Check ---")
      unbalanced_reactions = []
      for reaction in model.reactions:
          try:
              balance = reaction.check_mass_balance()
              if balance:
                  unbalanced_reactions.append({
                      "reaction": reaction.id,
                      "imbalance": balance
                  })
          except:
              pass
      
      if unbalanced_reactions:
          print(f"Found {len(unbalanced_reactions)} unbalanced reactions:")
          for item in unbalanced_reactions[:10]:
              print(f"  {item['reaction']}: {item['imbalance']}")
      else:
          print("All reactions are mass balanced")
      
      # Step 4: Identify dead-end metabolites
      print("\n--- Dead-end Metabolite Check ---")
      dead_end_metabolites = []
      for metabolite in model.metabolites:
          producing_reactions = [r for r in metabolite.reactions
                                if r.metabolites[metabolite] > 0]
          consuming_reactions = [r for r in metabolite.reactions
                                if r.metabolites[metabolite] < 0]
      
          if len(producing_reactions) == 0 or len(consuming_reactions) == 0:
              dead_end_metabolites.append({
                  "metabolite": metabolite.id,
                  "producers": len(producing_reactions),
                  "consumers": len(consuming_reactions)
              })
      
      if dead_end_metabolites:
          print(f"Found {len(dead_end_metabolites)} dead-end metabolites:")
          for item in dead_end_metabolites[:10]:
              print(f"  {item['metabolite']}: {item['producers']} producers, {item['consumers']} consumers")
      else:
          print("No dead-end metabolites found")
      
      # Step 5: Check for duplicate reactions
      print("\n--- Duplicate Reaction Check ---")
      reaction_equations = {}
      duplicates = []
      
      for reaction in model.reactions:
          equation = reaction.build_reaction_string()
          if equation in reaction_equations:
              duplicates.append({
                  "reaction1": reaction_equations[equation],
                  "reaction2": reaction.id,
                  "equation": equation
              })
          else:
              reaction_equations[equation] = reaction.id
      
      if duplicates:
          print(f"Found {len(duplicates)} duplicate reaction pairs:")
          for item in duplicates[:10]:
              print(f"  {item['reaction1']} == {item['reaction2']}")
      else:
          print("No duplicate reactions found")
      
      # Step 6: Identify orphan genes
      print("\n--- Orphan Gene Check ---")
      orphan_genes = [gene for gene in model.genes if len(gene.reactions) == 0]
      
      if orphan_genes:
          print(f"Found {len(orphan_genes)} orphan genes (not associated with reactions):")
          print(f"  First 10: {[g.id for g in orphan_genes[:10]]}")
      else:
          print("No orphan genes found")
      
      # Step 7: Check for thermodynamically infeasible loops
      print("\n--- Thermodynamic Loop Check ---")
      fva_loopless = flux_variability_analysis(model, loopless=True)
      fva_standard = flux_variability_analysis(model)
      
      loop_reactions = []
      for reaction_id in fva_standard.index:
          standard_range = fva_standard.loc[reaction_id, "maximum"] - fva_standard.loc[reaction_id, "minimum"]
          loopless_range = fva_loopless.loc[reaction_id, "maximum"] - fva_loopless.loc[reaction_id, "minimum"]
      
          if standard_range > loopless_range + 0.1:
              loop_reactions.append({
                  "reaction": reaction_id,
                  "standard_range": standard_range,
                  "loopless_range": loopless_range
              })
      
      if loop_reactions:
          print(f"Found {len(loop_reactions)} reactions potentially involved in loops:")
          loop_df = pd.DataFrame(loop_reactions).sort_values("standard_range", ascending=False)
          print(loop_df.head(10))
      else:
          print("No thermodynamically infeasible loops detected")
      
      # Step 8: Generate validation report
      print("\n--- Generating Validation Report ---")
      validation_report = {
          "model_id": model.id,
          "feasible": objective_value if 'objective_value' in locals() else None,
          "n_reactions": len(model.reactions),
          "n_metabolites": len(model.metabolites),
          "n_genes": len(model.genes),
          "n_unbalanced": len(unbalanced_reactions),
          "n_dead_ends": len(dead_end_metabolites),
          "n_duplicates": len(duplicates),
          "n_orphan_genes": len(orphan_genes),
          "n_loop_reactions": len(loop_reactions)
      }
      
      validation_df = pd.DataFrame([validation_report])
      validation_df.to_csv("model_validation_report.csv", index=False)
      print("Validation report saved to model_validation_report.csv")
      ```
      
      These workflows provide comprehensive templates for common COBRApy tasks. Adapt them as needed for specific research questions and models.
      
  • SKILL.md 15.7 KB
    ---
    name: alterlab-cobrapy
    description: Build and analyze genome-scale constraint-based metabolic models with COBRApy — flux balance analysis (FBA), flux variability analysis (FVA), gene and reaction knockouts, flux sampling, and SBML model I/O. Use when simulating metabolic networks, predicting growth or knockout phenotypes, or running systems-biology and metabolic-engineering analyses on SBML genome-scale models. Part of the AlterLab Academic Skills suite.
    license: GPL-2.0
    allowed-tools: Read Write Edit Bash(python:*) Bash(uv:*)
    compatibility: "Self-contained — runs under `uv run python` with `cobra` installed (0.32.1 as of 2026-09; depends on optlang, pandas < 3 and a solver). GLPK ships via swiglpk; CPLEX/Gurobi are optional and faster on big models. `load_model` and gapfilling from BiGG/BioModels need network access; everything else is offline."
    metadata:
        skill-author: AlterLab
        version: "1.1.0"
        last_updated: "2026-09-23"
    ---
    
    # COBRApy - Constraint-Based Reconstruction and Analysis
    
    ## Overview
    
    COBRApy is a Python library for constraint-based reconstruction and analysis (COBRA) of metabolic models, essential for systems biology research. Work with genome-scale metabolic models, perform computational simulations of cellular metabolism, conduct metabolic engineering analyses, and predict phenotypic behaviors.
    
    ## When to Use This Skill
    
    Use this skill when the user wants to:
    - Load a genome-scale metabolic model (SBML/JSON/YAML) and simulate growth with FBA/pFBA.
    - Predict knockout phenotypes, essential genes, or minimal media.
    - Explore flux space with FVA, flux sampling, or production envelopes.
    - Build, gapfill, or curate a constraint-based model.
    
    ### Does NOT Trigger
    
    | Scenario | Use Instead |
    |----------|-------------|
    | Looking up a pathway or reaction annotation rather than simulating | `alterlab-kegg`, `alterlab-reactome` |
    | Enzyme kinetic parameters (kcat, Km) for a reaction | `alterlab-brenda` |
    | Graph analysis of the metabolic network (centrality, communities) rather than flux | `alterlab-networkx` |
    | Metabolomics measurements and their identification | `alterlab-metabolomics-wb`, `alterlab-hmdb` |
    | Multi-objective optimization that is not a flux-balance problem | `alterlab-pymoo` |
    
    ## Installation and Requirements
    
    ```bash
    uv pip install cobra              # 0.32.x as of 2026-09
    uv pip install 'cobra[array]'     # scipy extra, for array-based model handling
    uv pip install 'cobra[chrr]'      # hopsy, enables the fast CHRR sampler
    ```
    
    **Requirements:** depends on optlang and a solver — GLPK ships by default via swiglpk, while CPLEX and Gurobi are optional and considerably faster on genome-scale models. pandas is a hard dependency (pinned `< 3`); matplotlib/seaborn only for plots. Flux sampling and parallel deletions use multiprocessing, so guard scripts with `if __name__ == "__main__":` on Windows/macOS spawn.
    
    > **Bundled model names.** `load_model` only recognizes three bundled aliases: `"textbook"` (the E. coli core model, `e_coli_core`), `"iJO1366"` (full E. coli genome-scale), and `"salmonella"`. Any other identifier (e.g. `"ecoli"`, `"e_coli_core"`) is not a bundled alias and triggers a remote lookup against BiGG/BioModels, which requires network access and may fail. Use `read_sbml_model("path.xml")` for your own models.
    
    ## Core Capabilities
    
    COBRApy provides comprehensive tools organized into several key areas:
    
    ### 1. Model Management
    
    Load existing models from repositories or files:
    ```python
    from cobra.io import load_model
    
    # Load bundled test models
    model = load_model("textbook")  # E. coli core model
    model = load_model("iJO1366")   # Full E. coli genome-scale model (BiGG)
    model = load_model("salmonella")
    
    # Load from files
    from cobra.io import read_sbml_model, load_json_model, load_yaml_model
    model = read_sbml_model("path/to/model.xml")
    model = load_json_model("path/to/model.json")
    model = load_yaml_model("path/to/model.yml")
    ```
    
    Save models in various formats:
    ```python
    from cobra.io import write_sbml_model, save_json_model, save_yaml_model
    write_sbml_model(model, "output.xml")  # Preferred format
    save_json_model(model, "output.json")  # For Escher compatibility
    save_yaml_model(model, "output.yml")   # Human-readable
    ```
    
    ### 2. Model Structure and Components
    
    Access and inspect model components:
    ```python
    # Access components
    model.reactions      # DictList of all reactions
    model.metabolites    # DictList of all metabolites
    model.genes          # DictList of all genes
    
    # Get specific items by ID or index
    reaction = model.reactions.get_by_id("PFK")
    metabolite = model.metabolites[0]
    
    # Inspect properties
    print(reaction.reaction)        # Stoichiometric equation
    print(reaction.bounds)          # Flux constraints
    print(reaction.gene_reaction_rule)  # GPR logic
    print(metabolite.formula)       # Chemical formula
    print(metabolite.compartment)   # Cellular location
    ```
    
    ### 3. Flux Balance Analysis (FBA)
    
    Perform standard FBA simulation:
    ```python
    # Basic optimization
    solution = model.optimize()
    print(f"Objective value: {solution.objective_value}")
    print(f"Status: {solution.status}")
    
    # Access fluxes
    print(solution.fluxes["PFK"])
    print(solution.fluxes.head())
    
    # Fast optimization (objective value only)
    objective_value = model.slim_optimize()
    
    # Change objective
    model.objective = "ATPM"
    solution = model.optimize()
    ```
    
    Parsimonious FBA (minimize total flux):
    ```python
    from cobra.flux_analysis import pfba
    solution = pfba(model)
    ```
    
    Geometric FBA (find central solution):
    ```python
    from cobra.flux_analysis import geometric_fba
    solution = geometric_fba(model)
    ```
    
    ### 4. Flux Variability Analysis (FVA)
    
    Determine flux ranges for all reactions:
    ```python
    from cobra.flux_analysis import flux_variability_analysis
    
    # Standard FVA
    fva_result = flux_variability_analysis(model)
    
    # FVA at 90% optimality
    fva_result = flux_variability_analysis(model, fraction_of_optimum=0.9)
    
    # Loopless FVA (eliminates thermodynamically infeasible loops)
    fva_result = flux_variability_analysis(model, loopless=True)
    
    # FVA for specific reactions
    fva_result = flux_variability_analysis(
        model,
        reaction_list=["PFK", "FBA", "PGI"]
    )
    ```
    
    ### 5. Gene and Reaction Deletion Studies
    
    Perform knockout analyses:
    ```python
    from cobra.flux_analysis import (
        single_gene_deletion,
        single_reaction_deletion,
        double_gene_deletion,
        double_reaction_deletion
    )
    
    # Single deletions
    gene_results = single_gene_deletion(model)
    reaction_results = single_reaction_deletion(model)
    
    # Double deletions (uses multiprocessing)
    double_gene_results = double_gene_deletion(
        model,
        processes=4  # Number of CPU cores
    )
    
    # Manual knockout using context manager
    with model:
        model.genes.get_by_id("b0008").knock_out()
        solution = model.optimize()
        print(f"Growth after knockout: {solution.objective_value}")
    # Model automatically reverts after context exit
    ```
    
    ### 6. Growth Media and Minimal Media
    
    Manage growth medium:
    ```python
    # View current medium
    print(model.medium)
    
    # Modify medium (must reassign entire dict)
    medium = model.medium
    medium["EX_glc__D_e"] = 10.0  # Set glucose uptake
    medium["EX_o2_e"] = 0.0       # Anaerobic conditions
    model.medium = medium
    
    # Calculate minimal media
    from cobra.medium import minimal_medium
    
    # Minimize total import flux
    min_medium = minimal_medium(model, minimize_components=False)
    
    # Minimize number of components (uses MILP, slower)
    min_medium = minimal_medium(
        model,
        minimize_components=True,
        open_exchanges=True
    )
    ```
    
    ### 7. Flux Sampling
    
    Sample the feasible flux space:
    ```python
    from cobra.sampling import sample
    
    # method defaults to "auto" in current cobrapy; the three options are:
    #   "chrr"  - coordinate hit-and-run with rounding, via the C++ hopsy library
    #             (install with cobra[chrr]); usually the fastest and best-mixing
    #   "optgp" - parallel, wants large n (>1000) to be efficient
    #   "achr"  - artificial centering hit-and-run, better for small n
    samples = sample(model, n=1000)                              # auto
    samples = sample(model, n=1000, method="optgp", processes=4)  # explicit OptGP
    samples = sample(model, n=1000, method="achr")
    
    # Validate samples
    from cobra.sampling import OptGPSampler
    sampler = OptGPSampler(model, processes=4)
    sampler.sample(1000)
    validation = sampler.validate(sampler.samples)
    print(validation.value_counts())  # Should be all 'v' for valid
    ```
    
    ### 8. Production Envelopes
    
    Calculate phenotype phase planes:
    ```python
    from cobra.flux_analysis import production_envelope
    
    # Standard production envelope
    envelope = production_envelope(
        model,
        reactions=["EX_glc__D_e", "EX_o2_e"],
        objective="EX_ac_e"  # Acetate production
    )
    
    # With carbon yield
    envelope = production_envelope(
        model,
        reactions=["EX_glc__D_e", "EX_o2_e"],
        carbon_sources="EX_glc__D_e"
    )
    
    # Visualize (use matplotlib or pandas plotting)
    import matplotlib.pyplot as plt
    envelope.plot(x="EX_glc__D_e", y="EX_o2_e", kind="scatter")
    plt.show()
    ```
    
    ### 9. Gapfilling
    
    Add reactions to make models feasible:
    ```python
    import cobra
    from cobra.flux_analysis import gapfill
    
    # Build a universal model of candidate reactions to draw from.
    # In practice, load a curated reaction database (e.g. the BiGG
    # universal reactions JSON via load_json_model) or assemble reactions
    # into an empty cobra.Model — there is no load_model("universal").
    universal = cobra.Model("universal_reactions")
    # ...populate `universal` with candidate cobra.Reaction objects...
    
    with model:
        # Create a gap for demonstration
        model.remove_reactions([model.reactions.PGI])
    
        # Find the minimal set of reactions from `universal` to restore feasibility
        solution = gapfill(model, universal, demand_reactions=False)
        for reaction in solution[0]:
            print(reaction.id)
    ```
    
    > **Note**: `gapfill` returns a list of reaction lists (one per iteration when `iterations > 1`), so iterate `solution[0]` rather than printing `solution` directly.
    
    ### 10. Model Building
    
    Build models from scratch:
    ```python
    from cobra import Model, Reaction, Metabolite
    
    # Create model
    model = Model("my_model")
    
    # Create metabolites
    atp_c = Metabolite("atp_c", formula="C10H12N5O13P3",
                       name="ATP", compartment="c")
    adp_c = Metabolite("adp_c", formula="C10H12N5O10P2",
                       name="ADP", compartment="c")
    pi_c = Metabolite("pi_c", formula="HO4P",
                      name="Phosphate", compartment="c")
    
    # Create reaction
    reaction = Reaction("ATPASE")
    reaction.name = "ATP hydrolysis"
    reaction.subsystem = "Energy"
    reaction.lower_bound = 0.0
    reaction.upper_bound = 1000.0
    
    # Add metabolites with stoichiometry
    reaction.add_metabolites({
        atp_c: -1.0,
        adp_c: 1.0,
        pi_c: 1.0
    })
    
    # Add gene-reaction rule
    reaction.gene_reaction_rule = "(gene1 and gene2) or gene3"
    
    # Add to model
    model.add_reactions([reaction])
    
    # Add boundary reactions
    model.add_boundary(atp_c, type="exchange")
    model.add_boundary(adp_c, type="demand")
    
    # Set objective
    model.objective = "ATPASE"
    ```
    
    ## Common Workflows
    
    ### Workflow 1: Load Model and Predict Growth
    
    ```python
    from cobra.io import load_model
    
    # Load model
    model = load_model("iJO1366")
    
    # Run FBA
    solution = model.optimize()
    print(f"Growth rate: {solution.objective_value:.3f} /h")
    
    # Show active pathways
    print(solution.fluxes[solution.fluxes.abs() > 1e-6])
    ```
    
    ### Workflow 2: Gene Knockout Screen
    
    ```python
    from cobra.io import load_model
    from cobra.flux_analysis import single_gene_deletion
    
    # Load model
    model = load_model("iJO1366")
    
    # Perform single gene deletions
    results = single_gene_deletion(model)
    
    # Find essential genes (growth < threshold)
    essential_genes = results[results["growth"] < 0.01]
    print(f"Found {len(essential_genes)} essential genes")
    
    # Find genes with minimal impact
    neutral_genes = results[results["growth"] > 0.9 * solution.objective_value]
    ```
    
    ### Workflow 3: Media Optimization
    
    ```python
    from cobra.io import load_model
    from cobra.medium import minimal_medium
    
    # Load model
    model = load_model("iJO1366")
    
    # Calculate minimal medium for 50% of max growth
    target_growth = model.slim_optimize() * 0.5
    min_medium = minimal_medium(
        model,
        target_growth,
        minimize_components=True
    )
    
    print(f"Minimal medium components: {len(min_medium)}")
    print(min_medium)
    ```
    
    ### Workflow 4: Flux Uncertainty Analysis
    
    ```python
    from cobra.io import load_model
    from cobra.flux_analysis import flux_variability_analysis
    from cobra.sampling import sample
    
    # Load model
    model = load_model("iJO1366")
    
    # First check flux ranges at optimality
    fva = flux_variability_analysis(model, fraction_of_optimum=1.0)
    
    # For reactions with large ranges, sample to understand distribution
    samples = sample(model, n=1000)
    
    # Analyze specific reaction
    reaction_id = "PFK"
    import matplotlib.pyplot as plt
    samples[reaction_id].hist(bins=50)
    plt.xlabel(f"Flux through {reaction_id}")
    plt.ylabel("Frequency")
    plt.show()
    ```
    
    ### Workflow 5: Context Manager for Temporary Changes
    
    Use context managers to make temporary modifications:
    ```python
    # Model remains unchanged outside context
    with model:
        # Temporarily change objective
        model.objective = "ATPM"
    
        # Temporarily modify bounds
        model.reactions.EX_glc__D_e.lower_bound = -5.0
    
        # Temporarily knock out genes
        model.genes.b0008.knock_out()
    
        # Optimize with changes
        solution = model.optimize()
        print(f"Modified growth: {solution.objective_value}")
    
    # All changes automatically reverted
    solution = model.optimize()
    print(f"Original growth: {solution.objective_value}")
    ```
    
    ## Key Concepts
    
    ### DictList Objects
    Models use `DictList` objects for reactions, metabolites, and genes - behaving like both lists and dictionaries:
    ```python
    # Access by index
    first_reaction = model.reactions[0]
    
    # Access by ID
    pfk = model.reactions.get_by_id("PFK")
    
    # Query methods
    atp_reactions = model.reactions.query("atp")
    ```
    
    ### Flux Constraints
    Reaction bounds define feasible flux ranges:
    - **Irreversible**: `lower_bound = 0, upper_bound > 0`
    - **Reversible**: `lower_bound < 0, upper_bound > 0`
    - Set both bounds simultaneously with `.bounds` to avoid inconsistencies
    
    ### Gene-Reaction Rules (GPR)
    Boolean logic linking genes to reactions:
    ```python
    # AND logic (both required)
    reaction.gene_reaction_rule = "gene1 and gene2"
    
    # OR logic (either sufficient)
    reaction.gene_reaction_rule = "gene1 or gene2"
    
    # Complex logic
    reaction.gene_reaction_rule = "(gene1 and gene2) or (gene3 and gene4)"
    ```
    
    ### Exchange Reactions
    Special reactions representing metabolite import/export:
    - Named with prefix `EX_` by convention
    - Positive flux = secretion, negative flux = uptake
    - Managed through `model.medium` dictionary
    
    ## Best Practices
    
    1. **Use context managers** for temporary modifications to avoid state management issues
    2. **Validate models** before analysis using `model.slim_optimize()` to ensure feasibility
    3. **Check solution status** after optimization - `optimal` indicates successful solve
    4. **Use loopless FVA** when thermodynamic feasibility matters
    5. **Set fraction_of_optimum** appropriately in FVA to explore suboptimal space
    6. **Parallelize** computationally expensive operations (sampling, double deletions)
    7. **Prefer SBML format** for model exchange and long-term storage
    8. **Use slim_optimize()** when only objective value needed for performance
    9. **Validate flux samples** to ensure numerical stability
    
    ## Troubleshooting
    
    **Infeasible solutions**: Check medium constraints, reaction bounds, and model consistency
    **Slow optimization**: Try different solvers (GLPK, CPLEX, Gurobi) via `model.solver`
    **Unbounded solutions**: Verify exchange reactions have appropriate upper bounds
    **Import errors**: Ensure correct file format and valid SBML identifiers
    
    ## References
    
    For detailed workflows and API patterns, refer to:
    - `references/workflows.md` - Comprehensive step-by-step workflow examples
    - `references/api_quick_reference.md` - Common function signatures and patterns
    
    Official documentation: https://cobrapy.readthedocs.io/en/latest/
    
    Part of the AlterLab Academic Skills suite.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related