У меня есть несколько точек данных, которые я соединяю, используя график с закрытой линией, и я хочу, чтобы у линии были гладкие края, аналогично тому, как это делают методы curveCardinal в d3. Ссылка здесь
Вот минимальный пример того, что я хочу сделать:
import numpy as np
from matplotlib import pyplot as plt
x = np.array([0.5, 0.13, 0.4, 0.5, 0.6, 0.7, 0.5])
y = np.array([1.0, 0.7, 0.5, 0.2, 0.4, 0.6, 1.0])
fig, ax = plt.subplots()
ax.plot(x, y)
ax.scatter(x, y)
Теперь я бы хотел сгладить / интерполировать линию, аналогично методам d3's curveCardinal. Вот несколько вещей, которые я попробовал.
from scipy import interpolate
tck, u = interpolate.splprep([x, y], s=0, per=True)
xi, yi = interpolate.splev(np.linspace(0, 1, 100), tck)
fig, ax = plt.subplots(1, 1)
ax.plot(xi, yi, '-b')
ax.plot(x, y, 'k')
ax.scatter(x[:2], y[:2], s=200)
ax.scatter(x, y)
Результат вышеприведенного кода неплох, но я надеялся, что кривая останется ближе к линии, когда точки данных будут далеко друг от друга (я увеличил размер двух таких точек данных выше, чтобы выделить это). По сути, кривая должна оставаться близко к линии.
Использование interp1d (имеет ту же проблему, что и код выше):
from scipy.interpolate import interp1d
x = [0.5, 0.13, 0.4, 0.5, 0.6, 0.7, 0.5]
y = [1.0, 0.7, 0.5, 0.2, 0.4, 0.6, 1.0]
orig_len = len(x)
x = x[-3:-1] + x + x[1:3]
y = y[-3:-1] + y + y[1:3]
t = np.arange(len(x))
ti = np.linspace(2, orig_len + 1, 10 * orig_len)
kind='cubic'
xi = interp1d(t, x, kind=kind)(ti)
yi = interp1d(t, y, kind=kind)(ti)
fig, ax = plt.subplots()
ax.plot(xi, yi, 'g')
ax.plot(x, y, 'k')
ax.scatter(x, y)
Я также посмотрел на алгоритм обрезки углов Чайкина, но мне не нравится результат.
def chaikins_corner_cutting(coords, refinements=5):
coords = np.array(coords)
for _ in range(refinements):
L = coords.repeat(2, axis=0)
R = np.empty_like(L)
R[0] = L[0]
R[2::2] = L[1:-1:2]
R[1:-1:2] = L[2::2]
R[-1] = L[-1]
coords = L * 0.75 + R * 0.25
return coords
fig, ax = plt.subplots()
ax.plot(x, y, 'k', linewidth=1)
ax.plot(chaikins_corner_cutting(x, 4), chaikins_corner_cutting(y, 4))
Я также поверхностно посмотрел на кривые Безье, matplotlibs PathPatch и реализации Fancy box, но я не смог получить удовлетворительных результатов.
Предложения приветствуются.