Showing Matplotlib Animation on Kaggle Kernel - python

In this Kaggle Kernel https://www.kaggle.com/asindico/new-york-taxi-exploration I can't manage to show a matplotlib animation using on Basemap and hexbin.
Here is the code snippet
import pandas as pd
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
from matplotlib import cm
from matplotlib import animation, rc
from IPython.display import HTML
%matplotlib inline
#40.758896, -73.985130.
west, south, east, north = -74.1, 40.60, -73.80, 40.9
day=1
df_day=df[((df.pickup_datetime<'2016-01-'+str(day+1))&
(df.pickup_datetime>='2016-01-'+str(day)))]
fig,axarr = plt.subplots()
m = Basemap(projection='merc', llcrnrlat=south, urcrnrlat=north,
llcrnrlon=west, urcrnrlon=east, lat_ts=south, resolution='i',ax=axarr)
def init():
df_time= df_day[((df_day.pu_hour>=0)&(df_day.pu_hour<0))]
x, y = m(df_time['pickup_longitude'].values, df_time['pickup_latitude'].values)
m.hexbin(x, y, gridsize=300, bins='log', cmap=cm.YlOrRd_r);
return (m,)
def animate(i):
df_time= df_day[((df_day.pu_hour>=i)&(df_day.pu_hour<i+1))]
x, y = m(df_time['pickup_longitude'].values, df_time['pickup_latitude'].values)
m.hexbin(x, y, gridsize=300, bins='log', cmap=cm.YlOrRd_r);
return (m,)
anim = animation.FuncAnimation(fig, animate, init_func=init,frames=5, interval=1,blit=False,repeat=True)
fig.set_size_inches(12,10)
anim.save('pickup_animation.gif', writer='imagemagick', fps=2)

To display the animated gif inside the notebook you may use
from IPython.display import Image, display
display(Image(url='pickup_animation.gif'))
You may also show the animation as html5 video
from IPython.display import HTML
HTML(anim.to_html5_video())
You may also show the matplotlib animation directly, using the notebook backend instead of the inline backend
%matplotlib notebook

Related

How to display audio at the right side of matplotlib

The following code display the image and audio in the top-bottom style:
Here is the test code:
import librosa
import matplotlib.pyplot as plt
import IPython.display as ipd
def plot_it(name, audio, sample_rate):
plt.figure(figsize=(8, 1))
plt.plot(audio)
plt.gca().set_title(name)
plt.show()
ipd.display(ipd.Audio(data=audio, rate=sample_rate))
Is it possible for changing the "top-bottom" style to "left-right" style for displaying the audio at the right side of the plt figure?
You can use a GridspecLayout which is similar to matplotlib's GridSpec. In order to direct to output into the needed grid cells, you can capture it using the Output widget:
import librosa
import matplotlib.pyplot as plt
import IPython.display as ipd
from ipywidgets import Output, GridspecLayout
def plot_it(name, audio, sample_rate):
grid = GridspecLayout(1, 2, align_items='center')
out = Output()
with out:
fig, ax = plt.subplots(figsize=(8, 1))
ax.plot(audio)
ax.set_title(name)
plt.close(fig)
ipd.display(ax.figure)
grid[0, 0] = out
out = Output()
with out:
ipd.display(ipd.Audio(data=audio, rate=sample_rate))
grid[0, 1] = out
ipd.display(grid)
name = 'nutcracker'
filename = librosa.example(name)
y, sr = librosa.load(filename)
plot_it(name, y, sr)
(It is essential to close the figure, otherwise you'll have double output of the figure. This is easier to do this using the OOP than the pyplot interface, that's why I changed your matplotlib code a bit)

Matplotlib inline in Jupyter - how to contol when the plot is shown?

