So I have been trying to get a plot to update every iteration through a loop. A stripped down version of my code is as follows:
1 import matplotlib.pyplot as plt
2 import numpy as np
3
4 x = np.linspace(0, 9, 10)
5 for j in range(10):
6 y = np.random.random(10)
7 plt.plot(x,y)
8 plt.show()
9 plt.pause(1)
10 plt.clf()
My issue is that I have to close each plot before the next one is created; it seems like the plot is stuck on plt.show(), whereas I expect a new plot to replace the current one every second without needing my interaction. I've consulted the following questions:
When to use cla(), clf() or close() for clearing a plot in matplotlib?
Python plt: close or clear figure does not work
Matplotlib pyplot show() doesn't work once closed
But none of the solutions seemed to work for me. Any help would be appreciated!
You should set interactive mode with plt.ion(), and use draw to update
import matplotlib.pyplot as plt
import numpy as np
plt.ion()
fig=plt.figure()
x = np.linspace(0, 9, 10)
for j in range(10):
y = np.random.random(10)
plt.plot(x,y)
fig.canvas.draw()
plt.pause(1)
plt.clf()
link to tutorial
Note that it might not work on all platforms; I tested on Pythonista/ios, which didn't work as expected.
From
matplotlib tutorial
Note
Interactive mode works with suitable backends in ipython and in the ordinary python shell, but it does not work in the IDLE IDE. If the default backend does not support interactivity, an interactive backend can be explicitly activated using any of the methods discussed in What is a backend?.
Related
I have a python program (not a notebook, a python file) where I produce several plots that show up one after the other. The program looks something like this:
import numpy as np
import matplotlib.pyplot as plt
functions = [np.sin, np.cos, np.abs, np.square]
x = np.linspace(-np.pi, np.pi, 100)
for func in functions:
plt.plot(x, func(x))
plt.show()
When I run the program in vscode I have to close one plot before the next one opens. The windows with the plots open at different locations every time and it would be more convenient if the X button was at the same place every time so i can click through them more easily. Is there a way to do this?
I solved it like this:
import numpy as np
import matplotlib.pyplot as plt
from pylab import get_current_fig_manager
functions = [np.sin, np.cos, np.abs, np.square]
x = np.linspace(-np.pi, np.pi, 100)
for func in functions:
thismanager = get_current_fig_manager()
thismanager.window.wm_geometry("+500+0")
plt.plot(x, func(x))
plt.show()
Like on this webpage: https://pyquestions.com/how-do-you-set-the-absolute-position-of-figure-windows-with-matplotlib
or as answered here: How do you set the absolute position of figure windows with matplotlib?.
I thought it was a vscode issue but everything is done by matplotlib. If anyone knows a more permanent solution, please let me know, as setting this for every plot is quite annoying.
I generate a lots of figures with a script which I do not display but store to harddrive. After a while I get the message
/usr/lib/pymodules/python2.7/matplotlib/pyplot.py:412: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (matplotlib.pyplot.figure) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam figure.max_num_figures).
max_open_warning, RuntimeWarning)
Thus, I tried to close or clear the figures after storing. So far, I tried all of the followings but no one works. I still get the message from above.
plt.figure().clf()
plt.figure().clear()
plt.clf()
plt.close()
plt.close('all')
plt.close(plt.figure())
And furthermore I tried to restrict the number of open figures by
plt.rcParams.update({'figure.max_num_figures':1})
Here follows a piece of sample code that behaves like described above. I added the different options I tried as comments at the places I tried them.
from pandas import DataFrame
from numpy import random
df = DataFrame(random.randint(0,10,40))
import matplotlib.pyplot as plt
plt.ioff()
#plt.rcParams.update({'figure.max_num_figures':1})
for i in range(0,30):
fig, ax = plt.subplots()
ax.hist([df])
plt.savefig("/home/userXYZ/Development/pic_test.png")
#plt.figure().clf()
#plt.figure().clear()
#plt.clf()
#plt.close() # results in an error
#plt.close('all') # also error
#plt.close(plt.figure()) # also error
To be complete, that is the error I get when using plt.close:
can't invoke "event" command: application has been destroyed
while executing "event generate $w <>"
(procedure "ttk::ThemeChanged" line 6)
invoked from within "ttk::ThemeChanged"
The correct way to close your figures would be to use plt.close(fig), as can be seen in the below edit of the code you originally posted.
from pandas import DataFrame
from numpy import random
df = DataFrame(random.randint(0,10,40))
import matplotlib.pyplot as plt
plt.ioff()
for i in range(0,30):
fig, ax = plt.subplots()
ax.hist(df)
name = 'fig'+str(i)+'.png' # Note that the name should change dynamically
plt.savefig(name)
plt.close(fig) # <-- use this line
The error that you describe at the end of your question suggests to me that your problem is not with matplotlib, but rather with another part of your code (such as ttk).
plt.show() is a blocking function, so in the above code, plt.close() will not execute until the fig windows are closed.
You can use plt.ion() at the beginning of your code to make it non-blocking. Even though this has some other implications the fig will be closed.
I was still having the same issue on Python 3.9.7, matplotlib 3.5.1, and VS Code (the issue that no combination of plt.close() closes the figure). I have three loops which the most inner loop plots more than 20 figures. The solution that is working for me is using agg as backend and del someFig after plt.close(someFig). Subsequently, the order of code would be something like:
import matplotlib
matplotlib.use('agg')
import matplotlib.pyplot as plt
someFig = plt.figure()
.
.
.
someFig.savefig('OUTPUT_PATH')
plt.close(someFig) # --> (Note 1)
del someFig
.
.
.
NOTE 1: If this line is removed, the output figures may not be plotted correctly! Especially when the number of elements to be rendered in the figure is high.
NOTE 2: I don't know whether this solution could backfire or not, but at least it is working and not hugging RAM or preventing plotting figures!
import tensorflow as tf
from matplotlib import pyplot as plt
sample_image = tf.io.read_file(str(PATH / 'Path to your file'))
sample_image = tf.io.decode_jpeg(sample_image)
print(sample_image.shape)
plt.figure("1 - Sample Image ")
plt.title(label="Sample Image", fontsize=12, color="red")
plt.imshow(sample_image)
plt.show(block=False)
plt.pause(3)
plt.close()
plt.show(block=False)
plt.pause(interval) do the trick
This does not really solve my problem, but it is a work-around to handle the high memory consumption I faced and I do not get any of the error messages as before:
from pandas import DataFrame
from numpy import random
df = DataFrame(random.randint(0,10,40))
import matplotlib.pyplot as plt
plt.ioff()
for i in range(0,30):
plt.close('all')
fig, ax = plt.subplots()
ax.hist([df])
plt.savefig("/home/userXYZ/Development/pic_test.png")
I have found that the latest update to python/matplotlib has broken a crucial feature, namely, the ability to regularly update or "refresh" a matplotlib plot during code execution. Below is a minimally (non-)working example.
import numpy as np
from matplotlib.pyplot import *
from time import sleep
x = np.array([0])
y = np.array([0])
figure()
for i in range(51):
gca().cla()
plot(x,y)
xlim([0,50])
ylim([0,2500])
draw()
show(block = False)
x = np.append(x,[x[-1]+1])
y = np.append(y,[x[-1]**2])
sleep(0.01)
If I run this program using Python 3.4.3 and matplotlib 1.4.3, I can see the plot continually update, and the curve grows as the program runs. However, using Python 3.5.1 with matplotlib 1.5.3, the matplotlib window opens but does not show the plot. Instead, it continually shows the window is "not responding" and only presents the final plot when the code finishes executing.
What can I do about this? Is there some way to achieve the functionality that I want using the latest release?
Note: I'm running this from the default IDLE environment if that makes a difference.
That is interesting. I'm used to draw interactive plots a little bit differently:
import numpy as np
import matplotlib.pyplot as plt
from time import sleep
x = np.array([0])
y = np.array([0])
plt.ion()
fig = plt.figure()
ax=fig.add_subplot(111)
ax.set_xlim([0,50])
ax.set_ylim([0,2500])
line, = ax.plot(x,y)
plt.show()
for i in range(51):
x = np.append(x,[x[-1]+1])
y = np.append(y,[x[-1]**2])
line.set_data(x,y)
plt.pause(0.01)
Can you (or anyone) check if this shows the same problems in Matplotlib 1.5?
Hi I would like to show a few figures in matplotlib without stopping calculations. I would like the figure to show up right after the calculations that concern it are finished for example:
import numpy as np
import pylab as py
x=np.linspace(0,50,51)
y=x
fig, axs = plt.subplots(1, 1)
cs = axs.plot(x, y)
now i want to show the plot without blocking the possibility to make some other calculations
plt.show(block=False)
plt.pause(5)
I create the second plot
y1=2*x
fig1, axs1 = plt.subplots(1, 1)
cs1 = axs1.plot(x, y1)
plt.show()
This works however the first freezes (after 5 secound pause which I added) until I call plt.show() at the end. It is crucial that the first figure shows and works, then after calculations another figure is added to it.
The following code should do what you want. I did this in an IPython Notebook.
from IPython import display
import matplotlib.pyplot as plt
def stream_plot(iterable, plotlife=10.):
for I in iterable:
display.clear_output(wait=True)
output = do_calculations_on_i(I)
plt.plot(output)
display.display(plt.gca());
time.sleep(plotlife); #how long to show the plot for
the wait=True will wait to clear the old plot until it has something new to plot, or any other output is printed.
I put the sleep in there so I can observe each plot before it is wiped away. This was useful for having to observe distributions for several entities. You may or may not need it for what you want to do.
I'm trying to plot streaming data in matplotlib. I can update the plot using interactive mode and the set_ydata function. It animates and everything looks good until the loop ends. Then the python kernel crashes and I get this message:
C:\Conda\lib\site-packages\matplotlib\backend_bases.py:2437:
MatplotlibDeprecationWarning: Using default event loop until function specific to
this GUI is implemented
warnings.warn(str, mplDeprecation)
Here's the code:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 10, 0.1)
y = np.sin(x)
plt.ion() #interactive mode on
ax = plt.gca()
line, = ax.plot(x,y)
ax.set_ylim([-5,5])
for i in np.arange(100):
line.set_ydata(y)
plt.draw()
y = y*1.01
plt.pause(0.1)
Can anyone tell me why this is crashing instead of just exiting the loop? I'm doing this in Jupyter with Python 3. And of course, if there's a better way to do this, I would love to hear about it. Thanks!
This code was adapted from How to update a plot in matplotlib?
It works well for me with mac_osx backend from Jupyter notebook in python 3.4.
Maybe you want to add plt.close() at the end to keep things tidy and prevent a hang up?