Imagegrid in Jupyter notebook - python

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

Related

refresh matplotlib in Jupyter when updating with ipywidget

I want to draw a line in a Jupyter notebook, which can be moved using an ipywidget slider. I also want to have the mouse coordinates displayed, for which I'm using %matplotlib notebook. Here is what I have so far :
%matplotlib notebook
from ipywidgets import interact
fig, ax = plt.subplots()
#interact(n=(-200, 0))
def show(n):
# fig.clear() #doesn't show anything
y = -n+x
ax.plot(x, y)
plt.show()
When moving the line using the slider, the plot doesn't refresh, all previous positions of the line
remain visible:
I tried to refresh using fig.clear(), but then noting shows.
How can I solve this?
I have an extensive answer about this here: Matplotlib figure is not updating with ipywidgets slider
but the short of my recommendations are:
use ipympl %matplotlib ipympl instead of notebook as this will play nicer with ipywidgets
Use mpl-interactions to handle making plots controlled by sliders.
It will do the optimal thing of using set_data for you rather than clearing and replotting the lines.
It also interprets the shorthand for numbers in a way that (I think) makes more sense when making plots (e.g. using linspace instead of arange) see https://mpl-interactions.readthedocs.io/en/stable/comparison.html for more details.
So for your example I recommend doing:
install libraries
pip install ipympl mpl-interactions
%matplotlib ipympl
from ipywidgets import interact
import matplotlib.pyplot as plt
from mpl_interactions import ipyplot as iplt
x = np.linspace(0,100)
fig, ax = plt.subplots()
def y(x, n):
return x - n
ctrls = iplt.plot(x, y, n=(-200,0))
it got a bit longer because I added the imports you left out of your question and also defined x.
Which gives you this:
That said if you don't want to use those I think what you want is ax.cla() I think when you do fig.clear you are also removing the axes which is why nothing shows up.
%matplotlib notebook
from ipywidgets import interact
fig, ax = plt.subplots()
#interact(n=(-200, 0))
def show(n):
y = -n+x
ax.cla()
ax.plot(x, y)
plt.show()

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()

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.

When I use matplotlib in jupyter notebook,it always raise " matplotlib is currently using a non-GUI backend" error?