I have a function that creates a figure and for some reason it is shown in Jupyter notebook twice, even though I didn't run show at all. I pass the fig and ax as an output of this function, and plan to show it only later.
I get confused between plt, fig and ax functionaries and guess that the answer is hidden somewhere there.
Here is an anonymised version of my code:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
%matplotlib inline
def plot_curve(dummydata):
# builds a chart
fig,ax = plt.subplots(1) # get subplots
fig.set_figheight(7)
fig.set_figwidth(12) #set shape
plt.plot(dummydata.x1, dummydata.y1,label = 'l1') #curve 1
plt.plot(dummydata.x2, dummydata.y2,label = 'l2') #curve2
plt.xlabel('xlabel') #labels
plt.ylabel('xlabel')
plt.yscale('linear') #scale and bounds
plt.ylim(0,100)
ymin,ymax= ax.get_ylim()
ax.axhline(1, color='k', linestyle=':', label = 'lab1') #guideline - horizontal
ax.axvline(2, color='r',linestyle='--', label = 'lab2') #guideline - vertical
ax.axvline(3, color='g',linestyle='--', label = 'lab3') #guideline - vertical
ax.arrow(1,2,3,0, head_width=0.1, head_length=0.01, fc='k', ec='k') # arrow
rect = mpl.patches.Rectangle((1,2), 2,3, alpha = 0.1, facecolor='yellow',
linewidth=0 , label= 'lab4') #yellow area patch
ax.add_patch(rect)
plt.legend()
plt.title('title')
return fig,ax
and then call it with:
for i in range(3):
dummydata = pd.DataFrame({
'x1':np.arange(1+i,100,0.1),
'y1':np.arange(11+i,110,0.1),
'x2':np.arange(1+i,100,0.1),
'y2':np.arange(21+i,120,0.1)
})
fig,ax = plot_curve(dummydata) #get the chart
What should I change to not show the figure by default, and show it only by my command?
Thanks
Try disabling matplotlib interactive mode using plt.ioff(). With interactive mode disabled the plots will only be shown with an explicit plt.show().
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
%matplotlib inline
# Desactivate interactive mode
plt.ioff()
def plot_curve(dummydata):
# the same code as before
Then in another cell
for i in range(3):
dummydata = pd.DataFrame({
'x1':np.arange(1+i,100,0.1),
'y1':np.arange(11+i,110,0.1),
'x2':np.arange(1+i,100,0.1),
'y2':np.arange(21+i,120,0.1)
})
# I'am assuming this should not be in the for loop
# The plot will NOT be shown because we are not in interactive mode
fig, ax = plot_curve(dummydata) #get the chart
No plot will be shown yet.
Now in another cell
# Now ANY plot (figure) which was created and not shown yet will be finally shown
plt.show()
The plot is finally shown. Note that if you have created several plots all of them will be shown now.
Try this:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
%matplotlib
With this importing you should not see the figure after plotting.
But you can see the figure by writing fig to IPython cell:
dummydata = pd.DataFrame({
'x1':np.arange(1,100,0.1),
'y1':np.arange(11,110,0.1),
'x2':np.arange(1,100,0.1),
'y2':np.arange(21,120,0.1)
})
fig,ax = plot_curve(dummydata) #get the chart
fig # Will now plot the figure.
Is this the desired output?

How can I make matplotlib titles searchable?

I am producing a few hundred matplotlib plots, I work in Jupyter Notebook. Each have it's own title. I want to be able to search for these titles. So when I download the file as html, and open it in browser, I'd like to find the title via using ctrl-f. How can I do that?
More details, here is an MCVE:
import matplotlib.pyplot as plt
x=range(5);y=range(5)
for i in range(6):
plt.figure()
plt.plot(x,y)
plt.title("Title"+str(i))
This produces nice plots, titled Title0 Title1 ... Title5. Howevere, these titles are part of the file and not searchable by ctrl-f, or browser doesn't detect them as text, though it would be desired.
I can do it in gnuplot but now I'd like to stick to Python.
You can generate markdown within a Jupyter notebook. Try this:
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from IPython.display import display, Markdown
display(Markdown('Title of graph goes here'))
x = np.linspace(0, 10, 30)
y = np.sin(x)
plt.plot(x, y, 'o', color='black');
Edit: I've just realised that in your example all the titles will be printed before the graphs. The solution is:
import matplotlib.pyplot as plt
# DO NOT USE %matplotlib inline
x=range(5);y=range(5)
for i in range(6):
ax = plt.figure()
_ = plt.plot(x,y)
title = "Title"+str(i)
display(Markdown(title))
display(ax)
You may print title for every figure (plt.show() necessary in this case):
import matplotlib.pyplot as plt
x=range(5);y=range(5)
for i in range(2):
plt.figure()
plt.plot(x,y)
plt.title("Title"+str(i))
print("Title"+str(i))
plt.show()

