You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Petri网模拟工具按钮函数异常:多按钮失效与绘图弹窗问题

解决方案

问题1:多按钮仅最后一个可点击的修复

原代码通过buttons.index(event.inaxes)获取按钮索引的方式不可靠——matplotlib的Axes引用会在后续创建操作中被干扰,导致无法正确匹配早期创建的按钮。正确做法是在创建按钮时直接绑定对应的变迁索引,通过闭包保存每个按钮的专属索引值,彻底避免动态查找的误差。

问题2:触发变迁后弹出新窗口的修复

点击事件中重复调用plt.show()是问题根源:该函数在非交互模式下会启动新的绘图窗口。应使用画布的draw_idle()方法更新原窗口内容,同时确保整个程序仅在主流程末尾调用一次plt.show(),避免重复触发窗口创建。

修改后的完整代码

def create_transition_buttons(num_transitions, markings_vector, incidence_matrix, ax, fig, G=None, num_places=None):
    buttons = []
    button_width = 0.1
    button_gap = 0.02

    def on_button_click(transition_idx):
        nonlocal markings_vector

        # 校验变迁是否可触发:有输入库所则所有输入库所标识必须>0,无输入则直接可触发
        input_places = incidence_matrix[:, transition_idx] == -1
        if not np.any(input_places) or np.all(markings_vector[input_places] > 0):
            # 更新库所标识
            modified = [False] * num_places
            for i in range(num_places):
                if incidence_matrix[i, transition_idx] == 1 and not modified[i]:
                    markings_vector[i] += 1
                    modified[i] = True
            for i in range(num_places):    
                if incidence_matrix[i, transition_idx] == -1 and not modified[i]:
                    markings_vector[i] -= 1
                    modified[i] = True

            # 重绘Petri网并更新原窗口
            ax.clear()
            draw_petri_net_graph(G, num_places, num_transitions, markings_vector, incidence_matrix)
            fig.canvas.draw_idle()

    for i in range(num_transitions):
        button_x = 0.05 + i * (button_width + button_gap)
        button_y = 0.05
        button_label = f"Fire T{i+1}"
        button_ax = plt.axes([button_x, button_y, button_width, 0.05])
        button = plt.Button(button_ax, button_label)
        # 通过lambda默认参数绑定当前按钮对应的变迁索引,避免闭包变量延迟绑定问题
        button.on_clicked(lambda event, idx=i: on_button_click(idx))
        buttons.append(button)

    # 移除函数内的plt.show(),统一移到主程序中调用
    return buttons

主程序调用示例

确保整个流程仅调用一次plt.show():

# 初始化绘图组件
fig, ax = plt.subplots()

# 初始化Petri网核心参数
num_places = 3
num_transitions = 2
markings_vector = np.array([1, 0, 0])
incidence_matrix = np.array([[-1, 0], [1, -1], [0, 1]])
G = None # 替换为你的图结构对象

# 创建变迁触发按钮
create_transition_buttons(num_transitions, markings_vector, incidence_matrix, ax, fig, G, num_places)

# 仅在此处启动绘图窗口
plt.show()

额外修正说明

原代码中的变迁触发条件逻辑存在误差,修改后的条件严格遵循Petri网规则:只有当所有输入库所的标识数量满足要求时,变迁才能触发;无输入库所的变迁可直接触发。

内容的提问来源于stack exchange,提问作者samm bodie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 22:35:08