Codemon Codemon - 4 months ago 40
Python Question

Smooth line with spline and datetime objects doesn't work

I have been trying to make a plot smoother, like it is done here, but my Xs are datetime objects that are not compatible with linspace..

I convert the Xs to matplotlib dates:

Xnew = matplotlib.dates.date2num(X)
X_smooth = np.linspace(Xnew.min(), Xnew.max(), 10)
Y_smooth = spline(Xnew, Y, X_smooth)


But then I get an empty plot, as my Y_smooth is

[ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. ]


for some unknown reason.

How can I make this work ?

EDIT

Here's what I get when I print the variables, i see nothing abnormal :

X : [datetime.date(2016, 7, 31), datetime.date(2016, 7, 30), datetime.date(2016, 7, 29)]
X new: [ 736176. 736175. 736174.]
X new max: 736176.0
X new min: 736174.0
XSMOOTH [ 736174. 736174.22222222 736174.44444444 736174.66666667
736174.88888889 736175.11111111 736175.33333333 736175.55555556
736175.77777778 736176. ]
Y [711.74, 730.0, 698.0]
YSMOOTH [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]

Answer

Your X values are reversed.

>>> from scipy.interpolate import spline
>>> import numpy as np
>>> spline(
...     [736176.0, 736175.0, 736174.0],  # <-- your original X is decreasing
...     [711.74, 730.0, 698.0],
...     np.linspace(736174.0, 736176.0, 10)  # <-- this is increasing
... )
array([ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.])

reverse X and Y first and it works

>>> spline(
...     [736174.0, 736175.0, 736176.0],  # <-- reverse order of X
...     [698.0, 730.0, 711.74],  # <-- reverse order of Y also
...     np.linspace(736174.0, 736176.0, 10)  # <-- to match new order
... )
array([  698.        ,   262.18297973,   159.33767533,   293.62017489,
         569.18656683,   890.19293934,  1160.79538066,  1285.149979  ,
        1167.41282274,   711.74      ])

cricket_007 suggestion might be better than using spline, as it seems that spline is poorly undocumented and may not be supported. For example, it is not listed on the scipy.interpolate main page or on the interploation tutorial. However interp1d is well documented and explained in detail. However you don't have enough points for a cubic spline, and a quadratic spline is poorly fit.

f = interp1d([736176.0, 736175.0, 736174.0], [711.74, 730.0, 698.0], kind='quadratic')

f(np.linspace(736176.0, 736174.0, 10))
array([ 711.74      ,  720.14123457,  726.06049383,  729.49777778,
        730.45308642,  728.92641975,  724.91777778,  718.4271605 ,
        709.4545679 ,  698.        ])

There is also a numpy equivalent that can be used once through although it may also have the x monotonically increasing condition.