同时加载 2 个 Tkinter 窗口。一个有动画的

问题描述 投票:0回答:1

以下脚本独立运行以运行场景:

首先打印结果,然后以动画结束绘图。

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” *** 首先抛出调用堆栈:

任何帮助表示赞赏。

python matplotlib tkinter tkinter-canvas matplotlib-animation
1个回答
0
投票

我不确定这是否正是您想要的,但您可以在 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()
© www.soinside.com 2019 - 2024. All rights reserved.