T cell co-inhibitory pathways

This notebook provides a reproducible analysis for a model of the T cell inhibitor checkpoints.

It contains the following results:

  • identify stable states
  • identify trap spaces
  • propagation of CTLA4 and PD1 values through the model

Authors: Celine Hernandez, Aurélien Naldi

In [1]:
import ginsim
import biolqm
from colomoto_jupyter import tabulate

import pandas as pd
import numpy as np
In [2]:
# Load and view the model
gs_model = ginsim.load("Hernandez_TcellCheckPoints_13april2020.zginml")
lqm_model = ginsim.to_biolqm(gs_model)
ginsim.show(gs_model, save="figure_interaction_graph_model")
Saving as figure_interaction_graph_model.svg
Out[2]:

Helper functions

Here we define some helper functions and color mapping rules to perform value propagation and visualize the result.

In [3]:
# Transforms a dictionary into a dash-like pattern used for space restrictions.
# If a model has 4 components A, B, C, D in this order,
#  {A:0, D:1} => "0--1"
def dash_pattern(model, dict_vals):
    specific_comps = dict_vals.keys()
    str_pattern = ""
    for comp in model.getComponents():
        if comp.toString() in specific_comps:
            str_pattern += str(dict_vals.get(comp.toString()))
        else :
            str_pattern += "-"
    return(str_pattern)

def restrict_model(model, **dict_vals):
    pattern = dash_pattern(lqm_model, dict_vals)
    return biolqm.restrict(lqm_model, pattern)

def fill_fixed(data, names, functions, mddman):
    all_values = [f for f in functions]
    for comp, func in zip(names, functions):
        if mddman.isleaf(func): data[comp] = func
        else: data[comp] = -1
    

def get_fixed_pattern(all_names, model, as_dict=False):
    # Build a container for the results
    pattern = {key: 100 for key in all_names}
    
    # Model manager and core components
    mddman = model.getMDDManager()
    core_components = [node.getNodeID() for node in model.getComponents()]
    extra_components = [node.getNodeID() for node in model.getExtraComponents()]
    
    # 1/ Non-extra values: if the model was not reduced, core components may also contain fixed values
    fill_fixed(pattern, core_components, model.getLogicalFunctions(), mddman)

    # Special value for input components
    for node in model.getComponents():
        if node.isInput():
            pattern[node.getNodeID()] = -2

    
    # 2/ Extra values : only available after reduction/percolation
    # Functions of each component
    fill_fixed(pattern, extra_components, model.getExtraLogicalFunctions(), mddman)

    if as_dict: return pattern
    return pd.Series(pattern, dtype=np.byte).values.tobytes()

def compare_fixed_pattern(all_names, model1, model2, as_dict=False):
    pattern1 = get_fixed_pattern(all_names, model1, as_dict=True)
    pattern2 = get_fixed_pattern(all_names, model2, as_dict=True)
    
    pattern = {}
    for c in pattern1:
        v1 = pattern1[c]
        v2 = pattern2[c]
        
        if v1 == v2: pattern[c] = v1
        elif v1 < 0: pattern[c] = 10 + v2
        elif v2 < 0: pattern[c] = 20 + v1
        else: pattern[c] = 100

    if as_dict: return pattern
    return pd.Series(pattern, dtype=np.byte).values.tobytes()


def show_fixed_comparison(gs_model, restricted_model1, restricted_model2, styler, save=None):
    name_components = [ n.getId() for n in gs_model.getNodeOrder() ]
    pattern = compare_fixed_pattern(name_components, restricted_model1, restricted_model2)
    styler.setState( pattern )
    return ginsim.show(gs_model, style=styler, save=save)    


def show_fixed(gs_model, restricted_model, styler, save=None):
    name_components = [ n.getId() for n in gs_model.getNodeOrder() ]
    fixed_pattern = get_fixed_pattern(name_components, restricted_model)
    styler.setState(fixed_pattern)
    return ginsim.show(gs_model, style=styler, save=save)


# Define color mapping rules

# Style for a single fixed pattern
styler_fixed = ginsim.lrg_style(gs_model)
styler_fixed.mapState2Color(0, 200, 25, 25)
styler_fixed.mapState2Color(1, 100, 175, 100)
styler_fixed.mapState2Color(2, 100, 225, 100)
styler_fixed.mapState2Color(-1, 255, 255, 255)
styler_fixed.mapState2Color(-2, 175, 175, 175)


