How to plot line (polygonal chain) with numpy/scipy/matplotlib with minimal smoothing

I am trying to plot a line in matplotlib.. I am searching for the right type of interpolation.. I want something like this

taken from canvasxpress.org/line.html

where every line is smoothed. I tried several combination of scipy and matplotlib, such as

x_new = np.arange(x, x_length, 1)
tck = interpolate.splrep(x, y, s=3)
y_new = interpolate.splev(x_new, tck, der=0)
ax.plot(x_new, y_new, color+lstyle)

but the best result I get is

my result

The line represents an increasing variable.. so it is a wrong representation. What can I search for?

Thanks

Edit: I am thinking about implementing a method from myself, but I don’t know if it has been already done.. pseudo code is the following

take x and y
calculate spline for each three points 
x[0], x[1], x[2] ... x[1], x[2], x[3] ... and so on
for each y[n] sums every computation done for it and divide by number of 
computations (i.e. y[1] is computed for triplette x[0..2] and x[1..3] so the 
sum is divided by two (average for each point is taken as its value)

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

For that type of graph, you want monotonic interpolation. The PchipInterpolator class (which you can refer to by its shorter alias pchip) in scipy.interpolate can be used:

import numpy as np
from scipy.interpolate import pchip
import matplotlib.pyplot as plt


# Data to be interpolated.
x = np.arange(10.0)
y = np.array([5.0, 10.0, 20.0, 15.0, 13.0, 22.0, 20.0, 15.0, 12.0, 16.0])

# Create the interpolator.
interp = pchip(x, y)

# Dense x for the smooth curve.
xx = np.linspace(0, 9.0, 101)

# Plot it all.
plt.plot(xx, interp(xx))
plt.plot(x, y, 'bo')
plt.ylim(0, 25)
plt.grid(True)
plt.show()

Result:

enter image description here

Method 2

The problem is not a display problem. It is an interpolation problem. You are interpolating using spline functions. Picking the right interpolation method is very much depending on the kind of data you have. You cannont expect to have an interpolation function which will behave right in every circumstances (the interpolation have no way to know that your function is increasing).

Method 3

You should either look at

scipy.interpolate.LSQUnivariateSpline and play with k parameter (degree of the spline)

or scipy.interpolate.UnivariateSpline and play with k and s parameter.

Method 4

It is important to understand that the interpolation is not just a line for visualization. It is a mathematical model representing how you think the system behaves (the system which generates the data that you measured). Different types of interpolations represent different assumptions about the system.

So, if you know that your system is such that a variable can only increase, you should fit an appropriate model (i.e. use the appropriate interpolation). Looking at your data, it looks like a 2nd degree polynomial or an exponential function might fit well. A Loess (local regression) fit will also work. You can use either tailored functions like numpy.polyfit(), or generic curve fitting with scipy.optimize.curve_fit(). If you have further knowledge about the system, you should use it to select which model to fit.

Method 5

I have looked around a bit. What you want is called

Monotone cubic interpolation,

see wikipedia here. You have a discussion on mathexchange about it here and I have found an implementation in python here. Let me know if this works!


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x