Смещение графиков на тепловых картах в Seaborn Facetgrid

Заранее извините за количество изображений, но они помогают продемонстрировать проблему

Я создал фрейм данных, который содержит измерения толщины пленки для ряда подложек, для ряда слоев в зависимости от координат:

|    | Sub | Result | Layer | Row | Col |
|----|-----|--------|-------|-----|-----|
|  0 |   1 |   2.95 | 3 - H |   0 |  72 |
|  1 |   1 |   2.97 | 3 - V |   0 |  72 |
|  2 |   1 |   0.96 | 1 - H |   0 |  72 |
|  3 |   1 |   3.03 | 3 - H | -42 |  48 |
|  4 |   1 |   3.04 | 3 - V | -42 |  48 |
|  5 |   1 |   1.06 | 1 - H | -42 |  48 |
|  6 |   1 |   3.06 | 3 - H |  42 |  48 |
|  7 |   1 |   3.09 | 3 - V |  42 |  48 |
|  8 |   1 |   1.38 | 1 - H |  42 |  48 |
|  9 |   1 |   3.05 | 3 - H | -21 |  24 |
| 10 |   1 |   3.08 | 3 - V | -21 |  24 |
| 11 |   1 |   1.07 | 1 - H | -21 |  24 |
| 12 |   1 |   3.06 | 3 - H |  21 |  24 |
| 13 |   1 |   3.09 | 3 - V |  21 |  24 |
| 14 |   1 |   1.05 | 1 - H |  21 |  24 |
| 15 |   1 |   3.01 | 3 - H | -63 |   0 |
| 16 |   1 |   3.02 | 3 - V | -63 |   0 |

и это продолжается для ›10 подпрограмм (на пакет) и 13 сайтов на подпрограмму, а также для 3 слоев - это df является составным. Я пытаюсь представить данные в виде сетки тепловых карт (адаптируя код из Как сделать тепловую карту квадратной в Seaborn FacetGrid - спасибо!)

Я могу довольно успешно построить подмножество df:

spam = df.loc[df.Sub== 6].loc[df.Layer == '3 - H']
spam_p= spam.pivot(index='Row', columns='Col', values='Result')

sns.heatmap(spam_p, cmap="plasma")

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

НО - есть некоторые недостающие результаты, где ошибки измерения слоя (возвращает "10000"), поэтому я заменил их на NaN:

df.Result.replace(10000, np.nan)

Тепловая карта одиночного морского пути с правильными осями

Чтобы построить сетку фасетов для отображения всех подпрограмм / слоев, я написал следующий код:

def draw_heatmap(*args, **kwargs):
    data = kwargs.pop('data')
    d = data.pivot(columns=args[0], index=args[1], 
    values=args[2])
    sns.heatmap(d, **kwargs)

fig = sns.FacetGrid(spam, row='Wafer', 
col='Feature', height=5, aspect=1)

fig.map_dataframe(draw_heatmap, 'Col', 'Row', 'Result', cbar=False, cmap="plasma", annot=True, annot_kws={"size": 20})

который дает:

изображение тепловой карты с неполным графиком осей