Change content of image interactively using slider widgets

I am trying to change content of an image interactively using a slider (e.g. for applying a median operation with different kernel sizes).
While this works well if I only show one resulting image (cf commented lines), I run into trouble when using the subplot function, since the image will not get updated.
What am I missing?
%matplotlib inline
from ipywidgets import interact, widgets
import matplotlib.pyplot as plt
import warnings
from skimage.morphology import disk
from skimage.filters import rank
from skimage.color import rgb2gray
import skimage.data
def f(Median_Size):
selem = disk(int(Median_Size))
with warnings.catch_warnings():
warnings.simplefilter("ignore")
img_median = rank.median(img_gray, selem=selem)
ax_neu.imshow(img_median, cmap="gray")
fig.canvas.draw()
#plt.imshow(img_median, cmap="gray") #This would work
#plt.show()
image = skimage.data.camera() #plt.imread("Test.png")
img_gray = rgb2gray(image)
fig = plt.figure(figsize=(6, 4))
ax_orig = fig.add_subplot(121)
ax_neu = fig.add_subplot(122)
ax_orig.imshow(img_gray, cmap="gray")
ax_neu.imshow(img_gray, cmap="gray")
interact(f, Median_Size=widgets.IntSlider(min=1,max=21,step=2,value=1))
Using %matplotlib notebook
Instead of the inline backend, you may use the notebook backend. This will allow to call figure.canvas.draw() as expected from running the code as a script. Replace the line %matplotlib inline by
%matplotlib notebook
and restart the Kernel.
Using display
You may display the newly changed figure after it has been changed. The drawback is that it creates the output twice. A workaround would then be to put interact in a new cell and capture the output from the first cell.
%%capture
%matplotlib inline
from ipywidgets import interact, widgets
from IPython.display import display
import matplotlib.pyplot as plt
import warnings
from skimage.morphology import disk
from skimage.filters import rank
from skimage.color import rgb2gray
import skimage.data
def f(Median_Size):
selem = disk(int(Median_Size))
with warnings.catch_warnings():
warnings.simplefilter("ignore")
img_median = rank.median(img_gray, selem=selem)
ax_neu.imshow(img_median, cmap="gray")
fig.canvas.draw()
display(fig)
image = skimage.data.camera() #plt.imread("Test.png")
img_gray = rgb2gray(image)
fig = plt.figure(figsize=(6, 4))
ax_orig = fig.add_subplot(121)
ax_neu = fig.add_subplot(122)
ax_orig.imshow(img_gray, cmap="gray")
ax_neu.imshow(img_gray, cmap="gray")
In a new cell
interact(f, Median_Size=widgets.IntSlider(min=1,max=21,step=2,value=1));
The output would then look like:

Simple Python/Matplotlib animation shows: empty graph - why? [duplicate]

