以下脚本独立运行以运行场景:
首先打印结果,然后以动画结束绘图。
import numpy as np
import matplotlib.pyplot as plt
import tkinter as tk
from tkinter import ttk
from matplotlib.animation import FuncAnimation
def run_model():
# Input parameters (example values)
frequency_per_year = 365
exposure_duration = 240 # minutes
product_amount = 5 # g
weight_fraction_substance = 0.6 # fraction
room_volume = 58 # m³
ventilation_rate = 0.5 # per hour
inhalation_rate = 10 # m³/hr
body_weight_kg = 65 # kg
# Advanced parameters
vapour_pressure = 2 # Pa
application_temperature = 18 # °C
molecular_weight = 100 # g/mol
# Conversion functions
def convert_to_seconds(duration):
return duration * 60 # minutes to seconds
def convert_to_kg(amount):
return amount / 1000 # g to kg
def convert_to_per_second(rate):
return rate / 3600 # per hour to per second
def convert_inhalation_rate(rate):
return rate # m³/hr
def convert_pressure(value):
return value # Pa
def convert_temperature(value):
return value + 273.15 # °C to K
def convert_molecular_weight(value):
return value # g/mol
# Convert units
exposure_duration_seconds = convert_to_seconds(exposure_duration)
product_amount_kg = convert_to_kg(product_amount)
ventilation_rate_per_second = convert_to_per_second(ventilation_rate)
inhalation_rate_m3_hr = convert_inhalation_rate(inhalation_rate)
temperature_k = convert_temperature(application_temperature)
vapour_pressure_pa = convert_pressure(vapour_pressure)
molecular_weight_kg_mol = convert_molecular_weight(molecular_weight)
# Universal gas constant
R = 8.314 # J/mol/K
# Time points (in seconds)
time_points = np.linspace(0, exposure_duration_seconds, 500)
# Calculate C_air over time
C_air_over_time = (product_amount_kg * weight_fraction_substance / room_volume) * np.exp(-ventilation_rate_per_second * time_points)
# Calculate C_sat
C_sat = (molecular_weight_kg_mol * vapour_pressure_pa) / (R * temperature_k)
# Convert C_air_over_time to mg/m^3 for plotting
C_air_over_time_mg_m3 = C_air_over_time * 1e6
# Calculate the total inhaled dose
total_inhaled_volume_m3 = inhalation_rate_m3_hr * (exposure_duration_seconds / 3600) # m^3
total_inhaled_dose_kg = np.trapz(C_air_over_time, time_points) * inhalation_rate_m3_hr / 3600 # kg
total_inhaled_dose_mg = total_inhaled_dose_kg * 1e6 # mg
# Calculate the external event dose
external_event_dose_mg_kg_bw = total_inhaled_dose_mg / body_weight_kg # mg/kg bw
# Calculate mean event concentration
mean_event_concentration = np.mean(C_air_over_time_mg_m3)
# Calculate peak concentration (TWA 15 min)
time_interval_15min = 15 * 60 # 15 minutes in seconds
if exposure_duration_seconds >= time_interval_15min:
time_points_15min = time_points[time_points <= time_interval_15min]
C_air_15min = C_air_over_time[time_points <= time_interval_15min]
TWA_15_min = np.mean(C_air_15min) * 1e6 # Convert to mg/m³
else:
TWA_15_min = mean_event_concentration
# Calculate mean concentration on day of exposure
mean_concentration_day_of_exposure = mean_event_concentration * (exposure_duration_seconds / 86400)
# Calculate year average concentration
year_average_concentration = mean_concentration_day_of_exposure * frequency_per_year / 365
# Calculate cumulative dose over time and convert to mg/kg body weight
time_step = time_points[1] - time_points[0]
cumulative_dose_kg = np.cumsum(C_air_over_time) * time_step * inhalation_rate_m3_hr / 3600 # kg
cumulative_dose_mg = cumulative_dose_kg * 1e6 # mg
cumulative_dose_mg_kg_bw = cumulative_dose_mg / body_weight_kg # mg/kg bw
# Final values for annotations
final_air_concentration = C_air_over_time_mg_m3[-1]
final_external_event_dose = cumulative_dose_mg_kg_bw[-1]
# Prepare results text
result_text = (
f"Mean event concentration: {mean_event_concentration:.1e} mg/m³\n"
f"Peak concentration (TWA 15 min): {TWA_15_min:.1e} mg/m³\n"
f"Mean concentration on day of exposure: {mean_concentration_day_of_exposure:.1e} mg/m³\n"
f"Year average concentration: {year_average_concentration:.1e} mg/m³\n"
f"External event dose: {external_event_dose_mg_kg_bw:.1f} mg/kg bw\n"
f"External dose on day of exposure: {external_event_dose_mg_kg_bw:.1f} mg/kg bw"
)
# Display results in a Tkinter window
result_window = tk.Tk()
result_window.title("Model Results")
ttk.Label(result_window, text=result_text, justify=tk.LEFT).grid(column=0, row=0, padx=10, pady=10)
ttk.Button(result_window, text="Close", command=result_window.destroy).grid(column=0, row=1, pady=(0, 10))
result_window.mainloop()
# Plotting with animation
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
# Initialize lines
line1, = ax1.plot([], [], lw=2)
line2, = ax2.plot([], [], lw=2)
# Plot air concentration over time
def init_air_concentration():
ax1.set_xlim(0, exposure_duration)
ax1.set_ylim(0, np.max(C_air_over_time_mg_m3) * 1.1)
ax1.set_title('Inhalation - Air concentration')
ax1.set_xlabel('Time (min)')
ax1.set_ylabel('Concentration (mg/m³)')
ax1.grid(True)
return line1,
def update_air_concentration(frame):
line1.set_data(time_points[:frame] / 60, C_air_over_time_mg_m3[:frame])
return line1,
# Plot external event dose over time
def init_external_dose():
ax2.set_xlim(0, exposure_duration)
ax2.set_ylim(0, np.max(cumulative_dose_mg_kg_bw) * 1.1)
ax2.set_title('Inhalation - External event dose over time')
ax2.set_xlabel('Time (min)')
ax2.set_ylabel('Dose (mg/kg bw)')
ax2.grid(True)
return line2,
def update_external_dose(frame):
line2.set_data(time_points[:frame] / 60, cumulative_dose_mg_kg_bw[:frame])
return line2,
ani1 = FuncAnimation(fig, update_air_concentration, frames=len(time_points), init_func=init_air_concentration, blit=True, interval=300/len(time_points), repeat=False)
ani2 = FuncAnimation(fig, update_external_dose, frames=len(time_points), init_func=init_external_dose, blit=True, interval=300/len(time_points), repeat=False)
plt.tight_layout()
plt.show()
if __name__ == "__main__":
run_model()
但是,我希望它们同时出现。或者,如果没有,则紧接着另一个,而不必先关闭结果窗口。
对此进行的各种尝试都会导致此问题:
*** 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“-[NSApplication macOSVersion]:无法识别的选择器发送到实例 0x13616f730” *** 首先抛出调用堆栈:
任何帮助表示赞赏。
我不确定这是否正是您想要的,但您可以在 tkinter 窗口中的 Canvas 上显示函数动画。这需要一些额外的导入,即
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
从这里您需要定义您的画布。在您的
run_model()
函数中,您想要在动画上方定义画布,如下所示:
canvas = FigureCanvasTkAgg(fig, master=result_window)
canvas_widget = canvas.get_tk_widget()
canvas_widget.pack(side=tk.TOP, fill=tk.BOTH, expand=1) # you can edit this to your needs
重要的是,您还将 tkinter 窗口的代码向下移动,以便在我们创建动画之前它不会运行。因此,将第 115-120 行下移到函数末尾。我从您的代码中删除了网格并仅使用了包,但这可以更改。该框架也不是必需的,但更适合组织目的。这将在屏幕上显示信息和两个情节动画。 注意:在您的动画中,您最初有
blit=True
。无论出于何种原因,这都会破坏动画,并且必须将其设置为 false 才能使其正常工作。
这是完整的代码:
import numpy as np
import matplotlib.pyplot as plt
import tkinter as tk
from tkinter import ttk
from matplotlib.animation import FuncAnimation
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
def run_model():
# Input parameters (example values)
frequency_per_year = 365
exposure_duration = 240 # minutes
product_amount = 5 # g
weight_fraction_substance = 0.6 # fraction
room_volume = 58 # m³
ventilation_rate = 0.5 # per hour
inhalation_rate = 10 # m³/hr
body_weight_kg = 65 # kg
# Advanced parameters
vapour_pressure = 2 # Pa
application_temperature = 18 # °C
molecular_weight = 100 # g/mol
# Conversion functions
def convert_to_seconds(duration):
return duration * 60 # minutes to seconds
def convert_to_kg(amount):
return amount / 1000 # g to kg
def convert_to_per_second(rate):
return rate / 3600 # per hour to per second
def convert_inhalation_rate(rate):
return rate # m³/hr
def convert_pressure(value):
return value # Pa
def convert_temperature(value):
return value + 273.15 # °C to K
def convert_molecular_weight(value):
return value # g/mol
# Convert units
exposure_duration_seconds = convert_to_seconds(exposure_duration)
product_amount_kg = convert_to_kg(product_amount)
ventilation_rate_per_second = convert_to_per_second(ventilation_rate)
inhalation_rate_m3_hr = convert_inhalation_rate(inhalation_rate)
temperature_k = convert_temperature(application_temperature)
vapour_pressure_pa = convert_pressure(vapour_pressure)
molecular_weight_kg_mol = convert_molecular_weight(molecular_weight)
# Universal gas constant
R = 8.314 # J/mol/K
# Time points (in seconds)
time_points = np.linspace(0, exposure_duration_seconds, 500)
# Calculate C_air over time
C_air_over_time = (product_amount_kg * weight_fraction_substance / room_volume) * np.exp(-ventilation_rate_per_second * time_points)
# Calculate C_sat
C_sat = (molecular_weight_kg_mol * vapour_pressure_pa) / (R * temperature_k)
# Convert C_air_over_time to mg/m^3 for plotting
C_air_over_time_mg_m3 = C_air_over_time * 1e6
# Calculate the total inhaled dose
total_inhaled_volume_m3 = inhalation_rate_m3_hr * (exposure_duration_seconds / 3600) # m^3
total_inhaled_dose_kg = np.trapz(C_air_over_time, time_points) * inhalation_rate_m3_hr / 3600 # kg
total_inhaled_dose_mg = total_inhaled_dose_kg * 1e6 # mg
# Calculate the external event dose
external_event_dose_mg_kg_bw = total_inhaled_dose_mg / body_weight_kg # mg/kg bw
# Calculate mean event concentration
mean_event_concentration = np.mean(C_air_over_time_mg_m3)
# Calculate peak concentration (TWA 15 min)
time_interval_15min = 15 * 60 # 15 minutes in seconds
if exposure_duration_seconds >= time_interval_15min:
time_points_15min = time_points[time_points <= time_interval_15min]
C_air_15min = C_air_over_time[time_points <= time_interval_15min]
TWA_15_min = np.mean(C_air_15min) * 1e6 # Convert to mg/m³
else:
TWA_15_min = mean_event_concentration
# Calculate mean concentration on day of exposure
mean_concentration_day_of_exposure = mean_event_concentration * (exposure_duration_seconds / 86400)
# Calculate year average concentration
year_average_concentration = mean_concentration_day_of_exposure * frequency_per_year / 365
# Calculate cumulative dose over time and convert to mg/kg body weight
time_step = time_points[1] - time_points[0]
cumulative_dose_kg = np.cumsum(C_air_over_time) * time_step * inhalation_rate_m3_hr / 3600 # kg
cumulative_dose_mg = cumulative_dose_kg * 1e6 # mg
cumulative_dose_mg_kg_bw = cumulative_dose_mg / body_weight_kg # mg/kg bw
# Final values for annotations
final_air_concentration = C_air_over_time_mg_m3[-1]
final_external_event_dose = cumulative_dose_mg_kg_bw[-1]
# Prepare results text
result_text = (
f"Mean event concentration: {mean_event_concentration:.1e} mg/m³\n"
f"Peak concentration (TWA 15 min): {TWA_15_min:.1e} mg/m³\n"
f"Mean concentration on day of exposure: {mean_concentration_day_of_exposure:.1e} mg/m³\n"
f"Year average concentration: {year_average_concentration:.1e} mg/m³\n"
f"External event dose: {external_event_dose_mg_kg_bw:.1f} mg/kg bw\n"
f"External dose on day of exposure: {external_event_dose_mg_kg_bw:.1f} mg/kg bw"
)
# Plotting with animation
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
# Initialize lines
line1, = ax1.plot([], [], lw=2)
line2, = ax2.plot([], [], lw=2)
# Plot air concentration over time
def init_air_concentration():
ax1.set_xlim(0, exposure_duration)
ax1.set_ylim(0, np.max(C_air_over_time_mg_m3) * 1.1)
ax1.set_title('Inhalation - Air concentration')
ax1.set_xlabel('Time (min)')
ax1.set_ylabel('Concentration (mg/m³)')
ax1.grid(True)
return line1,
def update_air_concentration(frame):
line1.set_data(time_points[:frame] / 60, C_air_over_time_mg_m3[:frame])
return line1,
# Plot external event dose over time
def init_external_dose():
ax2.set_xlim(0, exposure_duration)
ax2.set_ylim(0, np.max(cumulative_dose_mg_kg_bw) * 1.1)
ax2.set_title('Inhalation - External event dose over time')
ax2.set_xlabel('Time (min)')
ax2.set_ylabel('Dose (mg/kg bw)')
ax2.grid(True)
return line2,
def update_external_dose(frame):
line2.set_data(time_points[:frame] / 60, cumulative_dose_mg_kg_bw[:frame])
return line2,
# Display results in a Tkinter window
result_window = tk.Tk()
result_window.title("Model Results")
result_window.geometry('1920x1080')
canvas = FigureCanvasTkAgg(fig, master=result_window)
canvas_widget = canvas.get_tk_widget()
canvas_widget.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
frame = tk.Frame(result_window)
frame.pack(side=tk.BOTTOM, fill=tk.X)
label = ttk.Label(frame, text=result_text, justify=tk.LEFT)
button = ttk.Button(frame, text="Close", command=result_window.destroy)
label.pack(padx=10, pady=10)
button.pack(padx=10, pady=10)
ani1 = FuncAnimation(fig, update_air_concentration, frames=len(time_points), init_func=init_air_concentration, interval=300/len(time_points), repeat=False)
ani2 = FuncAnimation(fig, update_external_dose, frames=len(time_points), init_func=init_external_dose, interval=300/len(time_points), repeat=False)
result_window.mainloop()
if __name__ == "__main__":
run_model()