Он автоматически настроил оси, чтобы не отображать позиции, где есть NaN. Я пробовал маскировать (см. https://github.com/mwaskom/seaborn/issues/375), но просто ошибки с Inconsistent shape between the condition and the input (got (237, 15) and (7, 7)).

И в результате, когда не используется обрезанный набор данных (т.е. df вместо spam, код генерирует следующую сетку фасетов):

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

Графики с пропущенными значениями в крайних (краевых) положениях координат приводят к смещению графика внутри осей - здесь все, по-видимому, в верхнем левом углу. Sub # 5, слой 3-H должен выглядеть так:

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

т.е. пробелы в местах где стоят NaNs.

Почему сетка фасетов сдвигает весь сюжет вверх и / или влево? Альтернативой является динамическое создание подзаголовков на основе подсчета подсюжетов / слоев (тьфу!).

Любая помощь очень благодарна.

Полный набор данных для 2 слоев sub 5:

    Sub Result  Layer   Row     Col
0   5   2.987   3 - H   0       72
1   5   0.001   1 - H   0       72
2   5   1.184   3 - H   -42     48
3   5   1.023   1 - H   -42     48
4   5   3.045   3 - H   42      48 
5   5   0.282   1 - H   42      48
6   5   3.083   3 - H   -21     24 
7   5   0.34    1 - H   -21     24
8   5   3.07    3 - H   21      24
9   5   0.41    1 - H   21      24
10  5   NaN     3 - H   -63     0
11  5   NaN     1 - H   -63     0
12  5   3.086   3 - H   0       0
13  5   0.309   1 - H   0       0
14  5   0.179   3 - H   63      0
15  5   0.455   1 - H   63      0
16  5   3.067   3 - H   -21    -24
17  5   0.136   1 - H   -21    -24
18  5   1.907   3 - H   21     -24
19  5   1.018   1 - H   21     -24
20  5   NaN     3 - H   -42    -48
21  5   NaN     1 - H   -42    -48
22  5   NaN     3 - H   42     -48
23  5   NaN     1 - H   42     -48
24  5   NaN     3 - H   0      -72
25  5   NaN     1 - H   0      -72

person BAC83    schedule 16.08.2018    source источник
comment
Как я могу это проверить? Саб такой же, как вафля? Какой минимальный набор данных воспроизведет проблему?   -  person ImportanceOfBeingErnest    schedule 16.08.2018
comment
Да - извините, здесь несколько соглашений об именах, я собрал их вместе, чтобы задать вопрос. Саб == вафля.   -  person BAC83    schedule 16.08.2018
comment
И я внесу правку, чтобы помочь сгенерировать тестовый набор данных ...   -  person BAC83    schedule 16.08.2018
comment
Я добавил полный набор данных; однако вы всегда можете использовать эти данные несколько раз для имитации нескольких подпрограмм (очевидно). Если вы это сделаете - возможно, было бы неплохо включить больше (поддельных) значений, чтобы принудительно использовать разные / новые позиции, т.е. заменить некоторые NaN значениями.   -  person BAC83    schedule 16.08.2018


Ответы (1)


Вы можете создать список уникальных меток столбцов и строк и переиндексировать с ними сводную таблицу.

cols = df["Col"].unique()
rows = df["Row"].unique()

pivot = data.pivot(...).reindex_axis(cols, axis=1).reindex_axis(rows, axis=0)

как показано в этом ответе.

Некоторый полный код:

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

r = np.repeat([0,-2,2,-1,1,-3],2)
row = np.concatenate((r, [0]*2, -r[::-1]))
c = np.array([72]*2+[48]*4 + [24]*4 + [0]* 3)
col = np.concatenate((c,-c[::-1]))

df = pd.DataFrame({"Result" : np.random.rand(26),
                   "Layer" : list("AB")*13,
                   "Row" : row, "Col" : col})

df1 = df.copy()
df1["Sub"] = [5]*len(df1)
df1.at[10:11,"Result"] = np.NaN
df1.at[20:,"Result"] = np.NaN

df2 = df.copy()
df2["Sub"] = [3]*len(df2)
df2.at[0:2,"Result"] = np.NaN

df = pd.concat([df1,df2])

cols = np.unique(df["Col"].values)
rows = np.unique(df["Row"].values)

def draw_heatmap(*args, **kwargs):
    data = kwargs.pop('data')
    d = data.pivot(columns=args[0], index=args[1], 
                   values=args[2])
    d = d.reindex_axis(cols, axis=1).reindex_axis(rows, axis=0)
    print d
    sns.heatmap(d,  **kwargs)

grid = sns.FacetGrid(df, row='Sub', col='Layer', height=3.5, aspect=1 )

grid.map_dataframe(draw_heatmap, 'Col', 'Row', 'Result', cbar=False, 
                  cmap="plasma", annot=True)

plt.show()

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

person ImportanceOfBeingErnest    schedule 16.08.2018
comment
Спасибо за это - избавили меня от огромной головной боли. Если я правильно понимаю, ваше решение объясняет, почему графики дрейфовали по-разному; каждый из них необходимо переиндексировать для столбцов / строк. И еще раз спасибо за полный код, это действительно полезно для ознакомления с некоторыми профессиональными подходами к моим проблемам! Действительно ценю это. - person BAC83; 17.08.2018