Как построить, когда обе оси являются категориальными, ось Y является многоиндексной, а значения являются категориальными? - PullRequest
0 голосов
/ 15 октября 2018

Учитывая следующие данные:

DC,Mode,Mod,Ven,TY1,TY2,TY3,TY4,TY5,TY6,TY7,TY8
Intra,S,Dir,C1,False,False,False,False,False,True,True,False
Intra,S,Co,C1,False,False,False,False,False,False,False,False
Intra,M,Dir,C1,False,False,False,False,False,False,True,False
Inter,S,Co,C1,False,False,False,False,False,False,False,False
Intra,S,Dir,C2,False,True,True,True,True,True,True,False
Intra,S,Co,C2,False,False,False,False,False,False,False,False
Intra,M,Dir,C2,False,False,False,False,False,False,False,False
Inter,S,Co,C2,False,False,False,False,False,False,False,False
Intra,S,Dir,C3,False,False,False,False,True,True,False,False
Intra,S,Co,C3,False,False,False,False,False,False,False,False
Intra,M,Dir,C3,False,False,False,False,False,False,False,False
Inter,S,Co,C3,False,False,False,False,False,False,False,False
Intra,S,Dir,C4,False,False,False,False,False,True,False,True
Intra,S,Co,C4,True,True,True,True,False,True,False,True
Intra,M,Dir,C4,False,False,False,False,False,True,False,True
Inter,S,Co,C4,True,True,True,False,False,True,False,True
Intra,S,Dir,C5,True,True,False,False,False,False,False,False
Intra,S,Co,C5,False,False,False,False,False,False,False,False
Intra,M,Dir,C5,True,True,False,False,False,False,False,False
Inter,S,Co,C5,False,False,False,False,False,False,False,False

Импорт:

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

Чтобы воспроизвести мои DataFrame, скопируйте данные, затем используйте:

df = pd.read_clipboard(sep=',')

Я хотел бы создать сюжет, передающий ту же информацию, что и мой пример, но не обязательно с той же формой (я открыт для предложений).Я также хотел бы навести курсор на цвет и отобразить соответствующий Ven (например, C1, а не 1).:

Редактировать 2018-10-17:

Два решения, представленные на данный момент, являются полезными, и каждое из них выполняет свой аспект того, что я ищу.Тем не менее, ключевой вопрос, который я хотел бы решить, который не был явно указан до этого редактирования, заключается в следующем:

Я хотел бы выполнить построение без преобразования Ven вint;это числовое преобразование не практично с реальными данными.Таким образом, реальная задача вопроса - построить все категориальные данные с двумя категориальными осями.

enter image description here

Проблема, с которой я сталкиваюсь, заключается вданные являются категориальными, а ось Y является многоиндексированной.

Я сделал следующее для преобразования DataFrame:

# replace False witn nan
df = df.replace(False, np.nan)

# replace True with a number representing Ven (e.g. C1 = 1)    
def rep_ven(row):
    return row.iloc[4:].replace(True, int(row.Ven[1]))

df.iloc[:, 4:] = df.apply(rep_ven, axis=1)

# drop the Ven column
df = df.drop(columns=['Ven'])

# set multi-index
df_m = df.set_index(['DC', 'Mode', 'Mod'])

Построение преобразованного DataFrame производит:

plt.figure(figsize=(20,10))
heatmap = plt.imshow(df_m)
plt.xticks(range(len(df_m.columns.values)), df_m.columns.values)
plt.yticks(range(len(df_m.index)), df_m.index)
plt.show()

enter image description here

Этот график не очень обтекаемый, для каждого Ven есть четыре значения оси.Это подмножество данных, поэтому график будет очень длинным со всеми данными.

Ответы [ 2 ]

0 голосов
/ 16 октября 2018

Вот мое решение.Вместо построения я просто применяю стиль к DataFrame, см. https://pandas.pydata.org/pandas-docs/stable/style.html

# Transform Ven values from "C1", "C2" to 1, 2, ..
df['Ven'] = df['Ven'].str[1]

# Given a specific combination of dc, mode, mod, ven, 
# do we have any True cells?
g = df.groupby(['DC', 'Mode', 'Mod', 'Ven']).any()

# Let's drop any rows with only False values
g = g[g.any(axis=1)]

# Convert True, False to 1, 0
g = g.astype(int)

# Get the values of the ven index as an int array
# Note: we don't want to drop the ven index!!
# Otherwise styling won't work
ven = g.index.get_level_values('Ven').values.astype(int)

# Multiply 1 and 0 with Ven value
g = g.mul(ven, axis=0)

# Sort the index
g.sort_index(ascending=False, inplace=True)

# Now display the dataframe with styling

# first we get a color map
import matplotlib
cmap = matplotlib.cm.get_cmap('tab10')

def apply_color_map(val):
    # hide the 0 values
    if val == 0:
        return 'color: white; background-color: white' 
    else:
        # for non-zero: get color from cmap, convert to hexcode for css
        s = "color:white; background-color: " + matplotlib.colors.rgb2hex(cmap(val))
        return s
g
g.style.applymap(apply_color_map)

Доступные цветовые карты matplotlib можно увидеть здесь: Ссылка на цветовую карту , с некоторыми дополнительными пояснениями здесь: Выбор цветовой карты

The result

0 голосов
/ 15 октября 2018

Объяснение : Удалите строки, где TY1 - TY8 - все nan, чтобы создать свой график.См. этот ответ в качестве отправной точки для создания интерактивных аннотаций для отображения Ven.

Приведенный ниже код должен работать:

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

df = pd.read_clipboard(sep=',')

# replace False witn nan
df = df.replace(False, np.nan)

# replace True with a number representing Ven (e.g. C1 = 1)    
def rep_ven(row):
    return row.iloc[4:].replace(True, int(row.Ven[1]))

df.iloc[:, 4:] = df.apply(rep_ven, axis=1)

# drop the Ven column
df = df.drop(columns=['Ven'])

idx = df[['TY1','TY2', 'TY3', 'TY4','TY5','TY6','TY7','TY8']].dropna(thresh=1).index.values
df = df.loc[idx,:].sort_values(by=['DC', 'Mode','Mod'], ascending=False)

# set multi-index
df_m = df.set_index(['DC', 'Mode', 'Mod'])


plt.figure(figsize=(20,10))
heatmap = plt.imshow(df_m)
plt.xticks(range(len(df_m.columns.values)), df_m.columns.values)
plt.yticks(range(len(df_m.index)), df_m.index)
plt.show()

enter image description here

...