Skip to content

Commit 3760aae

Browse files
authored
Merge pull request #57 from BrainAnnex/dev
Fixed incorrect usage of "affinity" to "dissociation constant"
2 parents 700560f + ea798bc commit 3760aae

File tree

7 files changed

+162
-121
lines changed

7 files changed

+162
-121
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
### BETA 28.1 (v0.28.1)
1+
### BETA 28.2 (v0.28.2)
22

33

44

experiments/reactions_single_compartment/macromolecules_1.ipynb

Lines changed: 72 additions & 41 deletions
Large diffs are not rendered by default.

experiments/reactions_single_compartment/macromolecules_1.py

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,12 @@
4343
chem.get_macromolecules()
4444

4545
# %%
46-
chem.set_binding_site_affinity("M1", 3, "A", 1.0)
47-
chem.set_binding_site_affinity("M1", 8, "B", 3.2)
48-
chem.set_binding_site_affinity("M1", 15, "A", 10.0)
46+
chem.set_binding_site_affinity("M1", site_number=3, ligand="A", Kd=1.0)
47+
chem.set_binding_site_affinity("M1", site_number=8, ligand="B", Kd=3.2)
48+
chem.set_binding_site_affinity("M1", site_number=15, ligand="A", Kd=10.0)
4949

50-
chem.set_binding_site_affinity("M2", 1, "C", 5.6) # "M2" will get automatically added
51-
chem.set_binding_site_affinity("M2", 2, "A", 0.01)
50+
chem.set_binding_site_affinity("M2", site_number=1, ligand="C", Kd=5.6) # "M2" will get automatically added
51+
chem.set_binding_site_affinity("M2", site_number=2, ligand="A", Kd=0.01)
5252

5353
# %%
5454
chem.show_binding_affinities() # Review the values we have given for the binding affinities
@@ -73,7 +73,7 @@
7373
aff.chemical
7474

7575
# %%
76-
aff.affinity
76+
aff.Kd
7777

7878
# %%
7979

@@ -115,19 +115,19 @@
115115
dynamics.describe_state()
116116

117117
# %%
118-
dynamics.chem_data.show_binding_affinities() # Review the values the had given for the binding affinities
118+
dynamics.chem_data.show_binding_affinities() # Review the values we had given for the dissociation constants
119119

120120
# %% [markdown]
121121
# #### Notes:
122122
# **[B] = 0** => Occupancy of binding site 8 of M1 is also zero
123123
#
124124
# **[A] = 10.0** :
125-
# * 10x the binding affinity of A to site 3 of M1 (resulting in occupancy 0.9)
126-
# * same as the binding affinity of A to site 15 of M1 (occupancy 0.5)
127-
# * 1,000x the binding affinity of A to site 2 of M2 (occupancy almost 1, i.e. nearly saturated)
125+
# * 10x the dissociation constant of A to site 3 of M1 (resulting in occupancy 0.9)
126+
# * same as the dissociation constant of A to site 15 of M1 (occupancy 0.5)
127+
# * 1,000x the dissociation constant of A to site 2 of M2 (occupancy almost 1, i.e. nearly saturated)
128128
#
129129
#
130-
# **[C] = 0.56** => 1/10 of the binding affinity of C to site 1 of M2 (occupancy 0.1)
130+
# **[C] = 0.56** => 1/10 of the dissociation constant of C to site 1 of M2 (occupancy 0.1)
131131

132132
# %%
133133

@@ -144,7 +144,7 @@
144144
dynamics.describe_state()
145145

146146
# %% [markdown]
147-
# #### Note how all the various binding sites for ligand A, across all macromolecules, now have a different value for the fractional occupancy (very close to 1 because of the large value of [A] relative to each of the binding affinities for A.)
147+
# #### Note how all the various binding sites for ligand A, across all macromolecules, now have a different value for the fractional occupancy (very close to 1 because of the large value of [A] relative to each of the dissociation constants for A.)
148148
# The fractional occupancies for the other ligands (B and C) did not change
149149

