2013-10-01 2 views
11

У меня есть список значений (x, y), которые не равномерно распределены друг от друга. Here - архив, используемый в этом вопросе.Как генерировать равномерные значения интерполяции

Я могу интерполировать между значениями, но то, что я получаю, не является равным интерполирующим точкам. Вот что я делаю:

x_data = [0.613,0.615,0.615,...] 
y_data = [5.919,5.349,5.413,...] 

# Interpolate values for x and y. 
t = np.linspace(0, 1, len(x_data)) 
t2 = np.linspace(0, 1, 100) 
# One-dimensional linear interpolation. 
x2 = np.interp(t2, t, x_data) 
y2 = np.interp(t2, t, y_data) 

# Plot x,y data. 
plt.scatter(x_data, y_data, marker='o', color='k', s=40, lw=0.) 

# Plot interpolated points. 
plt.scatter(x2, y2, marker='o', color='r', s=10, lw=0.5) 

что приводит:

enter image description here

Как можно видеть, красные точки ближе друг к другу в разделах графа, где первоначально распределение точек плотнее.

я нужен способ, чтобы генерировать интерполированных точек эквидистантно расположенных по х, у в соответствии с заданной величиной шага (скажем 0.1)


В askewchan правильно указывает, когда я имею в виду "equispaced in x, y "Я имею в виду, что две последовательные интерполированные точки на кривой должны дистанцироваться друг от друга (эвклидовое расстояние прямой линии) на одно и то же значение.


Я попытался ответить unubtu, и это хорошо работает для гладких кривых, но, кажется, перерыв не так гладкими:

non-smooth-curve

Это происходит потому, что код вычисляет расстояние точки в евклидовом пути вместо прямого над кривой, и мне нужно расстояние по кривой, чтобы быть одинаковым между точками. Можно ли каким-то образом решить эту проблему?

+1

«_equispaced_ in x, y» означает эквидистант вдоль касательной кривой? – askewchan

+0

@askewchan извините, я выразил себя неоднозначно. Я реорганизую вопрос, чтобы сделать это более ясным. – Gabriel

+0

Другими словами, вы хотите 'dx = step/sqrt (1 + (y ') ** 2)' – askewchan

ответ

6

Давайте сначала рассмотрим простой случай. Предположим, что ваши данные выглядели как синяя линия, ниже.

enter image description here

Если вы хотите, чтобы выбрать равноотстоящие точки, которые были r расстояния друга от друга, тогда будет каким-то критическим значением для r где створка в (1,2) является первой равноудалена точкой.

Если вы хотите пункты, которые были больше, чем это критическое расстояние друг от друга, то первый равноудалены точка будет прыгать из (1,2) в какое-то место совсем другой - , изображенном на пересечении зеленой дуги синяя линия. Изменение не является постепенным.

Этот случай с игрушкой предполагает, что небольшое изменение параметра r может иметь радикальное, прерывистое влияние на решение.

Он также предполагает, что вы должны знать местоположение i-й эквидистантной точки , прежде чем вы сможете определить местоположение (i + 1) -й эквидистантной точки.

Таким образом, оказывается, требуется итеративный решение:

import numpy as np 
import matplotlib.pyplot as plt 
import math 

x, y = np.genfromtxt('data', unpack=True, skip_header=1) 
# find lots of points on the piecewise linear curve defined by x and y 
M = 1000 
t = np.linspace(0, len(x), M) 
x = np.interp(t, np.arange(len(x)), x) 
y = np.interp(t, np.arange(len(y)), y) 
tol = 1.5 
i, idx = 0, [0] 
while i < len(x): 
    total_dist = 0 
    for j in range(i+1, len(x)): 
     total_dist += math.sqrt((x[j]-x[j-1])**2 + (y[j]-y[j-1])**2) 
     if total_dist > tol: 
      idx.append(j) 
      break 
    i = j+1 

xn = x[idx] 
yn = y[idx] 
fig, ax = plt.subplots() 
ax.plot(x, y, '-') 
ax.scatter(xn, yn, s=50) 
ax.set_aspect('equal') 
plt.show() 

enter image description here

Примечание: Я установить соотношение сторон к 'equal', чтобы сделать его более очевидным, что точки находятся на одинаковом расстоянии.

+0

Это отличный ответ, жаль, что я так долго не возвращался к вам (увлекся еще одной проблемой). Этот код отлично работает для разумно плавных кривых, но, похоже, терпит неудачу за не очень хорошо выполненные кривые. См. Отредактированный вопрос. – Gabriel

+1

@Gabriel: Я отредактировал свой ответ. Это в основном то же самое - вы просто отслеживаете пробег всего расстояния, когда вы прыгаете между точками. – unutbu

+0

Большое спасибо @unubtu, этот ответ сейчас совершенен! – Gabriel

0

Возможна генерация эквидистантных точек вдоль кривой. Но должно быть больше определения того, что вы хотите для реального ответа. Извините, но код, который я написал для этой задачи, находится в MATLAB, но я могу описать общие идеи. Есть три возможности.

Во-первых, это точки, которые должны быть действительно равноудалены от соседей в терминах простого евклидова расстояния? Для этого потребуется найти пересечение в любой точке кривой с кругом фиксированного радиуса. Затем просто шагните по кривой.

Далее, если вы намереваетесь расстояние до среднего расстояния вдоль самой кривой, если кривая является кусочно-линейной, проблема снова легко сделать. Просто шагните по кривой, так как расстояние на отрезке линии легко измерить.

И, наконец, если вы намерены, чтобы кривая была кубическим сплайном, снова это не невероятно сложно, но это немного больше работы. Здесь уловка заключается в следующем:

  • Вычислить кусочно-линейную длину арклина из точки в точку вдоль кривой. Назовите его t.
  • Создайте пару кубических сплайнов, x (t), y (t).
  • Различают x и y как функции t. Поскольку это кубические сегменты, это легко. Производные функции будут кусочно квадратичными.
  • Используйте ode solver для перемещения по кривой, интегрируя дифференциальную функцию arclength. В MATLAB ODE45 работал красиво.

Таким образом, один интегрирует

sqrt((x')^2 + (y')^2) 

Опять же, в MATLAB, ode45 может быть установлен, чтобы определить те места, где функция пересекает определенные заданные точки.

Если ваши навыки MATLAB соответствуют задаче, вы можете посмотреть код в interparc для более подробного объяснения. Это достаточно хорошо прокомментированный код.

2

Следующий сценарий будет интерполировать точки с равным шагом x_max - x_min/len(x) = 0.04438

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

data = np.loadtxt('data.txt') 
x = data[:,0] 
y = data[:,1] 

f = interp1d(x, y) 
x_new = np.linspace(np.min(x), np.max(x), x.shape[0]) 
y_new = f(x_new) 

plt.plot(x,y,'o', x_new, y_new, '*r') 
plt.show() 

enter image description here

+0

Это решение генерирует точки, равные x, но не в y, поэтому не равномерно в * кривой *. Спасибо вам за ответ. – Gabriel

8

Преобразования х данных в параметризованном кривой, т.е. вычислить все все расстояния между точками и генерировать координаты на кривой кумулятивным суммированием. Затем интерполируем x- и y-координаты независимо друг от друга относительно новых координат.

import numpy as np 
from pylab import plot 

data = ''' 0.613 5.919 
    0.615 5.349 
    0.615 5.413 
    0.617 6.674 
    0.617 6.616 
    0.63 7.418 
    0.642 7.809 
    0.648 8.04 
    0.673 8.789 
    0.695 9.45 
    0.712 9.825 
    0.734 10.265 
    0.748 10.516 
    0.764 10.782 
    0.775 10.979 
    0.783 11.1 
    0.808 11.479 
    0.849 11.951 
    0.899 12.295 
    0.951 12.537 
    0.972 12.675 
    1.038 12.937 
    1.098 13.173 
    1.162 13.464 
    1.228 13.789 
    1.294 14.126 
    1.363 14.518 
    1.441 14.969 
    1.545 15.538 
    1.64 16.071 
    1.765 16.7 
    1.904 17.484 
    2.027 18.36 
    2.123 19.235 
    2.149 19.655 
    2.172 20.096 
    2.198 20.528 
    2.221 20.945 
    2.265 21.352 
    2.312 21.76 
    2.365 22.228 
    2.401 22.836 
    2.477 23.804''' 

data = np.array([line.split() for line in data.split('\n')],dtype=float) 

x,y = data.T 
xd =np.diff(x) 
yd = np.diff(y) 
dist = np.sqrt(xd**2+yd**2) 
u = np.cumsum(dist) 
u = np.hstack([[0],u]) 

t = np.linspace(0,u.max(),20) 
xn = np.interp(t, u, x) 
yn = np.interp(t, u, y) 

plot(x,y,'o') 
plot(xn,yn,'gs') 
xlim(0,5.5) 
ylim(10,17.5) 
+0

В моем случае он дает мне «ValueError: объект слишком глубокий для желаемого массива» в этой строке - 'xn = numpy.interp (t, u, x)' –

+0

Я просто запустил код, и он отлично работает. numpy - версия 1.10.1 и scipy 0.15.1 –

Смежные вопросы