cloud-sean commited on
Commit
225cf8d
·
verified ·
1 Parent(s): c532ee1

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +188 -0
app.py ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import plotly.graph_objects as go
4
+ import plotly.express as px
5
+
6
+ st.set_page_config(page_title="Interactive 12 Pubs of Christmas", layout="wide")
7
+
8
+ # ------------------------------------
9
+ # Parameters & Constants
10
+ # ------------------------------------
11
+ # Julia's data
12
+ julia_weight_lbs = 120
13
+ julia_weight_kg = julia_weight_lbs * 0.45359237
14
+ julia_weight_g = julia_weight_kg * 1000
15
+ julia_r = 0.55
16
+
17
+ # Sean's data
18
+ sean_weight_kg = 86.0
19
+ sean_weight_g = sean_weight_kg * 1000
20
+ sean_r = 0.68
21
+
22
+ beta = 0.015 # g/dL/h elimination rate
23
+ g_per_unit = 8
24
+
25
+ # Drink options
26
+ # We'll define a few drink types with their volumes and ABVs.
27
+ # For simplicity, we assume:
28
+ # - 1 UK pint = 568 ml
29
+ # - Half beer = Half pint = 284 ml
30
+ # - Shot = 30 ml
31
+ # - ABV is given in percentage.
32
+ # We'll approximate each drink's ethanol mass:
33
+ # Ethanol mass (g) = volume (ml) * density_of_ethanol(0.789 g/ml) * (ABV/100)
34
+ # For simplicity, we use a units-based approach:
35
+ # 1 unit (UK) = 10ml pure ethanol = 8g ethanol
36
+ # Units = (Volume in ml * ABV%) / 1000 (approx UK definition: 1 unit = 10ml pure ethanol)
37
+ # So ethanol in grams = Units * 8.
38
+
39
+ drink_options = {
40
+ "Guinness (Pint)": {"volume_ml": 568, "abv": 4.2},
41
+ "Heineken (Pint)": {"volume_ml": 568, "abv": 5.0},
42
+ "Stella Artois (Pint)": {"volume_ml": 568, "abv": 4.8},
43
+ "Half Beer (Generic)": {"volume_ml": 284, "abv": 4.0},
44
+ "Vodka Shot": {"volume_ml": 30, "abv": 40.0},
45
+ "Whiskey Shot": {"volume_ml": 30, "abv": 40.0},
46
+ "Cider (Pint)": {"volume_ml": 568, "abv": 4.5},
47
+ "Red Wine (175ml)": {"volume_ml": 175, "abv": 12.0}
48
+ }
49
+
50
+ # A function to calculate ethanol grams from a given drink
51
+ def alcohol_in_grams(volume_ml, abv_percent):
52
+ # 1 unit (UK) ~ (volume_ml * abv) / 1000 * (8g/unit)
53
+ units = (volume_ml * abv_percent) / 1000
54
+ return units * 8 # grams of ethanol
55
+
56
+ def bac_calculation(total_alcohol_g, W, r, t):
57
+ # Widmark formula approximation:
58
+ # BAC = (A/(W*r))*100 - beta*(t-1) if t>1
59
+ bac = (total_alcohol_g / (W * r)) * 100
60
+ if t > 1:
61
+ bac = bac - beta*(t-1)
62
+ return max(bac,0)
63
+
64
+ st.title("12 Pubs of Christmas - Interactive Drink Selection")
65
+
66
+ st.write("""
67
+ Select the drinks you (Julia) and Sean will consume each hour over a 6-hour period.
68
+ We'll estimate your BAC levels and show you comparisons.
69
+
70
+ **Note:** These are rough estimates and not medically accurate. Actual BAC varies by individual.
71
+ """)
72
+
73
+ hours = 6
74
+
75
+ col_drinks = st.columns(hours)
76
+ selected_drinks = []
77
+ st.subheader("Select Drinks for Each Hour")
78
+ for i in range(hours):
79
+ with col_drinks[i]:
80
+ drink_choice = st.selectbox(
81
+ f"Hour {i+1} Drink",
82
+ list(drink_options.keys()),
83
+ key=f"drink_hour_{i}"
84
+ )
85
+ selected_drinks.append(drink_choice)
86
+
87
+ # Calculate total alcohol consumed per hour
88
+ alcohol_by_hour = []
89
+ for i, d in enumerate(selected_drinks):
90
+ vol = drink_options[d]["volume_ml"]
91
+ abv = drink_options[d]["abv"]
92
+ grams = alcohol_in_grams(vol, abv)
93
+ alcohol_by_hour.append(grams)
94
+
95
+ # Cumulative alcohol and BAC calculations
96
+ time_points = list(range(hours+1)) # from 0 to 6
97
+ julia_bac = []
98
+ sean_bac = []
99
+ julia_alc_over_time = []
100
+ sean_alc_over_time = []
101
+
102
+ for t in time_points:
103
+ # total alcohol consumed up to hour t
104
+ total_alc = sum(alcohol_by_hour[:t])
105
+ # Julia BAC
106
+ julia_bac_val = bac_calculation(total_alc, julia_weight_g, julia_r, t)
107
+ julia_bac.append(julia_bac_val)
108
+ # Sean BAC
109
+ sean_bac_val = bac_calculation(total_alc, sean_weight_g, sean_r, t)
110
+ sean_bac.append(sean_bac_val)
111
+
112
+ df = pd.DataFrame({
113
+ "Hour": time_points,
114
+ "Julia_BAC": julia_bac,
115
+ "Sean_BAC": sean_bac,
116
+ "Total_Alcohol_Consumed_g": [sum(alcohol_by_hour[:t]) for t in time_points]
117
+ })
118
+
119
+ # Calculate difference
120
+ df["BAC_Difference"] = df["Julia_BAC"] - df["Sean_BAC"]
121
+
122
+ # Plot 1: BAC over time
123
+ st.subheader("BAC over Time")
124
+ fig_bac = go.Figure()
125
+ fig_bac.add_trace(go.Scatter(x=df["Hour"], y=df["Julia_BAC"], mode='lines+markers', name="Julia BAC", line=dict(color='firebrick', width=3)))
126
+ fig_bac.add_trace(go.Scatter(x=df["Hour"], y=df["Sean_BAC"], mode='lines+markers', name="Sean BAC", line=dict(color='royalblue', width=3)))
127
+ fig_bac.update_layout(title="Estimated BAC vs. Time (Hours)", xaxis_title="Hours", yaxis_title="BAC (%)", template="plotly_white")
128
+ st.plotly_chart(fig_bac, use_container_width=True)
129
+
130
+ # Plot 2: Alcohol consumed vs BAC (Dual-Axis)
131
+ st.subheader("Alcohol Consumed and BAC")
132
+ fig_bar_line = go.Figure()
133
+
134
+ # Bar for total alcohol consumed at each hour
135
+ fig_bar_line.add_trace(go.Bar(x=df["Hour"], y=df["Total_Alcohol_Consumed_g"], name="Total Alcohol (g)", marker_color='goldenrod', yaxis='y1'))
136
+ # Julia BAC line
137
+ fig_bar_line.add_trace(go.Scatter(x=df["Hour"], y=df["Julia_BAC"], name="Julia BAC", mode='lines+markers', line=dict(color='firebrick', width=3), yaxis='y2'))
138
+ # Sean BAC line
139
+ fig_bar_line.add_trace(go.Scatter(x=df["Hour"], y=df["Sean_BAC"], name="Sean BAC", mode='lines+markers', line=dict(color='royalblue', width=3), yaxis='y2'))
140
+
141
+ fig_bar_line.update_layout(
142
+ title="Total Alcohol (g) vs BAC (%) Over Time",
143
+ xaxis=dict(title="Hour"),
144
+ yaxis=dict(title="Total Alcohol (g)", side='left', range=[0, df["Total_Alcohol_Consumed_g"].max()*1.1]),
145
+ yaxis2=dict(title="BAC (%)", side='right', overlaying='y', range=[0, df[["Julia_BAC","Sean_BAC"]].max().max()*1.1]),
146
+ template="plotly_white"
147
+ )
148
+ st.plotly_chart(fig_bar_line, use_container_width=True)
149
+
150
+ # Plot 3: Difference in BAC
151
+ st.subheader("Difference in BAC (Julia - Sean)")
152
+ fig_diff = go.Figure(go.Bar(
153
+ x=df["Hour"],
154
+ y=df["BAC_Difference"],
155
+ text=[f"{d:.3f}%" for d in df["BAC_Difference"]],
156
+ textposition='outside',
157
+ marker_color='indianred'
158
+ ))
159
+ fig_diff.update_layout(
160
+ title="Difference in BAC Between Julia and Sean Over Time",
161
+ xaxis_title="Hour",
162
+ yaxis_title="Difference in BAC (%)",
163
+ template="plotly_white"
164
+ )
165
+ st.plotly_chart(fig_diff, use_container_width=True)
166
+
167
+ # Plot 4: Pie/Donut Chart of Alcohol Proportions if needed
168
+ # For a bit of fun, let's compare the total alcohol consumed to their body weight as a fraction
169
+ st.subheader("Alcohol as a Percentage of Body Weight")
170
+ # 1g = 0.001 kg
171
+ julia_pct_body_weight = (df["Total_Alcohol_Consumed_g"].iloc[-1] / julia_weight_g)*100
172
+ sean_pct_body_weight = (df["Total_Alcohol_Consumed_g"].iloc[-1] / sean_weight_g)*100
173
+
174
+ donut_data = pd.DataFrame({
175
+ "Person": ["Julia", "Sean"],
176
+ "Alcohol_as_pct_body_weight": [julia_pct_body_weight, sean_pct_body_weight]
177
+ })
178
+
179
+ fig_donut = px.pie(donut_data, values='Alcohol_as_pct_body_weight', names='Person', hole=0.5,
180
+ color='Person', color_discrete_map={"Julia":"firebrick","Sean":"royalblue"})
181
+ fig_donut.update_layout(title="Alcohol Consumed as % of Body Weight", template="plotly_white")
182
+ st.plotly_chart(fig_donut, use_container_width=True)
183
+
184
+ st.write("""
185
+ **Disclaimer:**
186
+ These BAC values are rough estimates. Actual impairment depends on many factors including metabolism,
187
+ recent food intake, and individual tolerance. This tool is for illustrative purposes only.
188
+ """)