Привязка граней соседних ячеек к сетке

#python #pandas #grid

#python #панды #сетка

Вопрос:

У меня есть список узлов во фрейме данных 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
 

Я обвел проблемные ячейки на картинке здесь:

введите описание изображения здесь

Ответ №1:

Я предполагаю, что каждая строка в вашей df метке обозначает занятую позицию, и вы хотите пометить соседние ячейки как передние, задние, левые или правые.

Если это так, вы можете сделать это векторизованным способом, но я должен признать: я много боролся с тем, чтобы заставить индексы и numpy broadcast работать правильно.

 # 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 на любой из граней):

помеченная сетка

Комментарии:

1. Очень элегантное решение.