将xy数据点图的所有交点与numpy相交?

时间:2013-07-29 15:47:37

标签: python numpy intersection points

我正在分析循环拉伸试验的数据。输入使用巨大的 x和y值列表。 为了描述材料是否硬化或软化,我需要得到每个循环回路的蓝色斜率。

tensile_test

slope

获得斜坡的较低点是儿童节,但是较高的一点,即挑战。

the_challenge

到目前为止,我已经采用了这种方法,在每个循环的局部最大值以下的几个点处切出循环,并从硬编号点数计算红线。通过poly1d(polyfit(x1,x2,1))进行红线的近似,然后使用fsolve来获得交点。但是它始终无法正常工作,因为点的分布并不总是相同。

问题是如何正确定义两条(红色)相交线的间隔。在上图中有3个实验和平均斜率。我花了几天时间试图为每个循环找到4个最接近的点,决定这不是最好的方法。最后,我在stackowerflow结束了这里。

所需输出是具有交叉点近似坐标的列表 - 如果要播放,here是曲线的数据(0,[[xvals],[yvals]])。

可以轻松阅读Theese
import csv
import sys
csv. field_size_limit(sys.maxsize)     

csvfile = 'data.csv'
tc_data = {}
for key, val in csv.reader(open(csvfile, "r")):
    tc_data[key] = val
for key in tc_data:
  tc = eval(tc_data[key])

x = tc[0]
y = tc[1]

2 个答案:

答案 0 :(得分:6)

这可能有点矫枉过正,但是一旦将曲线分成块,找到交叉点的正确方法是查看第一个块中的任何段是否与第二个块中的任何段相交。 / p>

我将为自己制作一些简单的数据,prolate cycloid的一部分,并且我将找到y坐标从增加到减少的位置,类似于here

a, b = 1, 2
phi = np.linspace(3, 10, 100)
x = a*phi - b*np.sin(phi)
y = a - b*np.cos(phi)
y_growth_flips = np.where(np.diff(np.diff(y) > 0))[0] + 1

plt.plot(x, y, 'rx')
plt.plot(x[y_growth_flips], y[y_growth_flips], 'bo')
plt.axis([2, 12, -1.5, 3.5])
plt.show()

enter image description here

如果您有两个细分,一个从点P0P1,另一个从点Q0Q1,您可以通过求解找到它们的交点向量方程P0 + s*(P1-P0) = Q0 + t*(Q1-Q0),如果st都在[0, 1]中,则两个网段实际相交。尝试所有细分:

x_down = x[y_growth_flips[0]:y_growth_flips[1]+1]
y_down = y[y_growth_flips[0]:y_growth_flips[1]+1]
x_up = x[y_growth_flips[1]:y_growth_flips[2]+1]
y_up = y[y_growth_flips[1]:y_growth_flips[2]+1]

def find_intersect(x_down, y_down, x_up, y_up):
    for j in xrange(len(x_down)-1):
        p0 = np.array([x_down[j], y_down[j]])
        p1 = np.array([x_down[j+1], y_down[j+1]])
        for k in xrange(len(x_up)-1):
            q0 = np.array([x_up[k], y_up[k]])
            q1 = np.array([x_up[k+1], y_up[k+1]])
            params = np.linalg.solve(np.column_stack((p1-p0, q0-q1)),
                                     q0-p0)
            if np.all((params >= 0) & (params <= 1)):
                return p0 + params[0]*(p1 - p0)

>>> find_intersect(x_down, y_down, x_up, y_up)
array([ 6.28302264,  1.63658676])

crossing_point = find_intersect(x_down, y_down, x_up, y_up)
plt.plot(crossing_point[0], crossing_point[1], 'ro')
plt.show()

enter image description here

在我的系统上,这可以处理每秒约20个交叉点,这不是超快的,但可能足以分析图形。您可以通过矢量化2x2线性系统的解决方案来解决问题:

def find_intersect_vec(x_down, y_down, x_up, y_up):
    p = np.column_stack((x_down, y_down))
    q = np.column_stack((x_up, y_up))
    p0, p1, q0, q1 = p[:-1], p[1:], q[:-1], q[1:]
    rhs = q0 - p0[:, np.newaxis, :]
    mat = np.empty((len(p0), len(q0), 2, 2))
    mat[..., 0] = (p1 - p0)[:, np.newaxis]
    mat[..., 1] = q0 - q1
    mat_inv = -mat.copy()
    mat_inv[..., 0, 0] = mat[..., 1, 1]
    mat_inv[..., 1, 1] = mat[..., 0, 0]
    det = mat[..., 0, 0] * mat[..., 1, 1] - mat[..., 0, 1] * mat[..., 1, 0]
    mat_inv /= det[..., np.newaxis, np.newaxis]
    import numpy.core.umath_tests as ut
    params = ut.matrix_multiply(mat_inv, rhs[..., np.newaxis])
    intersection = np.all((params >= 0) & (params <= 1), axis=(-1, -2))
    p0_s = params[intersection, 0, :] * mat[intersection, :, 0]
    return p0_s + p0[np.where(intersection)[0]]

是的,它很乱,但它有效,而且速度快了100倍:

find_intersect(x_down, y_down, x_up, y_up)
Out[67]: array([ 6.28302264,  1.63658676])

find_intersect_vec(x_down, y_down, x_up, y_up)
Out[68]: array([[ 6.28302264,  1.63658676]])

%timeit find_intersect(x_down, y_down, x_up, y_up)
10 loops, best of 3: 66.1 ms per loop

%timeit find_intersect_vec(x_down, y_down, x_up, y_up)
1000 loops, best of 3: 375 us per loop

答案 1 :(得分:1)

你可以非常简单地通过使用scipy中的interp1d函数来重新采样相同x值的所有行的y值。

http://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.interp1d.html