150150
# %%
@@ -159,7 +159,7 @@
159159
print(history)
160160

161161
# %%
162-
# Generate a sweep of [A] values along a log scale
162+
# Generate a sweep of [A] values along a log scale, from very low to very high (relative to the dissociation constants)
163163
start = 0.001
164164
stop = 200.
165165
num_points = 100
@@ -214,11 +214,14 @@
214214

215215
# Annotations (x values adjusted for the log scale)
216216
fig.add_annotation(x=-1.715, y=0.65,
217-
text="Binding Affinity: 0.01", font=dict(size=12, color="seagreen"), showarrow=True, ax=-100, ay=-20)
217+
text="Dissociation constant: 0.01<br>(HIGHER Binding Affinity)", font=dict(size=12, color="seagreen"), showarrow=True, ax=-100, ay=-20)
218218
fig.add_annotation(x=0.3, y=0.65,
219-
text="Binding Affinity: 1", font=dict(size=12, color="purple"), showarrow=True, ax=-100, ay=-20)
219+
text="Dissociation constant: 1", font=dict(size=12, color="purple"), showarrow=True, ax=-100, ay=-20)
220220
fig.add_annotation(x=0.6, y=0.3,
221-
text="Binding Affinity: 10", font=dict(size=12, color="darkorange"), showarrow=True, ax=100, ay=20)
221+
text="Dissociation constant: 10<br>(LOWER Binding Affinity)", font=dict(size=12, color="darkorange"), showarrow=True, ax=100, ay=10)
222+
223+
fig.add_annotation(x=1.8, y=0.51,
224+
text="50% OCCUPANCY", font=dict(size=14, color="gray"), bgcolor="white", opacity=0.8, showarrow=False)
222225

223226
# Customize y-axis tick values
224227
additional_y_values = [0.1, 0.5, 0.9] # Additional values to show on y-axis
@@ -232,13 +235,19 @@
232235
fig.show()
233236

234237
# %% [markdown]
235-
# Note that fractional occupancy 0.1 occurs at ligand concentrations of 1/10 the binding affinity;
236-
# occupancy 0.5 occurs at ligand concentrations equals to the binding affinity;
237-
# occupancy 0.9 occurs at ligand concentrations of 10x the binding affinity
238+
# #### When the binding affinity is lower (i.e. higher Dissociation Constant, Kd, orange curve), it takes higher ligand concentrations to attain the same fractional occupancies
239+
240+
# %% [markdown]
241+
# Note that fractional occupancy 0.1 occurs at ligand concentrations of 1/10 the dissociation constant (Kd);
242+
# occupancy 0.5 occurs at ligand concentrations equals to the dissociation constant;
243+
# occupancy 0.9 occurs at ligand concentrations of 10x the dissociation constant.
238244

239245
# %% [markdown]
240246
# ## The above simulation captures what's shown on Fig. 3A of
241247
# #### https://doi.org/10.1146/annurev-cellbio-100617-062719
242-
# ("Low-Affinity Binding Sites and the Transcription Factor Specificity Paradox in Eukaryotes"), which it is based on
248+
# ("Low-Affinity Binding Sites and the Transcription Factor Specificity Paradox in Eukaryotes"), a paper that guided this simulation
249+
250+
# %% [markdown]
251+
# #### In upcoming versions of Life123, the fractional occupancy values will regulate the rates of reactions catalyzed by the macromolecules...
243252

244253
# %%

src/modules/chemicals/chem_data.py

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -529,9 +529,9 @@ def single_reaction_describe(self, rxn_index: int, concise=False) -> str:
529529

530530

531531
class ChemicalAffinity(NamedTuple):
532-
# Used for binding to macromolecules (e.g. Transcription Factors to DNA)
533-
chemical: str
534-
affinity: float
532+
# Used for binding of ligands to macromolecules (e.g. Transcription Factors to DNA)
533+
chemical: str # Name of ligand
534+
Kd: float # Dissociation constant; inversely related to binding affinity
535535

