Question on data exchange between libsora and matplotlib.pyplot - python

In order to save a wave spectrum image, a typical code is as following,
###########################
import matplotlib.pyplot as plt
import librosa.display
y, sr = librosa.load(filename)
fig = plt.Figure()
canvas = FigureCanvas(fig)
...
librosa.display.specshow(logmelspec, sr=sample_rate, x_axis='time', y_axis='log')
fig.savefig('spec.png')
The question is, 'fig' is created in Figure class, and is also a parameter for FigureCanvas, librosa.display.specshow is a function belong to librosa.display class.
How does fig know the input data for fig.savefig ?
How does the data exchange work between 'fig' and 'librosa'?
When I run this code, it did save the right image as expected(however, if I build a FileDialog based application, load a new wav file and call 'fig.savefig' again, the image will become random).

It seems the following way can fix this issue,
plt.savefig("spec.png")
plt.clf()
plt.close()

Related

How to save a matplotlib.pause animation to video?

I have an animation created with plt.pause as below...
import matplotlib.pyplot as plt
for i in range(10):
plt.scatter(0, i)
plt.pause(0.01)
plt.show()
How can I save this as a video file, e.g. a .mp4 file?
First, I have to redefine the plotting as a function with the plotted point given by a frame i. plt.pause() can be replaced by matplotlib.animate. Finally, I used a package suggested here to get the conversion to .mp4 format. You will need to install MoviePy:
pip install MoviePy
and then I just animate the function with matplotlib.animate into a .gif format before sending it to MoviePy. You'll need to figure out what directory you want this all to happen in. I'm just using the current working directory.
Here is the code:
import matplotlib.pyplot as plt
import matplotlib.animation as ani
import os
import moviepy.editor as mp
frames=20
fig = plt.figure()
ax = plt.gca()
def scatter_ani(i=int):
plt.scatter(0, i)
name = r"\test.gif"
path = str(os.getcwd())
anim = ani.FuncAnimation(fig, scatter_ani, frames = frames, interval=50)
anim.save(path+name)
clip = mp.VideoFileClip(path+name)
clip.write_videofile(path+r"\test.mp4")
The gif is then
To tweak the length of the animation, check out the docs for matplotlib.animate. For example, if you want to clear all of the previous data-points and show only the dot moving up, then you need to clear the axes in the function, and bound the y-axis so you see the motion ie
def scatter_ani(i=int):
ax.clear()
ax.set_ylim(0, frames+1)
plt.scatter(0, i)
to get:

Viewing Matplotlib funcAnimation live plots in browser

I am generating a live plot using matplotlib's funcAnimation function such as in the example below. To be clear I am plotting data that is dynamically updating in real-time and I want to view these updates in the browser rather than in its own local plotting window.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation
import mpld3
def animate(i):
plt.clf()
#generate random data
x = np.array([i for i in range(100)])
y = np.random.normal(loc=0,scale=1, size = 100)
plt.scatter(x,y)
def main():
fig = plt.figure()
ani = animation.FuncAnimation(fig, animate, interval=1000)
ani.save('animation.gif', fps=10)
plt.show()
#mpld3.show()
if __name__ == '__main__':
main()
It opens the plot in its own little window.
I was wondering what is the best/quickest way to open this in browser instead? I tried using mpld3 as recommended in some places (see the commented bits of code in my code snippet), but all I get is a static page that does not update. I would like the plot to be redrawn in the browser during each redraw done by the animate fuction as it does when the plot is generated in it's own window instead as in the first image.
Thanks in advance for any help anyone has to offer!

Suppress display of final frame in matplotlib animation in jupyter

I am working on a project that involves generating a matplotlib animation using pyplot.imshow for the frames. I am doing this in a jupyter notebook. I have managed to get it working, but there is one annoying bug (or feature?) left. After the animation is created, Jupyter shows the last frame of the animation in the output cell. I would like the output to include the animation, captured as html, but not this final frame. Here is a simple example:
import numpy as np
from matplotlib import animation
from IPython.display import HTML
grid = np.zeros((10,10),dtype=int)
fig1 = plt.figure(figsize=(8,8))
ax1 = fig1.add_subplot(1,1,1)
def animate(i):
grid[i,i]=1
ax1.imshow(grid)
return
ani = animation.FuncAnimation(fig1, animate,frames=10);
html = HTML(ani.to_jshtml())
display(html)
I can use the capture magic, but that suppresses everything. This would be OK, but my final goal is to make this public, via binder, and make it as simple as possible for students to use.
I have seen matplotlib animations on the web that don't seem to have this problems, but those used plot, rather than imshow, which might be an issue.
Any suggestions would be greatly appreciated.
Thanks,
David
That's the answer I got from the same thing I was looking for in 'jupyter lab'. Just add plt.close().
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation
from IPython.display import HTML
grid = np.zeros((10,10),dtype=int)
fig1 = plt.figure(figsize=(8,8))
ax1 = fig1.add_subplot(1,1,1)
def animate(i):
grid[i,i]=1
ax1.imshow(grid)
return
ani = animation.FuncAnimation(fig1, animate,frames=10);
html = HTML(ani.to_jshtml())
display(html)
plt.close() # update

How can I use the display() function in Microsoft Azure Notebook

I am unable to display the .png file created by pyplot. I created the file in Microsoft Azure Jupyter Notebook. os.listdir() returns xx.png, so I know that the file was created. Yet, display(Image("xx.png")) does not show the image. I have read about ten related posts on stackoverflow and tried numerous variations of the command, but nothing works.
When I reproduce the problem on my local computer it works fine.
This question is a re-write of a previous question that was marked as duplicate and left to die. I hope that this post will make the question easier to understand.
Following is the code used to create the file:
from IPython.display import display
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import os
y = [2,4,6,8,10,12,14,16,18,20]
x = np.arange(10)
fig = plt.figure()
ax = plt.subplot(111)
ax.plot(x, y, label='$y = numbers')
plt.title('Legend inside')
ax.legend()
fig.savefig('xx.png')
There are two ways given the code you have to show the image.
1) You can call %matplotlib inline at the top of the notebook. This will inline graphics and you will see the image by calling fig
2) You can from IPython.display import Image and Image('xx.png') and the image should be displayed.
It appears you are missing an import statement, try :
from Ipython.display import Image
display(Image("xx.png"))

How to plot a queue of points?

I have the following code.
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
plt.ion()
plt.show()
mapping = defaultdict(partial(deque, maxlen=10))
My mapping structure contains a queues with x, y, z values. I want to plot only the point in queue so as the queue changes the plot should also change. How would I do that?
Note: This is challenging because the queue is of a bounded size and the plot has to reflect only whats in the queue.
The hacky way to do this is:
ln, = ax.plot(x,y,z)
# some code that updates the x,y,z values -> new_x,new_y,new_z
ln.remove
ln, = ax.plot(new_x,new_y,new_z)
plt.draw()
which removes the line with the old data and adds one with the new data.
If you are willing to write code that depends on the internals of matplotlib (which is a bad idea as the internal will likely change under you), you can also do this by:
ln._verts3d = new_x,new_y,new_z
Patch here for added a function to do this: https://github.com/matplotlib/matplotlib/pull/1629
The animation module nicely wraps up many of the things needed to do animation (including a way to stream output directly to ffmpeg), and there is a very nice tutorial.
Line3D docs, Line2D docs

Categories