标记网格中的相邻单元面

Labling neighboring cell faces in a grid

我在 pandas 数据框中有一个节点列表,如下所示:

    row  col
    ... 
36  182  240          
35  182  241          
34  182  242          
33  182  243         
58  183  220          
32  183  244          
31  183  245          
30  183  246          
29  183  247          
    ...

这个节点的网格是这样的:

我的代码标记了 X-ed 单元格的每个面,如果它连接到调整 X-ed 单元格,它被标记为 0,如果它没有连接(打开),它被标记为 1。代码在某些方面无法正常工作:

df["Front Face"] = 1
df["Back Face"]  = 1
df["Right Face"] = 1
df["Left Face"]  = 1

df = df.sort_values(by=['row','col'], ascending=True)
df = df.reset_index(drop=True)
for ix1 in df.index:
    try:
        if df["col"][ix1] == df["col"][ix1 + 1] - 1:
            df["Right Face"][ix1] = 0
            df["Left Face"][ix1 + 1]  = 0
        if df["col"][ix1] == df["col"][ix1 - 1] + 1:
            df["Left Face"][ix1] = 0
            df["Right Face"][ix1 - 1]  = 0
    except:
        pass


df= df.sort_values(by=['col','row'], ascending=True)
df= df.reset_index(drop=True)
for ix2 in df.index:
    try:
        if df["row"][ix2] == df["row"][ix2 + 1] - 1:
            df["Back Face"][ix2] = 0
            df["Front Face"][ix2 + 1]  = 0
        if df["row"][ix2] == df["row"][ix2 - 1] + 1:
            df["Front Face"][ix2] = 0
            df["Back Face"][ix2 - 1]  = 0
    except:
        pass

这是输出的一部分,单元格 182,243 和 183,244 缺少一个标签:

    row  col  Front Face  Back Face  Right Face  Left Face
36  182  240          1           1          0           0
35  182  241          1           1          0           0
34  182  242          1           1          0           0
33  182  243          1           0          1           0
58  183  220          1           0          1           1
32  183  244          0           1          0           1
31  183  245          1           1          0           0
30  183  246          1           1          0           0
29  183  247          1           1          0           0

我在这里圈出了图中有问题的单元格:

我假设您 df 中的每一行都标记了一个已占用的位置,并且您想将相邻的单元格标记为前、后、左或右。

如果是这样,您可以用矢量化的方式来做到这一点,但我不得不承认:我费了很大劲才让索引和 numpy 广播正常工作。

# A random 5 * 10 matrix with 10% of rows marked as "occupied"
n, m = 5, 10
count = int(n * m * 0.1)

df = pd.DataFrame({
    'row': np.random.randint(n, size=count),
    'col': np.random.randint(m, size=count)
}).drop_duplicates()

然后让我们构建 result 数据框:

from itertools import product

# Every row in `df` marks an occupied position
result = df.set_index(['row', 'col']).assign(Occupied = True)

# Now expand `result` into the full matrix
idx = product(range(n), range(m))
result = result.reindex(idx, fill_value=False)

# Every cell is Open initially
for col in ['Front Face', 'Back Face', 'Right Face', 'Left Face']:
    result[col] = 1

# Now start to build out a list of blocked cells
occupied = result.query('Occupied').index.to_frame().to_numpy()
valid_index = result.index

faces = {
    'Front Face': [-1, 0],
    'Back Face': [1, 0],
    'Left Face': [0, -1],
    'Right Face': [0, 1]
}

for face, offset in faces.items():
    blocked = valid_index.intersection([tuple(i) for i in occupied + offset])
    result.loc[blocked, face] = 0

为了说明结果,让我们构建一个辅助函数:

from IPython.display import display

def illustrate(result):   
    display_df = result['Occupied'].map({True: 'x', False: ''}).reset_index()
    display_df = display_df.pivot(index='row', columns='col', values='Occupied')
    
    is_open = result[['Front Face', 'Back Face', 'Right Face', 'Left Face']].all(axis=1)
    style_df = (
        is_open.map({
            True: 'background-color: white',
            False: 'background-color: rgba(255,0,0,0.2)'
        })
        .unstack()
    )
    
    display(display_df.style.apply(lambda _: style_df, axis=None))

illustrate(result)

结果(红色单元格在 任何 面上有一个 0):