我们尝试使用python与streamlit实现了一个交互式的空间微生物消杀效果分析的web应用示例,用于分析微生物在不同环境下的行为,并评估各种消毒方法的效果。
环境与微生物行为分析,用户可以选择地球或太空环境,并输入温度、湿度等参数,系统会模拟微生物(如大肠杆菌、霉菌等)的生长速率,预测其在无消毒处理时的峰值浓度。
消毒方法评估,提供多种消毒方法(如气体等离子体、臭氧、湿巾等),计算每种方法在不同环境下的效率(百分比),并生成图表对比。
安全评估与推荐,根据用户输入的环境条件和选择的消毒方法,显示峰值浓度是否超出安全标准(如空间站的1000 CFU/m³),并推荐适合该环境的消毒方案。
import streamlit as st
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import matplotlib as mpl
from matplotlib.font_manager import FontProperties
import sys
import plotly.graph_objects as go
import plotly.express as px
from plotly.subplots import make_subplots
# ===== 初始化设置 =====
st.set_page_config(
page_title="微生物消杀模拟系统",
page_icon="🦠",
layout="wide",
initial_sidebar_state="expanded"
)
# ===== 设置字体支持 =====
try:
font_path = 'C:/Windows/Fonts/arialuni.ttf' # 优先选择支持特殊字符的字体
if sys.platform == "darwin": # macOS
font_path = '/System/Library/Fonts/PingFang.ttc'
elif sys.platform == "linux": # Linux
font_path = '/usr/share/fonts/truetype/wqy/wqy-microhei.ttc'
font = FontProperties(fname=font_path)
plt.rcParams['font.family'] = font.get_name()
plt.rcParams['axes.unicode_minus'] = False
except Exception as e:
st.warning(f"字体设置异常: {str(e)},使用默认字体")
# ===== 环境类型设置 =====
ENVIRONMENT_TYPES = {
"地球环境": {
"gravity": 1.0,
"humidity_range": (30, 90),
"temperature_range": (10, 40),
"pressure": 1.0,
"radiation": "低"
},
"太空环境": {
"gravity": 0.01,
"humidity_range": (10, 50), # 太空湿度范围较窄
"temperature_range": (15, 35), # 太空温度范围较窄
"pressure": 0.7,
"radiation": "高"
}
}
# ===== 微生物种类数据库 =====
MICROBE_SPECIES = {
# 细菌
"大肠杆菌": {"type": "细菌", "growth_rate": 0.25, "resistance": 0.2, "radiation_resist": 0.1},
"金黄色葡萄球菌": {"type": "细菌", "growth_rate": 0.22, "resistance": 0.3, "radiation_resist": 0.15},
"沙门氏菌": {"type": "细菌", "growth_rate": 0.24, "resistance": 0.25, "radiation_resist": 0.12},
# 真菌
"霉菌": {"type": "真菌", "growth_rate": 0.18, "resistance": 0.4, "radiation_resist": 0.25},
"酵母菌": {"type": "真菌", "growth_rate": 0.16, "resistance": 0.35, "radiation_resist": 0.2},
"黑曲霉": {"type": "真菌", "growth_rate": 0.17, "resistance": 0.45, "radiation_resist": 0.3},
# 孢子
"枯草芽孢杆菌": {"type": "孢子", "growth_rate": 0.12, "resistance": 0.65, "radiation_resist": 0.6},
"艰难梭菌": {"type": "孢子", "growth_rate": 0.1, "resistance": 0.7, "radiation_resist": 0.65},
"炭疽杆菌": {"type": "孢子", "growth_rate": 0.11, "resistance": 0.75, "radiation_resist": 0.7}
}
# ===== 消杀方法数据库 =====
DISINFECTION_METHODS = {
"紫外线照射(254nm)": {
"efficiency": {"地球": 0.02, "太空": 0.015},
"limitations": "无法穿透物体阴影",
"cost": "中",
"safety": "安全"
},
"过氧化氢蒸汽": {
"efficiency": {"地球": 0.03, "太空": 0.025},
"limitations": "高湿度需求,可能腐蚀设备",
"cost": "高",
"safety": "中等"
},
"气体等离子体": {
"efficiency": {"地球": 0.025, "太空": 0.022},
"limitations": "可能产生有害副产物",
"cost": "高",
"safety": "中等"
},
"光催化氧化(TiO₂)": {
"efficiency": {"地球": 0.015, "太空": 0.01},
"limitations": "需要持续光照",
"cost": "中",
"safety": "安全"
},
"超临界CO₂": {
"efficiency": {"地球": 0.035, "太空": 0.03},
"limitations": "需要高压设备",
"cost": "很高",
"safety": "安全"
},
"臭氧(O₃)": {
"efficiency": {"地球": 0.027, "太空": 0.02},
"limitations": "高浓度对人体有害",
"cost": "中",
"safety": "低"
},
"环氧乙烷(EtO)": {
"efficiency": {"地球": 0.032, "太空": 0.025},
"limitations": "易燃易爆,有残留毒性",
"cost": "高",
"safety": "低"
},
"季铵盐湿巾": {
"efficiency": {"地球": 0.012, "太空": 0.005},
"limitations": "难以覆盖所有表面",
"cost": "低",
"safety": "安全"
}
}
# ===== 侧边栏参数设置 =====
st.sidebar.header("环境设置")
environment = st.sidebar.selectbox("环境类型", list(ENVIRONMENT_TYPES.keys()))
env_params = ENVIRONMENT_TYPES[environment]
st.sidebar.subheader(f"{environment}参数")
temp = st.sidebar.slider(
"温度(℃)",
min_value=env_params["temperature_range"][0],
max_value=env_params["temperature_range"][1],
value=25
)
humidity = st.sidebar.slider(
"湿度(%)",
min_value=env_params["humidity_range"][0],
max_value=env_params["humidity_range"][1],
value=45 if environment == "太空环境" else 60
)
volume = st.sidebar.selectbox("空间体积(m³)", [10, 50, 100, 200, 500], index=2)
st.sidebar.header("微生物参数")
microbe_species = st.sidebar.selectbox(
"微生物种类",
options=list(MICROBE_SPECIES.keys()),
index=0
)
# 获取微生物参数
microbe_params = MICROBE_SPECIES[microbe_species]
st.sidebar.markdown(f"**类型**: {microbe_params['type']}")
st.sidebar.markdown(f"**生长速率**: {microbe_params['growth_rate']:.2f}/h")
st.sidebar.markdown(f"**抗性**: {microbe_params['resistance']*100:.0f}%")
st.sidebar.markdown(f"**辐射抵抗**: {microbe_params['radiation_resist']*100:.0f}%")
init_concentration = st.sidebar.number_input(
"初始浓度(CFU/m³)",
min_value=100,
max_value=10000,
value=1000
)
st.sidebar.header("消杀方案")
selected_methods = st.sidebar.multiselect(
"选择消杀方法(可多选)",
options=list(DISINFECTION_METHODS.keys()),
default=["气体等离子体", "超临界CO₂"]
)
exposure_time = st.sidebar.slider("作用时间(分钟)", 1, 120, 30)
# ===== 核心算法 =====
def growth_rate(temp, humidity, microbe_params, env_params):
"""
微生物生长速率模型 - 基于文档2.1-2.11节
"""
base_rate = microbe_params["growth_rate"]
# 温度影响系数 - 25℃为最适温度
temp_factor = np.exp(-0.5 * ((temp - 25) / 10)**2)
# 湿度影响系数
if environment == "太空环境":
# 太空环境下湿度影响减小
humid_factor = 0.7 + 0.3 * ((humidity - 10) / 40) # 适应太空的窄湿度范围
else:
humid_factor = 0.5 + 0.5 * (humidity / 100)
# 重力影响系数
gravity_factor = 1.2 - 0.2 * env_params["gravity"] # 微重力环境下生长更快
# 辐射影响系数(针对太空环境)
radiation_factor = 1.0 if environment == "地球环境" else 0.9 + microbe_params["radiation_resist"] * 0.2
return base_rate * temp_factor * humid_factor * gravity_factor * radiation_factor
def disinfection_efficiency(method, time, microbe_params, env_params):
"""
消杀效率模型 - 基于文档3.1-3.8节
"""
method_params = DISINFECTION_METHODS[method]
# 基础效率
base_efficiency = method_params["efficiency"]["太空" if environment == "太空环境" else "地球"]
efficiency = base_efficiency * time
# 微生物抗性影响
efficiency *= (1 - microbe_params["resistance"])
# 环境因素影响
if environment == "太空环境":
# 太空环境下某些方法效率降低
if method in ["季铵盐湿巾", "臭氧(O₃)"]:
efficiency *= 0.8 # 太空环境下湿巾效果变差
elif method in ["光催化氧化(TiO₂)"]:
efficiency *= 0.9 # 光催化在太空环境下略有降低
# 效率上限
return min(0.95, efficiency) # 最大效率95%
# ===== 动态模拟 =====
# 生成时间序列
hours = np.linspace(0, 48, 200) # 扩展到48小时
growth_rate_val = growth_rate(temp, humidity, microbe_params, env_params)
growth_curve = init_concentration * np.exp(growth_rate_val * hours)
# 计算消杀时间点
disinfection_idx = min(int(exposure_time / (24*60) * len(hours)), len(hours)-1)
# ===== 主界面布局 =====
st.title(f"密闭空间微生物消杀效果模拟 - {environment}")
st.caption("基于《密闭空间微生物消杀方法研究进展》戴荣继等(北京理工大学)")
# 创建选项卡
tab1, tab2, tab3 = st.tabs(["生长与消杀曲线", "环境对比分析", "方法对比矩阵"])
with tab1:
# === 图1:微生物生长与消杀曲线 ===
st.subheader(f"{microbe_species}在不同消杀方案下的浓度变化")
fig1 = go.Figure()
fig1.add_trace(go.Scatter(
x=hours,
y=growth_curve,
mode='lines',
name='自然生长',
line=dict(color='blue', width=2)
))
# 添加各种消杀方案的曲线
colors = px.colors.qualitative.Plotly
for i, method in enumerate(selected_methods):
disinfection_eff = disinfection_efficiency(method, exposure_time, microbe_params, env_params)
# 消杀后曲线
post_disinfection = growth_curve.copy()
post_disinfection[disinfection_idx:] = (
growth_curve[disinfection_idx] * (1 - disinfection_eff) *
np.exp(growth_rate_val * (hours[disinfection_idx:] - hours[disinfection_idx]))
)
fig1.add_trace(go.Scatter(
x=hours,
y=post_disinfection,
mode='lines',
name=f"{method} (效率: {disinfection_eff*100:.1f}%)",
line=dict(color=colors[i % len(colors)], width=2, dash='dash')
))
# 添加消杀时间线
fig1.add_vline(
x=hours[disinfection_idx],
line_dash="dash",
line_color="green",
annotation_text=f"消杀开始 ({exposure_time}分钟)",
annotation_position="top right"
)
# 设置安全标准线
fig1.add_hline(
y=1000,
line_dash="dot",
line_color="red",
annotation_text="安全浓度上限 (1000 CFU/m³)",
annotation_position="bottom right"
)
fig1.update_layout(
title=f"微生物生长与消杀模拟曲线",
xaxis_title="时间 (小时)",
yaxis_title="微生物浓度 (CFU/m³)",
legend_title="消杀方法",
hovermode="x unified",
height=500
)
st.plotly_chart(fig1, use_container_width=True)
# === 效果对比表格 ===
st.subheader("消杀效果评估")
eff_data = []
for method in DISINFECTION_METHODS:
eff = disinfection_efficiency(method, exposure_time, microbe_params, env_params)
eff_data.append({
"消杀方法": method,
f"{exposure_time}分钟效率": f"{eff*100:.1f}%",
"适用场景": DISINFECTION_METHODS[method]["limitations"],
"安全性": DISINFECTION_METHODS[method]["safety"],
"成本": DISINFECTION_METHODS[method]["cost"]
})
df_eff = pd.DataFrame(eff_data)
df_eff = df_eff.sort_values(f"{exposure_time}分钟效率", ascending=False)
# 高亮显示所选方法
def highlight_selected(row):
if row["消杀方法"] in selected_methods:
return ['background-color: #e6f7ff'] * len(row)
return [''] * len(row)
st.dataframe(
df_eff.style.apply(highlight_selected, axis=1),
use_container_width=True
)
with tab2:
# === 图2:环境对比分析 ===
st.subheader("地球与太空环境微生物行为对比")
# 创建子图
fig2 = make_subplots(
rows=2,
cols=2,
subplot_titles=(
"不同温度下生长速率对比",
"不同湿度下生长速率对比",
"不同环境消毒效率对比",
"微生物类别抗性分析"
),
vertical_spacing=0.15
)
# 面板1:不同温度下生长速率对比
temps = np.linspace(10, 40, 20)
earth_growth = [growth_rate(t, 60, MICROBE_SPECIES["大肠杆菌"], ENVIRONMENT_TYPES["地球环境"]) for t in temps]
space_growth = [growth_rate(t, 30, MICROBE_SPECIES["大肠杆菌"], ENVIRONMENT_TYPES["太空环境"]) for t in temps]
fig2.add_trace(go.Scatter(
x=temps, y=earth_growth, name="地球环境-大肠杆菌",
line=dict(color='blue', width=2)), row=1, col=1)
fig2.add_trace(go.Scatter(
x=temps, y=space_growth, name="太空环境-大肠杆菌",
line=dict(color='red', width=2, dash='dash')), row=1, col=1)
# 面板2:不同湿度下生长速率对比
humidities = np.linspace(10, 90, 20)
earth_growth_h = [growth_rate(25, h, MICROBE_SPECIES["大肠杆菌"], ENVIRONMENT_TYPES["地球环境"]) for h in humidities]
space_growth_h = [growth_rate(25, h, MICROBE_SPECIES["大肠杆菌"], ENVIRONMENT_TYPES["太空环境"]) for h in humidities]
fig2.add_trace(go.Scatter(
x=humidities, y=earth_growth_h, name="地球环境-大肠杆菌",
line=dict(color='blue', width=2), showlegend=False), row=1, col=2)
fig2.add_trace(go.Scatter(
x=humidities, y=space_growth_h, name="太空环境-大肠杆菌",
line=dict(color='red', width=2, dash='dash'), showlegend=False), row=1, col=2)
# 面板3:不同环境下消杀效率对比
methods_list = list(DISINFECTION_METHODS.keys())
earth_eff = [disinfection_efficiency(m, 30, MICROBE_SPECIES["大肠杆菌"], ENVIRONMENT_TYPES["地球环境"])*100 for m in methods_list]
space_eff = [disinfection_efficiency(m, 30, MICROBE_SPECIES["大肠杆菌"], ENVIRONMENT_TYPES["太空环境"])*100 for m in methods_list]
fig2.add_trace(go.Bar(
x=methods_list, y=earth_eff, name="地球环境效率",
marker_color='blue'), row=2, col=1)
fig2.add_trace(go.Bar(
x=methods_list, y=space_eff, name="太空环境效率",
marker_color='red'), row=2, col=1)
# 面板4:微生物抗性分析
microbes = list(MICROBE_SPECIES.keys())
growth_rates = [MICROBE_SPECIES[m]["growth_rate"] for m in microbes]
resistances = [MICROBE_SPECIES[m]["resistance"] for m in microbes]
fig2.add_trace(go.Bar(
x=microbes, y=growth_rates, name="生长速率",
marker_color='green'), row=2, col=2)
fig2.add_trace(go.Bar(
x=microbes, y=resistances, name="抗性",
marker_color='purple'), row=2, col=2)
fig2.update_layout(
height=800,
title_text="环境与微生物特性综合分析",
showlegend=True
)
st.plotly_chart(fig2, use_container_width=True)
with tab3:
# === 图3:消杀方法对比矩阵 ===
st.subheader("消杀方法综合能力评估")
# 准备雷达图数据
categories = ['效率', '安全性', '成本效益', '环境适应性', '抗性覆盖']
radar_data = []
for method in DISINFECTION_METHODS:
params = DISINFECTION_METHODS[method]
# 评估维度(0-1)
efficiency = params["efficiency"]["地球"] * 1.2 # 效率权重较高
safety = 0.9 if params["safety"] == "安全" else 0.5
cost_effect = 0.8 if params["cost"] == "低" else 0.5
env_adapt = 0.85 if environment == "地球环境" else 0.7
resist_cover = 0.9 - min(params["efficiency"]["地球"], 0.3) # 效率越低,抗性覆盖越差
values = [efficiency, safety, cost_effect, env_adapt, resist_cover]
radar_data.append(go.Scatterpolar(
r=values,
theta=categories,
fill='toself',
name=method
))
fig3 = go.Figure(data=radar_data)
fig3.update_layout(
polar=dict(
radialaxis=dict(
visible=True,
range=[0, 1.2]
)),
showlegend=True,
title="消杀方法能力雷达图",
height=600
)
st.plotly_chart(fig3, use_container_width=True)
# 添加方法详情卡片
cols = st.columns(2)
for i, method in enumerate(selected_methods):
with cols[i % 2]:
params = DISINFECTION_METHODS[method]
eff_earth = params["efficiency"]["地球"] * 100
eff_space = params["efficiency"]["太空"] * 100
st.markdown(f"### {method}")
st.metric("地球环境效率", f"{eff_earth:.1f}%")
st.metric("太空环境效率", f"{eff_space:.1f}%")
st.markdown(f"**限制**: {params['limitations']}")
st.markdown(f"**安全性**: {params['safety']}")
st.markdown(f"**成本**: {params['cost']}")
# ===== 安全评估 =====
st.divider()
st.header("环境安全评估")
space_std = 1000 # 空间站安全标准 (CFU/m³)
# 当前选择的消杀方案评估
cols = st.columns(len(selected_methods)+1)
with cols[0]:
st.metric("无消杀峰值浓度", f"{max(growth_curve):.0f} CFU/m³",
delta=f"超出安全线{(max(growth_curve)/space_std-1)*100:.0f}%" if max(growth_curve) > space_std else "安全范围内",
delta_color="inverse")
for i, method in enumerate(selected_methods):
disinfection_eff = disinfection_efficiency(method, exposure_time, microbe_params, env_params)
post_disinfection = growth_curve.copy()
post_disinfection[disinfection_idx:] = (
growth_curve[disinfection_idx] * (1 - disinfection_eff) *
np.exp(growth_rate_val * (hours[disinfection_idx:] - hours[disinfection_idx]))
)
peak_concentration = max(post_disinfection)
with cols[i+1]:
st.metric(
f"{method}峰值",
f"{peak_concentration:.0f} CFU/m³",
delta=f"效率: {disinfection_eff*100:.1f}%",
delta_color="normal"
)
st.progress(disinfection_eff, text=f"消杀效率")
# === 方法推荐系统 ===
st.subheader("环境优化方案推荐")
if environment == "太空环境":
st.warning("太空环境注意事项:")
st.markdown("""
- 优先考虑气态消杀方法(等离子体、臭氧)
- 避免使用液体消毒剂(湿巾)
- 考虑辐射增强消杀效果
- 注意微重力对液体分布的影响
""")
recommended_methods = ["气体等离子体", "臭氧(O₃)", "超临界CO₂"]
else:
st.success("地球环境建议:")
st.markdown("""
- 可使用液体消毒剂(湿巾、过氧化氢溶液)
- 组合使用物理和化学方法
- 考虑经济性和安全性平衡
""")
recommended_methods = ["过氧化氢蒸汽", "紫外线照射(254nm)", "季铵盐湿巾"]
st.markdown(f"**推荐消杀方法**: {', '.join(recommended_methods)}")