【问题标题】:How to plot multi-index, categorical data?如何绘制多索引、分类数据?
【发布时间】:2019-03-19 10:38:29
【问题描述】:

给定以下数据:

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 的情况下执行绘图;这种数字转换不适用于真实数据。所以问题的实际范围是用两个分类轴绘制所有分类数据。

我遇到的问题是数据是分类的,并且 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()

这个图不是很精简,每个Ven 有四个轴值。这是数据的一个子集,因此包含所有数据的图表会很长。

【问题讨论】:

    标签: python-3.x pandas matplotlib data-visualization bokeh


    【解决方案1】:

    这是我的解决方案。我只是将样式应用于 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 颜色图:Colormap reference,并在此处进行一些补充说明:Choosing a colormap

    【讨论】:

    • 这很有趣,但显式编码color_ven 并不实用,因为真实的数据集更大。我确实喜欢彩色表格,它可能对不同的用例有所帮助。
    • 很好。我更改了代码以使用 matplotlib 颜色图,因此您可以使用几乎无限数量的值。
    【解决方案2】:

    说明:删除TY1-TY8 都是nan 的行以创建您的绘图。请参考this answer 作为起点,创建交互式注释以显示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()
    

    【讨论】:

      猜你喜欢
      • 2018-10-29
      • 2019-03-28
      • 2021-04-03
      • 2016-12-31
      • 2017-11-20
      • 1970-01-01
      • 1970-01-01
      • 2020-11-24
      • 2015-12-02
      相关资源
      最近更新 更多