I'd like to update a plot by redrawing a new curve (with 100 points) in real-time.
This works:
import time, matplotlib.pyplot as plt, numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
t0 = time.time()
for i in range(10000000):
x = np.random.random(100)
ax.clear()
ax.plot(x, color='b')
fig.show()
plt.pause(0.01)
print(i, i/(time.time()-t0))
but there is only ~10 FPS, which seems slow.
What is the standard way to do this in Matplotlib?
I have already read How to update a plot in matplotlib and How do I plot in real-time in a while loop using matplotlib? but these cases are different because they add a new point to an existing plot. In my use case, I need to redraw everything and keep 100 points.
I do not know any technique to gain an order of magnitude. Nevertheless you can slightly increase the FPS with
update the line data instead of creating a new plot with set_ydata (and/or set_xdata)
use Figure.canvas.draw_idle() instead of Figure.canvas.draw() (cf. this question).
Thus I would recommand you to try the following:
import time
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
t0 = time.time()
x = np.random.random(100)
l, *_ = ax.plot(x, color='b')
fig.show()
fig.canvas.flush_events()
ax.set_autoscale_on(False)
for i in range(10000000):
x = np.random.random(100)
l.set_ydata(x)
fig.canvas.draw_idle()
fig.canvas.flush_events()
print(i, i/(time.time()-t0))
Note that, as mentioned by #Bhargav in the comments, changing matplotlib backend can also help (e.g. matplotlib.use('QtAgg')).
I hope this help.
Related
Out of pure curiosity, I would love to know why the final plt.show() does not display both plots on ax. Only the first plt.show() seems to do anything, because only the plot of y = sin(x) shows up. Here is the code sample:
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
x = np.linspace(1, 100, 10)
ax.plot(x, np.sin(x))
plt.show()
ax.plot(x, x)
plt.show()
Appreciate any help on this, because it bugs me to not understand why this is the case, even after a lot of searches. PS: I know that the code is useless and dumb, but I would still like to know for future use.
Your code
## load libraries
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
x = np.linspace(1, 100, 10)
## assign first plot
ax.plot(x, np.sin(x))
#plt.show()
## assign second plot
ax.plot(x, x)
## render the plots
plt.show()
One reason why plt.show() didn't 'show' more than once.
You are using subplots.
Your plots are on the same axes
plt.show() display all open figures. Your ax.plot(x, np.sin(x)) will be shown and the figure closed. The second is on the same ax and will not be shown anymore.
Documentation: matplotlib.pyplot.show()
[Alternate]
If however you call plt.plot() separately, (without subplots axes), you would get two plots; each with its own dimensions.
PS: below works in Jupyter (mybinder)
## load libraries
import matplotlib.pyplot as plt1
import numpy as np
x = np.linspace(1, 100, 10)
## first plot
plt1.plot(x, np.sin(x))
## render first plot
plt1.show()
Followed by
## second plot
plt1.plot(x, x)
## render the plot
plt1.show()
Clarity from the documentation: matplotlib.pyplot is a state-based interface to matplotlib
[Updated]
#JohanC lumping up the explanatory code and the alternate code.
The explanation 1, 2, and 3 remains.
The alternate code remain. or
OP can put the two plots on their own ax, and have plt.show each.
I didn't intend including this before. However, for completeness:
## load libraries
import matplotlib.pyplot as plt
import numpy as np
## tuple of desired two axes
## unpack AxesSubplot on two rows
fig, (ax1, ax2), = plt.subplots(nrows=2)
## assign variable
x = np.linspace(1, 100, 10)
## assign first plot
ax1.plot(x, np.sin(x))
#plt.show()
## assign second plot
ax2.plot(x, x)
## render the plots
## Rendering might not be 'smooth' in Jupyter
plt.show()
On a (self-updating) matplotlib plot, like:
import matplotlib.pyplot as plt, numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
x = np.random.random(100)
l, *_ = ax.plot(x, color='b')
fig.show()
fig.canvas.flush_events()
ax.set_autoscale_on(False)
for i in range(10000000):
x = np.random.random(100)
l.set_ydata(x)
fig.canvas.draw_idle()
fig.canvas.flush_events()
how to use the default "Configure subplots" panel with sliders to adjust y-axis range limits? (see screenshot)
I've already seen matplotlib Slider examples like https://matplotlib.org/stable/gallery/widgets/slider_demo.html but I'm wondering if there is a more straightforward way in the simple case to change y-axis (or x-axis) range?
In python matplotlib finance
Is it possible to have two different figures with animation.FuncAnimation in mplfinance where one has 12 axis with different style and another figure has two planes one for bar and another for volume.
Another reason is that both figures having different intervals for refresh
There are two ways that I can think of to do this. I will show examples using simple matplotlib plots so as to focus on the animation function(s). If you understand the mplfinance animation example then you will be able make the analogous changes to make this work with mplfinance.
The two approaches are:
Maintain more than one plot with a single func animation. If different update frequencies are needed, use modulo to update one or more of the plots. The disadvantage here is that the update period of each plot must be some multiple of the update period of the fastest plot.
Create two func animations. This requires that each func animation be assigned to a different variable (and each such variable must remain in scope, i.e. not be deleted or destroyed, for the duration of animation).
Approach 1 Example: Single Func Animation maintaining two plots:
"""
A simple example of TWO curves from one func animation
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig = plt.figure()
ax1 = fig.add_subplot(1,2,1)
ax2 = fig.add_subplot(1,2,2,sharey=ax1)
x = np.arange(0, 2*np.pi, 0.01)
line1, = ax1.plot(x, np.sin(x))
line2, = ax2.plot(x, 0.5*np.sin(2.5*(x)))
def animate(i):
line2.set_ydata(0.5*np.sin(2.5*(x + i/5.0))) # update the data
if i%3 == 0: # modulo: update line1 only every third call
line1.set_ydata(np.sin(x + i/10.0)) # update the data
return line1,line2
ani1 = animation.FuncAnimation(fig, animate, np.arange(1, 200), interval=250)
plt.show()
Approach 2 Example: Two Func Animations maintaining two plots:
"""
A simple example of TWO animated plots
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig = plt.figure()
ax1 = fig.add_subplot(1,2,1)
ax2 = fig.add_subplot(1,2,2,sharey=ax1)
x = np.arange(0, 2*np.pi, 0.01)
line1, = ax1.plot(x, np.sin(x))
line2, = ax2.plot(x, 0.5*np.sin(2.5*(x)))
def animate1(i):
line1.set_ydata(np.sin(x + i/10.0)) # update the data
return line1,
def animate2(i):
line2.set_ydata(0.5*np.sin(2.5*(x + i/5.0))) # update the data
return line2,
ani1 = animation.FuncAnimation(fig, animate1, np.arange(1, 200), interval=250)
ani2 = animation.FuncAnimation(fig, animate2, np.arange(1, 200), interval=75)
plt.show()
If you create a script with either of the above examples and run under python (but do NOT run in a notebook or IDE, because that may or may not work) both cases should give an animation that looks something like this:
First of all, I apologies if this question was already asked and answered, I haven't found anything really specific about this so if you did, please share and I will delete this post.
What I would like to do is simply generate more separate plots after one another in separate figure in python, because I have an exercise sheet and the a) is to plot a poisson distribution and the b) is to plot a binomial distribution and so ever with c) and d), and I would like that the plots are gathered together in the same script but in separate figure.
I tried as simple as create a sin(x) and a cos(x) plot after one another but it didn't work, the sin and cos were displaying in the same plot.. My code was:
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = plt.plot(np.sin(x))
ax2 = plt.plot(np.cos(x))
ax1.set_xlabel('Time (s)')
ax1.set_title('sin')
ax1.legend()
ax2.set_xlabel('Time (s)')
ax2.set_title('cos')
ax2.legend()
plt.show()
Could anyone help me ?
How about this?
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 100)
fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212, sharex=ax1)
ax1.plot(np.sin(x))
ax2.plot(np.cos(x))
plt.show()
I suggest you should read a simple tutorial about subplots.
EDIT:
To create separate figures:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 100)
plt.figure()
plt.plot(np.sin(x))
plt.figure()
plt.plot(np.cos(x))
plt.show()
I want to see how a plot varies with different values using a loop. I want to see it on the same plot. But i do not want to remains of the previous plot in the figure. In MATLAB this is possible by creating a figure and just plotting over the same figure. Closing it when the loop ends.
Like,
fh = figure();
%for loop here
%do something with x and y
subplot(211), plot(x);
subplot(212), plot(y);
pause(1)
%loop done
close(fh);
I am not able to find the equivalent of this in matplotlib. Usually all the questions are related to plotting different series on the same plot, which seems to come naturally on matplotlib, by plotting several series using plt.plot() and then showing them all finally using plt.show(). But I want to refresh the plot.
There are essentially two different ways to create animations in matplotlib
interactive mode
Turning on interactive more is done using plt.ion(). This will create a plot even though show has not yet been called. The plot can be updated by calling plt.draw() or for an animation, plt.pause().
import matplotlib.pyplot as plt
x = [1,1]
y = [1,2]
fig, (ax1,ax2) = plt.subplots(nrows=2, sharex=True, sharey=True)
line1, = ax1.plot(x)
line2, = ax2.plot(y)
ax1.set_xlim(-1,17)
ax1.set_ylim(-400,3000)
plt.ion()
for i in range(15):
x.append(x[-1]+x[-2])
line1.set_data(range(len(x)), x)
y.append(y[-1]+y[-2])
line2.set_data(range(len(y)), y)
plt.pause(0.1)
plt.ioff()
plt.show()
FuncAnimation
Matplotlib provides an animation submodule, which simplifies creating animations and also allows to easily save them. The same as above, using FuncAnimation would look like:
import matplotlib.pyplot as plt
import matplotlib.animation
x = [1,1]
y = [1,2]
fig, (ax1,ax2) = plt.subplots(nrows=2, sharex=True, sharey=True)
line1, = ax1.plot(x)
line2, = ax2.plot(y)
ax1.set_xlim(-1,18)
ax1.set_ylim(-400,3000)
def update(i):
x.append(x[-1]+x[-2])
line1.set_data(range(len(x)), x)
y.append(y[-1]+y[-2])
line2.set_data(range(len(y)), y)
ani = matplotlib.animation.FuncAnimation(fig, update, frames=14, repeat=False)
plt.show()
An example to animate a sine wave with changing frequency and its power spectrum would be the following:
import matplotlib.pyplot as plt
import matplotlib.animation
import numpy as np
x = np.linspace(0,24*np.pi,512)
y = np.sin(x)
def fft(x):
fft = np.abs(np.fft.rfft(x))
return fft**2/(fft**2).max()
fig, (ax1,ax2) = plt.subplots(nrows=2)
line1, = ax1.plot(x,y)
line2, = ax2.plot(fft(y))
ax2.set_xlim(0,50)
ax2.set_ylim(0,1)
def update(i):
y = np.sin((i+1)/30.*x)
line1.set_data(x,y)
y2 = fft(y)
line2.set_data(range(len(y2)), y2)
ani = matplotlib.animation.FuncAnimation(fig, update, frames=60, repeat=True)
plt.show()
If you call plt.show() inside the loop you will see the plot for each element on the loop as long as you close the window containing the figure. The process, will be plot for the first element, then if you close the window you will see the plot for the second element in the loop, etc