from ipywidgets import interactive, FloatSlider, IntSlider, VBox, Label, HBox, Layout, interactive_output
import matplotlib.pyplot as plt
import numpy as np
from scipy.integrate import odeint
from IPython.display import display
# ODE system
def chaperone_dynamics(y, t, N, k_syn, f1, f2, f3, kd):
F, U, D = y
dFdt = f1 * k_syn*N + f2 * F * U - kd * F - f3 * F
dUdt = (1 - f1) * k_syn*N + f3 * F - f2 * F * U - kd * U
dDdt = kd * F + kd * U
return [dFdt, dUdt, dDdt]
# Plotting function
def plot_chaperone_dynamics(N, k_syn, f1, f2, f3, kd, t_max):
F0 = f1 * N
U0 = (1 - f1) * N
y0 = [F0, U0, 0.0]
t = np.linspace(0, t_max, 50000)
solution = odeint(chaperone_dynamics, y0, t, args=(N, k_syn, f1, f2, f3, kd))
F, U, D = solution.T
plt.figure(figsize=(8, 5))
plt.plot(t, F, label='Functional (F)')
plt.plot(t, U, label='Non-functional (U)')
plt.xlabel('Time (s)')
plt.ylabel('Chaperone Level')
plt.title('Chaperone Dynamics (Interactive)')
plt.grid()
plt.legend()
plt.show()State Variables
- ( F(t) ): Functional chaperone concentration
- ( U(t) ): Non-functional chaperone concentration
- ( D(t) ): Degraded (dead) protein concentration
Parameters
\(N\): Number of proteins produced
$k_{} $: Chaperone synthesis rate per cell
$ f_1 $: Fraction of synthesized chaperones that are functional
$ f_2 $: Refolding rate constant (U → F)
$ f_3 $: Misfolding rate constant (F → U)
$ k_d $: Degradation rate of both F and U
System of ODEs
$ \[\begin{aligned} \frac{dF}{dt} &= f_1 \cdot k_{\text{syn}} \cdot N + f_2 \cdot F \cdot U - f_3 \cdot F - k_d \cdot F \\ \frac{dU}{dt} &= (1 - f_1) \cdot k_{\text{syn}} \cdot N + f_3 \cdot F - f_2 \cdot F \cdot U - k_d \cdot U \\ \frac{dD}{dt} &= k_d \cdot F + k_d \cdot U \end{aligned}\]$
def param_box(slider, text):
return VBox([slider, Label(text)], layout=Layout(width='350px'))
N_slider = param_box(
IntSlider(min=1, max=100, step=1, value=1, description='N'),
"Number of proteins synthesis at once"
)
k_syn_slider = param_box(
FloatSlider(min=0.01, max=1, step=0.01, value=0.1, description='k_syn'),
"Rate of chaperone synthesis."
)
f1_slider = param_box(
FloatSlider(min=0.01, max=1.0, step=0.01, value=0.1, description='f1'),
"Frac. of synthesized that are functional."
)
f2_slider = param_box(
FloatSlider(
min=0.0, max=0.005, step=0.0001, value=0.0005,
description='f2',
readout=True,
readout_format='.4f',
),
"Refolding eff. (U → F)."
)
f3_slider = param_box(
FloatSlider(
min=0.0, max=0.01, step=0.0001, value=0.001,
description='f3',
readout=True,
readout_format='.4f',
),
"Misfolding rate (F → U)."
)
kd_slider = param_box(
FloatSlider(
min=0.0, max=0.01, step=0.0001, value=0.005,
description='kd',
readout=True,
readout_format='.4f',
),
"Degradation rate for F and U."
)
tmax_slider = param_box(
IntSlider(min=0, max=1e4, step=100, value=2000, description='t_max'),
"Max value of time to simulate."
)
controls = HBox([
VBox([N_slider, k_syn_slider, f1_slider],layout=Layout(border='1px solid gray', padding='10px')),
VBox([f2_slider, f3_slider, kd_slider],layout=Layout(border='1px solid gray', padding='10px')),
VBox([tmax_slider],layout=Layout(border='1px solid gray', padding='10px'))
])
widget = interactive_output(
plot_chaperone_dynamics,
{
'N': N_slider.children[0],
'k_syn': k_syn_slider.children[0],
'f1': f1_slider.children[0],
'f2': f2_slider.children[0],
'f3': f3_slider.children[0],
'kd': kd_slider.children[0],
't_max': tmax_slider.children[0]
}
)
display(controls, widget)