import matplotlib.pyplot as pl
%matplot inline
def learning_curves(X_train, y_train, X_test, y_test):
""" Calculates the performance of several models with varying sizes of training data.
The learning and testing error rates for each model are then plotted. """
print ("Creating learning curve graphs for max_depths of 1, 3, 6, and 10. . .")
# Create the figure window
fig = pl.figure(figsize=(10,8))
# We will vary the training set size so that we have 50 different sizes
sizes = np.rint(np.linspace(1, len(X_train), 50)).astype(int)
train_err = np.zeros(len(sizes))
test_err = np.zeros(len(sizes))
# Create four different models based on max_depth
for k, depth in enumerate([1,3,6,10]):
for i, s in enumerate(sizes):
# Setup a decision tree regressor so that it learns a tree with max_depth = depth
regressor = DecisionTreeRegressor(max_depth = depth)
# Fit the learner to the training data
regressor.fit(X_train[:s], y_train[:s])
# Find the performance on the training set
train_err[i] = performance_metric(y_train[:s], regressor.predict(X_train[:s]))
# Find the performance on the testing set
test_err[i] = performance_metric(y_test, regressor.predict(X_test))
# Subplot the learning curve graph
ax = fig.add_subplot(2, 2, k+1)
ax.plot(sizes, test_err, lw = 2, label = 'Testing Error')
ax.plot(sizes, train_err, lw = 2, label = 'Training Error')
ax.legend()
ax.set_title('max_depth = %s'%(depth))
ax.set_xlabel('Number of Data Points in Training Set')
ax.set_ylabel('Total Error')
ax.set_xlim([0, len(X_train)])
# Visual aesthetics
fig.suptitle('Decision Tree Regressor Learning Performances', fontsize=18, y=1.03)
fig.tight_layout()
fig.show()
when I run the learning_curves() function, it shows:
UserWarning:C:\Users\Administrator\Anaconda3\lib\site-packages\matplotlib\figure.py:397: UserWarning: matplotlib is currently using a non-GUI backend, so cannot show the figure
You don't need the line of fig.show(). Just remove it. Then there will be no warning message.
adding %matplotlib inline while importing helps for smooth plots in notebook
%matplotlib inline
import matplotlib.pyplot as plt
%matplotlib inline sets the backend of matplotlib to the 'inline' backend:
With this backend, the output of plotting commands is displayed inline within frontends like the Jupyter notebook, directly below the code cell that produced it. The resulting plots will then also be stored in the notebook document.
You can change the backend used by matplotlib by including:
import matplotlib
matplotlib.use('TkAgg')
before your line 1 import matplotlib.pyplot as pl, as it must be set first. See this answer for more information.
(There are other backend options, but changing backend to TkAgg worked for me when I had a similar problem)
Testing with https://matplotlib.org/examples/animation/dynamic_image.html I just add
%matplotlib notebook
which seems to work but is a little bumpy. I had to stop the kernal now and then :-(
Just type fig instead of fig.show()
You can still save the figure by fig.savefig()
If you want to view it on the web page, you can try
from IPython.display import display
display(fig)
I was trying to make 3d clustering similar to Towards Data Science Tutorial. I first thought fig.show() might be correct, but got the same warning...
Briefly viewed Matplot3d.. but then I tried plt.show() and it displayed my 3d model exactly as anticipated. I guess it makes sense too.
This would be equivalent to your pl.show()
Using python 3.5 and Jupyter Notebook
The error "matplotlib is currently using a non-GUI backend” also occurred when I was trying to display a plot using the command fig.show(). I found that in a Jupyter Notebook, the command fig, ax = plt.subplots() and a plot command need to be in the same cell in order for the plot to be rendered.
For example, the following code will successfully show a bar plot in Out[5]:
In [3]:
import matplotlib.pyplot as plt
%matplotlib inline
In [4]:
x = 'A B C D E F G H'.split()
y = range(1, 9)
In [5]:
fig, ax = plt.subplots()
ax.bar(x, y)
Out[5]: (Container object of 8 artists)
A successful bar plot output
On the other hand, the following code will not show the plot,
In [5]:
fig, ax = plt.subplots()
Out[5]:
An empty plot with only a frame
In [6]:
ax.bar(x, y)
Out[6]: (Container object of 8 artists)
In Out[6] there is only a statement of "Container object of 8 artists" but no bar plot is shown.
I had the same error. Then I used
import matplotlib
matplotlib.use('WebAgg')
it works fine.(You have to install tornado to view in web, (pip install tornado))
Python version: 3.7
matplotlib version: 3.1.1
If you are using any profiling libraries like pandas_profiling, try commenting out them and execute the code. In my case I was using pandas_profiling to generate a report for a sample train data. commenting out import pandas_profiling helped me solve my issue.
%matplotlib notebook worked for me.
But the takes time to load and but it is clear.
You imported matplotlib.pyplot as pl. In the end type pl.show() instead of fig.show()

Saving Python SymPy figures with a specific resolution/pixel density

I am wondering if there is a way to change the pixel density/resolution of sympy plots. For example, let's consider the simple code snippet below:
import sympy as syp
x = syp.Symbol('x')
miles_to_km = x * 1.609344
miles_to_km.evalf()
graph = syp.plot(miles_to_km, show=False)
graph.save('./figures/miles_to_km.png')
graph.show()
Notes:
When I tried using graph.savefig, I got an AttributeError: 'Plot' object has no attribute 'saveimage' I stumbled upon the saveimage method in some online resource, and it sounded like that this was the common approach -- I guess the API changed?
graph.save('./figures/miles_to_km.png', dpi=300) produces a type error: TypeError: save() got an unexpected keyword argument 'dpi'
Using the dpi attribute in plot does not throw any error but doesn't affect the image quality either: graph = syp.plot(miles_to_km, dpi=300, show=False)
I also tried using the matplotlib backend:
plt.figure()
graph = syp.plot(miles_to_km, show=False)
#graph.save('./figures/miles_to_km.png')
plt.savefig('./figures/miles_to_km.png')
graph.show()
where plt = matplotlib.pyplot. However, the canvas is blank. Also relevant info may be that I am running it in an IPython notebook with %matplotlib inline enabled.
I am using SymPy v. 0.7.6
the backend workaround below shows the plot in the IPython notebook, but it also produces a white canvas (as png)
graph = syp.plot(miles_to_km, show=False)
backend = graph.backend(graph)
backend.fig.savefig('ch01_2.png', dpi=300)
backend.show()
EDIT and Solution:
Thanks to Cody Piersall's answer the issue is now resolved. I updated to IPython 4.0 (Jupyter notebook) and plotted it as follows
graph = syp.plot(miles_to_km, show=False)
backend = graph.backend(graph)
backend.process_series()
backend.fig.savefig('miles_to_km.png', dpi=300)
backend.show()
This problem has been fixed, you can now simply use this:
graph = sympy.plot(f, show = False)
graph.save('fig.png')
Unfortunately, it doesn't seem to allow for the selection of a dpi.
Assuming you are using the matplotlib backend, which is the default if you have matplotlib installed, you just have to import matplotlib.pyplot and use pyplot.savefig.
This works because sympy uses matplotlib to do its plotting, and since matplotlib is stateful, it knows which plot you're working with.
Here is your example, but using savefig to save to a png.
import sympy as syp
x = syp.Symbol('x')
miles_to_km = x * 1.609344
miles_to_km.evalf()
graph = syp.plot(miles_to_km, show=False)
# Does not work in IPython Notebook, but works in a script.
import matplotlib.pyplot as plt
plt.savefig('./figures/miles_to_km.png', dpi=300)
If you are in an IPython notebook, the above will not work, but you can still save them with a specified dpi. You just have to be a little tricky about it.
# works in IPython Notebook
backend = graph.backend(graph)
ackend.fig.savefig('300.png', dpi=300)
backend.fig.savefig('20.png', dpi=20)

Categories

Resources