Добавить гистограмму вдоль определенной оси кластерной карты с индексом конкретных данных - PullRequest
0 голосов
/ 20 февраля 2019

Я пытаюсь добавить гистограмму (с накоплением или иным образом) для каждой строки в кластерной карте seaborn.

Допустим, у меня есть такой фрейм данных:

import pandas as pd
import numpy as np
import random

df = pd.DataFrame(np.random.randint(0,100,size=(100, 8)), columns=["heatMap_1","heatMap_2","heatMap_3","heatMap_4","heatMap_5", "barPlot_1","barPlot_1","barPlot_1"])

df['index'] = [ random.randint(1,10000000)  for k in df.index]
df.set_index('index', inplace=True)
df.head()
       heatMap_1    heatMap_2   heatMap_3   heatMap_4   heatMap_5   barPlot_1   barPlot_1   barPlot_1
index                               
4552288 9   3   54  37  23  42  94  31
6915023 7   47  59  92  70  96  39  59
2988122 91  29  59  79  68  64  55  5
5060540 68  80  25  95  80  58  72  57
2901025 86  63  36  8   33  17  79  86

Я могу использовать первые 5 столбцов (в этом примере, начинающихся с префикса heatmap_), чтобы создать кластерную карту seaborn, используя эту (илиэквивалент моря):

sns.clustermap(df.iloc[:,0:5], )

и столбчатая диаграмма с накоплением для последних четырех столбцов (в этом примере, начиная с префикса barPlot_), используя это: df.iloc[:,5:8].plot(kind='bar', stacked=True)

, но яЯ немного запутался в том, как объединить оба типа сюжета.Я понимаю, что кластерная карта создает свои собственные фигуры, и я не уверен, смогу ли я извлечь только тепловую карту из кластерной карты и затем использовать ее с подфигурами.(Обсуждается здесь: Добавление кластерной карты морского происхождения к рисунку с другими графиками ).Это создает странный вывод.Редактировать: Используя это:

import pandas as pd
import numpy as np
import random
import seaborn as sns; sns.set(color_codes=True)
import matplotlib.pyplot as plt
import matplotlib.gridspec


df = pd.DataFrame(np.random.randint(0,100,size=(100, 8)), columns=["heatMap_1","heatMap_2","heatMap_3","heatMap_4","heatMap_5", "barPlot_1","barPlot_2","barPlot_3"])
df['index'] = [ random.randint(1,10000000)  for k in df.index]
df.set_index('index', inplace=True)
g = sns.clustermap(df.iloc[:,0:5], )
g.gs.update(left=0.05, right=0.45)
gs2 = matplotlib.gridspec.GridSpec(1,1, left=0.6)
ax2 = g.fig.add_subplot(gs2[0])
df.iloc[:,5:8].plot(kind='barh', stacked=True, ax=ax2)

создает это: enter image description here

, которое не очень хорошо соответствует (то есть из-за дендрограмм есть сдвиг).

Другой вариант - вручную выполнить кластеризацию и создать тепловую карту matplotlib, а затем добавить связанные подфигуры, такие как столбцы (обсуждается здесь: Как получить плоскую кластеризацию, соответствующую цветным кластерам в дендрограмме, созданной scipy )

Есть ли способ использовать кластерную карту в качестве вспомогательного участка наряду с другими графиками?

Это результат, который я ищу [1] : enter image description here

1 Ответ

0 голосов
/ 04 марта 2019

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

def heatMapCluter(df):
    row_method = "ward"
    column_method = "ward"
    row_metric = "euclidean"
    column_metric = "euclidean"

    if column_method == "ward":
        d2 = dist.pdist(df.transpose())
        D2 = dist.squareform(d2)
        Y2 = sch.linkage(D2, method=column_method, metric=column_metric)
        Z2 = sch.dendrogram(Y2, no_plot=True)
        ind2 = sch.fcluster(Y2, 0.7 * max(Y2[:, 2]), "distance")
        idx2 = Z2["leaves"]
        df = df.iloc[:, idx2]
        ind2 = ind2[idx2]
    else:
        idx2 = range(df.shape[1])

    if row_method:
        d1 = dist.pdist(df)
        D1 = dist.squareform(d1)
        Y1 = sch.linkage(D1, method=row_method, metric=row_metric)
        Z1 = sch.dendrogram(Y1, orientation="right", no_plot=True)
        ind1 = sch.fcluster(Y1, 0.7 * max(Y1[:, 2]), "distance")
        idx1 = Z1["leaves"]
        df = df.iloc[idx1, :]
        ind1 = ind1[idx1]
    else:
        idx1 = range(df.shape[0])
    return df

Переставил исходный фрейм данных:

clusteredHeatmap = heatMapCluter(df.iloc[:, 0:5].copy())
# Extract the "barplot" rows and merge them
clusteredDataframe = df.reindex(list(clusteredHeatmap.index.values))
clusteredDataframe = clusteredDataframe.reindex(
    list(clusteredHeatmap.columns.values)
    + list(df.iloc[:, 5:8].columns.values),
    axis=1,
)

и затем использовал сеткудля построения обеих «подфигур» (кластерная карта и линейная диаграмма):

# Now let's plot this - first the heatmap and then the barplot.
# Since it is a "two" part plot which shares the same axis, it is
# better to use gridspec
fig = plt.figure(figsize=(12, 12))
gs = GridSpec(3, 3)
gs.update(wspace=0.015, hspace=0.05)
ax_main = plt.subplot(gs[0:3, :2])
ax_yDist = plt.subplot(gs[0:3, 2], sharey=ax_main)
im = ax_main.imshow(
    clusteredDataframe.iloc[:, 0:5],
    cmap="Greens",
    interpolation="nearest",
    aspect="auto",
)
clusteredDataframe.iloc[:, 5:8].plot(
    kind="barh", stacked=True, ax=ax_yDist, sharey=True
)

ax_yDist.spines["right"].set_color("none")
ax_yDist.spines["top"].set_color("none")
ax_yDist.spines["left"].set_visible(False)
ax_yDist.xaxis.set_ticks_position("bottom")


ax_yDist.set_xlim([0, 100])
ax_yDist.set_yticks([])
ax_yDist.xaxis.grid(False)
ax_yDist.yaxis.grid(False)

Блокнот Jupyter: https://gist.github.com/siddharthst/2a8b7028d18935860062ac7379b9279f

Изображение: enter image description here

1 - http://code.activestate.com/recipes/578175-hierarchical-clustering-heatmap-python/

...