Matplotlib set_data for errorbar plot

前端 未结 2 553
被撕碎了的回忆
被撕碎了的回忆 2021-01-05 19:56

Matplotlib\'s line2D objects, such as those returned by a call to plot, have a convenient method, set_data, that let\'s me quickly upd

相关标签:
2条回答
  • 2021-01-05 20:35

    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.

    0 讨论(0)
  • 2021-01-05 20:50

    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
    
    0 讨论(0)
提交回复
热议问题