Skip to content

matplotlib dynamic plotting #7759

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
MpCamp opened this issue Jan 7, 2017 · 9 comments
Closed

matplotlib dynamic plotting #7759

MpCamp opened this issue Jan 7, 2017 · 9 comments

Comments

@MpCamp
Copy link

MpCamp commented Jan 7, 2017

Hi, after computer change, matplotlib don't work dynamically.
Before, it was able to update the figure at each iteration of a loop. Today only the last data are plotted.
Configuration :
HP zBook 15 G3 with NVidia Quadro

###Bug report

Bug summary

A figure inside a loop are not updated at each step

Code for reproduction

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(128)
plt.figure(1)
plt.ion()
plt.hold(False)
for it in range(5):
    plt.plot(x, x+it)
    plt.draw()

plt.ioff()
plt.show()

Expected outcome

  • I expect to see one plot at each step of the for loop

Matplotlib version
1.5.1

Python version
3.5.2

OS
Ubuntu 16.04 LTS

  • All of them had been installed from Ubuntu repository using synaptic
@petehuang
Copy link
Contributor

petehuang commented Jan 7, 2017

I think you may need to add plt.pause(0.01) after plt.draw() - can you try that?

@MpCamp
Copy link
Author

MpCamp commented Jan 7, 2017 via email

@petehuang
Copy link
Contributor

I'm entirely the wrong person to ask for the "why", but I'm glad it works! I just shuttled around StackOverflow for the answer :)

@tacaswell
Copy link
Member

'why' is a bit of a long question (see #4779 for an old PR trying to document all of the details). In very short, we made many of the GUI embedding more asynchronous, that is calling plt.draw calls fig.canvas.draw_idle() which asks the GUI to re-render the figure. If you never turn control over to the GUI event loop to process it's events, then it does not have a chance to update it's self (you will also note that while your code is running you can not pan/zoom the figure).

Doing

import matplotlib.pyplot as plt
plt.ion()
import numpy as np

x = np.arange(128)
fig, ax = plt.subplots()

for it in range(5):
    ax.plot(x, x+it)
    # fig.canvas.draw_idle()  # required to work on mpl < 1.5
    fig.canvas.flush_events()
    time.sleep(1)

plt.ioff()
plt.show()

should do what you want.

@MpCamp
Copy link
Author

MpCamp commented Jan 8, 2017 via email

@petehuang
Copy link
Contributor

👍

Should we close this?

@MpCamp
Copy link
Author

MpCamp commented Jan 8, 2017 via email

@QuLogic QuLogic closed this as completed Jan 8, 2017
@maxgittelman
Copy link

maxgittelman commented Oct 25, 2017

Hey guys, any idea on how to fix my equivalent MatplotlibDeprecationWarning. I realized I essentially have the exact same problem except on a larger scale?

I have set up a server that will read in live data and produce two 3d plots. You can run this simulated code below (instead of reading in the data from the client).

import matplotlib.pyplot as plt
from threading import Thread, Lock, Condition
import random, time, socket
from mpl_toolkits.mplot3d import Axes3D
import numpy as np


class Plotter:
    def __init__(self):

        # temp list of data received by server
        self.data = [[] for i in range(3)]

        # threading variables
        self.mutex = Lock()
        self.points_received = 0
        self.cv = Condition()

        # initialize figure
        self.fig = plt.figure()
        self.run_plot = False
        self.ax = self.fig.add_subplot(111, projection='3d')
        self.ax.set_xlim(0, 1)
        self.ax.set_ylim(0, 1)
        self.ax.set_zlim(0, 1)
        plt.ion()
        plt.show()

    # This just simulates reading from a socket.
    def data_listener(self):
        while True:
            time.sleep(1)
            with self.mutex:
                new_data = [random.random() for i in range(3)]

                # append new data to be plotted and check max/min to update axes limits
                for axis in range(3):
                    self.data[axis].append(new_data[axis])

    def sub_plot(self):
        # wait until ready, <Enter> is pressed
        self.cv.acquire()
        while not self.run_plot:
            self.cv.wait()  # I think this causes the plot to not respond before hitting <Enter>
        self.cv.release()

        while self.run_plot:
            time.sleep(0.01)
            with self.mutex:
                try:
                    # add data and clear graph
                    self.ax.scatter(self.data[0], self.data[1], self.data[2])
                    self.data = [[] for i in range(3)]

                    plt.pause(0.000001)
                    # self.fig.canvas.flush_events()
                except:
                    print ("error")

    def cmdline_input(self):
        # Start then End Plot
        for status in ["start", "end"]:
            text_start = raw_input("Hit <Enter> to " + status + " plotting")
            while text_start != "":
                print "Wrong input"
                text_start = raw_input("Hit <Enter> to " + status + " plotting")

            self.cv.acquire()
            if status == "start":
                self.run_plot = True
            elif status == "end":
                self.run_plot = False
            self.cv.notify()
            self.cv.release()

    def run(self):
        d = Thread(target=self.data_listener)
        d.start()

        # start cmdline input
        c_start = Thread(target=self.cmdline_input)
        c_start.start()

        # subplot
        self.sub_plot()


if __name__ == '__main__':
    p = Plotter()
    p.run()

You guys have a better handle on how to fix this issue. Currently when I run the live plot (randomly sending over numbers), I can change the viewing angle with my cursor but I can't zoom in or out. I tried adding in self.fig.canvas.flush_events() after plt.pause(0.000001) but that didn't seem to functionally change anything.

I also noticed that when my plot isn't receiving live data, the window is unresponsive. I.e. If you try to maximize the window or change the window size the whole screen gets blurred. I have a feeling that this has something to do with me putting the plotting thread to sleep but maybe there's a simple fix?

@tacaswell
Copy link
Member

This question is probably better sent to the mailing list (matplotlib-users@python.org ; you will have to subscribe to post).

#4779 may also be informative reading.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants