Search code examples
python-3.xmatplotlibinterpolationnumerical-methodsderivative

How to plot the derivative of a Cubic spline in Python 3?


I am using Python 3 for a task related to numerical analysis.

I have to plot some points originated from a sine function. Moreover, I need to do a cubic interpolation of these points (cubic spline).

So, these tasks are done. The output picture is great and the code works. However, I need to check if the the derivative of the cubic spline looks like a cosine function.

Take a look at this image:

enter image description here

In orange, you see the cosine function. In blue, you see the sine function. In red, the 5 dots that I sampled. In purple, you can see a linear interpolation. And, in dashes, you see the cubic interpolation.

I need to plot the derivative of the dashed curve and compare it to the orange one.

Intuitively, I know they are going to be pretty similar. However, I was not able to prove that with a graph.

That's the code:

import math
import random
from numpy import array 
import numpy as np 
import matplotlib.pyplot as plot
from scipy.interpolate import interp1d
from scipy import interpolate
from scipy.misc import derivative as deriv

def random_sine():

    lista_f_x = []
    lista_x = []

    for i in range(1,6):

        aleatorio = random.uniform(0,360)
        aleatorio = math.radians(aleatorio)
        lista_x.append(aleatorio)

        sine_random = math.sin(aleatorio)
        lista_f_x.append(sine_random)

    lista_x = array(lista_x)
    lista_f_x = array(lista_f_x)

    return ("x",lista_x,"f(x)", lista_f_x) 

# para ter um grupo controle melhor, deixe esses valores aleatórios, gerados uma vez, como fixos
fixed_x = array([5.80990031, 1.7836885,  4.62073799, 0.89337425, 5.62219906])
fixed_y = array([-0.45581264,  0.97742392, -0.99580299,  0.77919112, -0.61389568])

x = fixed_x
y = fixed_y

"""
caso deseje usar os valores fixos
basta inserir o comentário "#" nas linhas
39, 40 e 41 abaixo
"""
#teste_dinamico = random_sine()
#x = teste_dinamico[1]
#y = teste_dinamico[3]

time = np.arange(0,10,0.1)

amplitude = np.sin(time)

amplitude_cosine = np.cos(time)

plot.plot(time, amplitude, time, amplitude_cosine)

plot.title('Função Seno')

plot.xlabel('Coordenadas de X')

plot.ylabel('Seno(x)')

plot.grid(True, which='both')

plot.axhline(y=0, color='k')

pares_x_y = list(zip(x,y))

sort_pares_x_y = sorted(pares_x_y)

x_ordenado = []
y_ordenado_simetric = []

for i in sort_pares_x_y:

    x_ordenado.append(i[0])
    y_ordenado_simetric.append(i[1])

x_ordenado = array(x_ordenado)
y_ordenado_simetric = array(y_ordenado_simetric)

f = interp1d(x_ordenado, y_ordenado_simetric)

f2 = interp1d(x_ordenado, y_ordenado_simetric, kind="cubic")

plot.plot(x_ordenado, f2(x_ordenado))

minimo = min(x_ordenado)
maximo = max(x_ordenado)

xnew = np.linspace(minimo, maximo, num=400, endpoint=True)

plot.plot(x_ordenado, y_ordenado_simetric, 'o', xnew, f(xnew), '-', xnew, f2(xnew), '--')

plot.scatter(x,y)

plot.show()

I tried to follow this post. However, the post suggests a different package. I am using interp1d so far and the post suggests using interpolate. I tried converting what I did so far but it didn't work.

What can I do?

If I have a curve being plot with matplotlib, is there an easier way to plot the curve's derivative?

What's the best strategy to solve this?

1 - Should I try again and change everything to the other package suggested on SO?

2 - Should I use some numerical method for differentiation?

Thanks in advance.


Solution

  • Other packages or functions might of course be more handy, but for understanding, you may simply calculate the derivative (dy/dx) yourself and plot it.

    plot.plot(xnew[:-1], np.diff(f2(xnew))/np.diff(xnew), color="red")
    

    Adding this line will result in

    enter image description here

    where the red line is the derivative of f2.