Обновление фигуры matplotlib во время симуляции - PullRequest
8 голосов
/ 16 июня 2020

Я пытаюсь реализовать фигуру 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"])

Когда я запускаю код, я более или менее просто пишу: 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)

Ответы [ 2 ]

6 голосов
/ 22 июня 2020

Оказывается, ваш код работает так, как он настроен. Вот единственная проблема с предоставленным вами кодом:

self.vis.graphs_dict["VariableY"]["graph"].x.append(self.internal_step)
self.vis.graphs_dict["VariableY"]["graph"].y.append(150)

Вы рисуете линию и правильно обновляете холст, однако вы продолжаете добавлять точно такие же координаты (x, y). Таким образом, симуляция обновляет линию, но линия упрощается до точки. Ваш тестовый пример этого не делает. Вы можете запустить фиктивный пример с вашим кодом, просто добавив строку, подобную этой:

self.internal_step += 5

перед добавлением новой точки x, и вы получите горизонтальную линию.

Дайте мне знать если это решит вашу проблему.

3 голосов
/ 23 июня 2020

Вероятно, не самый элегантный, но я использую plt.pause(0.1), когда хочу обновить графики во время выполнения. Он приостанавливается на 0,1 с и заставляет фактически отображаться все графики. (Работает в% debug в i python в качестве бонуса)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...