I have a python animation script (using matplotlib's funcAnimation), which runs in Spyder but not in Jupyter. I have tried following various suggestions such as adding "%matplotlib inline" and changing the matplotlib backend to "Qt4agg", all without success. I have also tried running several example animations (from Jupyter tutorials), none of which have worked. Sometimes I get an error message and sometimes the plot appears, but does not animate. Incidentally, I have gotten pyplot.plot() to work using "%matplotlib inline".
Does anyone know of a working Jupyter notebook with a simple inline animation example that uses funcAnimation.
[Note: I am on Windows 7]
notebook backend
'Inline' means that the plots are shown as png graphics. Those png images cannot be animated. While in principle one could build an animation by successively replacing the png images, this is probably undesired.
A solution is to use the notebook backend, which is fully compatible with FuncAnimation as it renders the matplotlib figure itself:
%matplotlib notebook
jsanimation
From matplotlib 2.1 on, we can create an animation using JavaScript. This is similar to the ani.to_html5() solution, except that it does not require any video codecs.
from IPython.display import HTML
HTML(ani.to_jshtml())
Some complete example:
import matplotlib.pyplot as plt
import matplotlib.animation
import numpy as np
t = np.linspace(0,2*np.pi)
x = np.sin(t)
fig, ax = plt.subplots()
ax.axis([0,2*np.pi,-1,1])
l, = ax.plot([],[])
def animate(i):
l.set_data(t[:i], x[:i])
ani = matplotlib.animation.FuncAnimation(fig, animate, frames=len(t))
from IPython.display import HTML
HTML(ani.to_jshtml())
Alternatively, make the jsanimation the default for showing animations,
plt.rcParams["animation.html"] = "jshtml"
Then at the end simply state ani to obtain the animation.
Also see this answer for a complete overview.
There is a simple example within this tutorial here: http://louistiao.me/posts/notebooks/embedding-matplotlib-animations-in-jupyter-notebooks/
To summarise the tutorial above, you basically need something like this:
from matplotlib import animation
from IPython.display import HTML
# <insert animation setup code here>
anim = animation.FuncAnimation() # With arguments of course!
HTML(anim.to_html5_video())
However...
I had a lot of trouble getting that to work. Essentially, the problem was that the above uses (by default) ffmpeg and the x264 codec in the background but these were not configured correctly on my machine. The solution was to uninstall them and rebuild them from source with the correct configuration. For more details, see the question I asked about it with a working answer from Andrew Heusser: Animations in ipython (jupyter) notebook - ValueError: I/O operation on closed file
So, try the to_html5_video solution above first, and if it doesn't work then also try the uninstall / rebuild of ffmpeg and x264.
Another option:
import matplotlib.animation
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams["animation.html"] = "jshtml"
plt.rcParams['figure.dpi'] = 150
plt.ioff()
fig, ax = plt.subplots()
x= np.linspace(0,10,100)
def animate(t):
plt.cla()
plt.plot(x-t,x)
plt.xlim(0,10)
matplotlib.animation.FuncAnimation(fig, animate, frames=10)
Here is the answer that I put together from multiple sources including the official examples. I tested with the latest versions of Jupyter and Python.
Download FFmpeg ( http://ffmpeg.zeranoe.com/builds/ )
Install FFmpeg making sure that you update the environmental variable ( http://www.wikihow.com/Install-FFmpeg-on-Windows ).
Run this script in Jupyter below. The variable imageList is the only thing that you need to modify. It is an list of images (your input).
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from IPython.display import HTML
#=========================================
# Create Fake Images using Numpy
# You don't need this in your code as you have your own imageList.
# This is used as an example.
imageList = []
x = np.linspace(0, 2 * np.pi, 120)
y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
for i in range(60):
x += np.pi / 15.
y += np.pi / 20.
imageList.append(np.sin(x) + np.cos(y))
#=========================================
# Animate Fake Images (in Jupyter)
def getImageFromList(x):
return imageList[x]
fig = plt.figure(figsize=(10, 10))
ims = []
for i in range(len(imageList)):
im = plt.imshow(getImageFromList(i), animated=True)
ims.append([im])
ani = animation.ArtistAnimation(fig, ims, interval=50, blit=True, repeat_delay=1000)
plt.close()
# Show the animation
HTML(ani.to_html5_video())
#=========================================
# Save animation as video (if required)
# ani.save('dynamic_images.mp4')
If you have a list of images and want to animate through them, you can use something like this:
from keras.preprocessing.image import load_img, img_to_array
from matplotlib import animation
from IPython.display import HTML
import glob
%matplotlib inline
def plot_images(img_list):
def init():
img.set_data(img_list[0])
return (img,)
def animate(i):
img.set_data(img_list[i])
return (img,)
fig = figure()
ax = fig.gca()
img = ax.imshow(img_list[0])
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=len(img_list), interval=20, blit=True)
return anim
imgs = [img_to_array(load_img(i)) for i in glob.glob('*.jpg')]
HTML(plot_images(imgs).to_html5_video())
Thank to Kolibril. I finally can run animation on Jupyter and Google Colab.
I modify some code which will generate animation of drawing random line instead.
import matplotlib.animation
import matplotlib.pyplot as plt
from itertools import count
import random
plt.rcParams["animation.html"] = "jshtml"
plt.rcParams['figure.dpi'] = 150
fig, ax = plt.subplots()
x_value = []
y_value = []
index = count();
def animate(t):
x_value.append(next(index))
y_value.append(random.randint(0,10))
ax.cla()
ax.plot(x_value,y_value)
ax.set_xlim(0,10)
matplotlib.animation.FuncAnimation(fig, animate, frames=10, interval = 500)
enter image description here

Categories

Resources