在模拟过程中更新 matplotlib 图

Phi*_*hil 8 python matplotlib

我尝试实现在我的环境模拟期间更新的 matplotlib 图。

以下类在我的测试中运行良好,但在我的环境中使用它时不会更新数字。在环境模拟期间,会显示图形,但未绘制线条。

我的猜测是 .draw() 没有像我认为的那样工作。

任何人都可以弄清楚这里的问题吗?

class Visualisation:
    def __init__(self, graphs):
        self.graphs_dict = {}
        for graph in graphs:
            fig = plt.figure()
            ax = fig.add_subplot(111)
            line, = ax.plot(graph.x, graph.y, 'r-')
            self.graphs_dict[graph.title] = {"fig": fig, "ax": ax, "line": line, "graph": graph}
            self.graphs_dict[graph.title]["fig"].canvas.draw()
        plt.ion()
        plt.show()

    def update(self, graph):
        graph = self.graphs_dict[graph.title]["graph"]
        self.graphs_dict[graph.title]["line"].set_xdata(graph.x)
        self.graphs_dict[graph.title]["line"].set_ydata(graph.y)
        self.graphs_dict[graph.title]["fig"].canvas.flush_events()
        x_lim, y_lim = self.get_lim(graph)
        self.graphs_dict[graph.title]["ax"].set_xlim(x_lim)
        self.graphs_dict[graph.title]["ax"].set_ylim(y_lim)
        self.graphs_dict[graph.title]["fig"].canvas.draw()

    @staticmethod
    def get_lim(graph):
        if graph.x_lim is None:
            x = np.array(graph.x)
            y = np.array(graph.y)
            x_lim = [x.min(), x.max()]
            y_lim = [y.min(), y.max()]
        else:
            x_lim = graph.x_lim
            y_lim = graph.y_lim
        return x_lim, y_lim

class Graph:
    def __init__(self, title, x, y, x_label="", y_label=""):
        """
        Sets up a graph for Matplotlib
        Parameters
        ----------
        title : String
            Title of the plot
        x : float
        y : float
        x_label : String
            x Label
        y_label : String
            y Label
        """
        self.title = title
        self.x = x
        self.y = y
        self.x_label = x_label
        self.y_label = y_label
        self.x_lim, self.y_lim = None, None

    def set_lim(self, x_lim, y_lim):
        self.x_lim = x_lim
        self.y_lim = y_lim

class Environment:
    def __init__(self, [..], verbose=0):
        """verbose : int
            0 - No Visualisation
            1 - Visualisation
            2 - Visualisation and Logging"""            

        self.vis = None
        self.verbose = verbose         

                    [......]

    def simulate(self):
        for _ in range(self.n_steps):
            [...]
            self.visualize()

    def visualize(self):
        if self.verbose == 1 or self.verbose == 2:
            if self.vis is None:
                graphs = [Graph(title="VariableY", x=[], y=[])]
                graphs[0].set_lim(x_lim=[0, 100], y_lim=[0, 300])
                self.vis = Visualisation(graphs=graphs)
            else:
                self.vis.graphs_dict["VariableY"]["graph"].x.append(self.internal_step)
                self.vis.graphs_dict["VariableY"]["graph"].y.append(150)
                self.vis.update(self.vis.graphs_dict["VariableY"]["graph"])
Run Code Online (Sandbox Code Playgroud)

当我运行代码时,我或多或少只是写:env.simulate().

代码在这里运行良好:

class TestSingularVisualisation(unittest.TestCase):
    def setUp(self):
        self.graph = Graph(title="Test", x=[0], y=[0])
        self.vis = Visualisation(graphs=[self.graph])

class TestSingleUpdate(TestSingularVisualisation):
    def test_repeated_update(self):
        for i in range(5):
            self.graph.x.append(i)
            self.graph.y.append(np.sin(i))
            self.vis.update(self.graph)
            time.sleep(1)
Run Code Online (Sandbox Code Playgroud)

cra*_*ael 6

原来你的代码按照它的设置方式工作。这是您提供的代码的唯一问题:

self.vis.graphs_dict["VariableY"]["graph"].x.append(self.internal_step)
self.vis.graphs_dict["VariableY"]["graph"].y.append(150)
Run Code Online (Sandbox Code Playgroud)

您正在绘制一条线并正确更新画布,但是,您一直在附加完全相同的 (x, y) 坐标。所以模拟确实更新了线,但线简化为一个点。您的测试用例不会这样做。您可以通过简单地添加这样的行来使用您的代码运行一个虚拟示例:

self.internal_step += 5
Run Code Online (Sandbox Code Playgroud)

在添加新的 x 点之前,您将生成一条水平线。

如果这能解决您的问题,请告诉我。