Redraw plt figure after adding new axes in a loop - matplotlib

After spending hours and hours I still can't figure this, seemingly simple, question out. Here is small snippet of code I am trying to make work (I am running this as a jupyter notebook cell):
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
for i in range(1, 11):
ax = fig.add_subplot(1, 10, i)
fig.canvas.draw()
plt.draw()
time.sleep(1)
I see my whole figure plotted after cell completes:
But I would like to see image redrawn every time when I add a new axes to it. Am I asking too much of matplotlib?

Related

how to make plt plot do not show figure [duplicate]

I need to create a figure in a file without displaying it within IPython notebook. I am not clear on the interaction between IPython and matplotlib.pylab in this regard. But, when I call pylab.savefig("test.png") the current figure get's displayed in addition to being saved in test.png. When automating the creation of a large set of plot files, this is often undesirable. Or in the situation that an intermediate file for external processing by another app is desired.
Not sure if this is a matplotlib or IPython notebook question.
This is a matplotlib question, and you can get around this by using a backend that doesn't display to the user, e.g. 'Agg':
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
plt.plot([1,2,3])
plt.savefig('/tmp/test.png')
EDIT: If you don't want to lose the ability to display plots, turn off Interactive Mode, and only call plt.show() when you are ready to display the plots:
import matplotlib.pyplot as plt
# Turn interactive plotting off
plt.ioff()
# Create a new figure, plot into it, then close it so it never gets displayed
fig = plt.figure()
plt.plot([1,2,3])
plt.savefig('/tmp/test0.png')
plt.close(fig)
# Create a new figure, plot into it, then don't close it so it does get displayed
plt.figure()
plt.plot([1,3,2])
plt.savefig('/tmp/test1.png')
# Display all "open" (non-closed) figures
plt.show()
We don't need to plt.ioff() or plt.show() (if we use %matplotlib inline). You can test above code without plt.ioff(). plt.close() has the essential role. Try this one:
%matplotlib inline
import pylab as plt
# It doesn't matter you add line below. You can even replace it by 'plt.ion()', but you will see no changes.
## plt.ioff()
# Create a new figure, plot into it, then close it so it never gets displayed
fig = plt.figure()
plt.plot([1,2,3])
plt.savefig('test0.png')
plt.close(fig)
# Create a new figure, plot into it, then don't close it so it does get displayed
fig2 = plt.figure()
plt.plot([1,3,2])
plt.savefig('test1.png')
If you run this code in iPython, it will display a second plot, and if you add plt.close(fig2) to the end of it, you will see nothing.
In conclusion, if you close figure by plt.close(fig), it won't be displayed.

How to get any kind of interactive plot with ipywidgets and matplotlib

I am just looking for some kind of working example which will allow me to have a slider and a sine wave plot whereby I can vary the frequency in a Jupyter Notebook. All the online demos that I have Googled don't work for me. The issue seems to be that the old matplotlib graph is not erased before the new one is created.
Here is my minimal example
import ipywidgets as widgets
from IPython.display import display, clear_output
import matplotlib.pyplot as plt
import numpy as np
def f(a):
clear_output(wait=True)
fig, ax = plt.subplots()
x = np.linspace(0, 2*np.pi, 100)
y = np.sin(a*x)
ax.grid()
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.plot(x,y)
ax.set_title("y = sin(x)")
%matplotlib inline
from time import sleep
for i in range(1,10):
clear_output(wait=True)
f(i)
sleep(1)
I have also tried
out = widgets.Output(layout={'border': '1px solid black'})
with out:
widgets.interact(f, a=1)
out.clear_output()
display(out)
However nothing I try will erase the previous matplotlib graph. They just all pile up on top of each other. I admit I am floundering as I don't really understand the API that well and the example in the documentation don't work for me.
I don't expect people to fix my code as it is probably rubbish. I am just looking for a working example which will allow me to interactively control the frequency and redraw the sine wave on a Jupyter notebook.
Here is a minimal example that works for me:
from ipywidgets import interact
import ipywidgets as widgets
import matplotlib.pyplot as plt
import numpy as np
def plot(freq):
x = np.linspace(0, 2*np.pi)
y = np.sin(x * freq)
plt.plot(x, y)
interact(plot, freq = widgets.FloatSlider(value=2, min=0.1, max=5, step=0.1))
default plot:
Screenshot of notebook after moving the slider to the right:

Live plotting in Jupyter Lab 3 using Matplotlib

I want to dynamically update the plot of a cell. I.e. the plot is initialized at the beginning of the cell, and updated in a (computationally heavy) for-loop, showing how the computation is progressing. In jupyter notebook, this can be done using pneumatics solution in What is the currently correct way to dynamically update plots in Jupyter/iPython?
%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt
import time
def pltsin(ax, colors=['b']):
x = np.linspace(0,1,100)
if ax.lines:
for line in ax.lines:
line.set_xdata(x)
y = np.random.random(size=(100,1))
line.set_ydata(y)
else:
for color in colors:
y = np.random.random(size=(100,1))
ax.plot(x, y, color)
fig.canvas.draw()
fig,ax = plt.subplots(1,1)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_xlim(0,1)
ax.set_ylim(0,1)
for f in range(5):
pltsin(ax, ['b', 'r'])
time.sleep(1)
I am looking for an equivalent way of doing it in jupyter lab. I tried replacing %matplotlib notebook with %matplotlib widget, using the ipympl library, but that didn't work: The figure only shows once the loop is finished.
What I do not want are solutions like the one proposed by Ziofil in or the one by Paidoo in jupyterlab interactive plot which clear the whole output, as I might print additional things such as e.g. a tqdm progress bar
This is a known for matplotlib for which there happily are workarounds.
The relevant issues are: https://github.com/matplotlib/matplotlib/issues/18596 and https://github.com/matplotlib/ipympl/issues/258
and probably the longest explanation is https://github.com/matplotlib/ipympl/issues/290#issuecomment-755377055
Both of these workarounds will work with ipympl.
Workaround 1
Use the async ipython event loop following this answer: https://stackoverflow.com/a/63517891/835607
Workaround 2
Split the plt.subplots and the updating plot code into two cells. If you wait for a second or two between executing the cells then the plot will have enough time to set itself up properly and it should all work. That looks like this:
Cell 1:
fig,ax = plt.subplots(1,1)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_xlim(0,1)
ax.set_ylim(0,1)
wait until the plot shows up then execute:
Cell 2:
for f in range(5):
pltsin(ax, ['b', 'r'])
time.sleep(1)

matplotlib.plot in embedded IPython immediately shows plot with no chance for modifying the returned axes

Embed IPython in a script and run:
from IPython import embed
# code ...
embed()
%matplotlib
#^ With or without; same result
fig = plt.figure()
Can't do anything with fig at this point.
It's already shown and the window is displayed,
even though I never called show.
plt.show() # does absolutely nothing
I normally import matplotlib in IPython this way:
%matplotlib inline
import matplotlib.pyplot as plt
ax, fig = plt.subplots()
plt.plot([[1,1], [2,2]])
plt.show()
Does this help?

Jupyter notebook matplotlib figures show up small until cell is completed

I'm trying to make a notebook where the data produced by a long for loop is put in a graph point by point. However, when using %matplotlib notebook and fig.canvas.draw() the graph is tiny up until the cell finishes running. (In fact, I've got many of those graphs and they are even tinyer when using more subplots.)
Here my code reproducing the behaviour in a jupyter notebook, at least on OS X with (latest) jupyter-core 4.3.0 and (latest) matplotlib 2.0.2.
%matplotlib notebook
import time
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 1)
for _ in range(5):
ax.plot([1,2,3], [1,2,3])
fig.canvas.draw()
time.sleep(1)
During the cell execution I get this plot
And when the cell finishes execution (after 5 seconds) I get this
I would like to get the larger image even during cell execution. What am I doing wrong?
As proposed by ImportanceOfBeingErnest, one solution is to put the figure creation in its own cell.
[1] %matplotlib notebook
import time
import matplotlib.pyplot as plt
[2] fig, ax = plt.subplots(1, 1)
[3] for _ in range(5):
ax.plot([1,2,3], [1,2,3])
fig.canvas.draw()
time.sleep(1)
Edit: This solutions does not work if you run all cells at once.