536536

537537

@@ -548,23 +548,22 @@ def __init__(self):
548548
super().__init__() # Invoke the constructor of its parent class
549549

550550

551-
self.macro_molecules = [] # List of names. EXAMPLE: ["M1", "M2"]
551+
self.macromolecules = [] # List of names. EXAMPLE: ["M1", "M2"]
552552
# The position in the list is referred to as the "index" of that macro-molecule
553-
# Names will be enforced to be unique
553+
# Names are enforced to be unique
554554

555-
self.binding_sites = {} # A dict whose keys are macromolecule names. The values are in turn dicts, indexed by site number.
555+
self.binding_sites = {} # A dict whose keys are macromolecule names.
556+
# The values are in turn dicts, indexed by binding-site number.
556557
# EXAMPLE:
557558
# {"M1": {1: ChemicalAffinity("A", 2.4), 2: ChemicalAffinity("C", 5.1)},
558559
# "M2": {1: ChemicalAffinity("C", 9.1), 2: ChemicalAffinity("B", 0.3), 3: ChemicalAffinity("A", 1.8), 4: ChemicalAffinity("C", 2.3)}
559560
# }
560561
# where "M1", "M2" are macro-molecules, and "A", "B", "C" are bulk chemicals (such as transcription factors),
561562
# all previously-declared;
562-
# the various ChemicalAffinity's are NamedTuples (objects) storing a bulk-chemical name and its affinity at that site.
563+
# the various ChemicalAffinity's are NamedTuples (objects) storing a ligand name and its dissociation constant at that site.
563564

564565
# Info on Binding Site Affinities : https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6787930/
565566

566-
# OLD: {"M1": {"A": 2.4, "B": 853.} } # Alt: [("A", 2.4), ("B", 853.)]
567-
568567

569568

570569

@@ -581,11 +580,11 @@ def add_macromolecules(self, names: Union[str, List[str]]) -> None:
581580
names = [names]
582581

583582
for m in names:
584-
if m in self.macro_molecules:
583+
if m in self.macromolecules:
585584
# Warn of redundant attempt to re-register an existing macromolecule name
586585
print(f"WARNING: Macromolecule `{m}` was already registered. Skipped...")
587586
else:
588-
self.macro_molecules.append(m) # Grow the list of registered macromolecules
587+
self.macromolecules.append(m) # Grow the list of registered macromolecules
589588

590589

591590