# Style for comparing two patterns
styler_comp = ginsim.lrg_style(gs_model)
styler_comp.mapState2Color(-2, 175, 175, 175) # INPUT: gray
styler_comp.mapState2Color(0, 255, 255, 180)  # OFF  in both: light yellow
styler_comp.mapState2Color(1, 255, 180, 120)  # ON   in both: light orange
styler_comp.mapState2Color(2, 255, 180, 120)  # HIGH in both: light orange
styler_comp.mapState2Color(-1, 255, 255, 255) # FREE in both: white
styler_comp.mapState2Color(10, 200, 255, 200) # OFF in the first: light green
styler_comp.mapState2Color(11, 125, 200, 125) # ON  in the first: dark green
styler_comp.mapState2Color(20, 200, 200, 255) # OFF in the second: light green
styler_comp.mapState2Color(21, 125, 125, 200) # ON  in the second: dark green
styler_comp.mapState2Color(100, 255, 180, 180) # Other (different values?): red

Identify stable states

In [4]:
# Model simplification:
#   * Fix all inputs to their inactive state.
fixed = { str(n):0 for n in lqm_model.getComponents() if n.isInput()}

# Keep 'i_pMHCII_binding', 'i_pMHCII_agonist', (not 'i_pMHCII_dose'), 'i_pMHCII_affinity', 'i_CD80' as proper inputs 
for n in ('i_pMHCII_binding', 'i_pMHCII_agonist', 'i_pMHCII_affinity', 'i_CD80', 'i_CD274'):
    del(fixed[n])

# Fix inputs to their active state
fixed['CTLA4'] = 0
In [5]:
# Apply the simplifications defined above to reduce the model
m_reduced = biolqm.perturbation(lqm_model, " ".join([ "%s%%%s" % (k,v) for (k,v) in fixed.items() ]))
m_reduced = biolqm.reduce(m_reduced, ":fixed :purge :no-extra")
In [6]:
# Define reporter components
reporter_components = ["TCRalphabeta", "CD28", "NFAT_nuc", "FOS", "JUN", "NF_KB", "IL2", "Proliferation", "DGKA", "Anergy", "Quiescence"]

fps = biolqm.fixpoints(m_reduced, autoconvert=False
      ).project_on_components( reporter_components )
df = biolqm.states_to_dataframe(fps)
df
Out[6]:
TCRalphabeta CD28 Quiescence Proliferation NF_KB NFAT_nuc DGKA Anergy FOS JUN IL2
0 0 0 1 0 0 0 0 0 0 0 0
1 0 1 1 0 0 0 0 0 0 0 0
2 1 0 1 0 0 0 0 0 0 0 0
3 1 1 1 0 0 0 0 0 0 0 0
4 1 1 1 0 1 0 0 0 0 0 0
5 1 1 0 0 0 0 0 0 0 1 0
6 1 1 0 0 1 0 0 0 0 1 0
7 1 1 0 1 1 1 0 0 1 1 1

Identify trap spaces (skipped)

In [7]:
# Define reporter components
reporter_components = ["TCRalphabeta", "CD28", "NFAT_nuc", "FOS", "JUN", "NF_KB", "IL2", "Proliferation", "DGKA", "Anergy", "Quiescence"]

if False:
    fps = biolqm.trapspaces(m_reduced, autoconvert=False
          ).project_on_components( reporter_components )
    biolqm.states_to_dataframe(fps)

Percolate CTLA4 and PD1 values

No constrain

First we want to visualize fixed values on the model without any constraint. Fixed values will appear in white. This will be used as a reference to see if percolating a value will change anything from this default setting.

In [8]:
# Reduce fixed values
lqm_model_fixed_reduced = biolqm.reduce(lqm_model, ":fixed :purge")
show_fixed(gs_model, lqm_model_fixed_reduced, styler_fixed)
Out[8]:

CTAL4:0

In [9]:
# Percolate a value of 0 for CTLA4
lqm_model_restricted_ctla4_0 = restrict_model(lqm_model, CTLA4=0)
show_fixed(gs_model, lqm_model_restricted_ctla4_0, styler_fixed)
Out[9]:

CTAL4:1

