Аннотированная тепловая карта с несколькими цветовыми схемами - PullRequest
0 голосов
/ 28 января 2019

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

enter image description here

Пример данных:

Sample  Step 2  Step 3  Step 4  Step 5  Step 6  Step 7  Step 8
A   64.847  54.821  20.897  39.733  23.257  74.942  75.945
B   64.885  54.767  20.828  39.613  23.093  74.963  75.928
C   65.036  54.772  20.939  39.835  23.283  74.944  75.871
D   64.869  54.740  21.039  39.889  23.322  74.925  75.894
E   64.911  54.730  20.858  39.608  23.101  74.956  75.930
F   64.838  54.749  20.707  39.394  22.984  74.929  75.941
G   64.887  54.781  20.948  39.748  23.238  74.957  75.909
H   64.903  54.720  20.783  39.540  23.028  74.898  75.911
I   64.875  54.761  20.911  39.695  23.082  74.897  75.866
J   64.839  54.717  20.692  39.377  22.853  74.849  75.939
K   64.857  54.736  20.934  39.699  23.130  74.880  75.903
L   64.754  54.746  20.777  39.536  22.991  74.877  75.902
M   64.798  54.811  20.963  39.824  23.187  74.886  75.895

Пример того, что я ищу: enter image description here

Ответы [ 2 ]

0 голосов
/ 29 января 2019

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

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

enter image description here

Получение переменного числа различных цветовых карт .Matplotlib предоставляет большое количество цветовых карт, однако они, как правило, сильно отличаются по яркости и насыщенности.Здесь представляется желательным иметь цветовые карты различного оттенка, но в остальном одинаковую насыщенность и яркость.
Можно создать цветовые карты на лету, выбрав n различных (и одинаково разнесенных) оттенков, и создать цветовую карту, используята же насыщенность и яркость.

Получение отдельной цветовой шкалы для каждого столбца .Так как значения в столбцах могут быть в совершенно разных масштабах, для определения отображаемых значений потребуется цветная полоса для каждого столбца, например, в первом столбце самый яркий цвет может соответствовать значению 1, а во втором столбце он может соответствоватьдо значения 100. Несколько цветовых полос могут быть созданы внутри осей GridSpec, которые расположены рядом с фактическими осями тепловой карты.Количество столбцов и строк этой сетки будет зависеть от количества столбцов в кадре данных.

В целом это может выглядеть следующим образом.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from matplotlib.gridspec import GridSpec

def get_hsvcmap(i, N, rot=0.):
    nsc = 24
    chsv = mcolors.rgb_to_hsv(plt.cm.hsv(((np.arange(N)/N)+rot) % 1.)[i,:3])
    rhsv = mcolors.rgb_to_hsv(plt.cm.Reds(np.linspace(.2,1,nsc))[:,:3])
    arhsv = np.tile(chsv,nsc).reshape(nsc,3)
    arhsv[:,1:] = rhsv[:,1:]
    rgb = mcolors.hsv_to_rgb(arhsv)
    return mcolors.LinearSegmentedColormap.from_list("",rgb)


def columnwise_heatmap(array, ax=None, **kw):
    ax = ax or plt.gca()
    premask = np.tile(np.arange(array.shape[1]), array.shape[0]).reshape(array.shape)
    images = []
    for i in range(array.shape[1]):
        col = np.ma.array(array, mask = premask != i)
        im = ax.imshow(col, cmap=get_hsvcmap(i, array.shape[1], rot=0.5), **kw)
        images.append(im)
    return images

### Create some dataset
ind = list("ABCDEFGHIJKLM")
m = len(ind)
n = 8
df = pd.DataFrame(np.random.randn(m,n) + np.random.randint(20,70,n), 
                  index=ind, columns=[f"Step {i}" for i in range(2,2+n)])

### Plot data
fig, ax = plt.subplots(figsize=(8,4.5))

ims = columnwise_heatmap(df.values, ax=ax, aspect="auto")

ax.set(xticks=np.arange(len(df.columns)), yticks=np.arange(len(df)),
       xticklabels=df.columns, yticklabels=df.index)
ax.tick_params(bottom=False, top=False, 
               labelbottom=False, labeltop=True, left=False)

### Optionally add colorbars.
fig.subplots_adjust(left=0.06, right=0.65)
rows = 3
cols = len(df.columns) // rows + int(len(df.columns)%rows > 0)
gs = GridSpec(rows, cols)
gs.update(left=0.7, right=0.95, wspace=1, hspace=0.3)
for i, im in enumerate(ims):
    cax = fig.add_subplot(gs[i//cols, i % cols])
    fig.colorbar(im, cax = cax)
    cax.set_title(df.columns[i], fontsize=10)

plt.show()

enter image description here

0 голосов
/ 28 января 2019

Мой первый подход будет основан на фигуре с несколькими сюжетами.Количество графиков будет равно количеству столбцов в вашем фрейме данных;разрыв между участками может быть уменьшен до нуля:

cm = ['Blues', 'Reds', 'Greens', 'Oranges', 'Purples', 'bone', 'winter']
f, axs = plt.subplots(1, df.columns.size, gridspec_kw={'wspace': 0})
for i, (s, a, c) in enumerate(zip(df.columns, axs, cm)):
    sns.heatmap(np.array([df[s].values]).T, yticklabels=df.index, xticklabels=[s], annot=True, fmt='.2f', ax=a, cmap=c, cbar=False)
    if i>0:
        a.yaxis.set_ticks([])

Результат: enter image description here

Не уверен, приведет ли это к полезным или даже к себеописание визуализации данных, но это ваш выбор - возможно, это поможет начать ...


Дополнительно:

Что касается добавления цветовых полос: конечно, вы можете,Но - помимо того, что я не знаю основы ваших данных и цели визуализации - я хотел бы добавить несколько соображений по поводу всего этого:

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

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

cm = ['Blues', 'Reds', 'Greens', 'Oranges', 'Purples', 'bone', 'winter']
f, axs = plt.subplots(1, df.columns.size, figsize=(10, 3))
for i, (s, a, c) in enumerate(zip(df.columns, axs, cm)):
    sns.heatmap(np.array([df[s].values]).T, yticklabels=df.index, xticklabels=[s], annot=True, fmt='.2f', ax=a, cmap=c)
    if i>0:
        a.yaxis.set_ticks([])
f.tight_layout()

enter image description here

Однако все, что сказано - осмелюсь усомнитьсячто это лучшая визуализация для ваших данных.Конечно, я не знаю, что вы хотите сказать, увидеть или найти на этих графиках, но в этом суть: если тип визуализации будет соответствовать потребностям, я думаю, я бы знал (или, по крайней мере, мог бы вообразить).

Например:
Простое df.plot() приводит к

enter image description here

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

Или вы явно после разницы в средствах каждого столбца?

(df - df.mean()).plot()

enter image description here

... или распределение каждого столбца вокруг них?

(df - df.mean()).boxplot()

enter image description here

Что я хочу сказать: данныеВизуализация становится мощной, когда сюжет начинает рассказывать о базовых данных, прежде чем вы начнете / должны что-то объяснять ...

...