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

如何在PyShiny中实现多图展示?代码问题求助

修复PyShiny动态生成图表的问题

问题根源

原代码的核心问题有两个:

  1. 循环中直接定义带装饰器的函数会触发闭包陷阱,所有函数最终使用的是循环变量j的最后一个值
  2. 用exec动态定义函数的语法错误,装饰器无法正确绑定到目标函数

修复后的完整代码

from shiny import App, render, ui
import matplotlib.pyplot as plt

# 辅助函数
def do_call(what, args=[], kwargs = {}):
    return what(*args, **kwargs)

max_plots = 5

app_ui = ui.page_fluid(
    ui.input_slider("n", "Number of plots", value=1, min=1, max=5),
    ui.output_ui("plots")
)

def server(input, output, session):
     
    @output
    @render.ui
    def plots():
        plot_output_list = []
        for i in range(1, input.n()+1):
            plotname = f"plot{i}"
            plot_output_list.append(ui.output_plot(plotname))
        return do_call(ui.TagList, plot_output_list)

    # 函数工厂:生成带指定编号的绘图函数
    def make_plot_func(plot_idx):
        @output
        @render.plot
        def plot_func():
            fig, ax = plt.subplots()
            ax.plot(range(1, plot_idx+1), range(1, plot_idx+1))
            return fig
        # 将生成的函数注册到output对象,对应动态命名的输出
        setattr(output, f"plot{plot_idx}", plot_func)

    # 循环生成所有绘图函数
    for j in range(1, max_plots+1):
        make_plot_func(j)

app = App(app_ui, server)

关键修复说明

  • 函数工厂规避闭包陷阱:通过make_plot_func工厂函数,将每个循环的plot_idx作为参数传入,确保每个绘图函数捕获的是独立的数值,不会被后续循环覆盖
  • 动态注册输出函数:使用setattr(output, 函数名, 函数对象),将生成的绘图函数绑定到output对象上,替代原代码中错误的exec用法
  • 规范matplotlib绘图:改用plt.subplots()创建明确的Figure和Axes对象,避免全局状态混乱,确保返回的是符合PyShiny要求的Figure实例

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 06:52:55