Reputation: 5486
I need your help. Please consider the code below, which plots a sinusoid using pylab
in IPython
. A slider below the axis enables the user to adjust the frequency of the sinusoid interactively.
%pylab
# setup figure
fig, ax = subplots(1)
fig.subplots_adjust(left=0.25, bottom=0.25)
# add a slider
axcolor = 'lightgoldenrodyellow'
ax_freq = axes([0.3, 0.13, 0.5, 0.03], axisbg=axcolor)
s_freq = Slider(ax_freq, 'Frequency [Hz]', 0, 100, valinit=a0)
# plot
g = linspace(0, 1, 100)
f0 = 1
sig = sin(2*pi*f0*t)
myline, = ax.plot(sig)
# update plot
def update(value):
f = s_freq.val
new_data = sin(2*pi*f*t)
myline.set_ydata(new_data) # crucial line
fig.canvas.draw_idle()
s_freq.on_changed(update)
Instead of the above, I need to plot the signal as vertical lines, ranging from the amplitude of each point in t
to the x-axis. Thus, my first idea was to use vlines
instead of plot
in line 15:
myline = ax.vlines(range(len(sig)), 0, sig)
This solution works in the non-interactive case. The problem is, plot
returns an matplotlib.lines.Line2D
object, which provides the set_ydata
method to update data interactively. The object returned by vlines
is of type matplotlib.collections.LineCollection
and does not provide such a method.
My question: how do I update a LineCollection
interactively?
Upvotes: 4
Views: 2597
Reputation: 1
Maybe using axvline
is also a possibility because it returns a matplotlib.lines.Line2D
object, see Line2D - Documentation & Interactively redraw axvline.
In contrast to vlines
it can handle set_ydata([ymin,ymax])
and set_xdata([xmin,xmax])
.
So when updating a vertical line to x=1.0 with a height of y=1.0 starting from the x-axis it looks like this
myline.set_ydata([0.0, 1.0])
myline.set_xdata([1.0,1.0])
Upvotes: 0
Reputation: 1
I will give examples for vlines
here.
If you have multiple lines, @scleronomic solution works perfect. You also might prefer one-liner:
myline.set_segments([np.array([[x, x_min], [x, x_max]]) for x in xx])
If you need to update only maximums, then you can do this:
def update_maxs(vline):
vline[:,1] = x_min, x_max
return vline
myline.set_segments(list(map(update_maxs, x.get_segments())))
Also this example could be useful: LINK
Upvotes: 0
Reputation: 4537
Using @Aaron Voelker
's comment of using set_segments
and wrapping it up in a function:
def update_vlines(*, h, x, ymin=None, ymax=None):
seg_old = h.get_segments()
if ymin is None:
ymin = seg_old[0][0, 1]
if ymax is None:
ymax = seg_old[0][1, 1]
seg_new = [np.array([[xx, ymin],
[xx, ymax]]) for xx in x]
h.set_segments(seg_new)
Analog for hlines
:
def update_hlines(*, h, y, xmin=None, xmax=None):
seg_old = h.get_segments()
if xmin is None:
xmin = seg_old[0][0, 0]
if xmax is None:
xmax = seg_old[0][1, 0]
seg_new = [np.array([[xmin, yy],
[xmax, yy]]) for yy in y]
h.set_segments(seg_new)
Upvotes: 0