Predict mutations with Pint, refine with MaBoSS#

This notebook shows a possible way to combine formal prediction of mutation performed by Pint with the quantiative evaluation of attractors reachability with MaBoSS.

A detailed use case of such an analysis can be found in the notebook “Usecase - Mutations enabling tumour invasion”.

Model#

We load a model of cell fate decision model from CellCollective using bioLQM:

import biolqm
lqm = biolqm.load("http://ginsim.org/sites/default/files/SuppMat_Model_Master_Model.zginml")

Downloading ‘http://ginsim.org/sites/default/files/SuppMat_Model_Master_Model.zginml’

Wild-type simulation with MaBoSS#

We convert the model to MaBoSS, and configure the simulation

import maboss
wt_sim = biolqm.to_maboss(lqm)
wt_sim.network.set_output(('Metastasis', 'Migration', 'Invasion', 'Apoptosis', 'CellCycleArrest'))
wt_sim.network.set_istate("ECMicroenv", [0, 1]) # ECM is active
wt_sim.network.set_istate("DNAdamage", [0.5, 0.5]) # DNAdamage can start either active or inactive
wt_sim.update_parameters(max_time=50)

We perform the simulation with MaBoSS, this can take several seconds.

wt_res = wt_sim.run()

We plot the distribution of attractors at the end of the simulations:

wt_res.plot_piechart()
../../_images/2bc9f6d476edad1a7e233bea2d4f188ffe40d0e746442abc5f20bb3fb41c039a.png

Mutation prediction with Pint#

Now, we use Pint to predict mutations which remove any possible activation of apoptosis.

import pypint
m = biolqm.to_pint(lqm)
m.initial_state["ECMicroenv"] = 1
m.initial_state["DNAdamage"] = {0,1}
mutants = m.oneshot_mutations_for_cut("Apoptosis=1", exclude={"ECMicroenv", "DNAdamage"})
mutants

This computation is an under-approximation: returned mutations are all valid, but they may be non-minimal, and some solutions may be missed.

Limiting solutions to mutations of at most 5 automata. Use maxsize argument to change.

[{'ZEB2': 1},
 {'AKT1': 1},
 {'AKT2': 1},
 {'ERK': 1},
 {'SNAI2': 1, 'ZEB1': 1, 'NICD': 1},
 {'SNAI2': 1, 'ZEB1': 1, 'p63': 0},
 {'SNAI2': 1, 'ZEB1': 1, 'miR203': 1},
 {'SNAI2': 1, 'NICD': 1, 'p73': 0},
 {'SNAI2': 1, 'p63': 0, 'p73': 0},
 {'SNAI2': 1, 'p73': 0, 'miR203': 1},
 {'ZEB1': 1, 'NICD': 1, 'p53': 0},
 {'ZEB1': 1, 'p63': 0, 'p53': 0},
 {'ZEB1': 1, 'p53': 0, 'miR203': 1},
 {'NICD': 1, 'p53': 0, 'p73': 0},
 {'p63': 0, 'p53': 0, 'p73': 0},
 {'p53': 0, 'p73': 0, 'miR203': 1}]

Each returned solution gives a combination of mutations which are guaranteed to remove the capability to activate apoptosis, even transiently.

Collecting experiments#

Among the results returned by Pint, we want to try any potential double-mutant that may be sufficient to remove the reachability of a stable apoptosis.

We use Python standard library functions to compute all the couple of mutations in each predicted mutations, and then merge these couples in a single set of candidate double-mutants.

from itertools import combinations
from functools import reduce
mutant_combinations = [combinations(m.items(), 2) for m in mutants if len(m) >= 2]
candidates = reduce(set.union, mutant_combinations, set())
candidates
{(('NICD', 1), ('p53', 0)),
 (('NICD', 1), ('p73', 0)),
 (('SNAI2', 1), ('NICD', 1)),
 (('SNAI2', 1), ('ZEB1', 1)),
 (('SNAI2', 1), ('miR203', 1)),
 (('SNAI2', 1), ('p63', 0)),
 (('SNAI2', 1), ('p73', 0)),
 (('ZEB1', 1), ('NICD', 1)),
 (('ZEB1', 1), ('miR203', 1)),
 (('ZEB1', 1), ('p53', 0)),
 (('ZEB1', 1), ('p63', 0)),
 (('p53', 0), ('miR203', 1)),
 (('p53', 0), ('p73', 0)),
 (('p63', 0), ('p53', 0)),
 (('p63', 0), ('p73', 0)),
 (('p73', 0), ('miR203', 1))}

Double-mutant experiments with MaBoSS#

For each candidate double-mutant, we copy the MaBoSS wild-type model, apply the corresponding mutation and run the simulations. As there are 16 candidates to evaluate, the overall execution can take several minutes.

import matplotlib.pyplot as plt # for customizing the plots
for mutant in sorted(candidates):
    mut_sim = wt_sim.copy()
    for (node, value) in mutant:
        mut_sim.mutate(node, "ON" if value else "OFF")
    mut_res = mut_sim.run()
    mut_res.plot_piechart(embed_labels=False, autopct=4)
    mutant_name = "/".join(["%s:%s"%m for m in mutant])
    plt.title("%s mutant" % mutant_name)
../../_images/009db3d0245c65beaeaac53bd1ea932c4cc26cdac6d43effeb45c9f59b88fef5.png ../../_images/2e17bc505bbdc7fa49e3fad4de62c9089a4516721f4f06882557436d0c0e5ab2.png ../../_images/c7aae6f67987d9b9d21c48e28d59af5243f2aaeb631c2887110d1ebcdb02974f.png ../../_images/cefaaac0439b7fd4e1722b39ac4cfa4e719a6b7c4b821f89a2b3daefb62c754b.png ../../_images/a8a81a82020205714be48a55e227cd0efba737481adee42c2595d77cf17c5c0a.png ../../_images/57f8e678412141f954fc5473ef58f76a55d741288481b517cf1e42fd7f121d5e.png ../../_images/7e6a17fb4462e2c39ac4ac277e7afe482cf50024ff69a7f65799eda97492e9e4.png ../../_images/904b7d351f4671fa2ff2f49107a20d2f7638eb4186569f28f33811554b194289.png ../../_images/1f8e8a51f6edd70ba483996619bf18a852cea53380474fb310397ddb10ea8627.png ../../_images/b883685dc2de6c2f3a3ee3adcaaadfe5a801edd07b81fccd0a43f42f6b6bbc32.png ../../_images/28ec7c4efbcf1757dc614fc63652123159f12766b5310802db7aad7f7b7d0c3f.png ../../_images/2d88e59146ec5d53cfc1dd7a538127f233245ae0155c0cacee9994b073a65b80.png ../../_images/079a092a9c0d0828993005ef6ef7f35dbfd89f1ad4fc2f126d30be90fda64a8a.png ../../_images/2accbedfa92f2c06c6b3080c6b6631e58408f6a82c64589e03bddb5d7ca0e0a8.png ../../_images/0f05094b20649f19587d24876522441367c5f6c7c6111ae9b0ef580e533ef030.png ../../_images/12928c03880c8b787ad2471369078eb5fefc283caa1af290d59b8a4ab91010b9.png