ProfRick commited on
Commit
6253dbf
·
verified ·
1 Parent(s): cad2eab

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -228
app.py DELETED
@@ -1,228 +0,0 @@
1
-
2
- import streamlit as st
3
- import numpy as np
4
- import matplotlib.pyplot as plt
5
- from matplotlib.patches import Circle, Arc, Rectangle
6
- from matplotlib.lines import Line2D
7
-
8
- st.set_page_config(page_title="Flow Down Gradients — Simple Explorer", layout="wide")
9
-
10
- # ---------------- Pressure presets (mmHg) ----------------
11
- PRESSURE_PRESETS = {
12
- "Demo Preset": {
13
- "cap_o2": 52, "cap_co2": 49,
14
- "alv_o2": 55, "alv_co2": 45,
15
- "thoracic": 761,
16
- },
17
- "Preset 1": {
18
- "cap_o2": 50, "cap_co2": 45,
19
- "alv_o2": 100, "alv_co2": 40,
20
- "thoracic": 763,
21
- },
22
- "Preset 2": {
23
- "cap_o2": 60, "cap_co2": 45,
24
- "alv_o2": 58, "alv_co2": 40,
25
- "thoracic": 757,
26
- },
27
- "Preset 3": {
28
- "cap_o2": 48, "cap_co2": 45,
29
- "alv_o2": 53, "alv_co2": 8,
30
- "thoracic": 768,
31
- },
32
- }
33
-
34
- def get_pressure_preset_from_query():
35
- qp = st.query_params
36
- key = qp.get("preset") if "preset" in qp else None
37
- if key in PRESSURE_PRESETS:
38
- return key
39
- return "Demo Preset"
40
-
41
- if "pressure_preset" not in st.session_state:
42
- st.session_state.pressure_preset = get_pressure_preset_from_query()
43
-
44
- # ---------------- Action Potential presets ----------------
45
- AP_PRESETS = {
46
- "Preset 1": {"more_na": "Extracellular", "more_k": "Intracellular", "more_neg": "Intracellular"},
47
- "Preset 2": {"more_na": "Intracellular", "more_k": "Extracellular", "more_neg": "Extracellular"},
48
- "Preset 3": {"more_na": "Extracellular", "more_k": "Intracellular", "more_neg": "Extracellular"},
49
- }
50
-
51
- if "ap_preset" not in st.session_state:
52
- st.session_state.ap_preset = "Preset 1"
53
-
54
- # ---------------- UI ----------------
55
- st.title("Flow Down Gradients — Simple Explorer")
56
-
57
- tab1, tab2 = st.tabs([
58
- "Pressure (Alveolus ↔ Capillary)",
59
- "Concentration: Action Potential (extracellular ↔ intracellular)",
60
- ])
61
-
62
- # ---------------- Tab 1: Pressure ----------------
63
- with tab1:
64
- st.subheader("Pressure Gradients (mmHg)")
65
- # Preset buttons
66
- bcols = st.columns(4)
67
- for name, col in zip(PRESSURE_PRESETS.keys(), bcols):
68
- if col.button(name, use_container_width=True):
69
- st.session_state.pressure_preset = name
70
-
71
- # Current preset
72
- preset_name = st.session_state.pressure_preset
73
- p = PRESSURE_PRESETS[preset_name]
74
-
75
- # Values
76
- st.markdown(f"**Current preset:** {preset_name}")
77
- st.markdown(
78
- f"- **Intracapillary O₂:** {p['cap_o2']} mmHg \n"
79
- f"- **Intracapillary CO₂:** {p['cap_co2']} mmHg \n"
80
- f"- **Intraalveolar O₂:** {p['alv_o2']} mmHg \n"
81
- f"- **Intraalveolar CO₂:** {p['alv_co2']} mmHg \n"
82
- f"- **Thoracic pressure:** {p['thoracic']} mmHg"
83
- )
84
-
85
- # Diagram (enlarged, placed below values)
86
- fig, ax = plt.subplots(figsize=(11.5, 5.6))
87
- ax.set_xlim(0, 12); ax.set_ylim(0, 6); ax.axis("off")
88
-
89
- # Alveolus: round sac
90
- alve_center = (4.0, 3.0); alve_r = 2.1
91
- alve = Circle(alve_center, alve_r, fill=False, lw=2)
92
- ax.add_patch(alve)
93
- ax.text(alve_center[0], alve_center[1] + alve_r + 0.35, "Alveolus", ha="center", fontsize=13)
94
-
95
- # Capillary: thin vessel hugging right side (two arcs + short straight segments)
96
- cap_outer = Arc((6.2, 3.0), 3.6, 3.6, angle=0, theta1=-65, theta2=65, lw=6, capstyle="round")
97
- cap_inner = Arc((6.2, 3.0), 3.0, 3.0, angle=0, theta1=-65, theta2=65, lw=6, capstyle="round")
98
- ax.add_patch(cap_outer); ax.add_patch(cap_inner)
99
- # Straight ends to right
100
- ax.plot([7.8, 11.0], [4.2, 4.2], lw=6, solid_capstyle="round")
101
- ax.plot([7.8, 11.0], [1.8, 1.8], lw=6, solid_capstyle="round")
102
- ax.text(11.2, 3.0, "Capillary", va="center", fontsize=13, rotation=90)
103
-
104
- # Accessibility-friendly markers/colors
105
- color_o2, marker_o2 = "tab:blue", "o" # O2 = blue circle
106
- color_co2, marker_co2 = "tab:orange", "s" # CO2 = orange square
107
-
108
- # Dot counts scaled from mmHg (cap at 150 points per region)
109
- maxdots = 150
110
- ao2 = int(np.clip(p["alv_o2"], 0, maxdots))
111
- aco2 = int(np.clip(p["alv_co2"], 0, maxdots))
112
- co2 = int(np.clip(p["cap_o2"], 0, maxdots))
113
- cco2 = int(np.clip(p["cap_co2"], 0, maxdots))
114
-
115
- # Alveolar dots: random inside circle
116
- rngA = np.random.default_rng(101)
117
- need = ao2 + aco2
118
- if need > 0:
119
- xs, ys = [], []
120
- while len(xs) < need:
121
- x = rngA.uniform(alve_center[0]-alve_r+0.12, alve_center[0]+alve_r-0.12)
122
- y = rngA.uniform(alve_center[1]-alve_r+0.12, alve_center[1]+alve_r-0.12)
123
- if (x-alve_center[0])**2 + (y-alve_center[1])**2 <= (alve_r-0.18)**2:
124
- xs.append(x); ys.append(y)
125
- xs = np.array(xs); ys = np.array(ys)
126
- if ao2 > 0:
127
- ax.scatter(xs[:ao2], ys[:ao2], s=36, c=color_o2, marker=marker_o2)
128
- if aco2 > 0:
129
- ax.scatter(xs[ao2:], ys[ao2:], s=36, c=color_co2, marker=marker_co2)
130
-
131
- # Capillary dots: right rectangular segment for clarity
132
- rngC = np.random.default_rng(202)
133
- cx = rngC.uniform(8.2, 10.8, co2 + cco2)
134
- cy = rngC.uniform(1.95, 4.05, co2 + cco2)
135
- if co2 > 0:
136
- ax.scatter(cx[:co2], cy[:co2], s=36, c=color_o2, marker=marker_o2)
137
- if cco2 > 0:
138
- ax.scatter(cx[co2:], cy[co2:], s=36, c=color_co2, marker=marker_co2)
139
-
140
- # Clean, accessible legend using Line2D handles (not cramped)
141
- legend_elements = [
142
- Line2D([0], [0], marker=marker_o2, color='w', label='O₂ (Blue • Circle)',
143
- markerfacecolor=color_o2, markersize=10),
144
- Line2D([0], [0], marker=marker_co2, color='w', label='CO₂ (Orange • Square)',
145
- markerfacecolor=color_co2, markersize=10),
146
- ]
147
- ax.legend(handles=legend_elements, loc='upper left', bbox_to_anchor=(0.02, 0.98), frameon=False)
148
-
149
- # Stamp preset name
150
- ax.text(0.98, 0.05, f"{preset_name}", transform=ax.transAxes, ha="right", va="bottom", fontsize=11, alpha=0.8)
151
-
152
- st.pyplot(fig, clear_figure=True)
153
-
154
- # ---------------- Tab 2: Action Potential (presets, no sliders) ----------------
155
- with tab2:
156
- st.subheader("Static starting conditions (no animation)")
157
- bcols = st.columns(3)
158
- for name, col in zip(AP_PRESETS.keys(), bcols):
159
- if col.button(name, use_container_width=True):
160
- st.session_state.ap_preset = name
161
-
162
- ap = AP_PRESETS[st.session_state.ap_preset]
163
- st.markdown(f"**Current preset:** {st.session_state.ap_preset}")
164
- st.markdown(
165
- f"- More **Na⁺**: {ap['more_na']} \n"
166
- f"- More **K⁺**: {ap['more_k']} \n"
167
- f"- More **negative**: {ap['more_neg']}"
168
- )
169
-
170
- fig, ax = plt.subplots(figsize=(11.5, 5.0))
171
- ax.set_xlim(0, 12); ax.set_ylim(0, 6); ax.axis("off")
172
-
173
- # Compartments
174
- ax.add_patch(Rectangle((0.8, 1.0), 4.5, 4.0, fill=False, lw=2)) # Extracellular
175
- ax.add_patch(Rectangle((6.7, 1.0), 4.5, 4.0, fill=False, lw=2)) # Intracellular
176
- ax.plot([6.2, 6.2], [1.0, 5.0], lw=8) # Membrane
177
-
178
- ax.text(3.05, 5.25, "Extracellular", ha="center", fontsize=12)
179
- ax.text(8.95, 5.25, "Intracellular", ha="center", fontsize=12)
180
-
181
- # Polarity signs ABOVE labels
182
- if ap["more_neg"] == "Intracellular":
183
- ax.text(3.05, 5.85, "+", ha="center", va="center", fontsize=24, alpha=0.6)
184
- ax.text(8.95, 5.85, "−", ha="center", va="center", fontsize=24, alpha=0.9)
185
- else:
186
- ax.text(3.05, 5.85, "−", ha="center", va="center", fontsize=24, alpha=0.9)
187
- ax.text(8.95, 5.85, "+", ha="center", va="center", fontsize=24, alpha=0.6)
188
-
189
- # Colors + shapes (accessibility): Na+ = blue circle, K+ = orange square
190
- color_na, marker_na = "tab:blue", "o"
191
- color_k, marker_k = "tab:orange", "s"
192
-
193
- # Dot counts: base + extra on "more" side
194
- base_amt = 12
195
- extra_amt = 12
196
- na_out = base_amt + (extra_amt if ap["more_na"] == "Extracellular" else 0)
197
- na_in = base_amt + (extra_amt if ap["more_na"] == "Intracellular" else 0)
198
- k_out = base_amt + (extra_amt if ap["more_k"] == "Extracellular" else 0)
199
- k_in = base_amt + (extra_amt if ap["more_k"] == "Intracellular" else 0)
200
-
201
- rng2 = np.random.default_rng(808)
202
- xo = rng2.uniform(1.1, 5.0, na_out + k_out); yo = rng2.uniform(1.2, 4.8, na_out + k_out)
203
- xi = rng2.uniform(7.0, 11.4, na_in + k_in ); yi = rng2.uniform(1.2, 4.8, na_in + k_in )
204
-
205
- # Draw ions with fixed color+shape per type, regardless of side
206
- if na_out > 0:
207
- ax.scatter(xo[:na_out], yo[:na_out], s=45, c=color_na, marker=marker_na, label="Na⁺")
208
- if k_out > 0:
209
- ax.scatter(xo[na_out:], yo[na_out:], s=45, c=color_k, marker=marker_k, label="K⁺")
210
- if na_in > 0:
211
- ax.scatter(xi[:na_in], yi[:na_in], s=45, c=color_na, marker=marker_na)
212
- if k_in > 0:
213
- ax.scatter(xi[na_in:], yi[na_in:], s=45, c=color_k, marker=marker_k)
214
-
215
- # Legend
216
- legend_elements = [
217
- Line2D([0], [0], marker=marker_na, color='w', label='Na⁺ (Blue • Circle)',
218
- markerfacecolor=color_na, markersize=10),
219
- Line2D([0], [0], marker=marker_k, color='w', label='K⁺ (Orange • Square)',
220
- markerfacecolor=color_k, markersize=10),
221
- ]
222
- ax.legend(handles=legend_elements, loc='upper left', bbox_to_anchor=(0.01, 0.98), frameon=False)
223
-
224
- # Stamp preset
225
- ax.text(0.98, 0.05, f"{st.session_state.ap_preset}", transform=ax.transAxes,
226
- ha="right", va="bottom", fontsize=11, alpha=0.8)
227
-
228
- st.pyplot(fig, clear_figure=True)