I have several plots in one figure using subplot. Each axes instance is used to refrence a specific set of axes. Like so:
ax[0] = fig.add_subplot(2, 2, 1)
ax[1] = fig.add_subplot(2, 1, 2)
ax[2] = fig.add_subplot(2, 2, 2,projection='3d')
As you can see, one of my sets of axes is a 3d plot. I make a change to one of the properties of the other plots like so:
plt.setp(zh, xdata=event.xdata,ydata=event.ydata)
and re-draw like so:
zh.figure.canvas.draw();
However, this is re-drawing the ENTIRE figure with all suplots, including the 3D projected one, which is slowing things down quite significantly.
I've tried this:
ax[0].draw_artist(zh)
Which I thought had promise, but the axes isn't being updated. I'm not getting an error, it's just not re-drawing. I also tried:
zh.axes.draw(zh,ax[0])
but that gives the error:
AttributeError: 'Line2D' object has no attribute 'open_group'
Any ideas as to why this is happening, and how I can just re-draw the axes instance that I'm changing instead of the entire figure?
EDIT:
zh is a Line2D object:
zh, = plt.plot(z.real, z.imag, 'x', ms=10)
To set the limits for X-axis only, We could use xlim() and set_xlim() methods. Similarly to set the limits for Y-axis, we could use ylim() and set_ylim() methods. We can also use axis() method which can control the range of both axes.
You can't draw a single axes, but you can update only a single axes.
Basically, you need to blit things. If the range (and therefore the ticks, etc) of the axes are changing, this gets more complicated. For the moment, I'll assume that's not the case.
As an over-simplified example:
import matplotlib.pyplot as plt
import numpy as np
plt.ion()
x = np.linspace(0, 4*np.pi, 100)
fig, axes = plt.subplots(nrows=3)
fig.canvas.draw()
background = fig.canvas.copy_from_bbox(axes[0].bbox)
lines = [ax.plot(x, np.cos(x))[0] for ax in axes]
fig.canvas.draw()
for phase in range(1000):
fig.canvas.restore_region(background)
lines[0].set_ydata(np.cos(x + phase / 5.0))
axes[0].draw_artist(lines[0])
fig.canvas.blit(axes[0].bbox)
However, the new matplotlib.animations
will handle doing this for you, and will only blit the axes of the artists you specify.
Here's the same example written using matplotlib.animations.FuncAnimation
:
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
x = np.linspace(0, 4*np.pi, 100)
fig, axes = plt.subplots(nrows=3)
lines = [axes[0].plot(x, np.cos(x), animated=True)[0]]
lines += [ax.plot(x, np.cos(x)) for ax in axes[1:]]
class Update(object):
def __init__(self, line):
self.phase = 0
self.line = line
def __call__(self, _):
self.line.set_ydata(np.cos(x + self.phase / 5.0))
self.phase += 1.0
return [self.line]
anim = FuncAnimation(fig, Update(lines[0]), interval=0, blit=True)
plt.show()
Which artists are animated (and which axes are updated) is controlled by the artists the function (or callable object, as in this case) returns.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With