Search code examples
pythondatetimematplotliberrorbar

errorbar plot against datetime fails


Errorbar plotting does not always work when the x axis is a datetime:

z = pd.DataFrame({'timestamp': {0: pd.Timestamp('2018-06-16 04:33:27'),
  1: pd.Timestamp('2018-06-16 18:07:40')},
 'average': {0: 1.4158309812874796, 1: 1.4293226152856995},
 'stdev': {0: 0.5721450460404708, 1: 0.5771658975429514}})

Now z is

            timestamp   average     stdev
0 2018-06-16 04:33:27  1.415831  0.572145
1 2018-06-16 18:07:40  1.429323  0.577166

plt.plot(z.timestamp, z.average) works as expected, but plt.errorbar(z.timestamp, z.average, yerr=z.stdev) produces

<ErrorbarContainer object of 3 artists>
Error in callback <function install_repl_displayhook.<locals>.post_execute at 0x7fe251344840> (for post_execute):


Truncated Traceback (Use C-c C-x to view full TB):
~/.virtualenvs/algorisk/local/lib64/python3.6/site-packages/matplotlib/dates.py in viewlim_to_dt(self)
   1024                              'often happens if you pass a non-datetime '
   1025                              'value to an axis that has datetime units'
-> 1026                              .format(vmin))
   1027         return num2date(vmin, self.tz), num2date(vmax, self.tz)
   1028 

ValueError: view limit minimum -7.64586229992263e+16 is less than 1 and is an invalid Matplotlib date value. This often happens if you pass a non-datetime value to an axis that has datetime units

What am I doing wrong?

PS. Other values seem to work. E.g.,

plt.errorbar(np.array([datetime.datetime(2018,7,30,12),
            datetime.datetime(2018,7,30,15)]).astype("datetime64[h]"),
         np.array([2,3]),
         yerr=np.array([1,2]))

works as expected.


Solution

  • Natively, matplotlib can plot numpy arrays. Instead of providing pandas Series to the plotting function you probably want to provide the underlying numpy arrays, obtained via .values.

    import pandas as pd
    import matplotlib.pyplot as plt
    
    df = pd.DataFrame({'timestamp': {0: pd.Timestamp('2018-06-16 04:33:27'),
                                    1: pd.Timestamp('2018-06-16 18:07:40')},
                      'average': {0: 1.4158309812874796, 1: 1.4293226152856995},
                      'stdev': {0: 0.5721450460404708, 1: 0.5771658975429514}})
    
    plt.errorbar(df.timestamp.values, df.average.values, yerr=df.stdev.values)
    
    plt.show()