【问题标题】:Label points in section of np.meshgridnp.meshgrid 部分中的标签点
【发布时间】:2021-08-20 10:38:08
【问题描述】:

我正在尝试根据 x 和 y 点位于 python 网格的特定部分中来标记它们。这些点存储在 pandas 数据框中。

这里我有一个坐标的散点图,在它们上方我正在绘制网格。 整个网格要大得多,从左下点 (500,1250) 到右上角 (2750, 3250),这意味着整个网格是 225x200 部分。

我想遍历网格的各个部分并检查一个点是否在里面。如果一个点在该部分内,我想为该点添加一个标签。标签应与部分名称相同。 我想在数据框中添加一个名为“section”的列,用于存储点所属的部分。

在示例中(上图),我想用 770

我的代码目前如下所示:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection


df = pd.read_csv('./file.csv', sep=';')

x_min = df['X[mm]'].min()
x_max = df['X[mm]'].max()
y_min = df['Y[mm]'].min()
y_max = df['Y[mm]'].max()
#side of the square in mm:
square_side = 10 

xs = np.arange(x_min, x_max+square_side, square_side)
ys = np.arange(y_min, y_max+square_side, square_side)
x_2, y_2 = np.meshgrid(xs, ys, indexing = 'ij')


fig, ax = plt.subplots(figsize=(9,9))
ax.plot(df['X[mm]'], df['Y[mm]'], linewidth=0.2, c='black')

#plot meshgrid as grid instead of points:
segs1 = np.stack((x_2[:,[0,-1]],y_2[:,[0,-1]]), axis=2)
segs2 = np.stack((x_2[[0,-1],:].T,y_2[[0,-1],:].T), axis=2)
plt.gca().add_collection(LineCollection(np.concatenate((segs1, segs2))))

ax.set_aspect('equal', 'box')
plt.show()

我还有一个函数可以确定点是否在矩形内(这不使用网格):

def is_inside_rect(M, A, B, D):
    '''Check if a point M is inside a rectangle with corners A, B, C, D'''
    # 0 <= dot(BC,BM) <= dot(BC,BC)
    #print(np.dot(B - A, D - A))
    return 0 <= np.dot(B - A, M - A) <= np.dot(B - A, B - A) and 0 <= np.dot(D - B, M - B) <= np.dot(D - B, D - B)

我想过在这样的while循环中使用它:

x = x_min
y = y_min

while (x <= x_max + square_side) and (y <= y_max + square_side):  
    A = np.array([x, y]) 
    B = np.array([x + square_side, y]) 
    D = np.array([x + square_side, y + square_side])
    
    print(A, B, D)
    df['c'] = df[['X[mm]', 'Y[mm]']].apply(lambda coord: 'red' if is_inside_rect(np.array(coord), A, B, D) else 'black', axis=1)
    x += square_side
    y += square_side

但这非常慢,而且每次迭代都会改变所有点的颜色。

【问题讨论】:

    标签: python pandas numpy matplotlib


    【解决方案1】:

    由于所有点的大小都相同,因此无需事先定义所有正方形,然后确定哪些正方形具有哪些点。我会使用每个点的坐标来直接确定它会落在哪个方格。

    为了简单起见,让我们以一维的情况为例。您想将数轴上的点分组为“正方形”(实际上是一维线段)。如果您的第一个正方形从 x=0 开始,第二个正方形从 x=10 开始,第三个正方形从 x=20 开始,依此类推,您如何找到任意点 x 的正方形?您知道您的正方形间隔为 10(并且您知道它们从 0 开始,这使事情变得更容易),因此您可以简单地除以 10 并向下取整以获得平方索引。

    您可以在 3 维(或 n 维)中轻松地做同样的事情。

    square_side = 10
    x_min = df['X[mm]'].min()
    y_min = df['Y[mm]'].min()
    
    def label_point(x, y):
        # Double forward slash is integer (round down) division
        # Add 1 here if you really want 1-based indexing
        x_label = (x - x_min) // square_side
    
        y_label = chr(ord('A') + (y - y_min) // square_side)
        
        return f'{y_label}{x_label}'
    
    df['label'] = df[['X[mm]', 'Y[mm]']].apply(lambda coord: label_point(*coord), axis=1)
    

    至于效率,这个方案只看每个点一次,并且对每个点做恒定的工作量,所以在点数上是O(n)。您的解决方案查看每个正方形一次,对于每个正方形查看每个点,这是 O(n × m),其中 n 是点数,m 是正方形数。

    您的解决方案更通用,因为您的is_inside_rect 函数在您的矩形网格具有任意旋转时起作用。在这种情况下,我建议您围绕原点旋转所有点,然后运行我的解决方案。

    此外,您的循环会在每个循环的 x 和 y 上添加 10,因此您正在对角线遍历您的空间。我不认为你打算这样做。

    【讨论】:

    • 谢谢。我试过这个,但我得到 TypeError: ('label_point() 需要 2 个位置参数,但给出了 887323','发生在索引 X[mm]')
    • @FedericaTomola 抱歉,您需要 axis=1 in .apply()
    猜你喜欢
    • 1970-01-01
    • 2017-10-24
    • 2016-05-01
    • 1970-01-01
    • 2018-06-11
    • 2012-11-28
    • 1970-01-01
    • 2021-09-06
    • 2011-12-24
    相关资源
    最近更新 更多