使用 python seaborn 的具有不同权重的多维数据的离散颜色图

Discrete colormap for multidimensional data with varying weights using python seaborn

我有一个如下所示的数据集:

df = pd.DataFrame({"Sunday":    {'a1':0.1,'a2':0.15,'a4':0.05,'a6':0.1,'b2':0.05,'b3':0.05,'b4':0.2,'c1':0.15,'c4':0.15},
                   "Monday":    {'a2':0.05,'a3':0.15,'a5':0.25,'b1':0.05,'b3':0.1,'b4':0.1,'c3':0.1,'c5':0.05,'c7':0.15},
                   "Tuesday":   {'a1':0.2,'a3':0.15,'a6':0.05,'b2':0.35,'b3':0.05,'c1':0.1,'c4':0.1},
                   "Wednesday": {'a2':0.05,'a3':0.05,'a4':0.35,'a6':0.2,'b1':0.1,'b3':0.05,'b4':0.05,'c1':0.05,'c6':0.1},
                   "Thursday":  {'a1':0.25,'a3':0.05,'a4':0.3,'a5':0.05,'a6':0.1,'b1':0.05,'b4':0.05,'c2':0.1,'c4':0.05},
                   "Friday":    {'a1':0.1,'a2':0.15,'a5':0.1,'a7':0.05,'b2':0.05,'b1':0.15,'b4':0.2,'c3':0.05,'c4':0.05,'c5':0.05,'c7':0.05},
                   "Saturday":  {'a1':0.15,'a3':0.05,'b2':0.05,'b3':0.05,'b4':0.4,'c1':0.1,'c5':0.1,'c7':0.1}
                   }}

字典中每一天的键都是分类的,它们分为三种一般类型 a、b、c:它们中的每一种都有一定数量的子类型。 a型有6个亚型,b型有4个亚型,c型有7个亚型。字典中的值代表权重(重要性)。并非每个观察(天)都需要存在所有可能的子类型。每个观测值(天)中的 Nan 值应被忽略(创建图时)。

我想使用离散颜色图可视化此数据,类似于在 post 中所做的:heatmap-like plot, but for categorical variables in seaborn。他们的解决方案非常优雅,但我的问题稍微复杂一些,因为我还想反映每个子类型的权重——通过代表它的矩形的高度(显示在 y 轴上)。每天的权重总和为 1。在 x 轴上,我想显示工作日。所有分配了颜色的子类型都应显示在右侧的颜色条上,并带有相应的代码名称:'a1',...,'a6','b1',...,'b4','c1',...,'c7'.

最后,我想使用不同的颜色映射来为不同的子类型着色:例如,蓝色代表 a 类型,绿色代表 b 类型,红色代表 c 类型。

我想使用 Python Seaborn 包来完成此操作,但如果您可以使用不同的包提出更好的解决方案,我不介意改用它。

如果有任何建议,我将不胜感激。谢谢。

要使用 seaborn 创建堆叠条形图,您似乎需要在彼此之上绘制总和条形图(参见 this blogpost)。对于 18 种类型,这变得相当复杂。

使用 pandas 情节,事情会更容易一些,尽管需要一些操作:

import matplotlib.pyplot as plt
import pandas as pd

df = pd.DataFrame({"Sunday":    {'a1':0.1,'a2':0.15,'a4':0.05,'a6':0.1,'b2':0.05,'b3':0.05,'b4':0.2,'c1':0.15,'c4':0.15},
                   "Monday":    {'a2':0.05,'a3':0.15,'a5':0.25,'b1':0.05,'b3':0.1,'b4':0.1,'c3':0.1,'c5':0.05,'c7':0.15},
                   "Tuesday":   {'a1':0.2,'a3':0.15,'a6':0.05,'b2':0.35,'b3':0.05,'c1':0.1,'c4':0.1},
                   "Wednesday": {'a2':0.05,'a3':0.05,'a4':0.35,'a6':0.2,'b1':0.1,'b3':0.05,'b4':0.05,'c1':0.05,'c6':0.1},
                   "Thursday":  {'a1':0.25,'a3':0.05,'a4':0.3,'a5':0.05,'a6':0.1,'b1':0.05,'b4':0.05,'c2':0.1,'c4':0.05},
                   "Friday":    {'a1':0.1,'a2':0.15,'a5':0.1,'a7':0.05,'b2':0.05,'b1':0.15,'b4':0.2,'c3':0.05,'c4':0.05,'c5':0.05,'c7':0.05},
                   "Saturday":  {'a1':0.15,'a3':0.05,'b2':0.05,'b3':0.05,'b4':0.4,'c1':0.1,'c5':0.1,'c7':0.1}
                   })
df.fillna(0, inplace=True)  # replace NA with zeros
df2 = df.T  # switch rows and columns
df2 = df2.reindex(sorted(df2.columns), axis=1)  # reorder the columns
types = df2.columns
num_type = {letter: len([t for t in types if t[0] == letter]) for letter in 'abc'}
df2.plot.bar(stacked=True, rot=0, figsize=(10, 5),
             color=[plt.cm.Blues_r(i / 7) for i in range(num_type['a'])]
                   + [plt.cm.Greens_r(i / 7) for i in range(num_type['b'])]
                   + [plt.cm.Reds_r(i / 7) for i in range(num_type['c'])])
plt.legend(bbox_to_anchor=(1.02, 1), loc='upper left') # legend outside the main plot
plt.tight_layout() # fit legend and labels
plt.show()

PS:获得 seaborn 图所需的一些操作包括将索引转换为命名列(例如 'type')并将数据转换为长格式。

df.fillna(0, inplace=True)
df.index = df.index.set_names(['type'])
df.reset_index(inplace=True)
types = sorted(np.unique(df['type']))
df_long = df.melt(var_name='day', value_name='weight', id_vars='type')
sns.barplot(x='day', y='weight', hue='type', hue_order=types, data=df_long)