aminemos commited on
Commit
6150a83
·
verified ·
1 Parent(s): cd83f37

initial commit

Browse files
Files changed (1) hide show
  1. app.py +165 -0
app.py ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import pandas as pd
3
+ import matplotlib.pyplot as plt
4
+ from scipy.integrate import odeint
5
+ from scipy.optimize import fsolve
6
+ import gradio as gr
7
+
8
+ # Population and time settings
9
+ population_size = 100
10
+ time_points = np.linspace(0, 24, 100)
11
+
12
+ # PK parameters for Enrofloxacin and Ciprofloxacin
13
+ pk_parameters = {
14
+ 'Enrofloxacin': {
15
+ 'Cmax_mean': 1.35, 'Cmax_std': 0.15,
16
+ 'Tmax_mean': 4.00, 'Tmax_std': 1,
17
+ 'Ke_mean': 0.03, 'Ke_std': 0.003,
18
+ 'F_mean': 0.7, 'F_std': 0.1,
19
+ 'Vd_mean': 24.76, 'Vd_std': 3.67,
20
+ 'pKa': 6.0,
21
+ 'type': 'acidic'
22
+ },
23
+ 'Ciprofloxacin': {
24
+ 'Cmax_mean': 0.08, 'Cmax_std': 0.01,
25
+ 'Tmax_mean': 3.44, 'Tmax_std': 1.01,
26
+ 'Ke_mean': 0.04, 'Ke_std': 0.01,
27
+ 'F_mean': 0.6, 'F_std': 0.1,
28
+ 'Vd_mean': 17.46, 'Vd_std': 6.40,
29
+ 'pKa': 7.7,
30
+ 'type': 'acidic'
31
+ }
32
+ }
33
+
34
+ # MIC values for pathogens
35
+ MIC_values = {
36
+ 'E.coli': 0.06,
37
+ 'S.Enteritidis': 0.1,
38
+ 'M.gallisepticum': 0.1,
39
+ 'C.perfringens': 0.12
40
+ }
41
+
42
+ # Ionization calculations
43
+ def unionized_fraction_acidic(pH, pKa):
44
+ return 1 / (1 + 10 ** (pH - pKa))
45
+
46
+ def unionized_fraction_basic(pH, pKa):
47
+ return 1 / (1 + 10 ** (pKa - pH))
48
+
49
+ def calculate_unionized_concentration(concentration, pH, pKa, drug_type):
50
+ if drug_type == "acidic":
51
+ unionized_fraction = unionized_fraction_acidic(pH, pKa)
52
+ elif drug_type == "basic":
53
+ unionized_fraction = unionized_fraction_basic(pH, pKa)
54
+ else:
55
+ raise ValueError("Invalid drug type. Must be 'acidic' or 'basic'.")
56
+ return concentration * unionized_fraction
57
+
58
+ # Simulate drug concentration
59
+ def pk_model(C, t, ka, ke, Vd, F, dose):
60
+ dCdt = (F * dose * ka / Vd) * np.exp(-ka * t) - (ke * C[0])
61
+ return dCdt
62
+
63
+ def solve_for_ka(Tmax_target, ke):
64
+ ka_guess = max(ke * 2, 0.01)
65
+ def equation(ka): return (np.log(ka) - np.log(ke)) / (ka - ke) - Tmax_target
66
+ ka_solution = fsolve(equation, ka_guess)
67
+ return ka_solution[0] if ka_solution[0] > 0 else 0.05
68
+
69
+ def simulate_concentration(dose, ke, Vd, F, Cmax_target, drug_type, pH, pKa):
70
+ ka = solve_for_ka(pk_parameters['Enrofloxacin']['Tmax_mean'], ke)
71
+ concentration = odeint(pk_model, [0], time_points, args=(ka, ke, Vd, F, dose))[:, 0]
72
+ if np.max(concentration) > 0:
73
+ concentration *= (Cmax_target / np.max(concentration))
74
+ return calculate_unionized_concentration(concentration, pH, pKa, drug_type)
75
+
76
+ def simulate_multiple_doses(pk_params, doses, pH):
77
+ all_data = []
78
+ for molecule, params in pk_params.items():
79
+ for i in range(population_size):
80
+ F = np.random.normal(params['F_mean'], params['F_std'])
81
+ ke = np.random.normal(params['Ke_mean'], params['Ke_std'])
82
+ Vd = np.random.normal(params['Vd_mean'], params['Vd_std'])
83
+ Cmax_target = np.random.normal(params['Cmax_mean'], params['Cmax_std'])
84
+ pKa = params['pKa']
85
+ ref_conc = simulate_concentration(10, ke, Vd, F, Cmax_target, params['type'], pH, pKa)
86
+ for dose in doses:
87
+ scaled_conc = ref_conc * (dose / 10)
88
+ all_data.extend([{
89
+ 'Individual': i + 1,
90
+ 'Molecule': molecule,
91
+ 'Dose': dose,
92
+ 'Time': t,
93
+ 'Concentration': conc
94
+ } for t, conc in zip(time_points, scaled_conc)])
95
+ return pd.DataFrame(all_data)
96
+
97
+ def calculate_pkpd_metrics(concentrations, time_points, MIC):
98
+ AUC = np.trapz(concentrations, time_points)
99
+ Cmax = np.max(concentrations)
100
+ T_above_MIC = time_points[concentrations > MIC]
101
+ T_above_MIC_duration = (T_above_MIC[-1] - T_above_MIC[0]) if len(T_above_MIC) > 0 else 0
102
+ AUIC = np.trapz(concentrations[concentrations > MIC] - MIC, time_points[concentrations > MIC]) if np.any(concentrations > MIC) else 0
103
+ return AUC, Cmax, T_above_MIC_duration, AUIC
104
+
105
+ def plot_pkpd_and_ionization(pk_params, df, MIC, doses, pH_range):
106
+ fig, axes = plt.subplots(len(pk_params), len(doses) + 1, figsize=(20, len(pk_params) * 5))
107
+ for row, (molecule, params) in enumerate(pk_params.items()):
108
+ pKa = params['pKa']
109
+ for col, dose in enumerate(doses):
110
+ group = df[(df['Molecule'] == molecule) & (df['Dose'] == dose)]
111
+ mean_conc = group.groupby('Time')['Concentration'].mean().values
112
+ ax = axes[row, col]
113
+ ax.plot(time_points[:len(mean_conc)], mean_conc, label=f"{molecule}, Dose: {dose} mg/kg")
114
+ ax.axhline(MIC, color='red', linestyle='--', label=f'MIC = {MIC:.2f}')
115
+
116
+ # Calculate PKPD metrics
117
+ AUC, Cmax, T_above_MIC, AUIC = calculate_pkpd_metrics(mean_conc, time_points[:len(mean_conc)], MIC)
118
+
119
+ # Fill AUIC area
120
+ ax.fill_between(time_points[:len(mean_conc)], MIC, mean_conc, where=(mean_conc > MIC), color='green', alpha=0.3, label="AUIC")
121
+ ax.text(0.6 * time_points[-1], 0.8 * np.max(mean_conc),
122
+ f"AUC: {AUC:.2f}\nCmax: {Cmax:.2f}\nT>MIC: {T_above_MIC:.2f} h\nAUIC: {AUIC:.2f}",
123
+ fontsize=9, bbox=dict(facecolor='white', alpha=0.8))
124
+
125
+ ax.set_title(f"{molecule} - Dose {dose} mg/kg")
126
+ ax.set_xlabel('Time (h)')
127
+ ax.set_ylabel('Concentration (mg/L)')
128
+ ax.legend()
129
+ ax = axes[row, -1]
130
+ unionized = [unionized_fraction_acidic(pH, pKa) for pH in pH_range]
131
+ ax.plot(pH_range, unionized, label=f"Ionization Profile ({molecule})")
132
+ ax.set_title(f"Ionization Profile: {molecule}")
133
+ ax.set_xlabel('pH')
134
+ ax.set_ylabel('Unionized Fraction')
135
+ ax.legend()
136
+ plt.tight_layout()
137
+ return fig
138
+
139
+ # Gradio Function
140
+ def gradio_function(pH_input, pathogen, dose_input):
141
+ if pathogen not in MIC_values:
142
+ raise ValueError("Invalid pathogen.")
143
+ MIC = MIC_values[pathogen]
144
+ doses = [int(d) for d in dose_input.split(',')]
145
+ pH_range = np.linspace(0, 14, 100)
146
+ df = simulate_multiple_doses(pk_parameters, doses, pH_input)
147
+ fig = plot_pkpd_and_ionization(pk_parameters, df, MIC, doses, pH_range)
148
+ return fig
149
+
150
+
151
+ # Gradio Interface
152
+ interface = gr.Interface(
153
+ fn=gradio_function,
154
+ inputs=[
155
+ gr.Slider(0, 14, step=0.1, label="Water pH Value"),
156
+ gr.Dropdown(list(MIC_values.keys()), label="Pathogen"),
157
+ gr.Textbox(value="5,15,20", label="Doses (mg/kg, comma-separated)")
158
+ ],
159
+ outputs=gr.Plot(),
160
+ title="Qomics All Rights Reserved (C)",
161
+ live=True
162
+ )
163
+
164
+
165
+ interface.launch()