Mix matplotlib interactive and inline plots? - python

Many plots just doesn't need to be interactive so I tried to change them to inline plots.
I tried the following without success:
plt.close(fig). It clear the figure
plt.ioff(), failed
wrap codes between %matplotlib inline %matplotlib notebook. It close other interactive plots

There can only ever be one single backend be active. It would be possible to change the backend, but that would require to close the interactive figures.
An option is to work with interactive backend throughout (e.g. %matplotlib widget) and call a custom function that shows a png image inline once that is desired.
#Cell1
%matplotlib widget
#Cell2
import matplotlib.pyplot as plt
def fig2inline(fig):
from IPython.display import display, Image
from io import BytesIO
plt.close(fig)
buff = BytesIO()
fig.savefig(buff, format='png')
buff.seek(0)
display(Image(data=buff.getvalue()))
#Cell3: (show the interactive plot)
fig, ax = plt.subplots(figsize=(3, 1.7))
ax.plot([1,3,4]);
#Cell4: (show the inline plot)
fig2, ax2 = plt.subplots(figsize=(3, 1.7))
ax2.plot([3,1,1]);
fig2inline(fig2)

Related

Printing cursor coordinates in a matplotib figure in a Jupyter notebook: the smooth way

I want to display the coordinates of my cursor in an image displayed with matplotlib within a Jupyter notebook.
I am using the %matplotlib notebook magic as per this question.
While this provides a nice answer for a static figure, this results in a huge amount of flickering and bugs (the figure sometimes not showing) when used in an interactive setting where the figure is constantly redrawn during slicing. For example,
%matplotlib notebook
from ipywidgets import interact
import matplotlib.pyplot as plt
import numpy as np
vol = np.random.uniform(size=(16, 16, 16))
#interact(z=(0, 15))
def show(z):
plt.imshow(vol[z])
plt.show()
Without %matplotlib notebook, the figure is updating without any flicker, but does not show the cursor coordinates. With the magic, the coordinates are displayed, but the flickering is unbearable.
Is there a way to have pixel coordinates without flickering in that simple situation?
The problem is the use of plt.show(), which will replace the figure. Instead you probably want to update the existing figure.
%matplotlib notebook
from ipywidgets import interact
import matplotlib.pyplot as plt
import numpy as np
vol = np.random.uniform(size=(16, 16, 16))
fig, ax = plt.subplots()
im = ax.imshow(vol[0])
#interact(z=(0, 15))
def show(z):
im.set_array(vol[z])
im.set_clim(vol[z].min(), vol[z].max())
fig.canvas.draw_idle()
Note the the above provides the same functionality as the code in the question, i.e. each array is normalized individually. However, you might decide to set the color normalization only once such that all arrays share the same color limits.
%matplotlib notebook
from ipywidgets import interact
import matplotlib.pyplot as plt
import numpy as np
vol = np.random.uniform(size=(16, 16, 16))
fig, ax = plt.subplots()
im = ax.imshow(vol[0], vmin=vol.min(), vmax=vol.max())
fig.colorbar(im)
#interact(z=(0, 15))
def show(z):
im.set_array(vol[z])
fig.canvas.draw_idle()

Imagegrid in Jupyter notebook