@@ -595,11 +594,11 @@ def get_macromolecules(self) -> [str]:
595594
596595
:return: A (possibly empty) list of the names of all the registered macromolecules
597596
"""
598-
return self.macro_molecules
597+
return self.macromolecules
599598

600599

601600

602-
def set_binding_site_affinity(self, macromolecule: str, site_number: int, chemical: str, affinity) -> None:
601+
def set_binding_site_affinity(self, macromolecule: str, site_number: int, ligand: str, Kd) -> None:
603602
"""
604603
Set the values of the binding affinity of the given macromolecule, at the indicated site on it,
605604
for the specified chemical species.
@@ -616,18 +615,19 @@ def set_binding_site_affinity(self, macromolecule: str, site_number: int, chemic
616615
:param macromolecule: Name of a macromolecule; if not previously-declared,
617616
it will get added to the list of registered macromolecules
618617
:param site_number: Unique integer to identify a binding site on the macromolecule
619-
:param chemical: Name of a previously-declared (bulk) chemical;
618+
:param ligand: Name of a previously-declared (bulk) chemical;
620619
if not found, an Exception will be raised TODO: inconsistent with "macromolecule" arg
621-
:param affinity: A number, in units of concentration
620+
:param Kd: Dissociation constant, in units of concentration (typically microMolar).
621+
Note that the dissociation constant is inversely proportional to the binding affinity
622622
:return: None
623623
"""
624-
assert chemical in self.get_all_names(), \
625-
f"set_binding_site_affinity(): no chemical named `{chemical}` found; use add_chemical() first"
624+
assert ligand in self.get_all_names(), \
625+
f"set_binding_site_affinity(): no chemical named `{ligand}` found; use add_chemical() first"
626626

627627
assert type(site_number) == int, \
628628
f"set_binding_site_affinity(): the argument `site_number` must be an integer"
629629

630-
if macromolecule not in self.macro_molecules:
630+
if macromolecule not in self.macromolecules:
631631
self.add_macromolecules([macromolecule])
632632

633633
if self.binding_sites.get(macromolecule) is None:
@@ -637,12 +637,12 @@ def set_binding_site_affinity(self, macromolecule: str, site_number: int, chemic
637637

638638
if site_number in binding_data:
639639
existing_affinity_data = binding_data[site_number]
640-
if existing_affinity_data.chemical != chemical:
640+
if existing_affinity_data.chemical != ligand:
641641
raise Exception(f"set_binding_site_affinity(): "
642642
f"site number {site_number} of macromolecule `{macromolecule}` was previously associated to chemical `{existing_affinity_data.chemical}` "
643-
f"(attempting to set an affinity value for chemical `{chemical}`)")
643+
f"(attempting to set an affinity value for chemical `{ligand}`)")
644644

645-
binding_data[site_number] = ChemicalAffinity(chemical=chemical, affinity=affinity)
645+
binding_data[site_number] = ChemicalAffinity(chemical=ligand, Kd=Kd)
646646

647647

648648

@@ -653,10 +653,10 @@ def get_binding_site_affinity(self, macromolecule: str, site_number: int) -> Che
653653
654654
:param macromolecule: Name of a macromolecule; if not found, an Exception will get raised
655655
:param site_number: Integer to identify a binding site on the macromolecule
656-
:return: The NamedTuple (chemical, affinity)
656+
:return: The NamedTuple (ligand name, dissociation constant)
657657
if no value was previously set, an Exception is raised
658658
"""
659-
assert macromolecule in self.macro_molecules, \
659+
assert macromolecule in self.macromolecules, \
660660
f"get_binding_site_affinity(): no macromolecule named `{macromolecule}` found"
661661

662662
assert type(site_number) == int, \
@@ -742,6 +742,7 @@ def get_ligand_name(self, macromolecule: str, site_number: int) -> str:
742742
return ligand_data.chemical
743743

744744

745+
745746
def show_binding_affinities(self) -> None:
746747
"""
747748
@@ -752,7 +753,7 @@ def show_binding_affinities(self) -> None:
752753
print(mm, " :")
753754
for site_number in self.get_binding_sites(mm):
754755
aff = self.get_binding_site_affinity(macromolecule=mm, site_number=site_number)
755-
print(f" Site {site_number} - Binding affinity for {aff.chemical} : {aff.affinity}")
756+
print(f" Site {site_number} - Kd (dissociation const) for {aff.chemical} : {aff.Kd}")
756757

757758

758759

@@ -774,7 +775,7 @@ def clear_macromolecules(self) -> None:
774775
775776
:return: None
776777
"""
777-
self.macro_molecules = []
778+
self.macromolecules = []
778779
self.binding_sites = {}
779780

780781

src/modules/reactions/reaction_dynamics.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1608,7 +1608,7 @@ def update_occupancy(self) -> None:
16081608
for (site_number, ligand) in d.items():
16091609
aff_data = self.chem_data.get_binding_site_affinity(mm, site_number)
16101610
conc = self.get_chem_conc(ligand)
1611-
fractional_occupancy = self.sigmoid(conc=conc, Kd=aff_data.affinity)
1611+
fractional_occupancy = self.sigmoid(conc=conc, Kd=aff_data.Kd)
16121612

16131613
self.set_occupancy(macromolecule=mm, site_number=site_number, fractional_occupancy=fractional_occupancy)
16141614

0 commit comments

Comments
 (0)