简体   繁体   中英

Matplotlib set_data for errorbar plot

Matplotlib's line2D objects, such as those returned by a call to plot , have a convenient method, set_data , that let's me quickly update the values plotted by a single line without affecting the rest of the plot or the formatting of the line.

#sample plot
from matplotlib.pyplot import plot
p = plot(arange(10),arange(10))[0]

#now update the data
p.set_data(arange(10),arange(10)+2)
draw()

Is there any relatively simple (few lines of code) way to do the same with an errorbar plot? I'd like to be able to set up a complicated plot with assorted text, arrows, lines, etc., then quickly cycle just the errorbar portion of the plot through several different sets of data.

The object returned by errorbar seems to be pretty complex and so far my attempts at deleting and redrawing have failed.

Thanks to the help from @tacaswell . Below is the python function that can both update xerr and yerr , as well as the x_data and y_data for the baseline plotting:

def adjustErrbarxy(self, errobj, x, y, x_error, y_error):
    ln, (errx_top, errx_bot, erry_top, erry_bot), (barsx, barsy) = errobj
    x_base = x
    y_base = y

    xerr_top = x_base + x_error
    xerr_bot = x_base - x_error
    yerr_top = y_base + y_error
    yerr_bot = y_base - y_error

    errx_top.set_xdata(xerr_top)
    errx_bot.set_xdata(xerr_bot)
    errx_top.set_ydata(y_base)
    errx_bot.set_ydata(y_base)

    erry_top.set_xdata(x_base)
    erry_bot.set_xdata(x_base)
    erry_top.set_ydata(yerr_top)
    erry_bot.set_ydata(yerr_bot)

    new_segments_x = [np.array([[xt, y], [xb,y]]) for xt, xb, y in zip(xerr_top, xerr_bot, y_base)]
    new_segments_y = [np.array([[x, yt], [x,yb]]) for x, yt, yb in zip(x_base, yerr_top, yerr_bot)]
    barsx.set_segments(new_segments_x)
    barsy.set_segments(new_segments_y)

The first input parameter ( self is for python class) is the already created errorbar plot handler, that is also the object whose properties need to be updated; x and y are the updated numpy arrays which should be shown the average values along x and y axis; the last two parameters x_error and y_error are the errorbar ranges calculated for x and y arrays. If only the errorbars are need to be updated, the x_base and y_base should be writen as ln.get_xdata() and ln.get_ydata() , respectively.

Up to now, the solution for the errorbar updating in matplotlib is truly non-trivial, hope it be much easier in the future versions.

I followed the link provided by Tong and learned that there is a problem in his code - input of self variable is not needed. There is also a more generalized solution provided by mitpre - I used it and it works great. Below is the code for quicker reference:

def update_errorbar(errobj, x, y, xerr=None, yerr=None):
    ln, caps, bars = errobj


    if len(bars) == 2:
        assert xerr is not None and yerr is not None, "Your errorbar object has 2 dimension of error bars defined. You must provide xerr and yerr."
        barsx, barsy = bars  # bars always exist (?)
        try:  # caps are optional
            errx_top, errx_bot, erry_top, erry_bot = caps
        except ValueError:  # in case there is no caps
            pass

    elif len(bars) == 1:
        assert (xerr is     None and yerr is not None) or\
               (xerr is not None and yerr is     None),  \
               "Your errorbar object has 1 dimension of error bars defined. You must provide xerr or yerr."

        if xerr is not None:
            barsx, = bars  # bars always exist (?)
            try:
                errx_top, errx_bot = caps
            except ValueError:  # in case there is no caps
                pass
        else:
            barsy, = bars  # bars always exist (?)
            try:
                erry_top, erry_bot = caps
            except ValueError:  # in case there is no caps
                pass

    ln.set_data(x,y)

    try:
        errx_top.set_xdata(x + xerr)
        errx_bot.set_xdata(x - xerr)
        errx_top.set_ydata(y)
        errx_bot.set_ydata(y)
    except NameError:
        pass
    try:
        barsx.set_segments([np.array([[xt, y], [xb, y]]) for xt, xb, y in zip(x + xerr, x - xerr, y)])
    except NameError:
        pass

    try:
        erry_top.set_xdata(x)
        erry_bot.set_xdata(x)
        erry_top.set_ydata(y + yerr)
        erry_bot.set_ydata(y - yerr)
    except NameError:
        pass
    try:
        barsy.set_segments([np.array([[x, yt], [x, yb]]) for x, yt, yb in zip(x, y + yerr, y - yerr)])
    except NameError:
        pass

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM