I would like to plot a graph of some experimental data which is sampled at a relatively high rate, but approximates a smooth curve using markers spaced at equal arc-length intervals as shown in the graph below:
I know about the markevery
argument to plot, but that would bunch up the markers to the right of the plot and probably have quite few markers on the left. The solution should be independent of the scales on the x and y axes. I am open to installing additional modules, but it should be a python+matplotlib solution.
I think I have put together a relatively good solution. The only problem is taking the data ratio into account in a way that also uses information about the aspect ratio of the final plot. I've not found a reliable way to do this, although this function will accept a data ratio so you can play until the output looks right:
def spacedmarks(x, y, Nmarks, data_ratio=None):
import scipy.integrate
if data_ratio is None:
data_ratio = plt.gca().get_data_ratio()
dydx = gradient(y, x[1])
dxdx = gradient(x, x[1])*data_ratio
arclength = scipy.integrate.cumtrapz(sqrt(dydx**2 + dxdx**2), x, initial=0)
marks = linspace(0, max(arclength), Nmarks)
markx = interp(marks, arclength, x)
marky = interp(markx, x, y)
return markx, marky
Example of use (this is suitable for pylab mode in iPython):
x = linspace(0, 10*pi, 1000)
y = sin(x*2) + sin(x+1)
plot(x, y)
markx, marky = spacedmarks(x, y, 80)
plot(markx, marky, 'o', color='blue')
Result:
Since matplotlib 1.4, you can use markevery with real numbers to achieve this.
Documentation: http://matplotlib.org/api/lines_api.html#matplotlib.lines.Line2D.set_markevery
Example:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10*np.pi, 1000)
y = np.sin(x*2) + np.sin(x + 1)
plt.plot(x, y, marker='o', markevery=0.05)
plt.show()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With