In my opinion splines are great for this. The idea is to construct a spline interpolating your unevenly spaced data, and then to evaluate the spline derivatives at any point in space.
This can be done with my own BSplineKit.jl package, but there are other very good alternatives that can do the same.
This is an example using BSplineKit (I’ll add it soon to the docs):
using BSplineKit
using LaTeXStrings
using Plots
using Random
# Actual function and its derivative
f(x) = sin(2π * x)
f′(x) = 2π * cos(2π * x)
# Generate uneven grid of ``N`` points in ``[0, 1]``
N = 20
rng = MersenneTwister(42)
x = sort!(rand(rng, N))
x[1] = 0; x[end] = 1; # make sure endpoints are included
y = f.(x) # actual function at grid points
# Interpolate data with B-splines of order 6 (polynomial degree 5)
yint = interpolate(x, y, BSplineOrder(6))
# Extract resulting spline and generate its first derivative
S = spline(yint) # this is the spline interpolation of f
S′ = diff(S, Derivative(1)) # this is a spline approximating f′
# Evaluate splines and plot
xplot = 0:0.01:1
plt = plot(f, 0, 1; label = L"f(x)", xlabel = L"x", title = "Function interpolation")
plot!(plt, xplot, S.(xplot); label = "Interpolation")
scatter!(plt, x, y; label = "Input data")
plt = plot(f′, 0, 1; label = L"f'(x)", xlabel = L"x", legend = :top, title = "Derivative approximation")
plot!(plt, xplot, S′.(xplot); label = "Interpolation")
scatter!(plt, x, S′.(x); label = "Interpolation at grid points")
This gives the following approximations for f
and its derivative: