We are comparing known ligands and known proteins with known ranges of Kd. Complex concentration and fluorescence of the complex are assumed to be directly related, but issues and errors of fluorescence will also be addressed, for example the detection limit of our fluorimeter will be taken into account. At the very end, a model of competitive ligand binding will also be addressed.
In [1]:
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from IPython.display import display, Math, Latex #Do we even need this anymore?
%pylab inline
This is a simple model of our system.
We are assuming complex concentration [LP] is proportional to complex fluorescence (in this particular assay).
We estimate/know the total Ligand $[L]_{tot} = [L] + [PL]$ and Protein $[P]_{tot} = [P] + [PL]$ concentration from the experimental setup, and presume we can measure the complex concentration in some way $[PL]$.
From this relation can calculate $K_d$ from these three values.
What binding curve would we expect?
In [2]:
Kd = 2e-9 # M
The protein concentration for our assay will be 1 nM (half of the Kd).
In [3]:
Ptot = 1e-9 # M
The ligand concentration will be a 12-point half-log dilution from 20 uM ligand (down to ~60 pM).
In [4]:
Ltot = 20.0e-6 / np.array([10**(float(i)/2.0) for i in range(12)]) # M
To calculate $[PL]$ as a function of $[P]_{tot}$, $[L]_{tot}$, and $K_d$, we start with
Then we need to put L and P in terms of $[L]_{tot}$ and $[P]_{tot}$, using
This gives us:
Rearranging to form a quadratic equations, we get:
Using the solution for the quadratic equation:
where $x = [PL]$, $a = 1$, $b = -([P]_{tot}+[L]_{tot}+K_d)$, and $c = [P]_{tot} [L]_{tot}$. We get as the only reasonable solution:
In [5]:
# Now we can use this to define a function that gives us PL from Kd, Ptot, and Ltot.
def two_component_binding(Kd, Ptot, Ltot):
"""
Parameters
----------
Kd : float
Dissociation constant
Ptot : float
Total protein concentration
Ltot : float
Total ligand concentration
Returns
-------
P : float
Free protein concentration
L : float
Free ligand concentration
PL : float
Complex concentration
"""
PL = 0.5 * ((Ptot + Ltot + Kd) - np.sqrt((Ptot + Ltot + Kd)**2 - 4*Ptot*Ltot)) # complex concentration (uM)
P = Ptot - PL; # free protein concentration in sample cell after n injections (uM)
L = Ltot - PL; # free ligand concentration in sample cell after n injections (uM)
return [P, L, PL]
In [6]:
[L, P, PL] = two_component_binding(Kd, Ptot, Ltot)
In [7]:
print Ltot
In [8]:
print PL
In [9]:
# y will be complex concentration
# x will be total ligand concentration
plt.semilogx(Ltot, PL / Ptot, 'ko')
plt.xlabel('$[L]_{tot}$ / M')
plt.ylabel('fractional binding $[PL] / [P]_{tot}$')
plt.ylim(0, 1.05)
plt.axvline(Kd,color='r',linestyle='--',label='K_d')
plt.legend();
Okay, so now lets do something a little more fun.
In [10]:
[L2, P2, PL2] = two_component_binding(Kd, Ptot/2, Ltot)
[L3, P3, PL3] = two_component_binding(Kd, Ptot*2, Ltot)
In [11]:
# y will be complex concentration
# x will be total ligand concentration
plt.semilogx(Ltot,PL,'b',Ltot,PL2,'g',Ltot,PL3,'k')
plt.xlabel('$[L]_{tot}$ / M')
plt.ylabel('$[PL]$ / M')
plt.ylim(0,2.05e-9)
plt.axhline(Ptot,color='b',linestyle='--',label='$[P]_{tot}$')
plt.axhline(Ptot/2,color='g',linestyle='--',label='$[P]_{tot}$/2')
plt.axhline(Ptot*2,color='k',linestyle='--', label='$[P]_{tot}$*2')
plt.axvline(Kd,color='r',linestyle='--',label='$K_d$')
plt.legend();
Say we have one molecule that has a different Kd for a bunch of proteins. We'll keep the protein concentration the same, but look at how our complex concentration changes as a function of Kd.
In [12]:
[L4, P4, PL4] = two_component_binding(Kd/10, Ptot, Ltot)
[L5, P5, PL5] = two_component_binding(Kd*10, Ptot, Ltot)
In [13]:
# y will be complex concentration
# x will be total ligand concentration
plt.semilogx(Ltot,PL,'o',label='$K_d$');
plt.semilogx(Ltot,PL4,'violet',label='0.1 $K_d$');
plt.semilogx(Ltot,PL5,'.75',label='10 $K_d$')
plt.xlabel('$[L]_{tot} / M$')
plt.ylabel('$[PL]$ / M')
plt.ylim(0,1.05e-9)
plt.axhline(Ptot,color='0.75',linestyle='--',label='$[P]_{tot}$')
#plt.axvline(Kd/10,color='violet',label='Kd/10')
#plt.axvline(Kd*10,color='.75',label='Kd*10')
plt.axvline(Kd,color='r',linestyle='--',label='$K_d$')
plt.legend();
In [14]:
# Let's plot Kd's ranging from 1mM to 10pM
Kd_max = 1e-3 # M
In [15]:
[La, Pa, PLa] = two_component_binding(Kd_max, Ptot, Ltot)
[Lb, Pb, PLb] = two_component_binding(Kd_max/10, Ptot, Ltot)
[Lc, Pc, PLc] = two_component_binding(Kd_max/100, Ptot, Ltot)
[Ld, Pd, PLd] = two_component_binding(Kd_max/1e3, Ptot, Ltot)
[Le, Pe, PLe] = two_component_binding(Kd_max/1e4, Ptot, Ltot)
[Lf, Pf, PLf] = two_component_binding(Kd_max/1e5, Ptot, Ltot)
[Lg, Pg, PLg] = two_component_binding(Kd_max/1e6, Ptot, Ltot)
[Lh, Ph, PLh] = two_component_binding(Kd_max/1e7, Ptot, Ltot)
[Li, Pi, PLi] = two_component_binding(Kd_max/1e8, Ptot, Ltot)
[Lj, Pj, PLj] = two_component_binding(Kd_max/1e9, Ptot, Ltot)
In [16]:
# y will be complex concentration
# x will be total ligand concentration
plt.figure(figsize=(10,3))
plt.semilogx(Ltot,PLa,'-bo',label='1 mM');
plt.semilogx(Ltot,PLb,'-ko',label='100 $\mu$M');
plt.semilogx(Ltot,PLc,'-go',label='10 $\mu$M');
plt.semilogx(Ltot,PLd,'-ro',label='1 $\mu$M');
plt.semilogx(Ltot,PLe,'-co',label='100 nM');
plt.semilogx(Ltot,PLf,'-mo',label='10 nM');
plt.semilogx(Ltot,PLg,'-yo',label='1 nM');
plt.semilogx(Ltot,PLh,'-bo',label='100 pM');
plt.semilogx(Ltot,PLi,'-ko',label='10 pM');
plt.semilogx(Ltot,PLj,'-go',label='1 pM');
plt.xlabel('$[L]_{tot}$ / M')
plt.ylabel('$[PL]$ / M')
plt.xlim(1.5e-12,1.5e-4)
plt.axhline(0.1e-9,color='0.75',linestyle='--',label='detection limit');
plt.legend(loc=0);
In [ ]:
We're going to pick 10 kinases and look at what binding curves we would expect to the fluorescent inhibitor bosutinib. Info from: http://www.guidetopharmacology.org/GRAC/LigandDisplayForward?tab=screens&ligandId=5710 Specifically: http://www.guidetopharmacology.org/GRAC/LigandScreenDisplayForward?ligandId=5710&screenId=2
In [17]:
Kd_Src = 1.0e-9 # M
Kd_Abl = 0.12e-9 # M
Kd_Abl_T315I = 21.0e-9 # M
Kd_p38 = 3000.0e-9 # M
Kd_Aur = 3000.0e-9 # M
Kd_CK2 = 3000.0e-9 # M
Kd_SYK = 290.0e-9 # M
Kd_DDR = 120.0e-9 # M
Kd_MEK = 19.0e-9 # M
#This CK2, Aur, and p38 value is actually 'greater than'.
In [18]:
[L6, P6, PL6] = two_component_binding(Kd_Src, Ptot, Ltot)
[L7, P7, PL7] = two_component_binding(Kd_Abl, Ptot, Ltot)
[L8, P8, PL8] = two_component_binding(Kd_Abl_T315I, Ptot, Ltot)
[L9, P9, PL9] = two_component_binding(Kd_p38, Ptot, Ltot)
In [19]:
# y will be complex concentration
# x will be total ligand concentration
Src, = plt.semilogx(Ltot,PL6,'o', label='Src')
Abl, = plt.semilogx(Ltot,PL7,'violet', label = 'Abl')
AblGK, = plt.semilogx(Ltot,PL8,'.75', label = 'AblGK')
p38, = plt.semilogx(Ltot,PL9,'k', label = 'p38')
plt.axhline(0.1e-9,color='0.75',linestyle='--', label='detection limit');
plt.xlabel('$[L]_{tot}$')
plt.ylabel('$[PL]$')
#plt.legend(handles=[Src, Abl, AblGK, p38], loc =0);
plt.legend(loc=0);
In [ ]: