Simple Python animation using pause command not working - python

I wanted to create a simple animation using plt.pause() command in python. So I tried the first example from this page. If you go there, it shows you a nice animation of a graph growing smoothly. I copy-paste it below
from matplotlib import pyplot as plt
x = []
y = []
for i in range(100):
x.append(i)
y.append(i)
# Mention x and y limits to define their range
plt.xlim(0, 100)
plt.ylim(0, 100)
# Ploting graph
plt.plot(x, y, color = 'green')
plt.pause(0.01)
plt.show()
However, it is giving me 100 different plots with an incremental increase until it completes the range. I think the problem is with figures appearing without waiting for the plt.show() command? Help me. I am using Jupiter 6.0.3 and sypder 4.1.3

Without the .show() command the plot will disappear at the completion of the code. however the animation should still be visible as it is created by the .plot() command.
I am not able to reproduce your problem using Python 3.9.7.
You can always try running the script outside of the IDE using python pathtoscript and see if that resolves the issue.

To build on #Regretful's answer, if you're running in a Jupyter notebook, use %matplotlib qt or some other non-inline backend to get the usual pop-up window, rather than static images.
No idea for Spyder, though!

Related

Matplotlib bbox_inches issue

I have this very simple code:
import math
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 2*math.pi)
fig, ax = plt.subplots()
ax.plot(x,np.sin(x))
plt.savefig('sinwave.png', bbox_inches='tight')
plt.show()
So what I would expect is that there is white background inside my plotting area, but no background around it, e.g. transparent background (only) behind the ticks and tick labels.
However, something is going wrong and it isn't working, the whole background is white. When I send it to a friend it works exactly as expected.
So I thought creating a new environment might fix it but the issue persisted. I tried it in ipython, jupyter lab and jupyter notebook, all with the same result (as to be expected but I just thought I would try). I'm using python 3.10.8 and matplotlib 3.6.2 on a Mac (2019 MacBook Pro) but it also doesn't work with other versions of python or matplotlib.
This is just a simple example but I have some 3-4 month old code which did exactly what I want back then and is now not doing it any more. Very odd.
Any ideas what might be going wrong? I really thought the new environment would fix the issue but no luck.
I'm fairly new to the community so let me know if you need any further details about my system (as it seems to be an issue with my computer/python install maybe??).
Cheers
Markus
Below are both images, you can't see the difference here as it's on white background but it's straight forward if opened e.g. in illustrator or photoshop.
fig = plt.figure()
fig.patch.set_facecolor('white')
fig.patch.set_alpha(0.6) #play with the alpha value
ax = fig.add_subplot(111)
ax.patch.set_facecolor('white')
ax.patch.set_alpha(0.0) #play with the alpha value
Then simply plot here
Plt.scatter(x,y)
Plt.show()

Visual Stdio Code, PyCharm, and Thonny behave differently running simple matplotlib demo code

I want to use Python's matplotlib to display some sensor data in 3D and in real time. My starting place was to try do just plot a sine wave from one of the many examples from the web. A "Hello World" if you will.
I started with a fresh install of PyCharm on my reasonably fresh Windows 11 PC. This setup works fine for things that don't involve matplotlib.
After a while I came to the conclusion that PyCharm was just not working the way I expected, and for the fun of it ran the code using Thonny (yeah, I have several Raspberry Pis), and it worked as expected.
Just because I could, I tried the same code using Visual Studio Code 2022. It didn't work the same way PyCharm didn't.
PyCharm and VS Code would output the printed "value" and open the "figure" window, but would not display the sine wave plot. Eventually the "figure" window would say "not responding" for both.
The Thonny output was as expected, and there was no "not responding" message.
The only difference I see is that the PyCharm and VS Code use virtual environments, and Thonny does not.
I'll admit to not being the sharpest knife in the drawer, and will be appreciative of suggestions.
Edit -- Also, running the code from the command line (Windows Terminal (Admin) acts the same way as for PyCharm and VS Code. /Edit
The code in question is:
import numpy as np
import time
import matplotlib.pyplot as plt
figure, ax = plt.subplots(figsize=(4,5))
x = np.linspace(0, 20, 80)
y = np.sin(x)
plt.ion()
plot1, = ax.plot(x, y)
plt.xlabel("X-Axis",fontsize=18)
plt.ylabel("Y-Axis",fontsize=18)
for value in range(25):
update_y_value = np.sin(x-2.5*value)
plot1.set_xdata(x)
plot1.set_ydata(update_y_value)
figure.canvas.draw()
figure.canvas.flush_events()
time.sleep(0.05)
print(value)
plt.show()
I was confused by this at one point, basically for displaying graphics on the screen it's much easier if running directly on the machine since virtual terminals don't have access to your screen by default. There are ways to get around it and give them this access (https://virtualizationreview.com/articles/2017/02/08/graphical-programs-on-windows-subsystem-on-linux.aspx), but often it's much easier to just run the program from Windows natively using something like CMD (or it seems like Thonny worked for you). You also might want to consider trying out Jupyter Notebook depending on what you're doing. Using virtual subsystems like WSL has given me lots of problems with this in the past.
I finally found an example that I can use as a starting place for what I really want to do. The following sample runs reliably in all of VS Code, PyCharm and Thonny IDEs.
That snealy little "plt.pause(1e-17)" seems to make a lot of difference.
import numpy as np
import matplotlib.pyplot as plt
xdata = []
ydata = []
axes = plt.gca()
axes.set_xlim(0, 100)
axes.set_ylim(-2, +2)
line, = axes.plot(xdata, ydata, 'r-')
x = np.linspace(0, 19, 100)
y = np.sin(x)
plt.xlabel("X-Axis", fontsize=18)
plt.ylabel("Y-Axis", fontsize=18)
for value in range(100):
xdata.append(value)
ydata.append(y[value])
line.set_xdata(xdata)
line.set_ydata(ydata)
plt.pause(1e-17)
plt.show()

Visualizing Python interactive plots outside of Jupyter

I am making some small tests in Jupyter. The user should see two plots, one on the left and one on the right. Than after clicking somewhere on the left plot something on the right plot should happen. For example here a click on the left plot will produce a red dot on the right plot in the same place:
%matplotlib notebook
def onclick(event):
ax.clear()
ax2.clear()
ax.set_xlim(0,10)
ax.set_ylim(0,10)
ax2.set_xlim(0,10)
ax2.set_ylim(0,10)
ax2.plot([event.xdata],[event.ydata],'o',color='red')
ax.figure.canvas.draw_idle()
ax2.figure.canvas.draw_idle()
fig = plt.figure(figsize=(20,10))
ax = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
ax.set_xlim(0,10)
ax.set_ylim(0,10)
ax2.set_xlim(0,10)
ax2.set_ylim(0,10)
cid = fig.canvas.mpl_connect('button_press_event',onclick)
This works, but the visualization in Jupyter is not the best. Is there a way to have this kind of interactive plots working outside of a Jupyter notebook ? Maybe in a window with varying dimensions ? As an example, how would one proceed with the example above ?
You can use plotly and export your plots to html file:
https://plotly.com/python/interactive-html-export/
I think I found a possible simple answer to my needs. Simply put the code in the question in a python script, remove the 'magic' command and insert at the end:
plt.show(block=True)
This way matplotlib will just use a different backend than notebook or inline in Jupiter and plot the figure in a separate window. This window is compatible with the interactive commands from matplotlib. I am not sure about widget compatibility though I will try and update the answer.
Update: I do not think ipywidgets can be used with plt.show() since these are not plotted in an axes, but there are some widgets within matplotlib (matplotlib.widgets) that can be used. Though, the resulting speed in my case is not satisfactory so I would avoid combining matplotlib widgets with matplotlib event catching.

Matplotlib GUI showing even though I never called plt.show()

I am using the following functions in order...
- plt.figure()
- plt.plot()
- plt.ylim
- plt.xticks()
- figure = plt.gcf()
- figure.set_size_inches()
- plt.savefig()
I just want to save the figure as png, which I've been doing successfully. But the GUI keeps showing up and I am going to generate a bunch of graphs in one script, I don't want the GUI popping up every time one is created and slow my run time.
Does anyone know why it is showing up still?
If you are using a Jupyter Notebook, there are a number of potential solutions posted here.
To summarize, try this to disable inline output from Matplotlib:
import matplotlib as plt
plt.ioff()
Or put this at the start of a cell to prevent it from creating output:
%%capture

Plot one figure at a time without closing old figure (matplotlib)

Is there a way to plot a set of figures one at a time without closing the previous figure, maintaining control of the UI, and keeping the figures open at the end? Perhaps using a more appropriate backend, or writing it using the OO style instead of the pyplot/pylab style used below?
e.g. I know I can do
plt.ioff()
for i in range(10)
plt.figure()
arr = thisFunctionTakesTenSecondsToGenerateMyArray()
plt.plot(arr)
plt.show()
which will wait for me to close the figure at every iteration
I can also do
plt.ion()
for i in range(10)
plt.figure()
arr = thisFunctionTakesTenSecondsToGenerateMyArray()
plt.plot(arr)
which will plot them as fast as it can generate them (e.g. 10 secs) but will block my entire UI (e.g. I can't even move the windows around), won't show the axes (I only see the figure window), and also will automatically close all the figures at the end of the loop.
The third option that I'm not looking for is this
plt.ioff()
for i in range(10)
plt.figure()
arr = thisFunctionTakesTenSecondsToGenerateMyArray()
plt.plot(arr)
plt.show()
which involves waiting 100 seconds before seeing anything on my screen.
I'm looking for behavior similar to Matlab where I can do
for i = 1:10
figure()
arr = thisFunctionTakesTenSecondsToGenerateMyArray()
plot(arr)
drawnow
which will draw a figure every 10 seconds, and also allow me to move the windows around e.g. if fig 3 is on top and I want to go back to fig 1 while fig 4 is being generated.
Edit:
Using Python 2.7.13, Matplotlib 2.0.0. Running it using Spyder 3.1.3 on Windows 7 SP1 - I've tried running it in the built-in IPython console, the vanilla Python console, and from a script all with the same results.
Ideally, I would like to be able to run it both from a script and interactively, i.e. by executing a script or by copying and pasting into the console.
just add plt.pause(0.0001) inside the loop after plt.show(block=False), and a final plt.show() at the end in case you are executing the script from the operating system command line.

Categories

Resources