I'm following an example from the matplotlib documentation on Imagegrid, and I'm trying to replicate it from within Jupyter notebook:
% matplotlib inline
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import ImageGrid
import numpy as np
im = np.arange(100)
im.shape = 10, 10
fig = plt.figure(1, (4., 4.))
grid = ImageGrid(fig, 111, # similar to subplot(111)
nrows_ncols=(2, 2), # creates 2x2 grid of axes
axes_pad=0.1, # pad between axes in inch.
)
for i in range(4):
grid[i].imshow(im) # The AxesGrid object work as a list of axes.
plt.show()
Expected output:
What I'm getting:
I'm not getting the grid of images, as you can see. What am I doing wrong?
EDIT
If I remove the %matplotlib inline option, I just get this (it's cell[1] to prove I restarted my kernel):
No plots shown.
I'm running matplotlib version 3.0.0, checked with conda list matplotlib, jupyter is 4.4.0, checked with jupyter --version. On Windows 10, Anaconda, python 3.6.
This is an issue with matplotlib 3.0.0. This has now been fixed, such that it will not occur in the upcoming 3.0.1 bugfix release.
In the meantime you have two options.
Revert to matplotlib 2.2.3
Decide to not crop the images when using %matplotlib inline. Do so via
%config InlineBackend.print_figure_kwargs = {'bbox_inches':None}
in IPython or Jupyter.
Remove
%matplotlib inline
and restart everything or put it in a separate cell as seen below. It appears that the magic command always needs to be run in a separate cell before the plotting and if it was run before the kernel needs to be restarted. See here
enter link description here
and it will work. %matplotlib inline is not necessary to render plots in jupyter it is just a convenience. plt.show() will render plots whenever it is called.
I have had this issue with some mpl in jupyter. I think the issue is that the magic command causes it to render any plot as soon as it is available as opposed to mpl which waits until it is told to render and how.
Full example code straight from the mpl example you linked in your question:
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import ImageGrid
import numpy as np
im = np.arange(100)
im.shape = 10, 10
fig = plt.figure(1, (4., 4.))
grid = ImageGrid(fig, 111, # similar to subplot(111)
nrows_ncols=(2, 2), # creates 2x2 grid of axes
axes_pad=0.1, # pad between axes in inch.
)
for i in range(4):
grid[i].imshow(im) # The AxesGrid object work as a list of axes.
plt.show() # Renders all available axes when called

How do you update inline images in Ipython?

Edit: My question is not in regards to an "animation" per se. My question here, is simply about how to continuously show, a new inline image, in a for loop, within an Ipython notebook.
In essence, I would like to show an updated image, at the same location, inline, and have it update within the loop to show. So my code currently looks something like this:
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from IPython import display
%matplotlib inline
fig, ax = plt.subplots(nrows = 1, ncols = 1, figsize=(10, 10))
for ii in xrange(10):
im = np.random.randn(100,100)
ax.cla()
ax.imshow(im, interpolation='None')
ax.set_title(ii)
plt.show()
The problem is that this currently just..., well, shows the first image, and then it never changes.
Instead, I would like it to simply show the updated image at each iteration, inline, at the same place. How do I do that? Thanks.
I am not sure that you can do this without animation. Notebooks capture the output of matplotlib to include in the cell once the plotting is over. The animation framework is rather generic and covers anything that is not a static image. matplotlib.animation.FuncAnimation would probably do what you want.
I adapted your code as follows:
%matplotlib notebook
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation
f = plt.figure()
ax = f.gca()
im = np.random.randn(100,100)
image = plt.imshow(im, interpolation='None', animated=True)
def function_for_animation(frame_index):
im = np.random.randn(100,100)
image.set_data(im)
ax.set_title(str(frame_index))
return image,
ani = matplotlib.animation.FuncAnimation(f, function_for_animation, interval=200, frames=10, blit=True)
Note: You must restart the notebook for the %matplotlib notebook to take effect and use a backend that supports animation.
EDIT: There is normally a way that is closer to your original question but it errors on my computer. In the example animation_demo there is a plain "for loop" with a plt.pause(0.5) statement that should also work.
You can call figure.canvas.draw() each time you append something new to the figure. This will refresh the plot (from here). Try:
import numpy as np
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
from IPython import display
from time import sleep
fig = plt.figure()
ax = fig.gca()
fig.show()
for ii in range(10):
im = np.random.randn(100, 100)
plt.imshow(im, interpolation='None')
ax.set_title(ii)
fig.canvas.draw()
sleep(0.1)
I could not test this in an IPython Notebook, however.

Matplotlib Object Oriented Code to display inline in the notebook

Any ideas on how I can get this code
# -*- noplot -*-
"""
=============================
The object-oriented interface
=============================
A pure OO (look Ma, no pylab!) example using the agg backend
"""
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure
fig = Figure()
canvas = FigureCanvas(fig)
ax = fig.add_subplot(111)
ax.plot([1, 2, 3])
ax.set_title('hi mom')
ax.grid(True)
ax.set_xlabel('time')
ax.set_ylabel('volts')
from the matplotlib example gallery at this link to show me the chart in-line in my notebook?
Please Note:
I want to avoid using pyplot as I am trying to use matplotlib using their "Object Oriented" Library only
I have no issues getting pyplot based plots to render inline in my notebook using the %matplotlib inline or %matplotlib notebook magic
This confusing Object Oriented API of matplotlib isn't necessarily rendering inline.
Should I be using a different canvas?
Using fig.show() gives me the following error
AttributeError: 'FigureCanvasAgg' object has no attribute 'manager'
Figure.show works only for figures managed by pyplot, normally created by pyplot.figure().
Also, this particular canvas doesn't have a show method. So I am totally lost on how to get these darn Obj Oriented plots to render inline.
To display a figure which does not live in pyplot and has no figure manager associated with it, you can use IPython.core.display:
from IPython.core.display import display
display(fig)
Just note that there is actually no reason at all not to use pyplot to create the figure. Using pyplot, the code is much cleaner and will automatically show.
%matplotlib inline
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1, 2, 3])
ax.set_title('hi mom')
ax.grid(True)
ax.set_xlabel('time')
ax.set_ylabel('volts');

Jupyter, Interactive Matplotlib: Hide the toolbar of the interactive view

I am starting using the interactive plotting from Matplotlib:
%matplotlib notebook
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, figsize=(8, 3))
plt.plot([i for i in range (10)],np.random.randint(10, size=10))
plt.show()
Anyone knows if there is a way to hide the toolbars of the interactive mode?
I disabled the interactive mode buttons and toolbar with some python generated css.
Run the following in one of the notebook cells:
%%html
<style>
.output_wrapper button.btn.btn-default,
.output_wrapper .ui-dialog-titlebar {
display: none;
}
</style>
Unfortunately there's no good css selectors on the buttons, so I've tried to use as specific selector as possible, though this may end up disabling other buttons that you might generate in the output cell.
Indeed, this approach affects all output cells in the notebook.
Use the magic %matplotlib ipympl with canvas. toolbar_visible=False. To prevent double-appearence of figure, use plt. ioff() while instantiate figure:
import matplotlib.pyplot as plt
plt.ioff()
fig, ax = plt.subplots()
plt.ion()
fig.canvas.toolbar_visible = False
display(fig.canvas)
It's a little bit doubly, but so you know how to play with plt
Edit: Haven't mind you on jupyter. This works on jupyterlab

Categories

Resources