In [10]:
# Percolate a value of 1 for CTLA4
lqm_model_restricted_ctla4_1 = restrict_model(lqm_model, CTLA4=1)
show_fixed(gs_model, lqm_model_restricted_ctla4_1, styler_fixed, save="figure_percolation_ctla4_1")
Saving as figure_percolation_ctla4_1.svg
Out[10]:

Display fixed point

In [11]:
print("Before restriction : Total components : %d, Extra components : %d" % (len(lqm_model.getComponents()),
                                                        len(lqm_model.getExtraComponents())))
print("After restriction : Total components : %d, Extra components : %d" % (len(lqm_model_restricted_ctla4_1.getComponents()),
                                                        len(lqm_model_restricted_ctla4_1.getExtraComponents())))
#biolqm.fixpoints(lqm_model_restricted_ctla4_1, "extra")
Before restriction : Total components : 216, Extra components : 0
After restriction : Total components : 43, Extra components : 173
In [12]:
# Stable state pattern with signal
fix_points_ctla4_1_nb1 = {'i_pMHCII_binding':1, 'i_pMHCII_agonist':1, 'i_pMHCII_dose':0, 'i_pMHCII_affinity':1, 'TCRalphabeta':0, 'pTCR':0, 'i_CD80':1, 'i_CD86':0, 'CD28':0, 'CTLA4':1, 'IDO_DC':1, 'i_ICOSLG':0, 'ICOS':0, 'i_CD5':0, 'i_ALCAM':0, 'CD6':0, 'i_CD274':0, 'i_PDCD1LG2':0, 'PDCD1':0, 'i_TNFRSF14':0, 'BTLA':0, 'i_LGALS9':0, 'TIM3':0, 'i_OX40L':0, 'OX40':0, 'i_cAMP':0, 'PKA':0, 'CD4':1, 'f_MAL':1, 'f_UNC119':1, 'f_RAB11A':1, 'f_PTPRJ':0, 'f_14_3_3':0, 'f_PRKDC':1, 'f_MDM2':0, 'f_NCKAP1L':1, 'f_NCKAP1':1, 'f_BAIAP2':1, 'f_CYFIP1':1, 'f_BRK1':1, 'f_WASF2':1, 'f_ABI1':1, 'f_ABI2':1, 'f_ACTR2':1, 'f_ACTR3':1, 'f_PRDX1':0, 'f_CRACR2A':1, 'f_ROS':0, 'f_RCAN1':0, 'f_CABIN1':0, 'f_AKAP5':0, 'f_BBC3':0, 'f_APAF1':0, 'f_DEPTOR':0, 'f_RICTOR':1, 'f_MLST8':1, 'f_MTOR':1, 'f_Glucose':1, 'MAP2K6':0, 'f_DUSP2':0, 'f_DUSP4':0, 'DUSP5':0, 'f_DUSP6':0, 'f_DUSP10':0, 'f_DUSP22':0, 'f_Axin1':0, 'f_SMAD3':0, 'f_Th1':0, 'f_BAT3':0, 'INF2':0, 'LCK':1, 'pY505LCK':1, 'pY394LCK':1, 'pS59LCK':100, 'LCK_activity':1, 'CSK':1, 'PAG1':1, 'LIME1':1, 'PTPN6':0, 'PTPN22':0, 'PTPRC':1, 'PTPN11':1, 'PP2A':1, 'CBL':0, 'CBLB':1, 'INPP5D':0, 'FYN':1, 'ZAP70':0, 'LAT':0, 'GRB2':0, 'SOS':0, 'GAB2':0, 'GRAP2':0, 'GRAP':0, 'LCP2':0, 'ITK':0, 'SHB':0, 'TXK':0, 'MAP4K1':1, 'MAP4K3':0, 'PLCG1_binding':0, 'PTEN':1, 'PI3K':0, 'PIP2':100, 'IP3':0, 'DAG':100, 'PIP3':0, 'PDPK1':0, 'AKT1':0, 'FOXO1':1, 'GSK3A':1, 'GSK3B':1, 'TP53':1, 'CDKN1A':1, 'CDKN1B':0, 'Quiescence':1, 'PCNA':0, 'CTNNB1':0, 'CCND1':0, 'MYC':0, 'Proliferation':0, 'PRKCQ':0, 'CARD11':0, 'BCL10':0, 'MALT1':0, 'MAP3K7':0, 'MAP3K3':0, 'CHUK':0, 'IKBKG':0, 'IKBKB':0, 'NFKBIA':1, 'NF_KB':0, 'CREBBP':1, 'FOXP3':0, 'CTLA4_out':0, 'Treg':0, 'BAD':1, 'BCL2L1':0, 'VDAC1':1, 'CYCS':1, 'Caspase9':0, 'Survival':0, 'Apoptosis':0, 'RPTOR':1, 'GYS1':0, 'Glycogenesis':0, 'mTORC2':1, 'mTORC1':0, 'RPS6KA1':0, 'RPS6KB1':0, 'TSC1_TSC2':1, 'RHEB':0, 'Growth':0, 'Triglyceride_synthesis':1, 'Protein_synthesis':0, 'NCK1':0, 'CDC42':0, 'WAS':0, 'RAC1':0, 'WAVE_cplx':0, 'ARP2_3':0, 'PAK1':0, 'LIMK1':0, 'CFL1':1, 'HCLS1':0, 'VAV1':0, 'SH3BP2':0, 'ABL1':1, 'Actin_polymerisation':0, 'RHOA':0, 'ROCK1':0, 'MLCP':1, 'Actin_contraction_migration':0, 'FYB':0, 'Adhesion_Integrin':0, 'IP3R1':0, 'Calcium_ER':0, 'Calcium_cyt':0, 'SERCA':0, 'STIM1':1, 'ORAI1':0, 'PMCA':0, 'Mitochondria':0, 'Calmodulin':0, 'Calcineurin':0, 'CAMK4':0, 'CAMK2G':1, 'NFAT_nuc':0, 'PDCD1_out':0, 'DGKA':0, 'Anergy':0, 'RASGRP1':0, 'HRAS':0, 'RAF1':0, 'MAP2K1':0, 'MAPK3':0, 'MAPK1':0, 'ELK1':0, 'FOS':0, 'MAP3K1':0, 'MAP3K11':1, 'MAP2K4':0, 'MAP2K7':0, 'JNK':0, 'JUN':0, 'GADD45A':1, 'ATF2':0, 'p38':0, 'RPS6KA4':0, 'RPS6KA5':0, 'CREB1':0, 'DUSP1':0, 'IL2':0, 'Differentiation':0, 'Th2':0, 'PLCG1':0}
fix_points_ctla4_1_nb2 = {'i_pMHCII_binding':1, 'i_pMHCII_agonist':1, 'i_pMHCII_dose':0, 'i_pMHCII_affinity':1, 'TCRalphabeta':0, 'pTCR':0, 'i_CD80':1, 'i_CD86':0, 'CD28':0, 'CTLA4':1, 'IDO_DC':1, 'i_ICOSLG':0, 'ICOS':0, 'i_CD5':0, 'i_ALCAM':0, 'CD6':0, 'i_CD274':0, 'i_PDCD1LG2':0, 'PDCD1':0, 'i_TNFRSF14':0, 'BTLA':0, 'i_LGALS9':0, 'TIM3':0, 'i_OX40L':0, 'OX40':0, 'i_cAMP':0, 'PKA':0, 'CD4':1, 'f_MAL':1, 'f_UNC119':1, 'f_RAB11A':1, 'f_PTPRJ':0, 'f_14_3_3':0, 'f_PRKDC':1, 'f_MDM2':0, 'f_NCKAP1L':1, 'f_NCKAP1':1, 'f_BAIAP2':1, 'f_CYFIP1':1, 'f_BRK1':1, 'f_WASF2':1, 'f_ABI1':1, 'f_ABI2':1, 'f_ACTR2':1, 'f_ACTR3':1, 'f_PRDX1':0, 'f_CRACR2A':1, 'f_ROS':0, 'f_RCAN1':0, 'f_CABIN1':0, 'f_AKAP5':0, 'f_BBC3':0, 'f_APAF1':0, 'f_DEPTOR':0, 'f_RICTOR':1, 'f_MLST8':1, 'f_MTOR':1, 'f_Glucose':1, 'MAP2K6':0, 'f_DUSP2':0, 'f_DUSP4':0, 'DUSP5':0, 'f_DUSP6':0, 'f_DUSP10':0, 'f_DUSP22':0, 'f_Axin1':0, 'f_SMAD3':0, 'f_Th1':0, 'f_BAT3':0, 'INF2':0, 'LCK':1, 'pY505LCK':1, 'pY394LCK':1, 'pS59LCK':100, 'LCK_activity':1, 'CSK':1, 'PAG1':1, 'LIME1':1, 'PTPN6':0, 'PTPN22':0, 'PTPRC':1, 'PTPN11':1, 'PP2A':1, 'CBL':0, 'CBLB':1, 'INPP5D':0, 'FYN':1, 'ZAP70':0, 'LAT':0, 'GRB2':0, 'SOS':0, 'GAB2':0, 'GRAP2':0, 'GRAP':0, 'LCP2':0, 'ITK':0, 'SHB':0, 'TXK':0, 'MAP4K1':1, 'MAP4K3':0, 'PLCG1_binding':0, 'PTEN':1, 'PI3K':0, 'PIP2':100, 'IP3':0, 'DAG':100, 'PIP3':0, 'PDPK1':0, 'AKT1':0, 'FOXO1':1, 'GSK3A':1, 'GSK3B':1, 'TP53':1, 'CDKN1A':1, 'CDKN1B':0, 'Quiescence':1, 'PCNA':0, 'CTNNB1':0, 'CCND1':0, 'MYC':0, 'Proliferation':0, 'PRKCQ':0, 'CARD11':0, 'BCL10':0, 'MALT1':0, 'MAP3K7':0, 'MAP3K3':0, 'CHUK':0, 'IKBKG':0, 'IKBKB':0, 'NFKBIA':1, 'NF_KB':0, 'CREBBP':1, 'FOXP3':0, 'CTLA4_out':0, 'Treg':0, 'BAD':1, 'BCL2L1':0, 'VDAC1':1, 'CYCS':1, 'Caspase9':0, 'Survival':0, 'Apoptosis':0, 'RPTOR':1, 'GYS1':0, 'Glycogenesis':0, 'mTORC2':1, 'mTORC1':0, 'RPS6KA1':0, 'RPS6KB1':0, 'TSC1_TSC2':1, 'RHEB':0, 'Growth':0, 'Triglyceride_synthesis':1, 'Protein_synthesis':0, 'NCK1':0, 'CDC42':0, 'WAS':0, 'RAC1':0, 'WAVE_cplx':0, 'ARP2_3':0, 'PAK1':0, 'LIMK1':0, 'CFL1':1, 'HCLS1':0, 'VAV1':0, 'SH3BP2':0, 'ABL1':1, 'Actin_polymerisation':0, 'RHOA':0, 'ROCK1':0, 'MLCP':1, 'Actin_contraction_migration':0, 'FYB':0, 'Adhesion_Integrin':0, 'IP3R1':0, 'Calcium_ER':1, 'Calcium_cyt':0, 'SERCA':0, 'STIM1':0, 'ORAI1':0, 'PMCA':0, 'Mitochondria':0, 'Calmodulin':0, 'Calcineurin':0, 'CAMK4':0, 'CAMK2G':1, 'NFAT_nuc':0, 'PDCD1_out':0, 'DGKA':0, 'Anergy':0, 'RASGRP1':0, 'HRAS':0, 'RAF1':0, 'MAP2K1':0, 'MAPK3':0, 'MAPK1':0, 'ELK1':0, 'FOS':0, 'MAP3K1':0, 'MAP3K11':1, 'MAP2K4':0, 'MAP2K7':0, 'JNK':0, 'JUN':0, 'GADD45A':1, 'ATF2':0, 'p38':0, 'RPS6KA4':0, 'RPS6KA5':0, 'CREB1':0, 'DUSP1':0, 'IL2':0, 'Differentiation':0, 'Th2':0, 'PLCG1':0}
# Display the model
ginsim.show(gs_model, fix_points_ctla4_1_nb2)
Out[12]:

PD1:0

In [13]:
# Percolate a value of 0 for PD1
lqm_model_restricted_pdcd1_0 = restrict_model(lqm_model, PDCD1=0)
show_fixed(gs_model, lqm_model_restricted_pdcd1_0, styler_fixed)
Out[13]:

PD1:1

In [14]:
# Percolate a value of 1 for PD1
lqm_model_restricted_pdcd1_1 = restrict_model(lqm_model, PDCD1=1)
show_fixed(gs_model, lqm_model_restricted_pdcd1_1, styler_fixed, save="figure_percolation_pd1_1")
Saving as figure_percolation_pd1_1.svg
Out[14]: