Python 如何在matplotlib中按不同组绘制直方图?

Python 如何在matplotlib中按不同组绘制直方图?,python,pandas,matplotlib,plot,histogram,Python,Pandas,Matplotlib,Plot,Histogram,我有一张像这样的桌子: value type 10 0 12 1 13 1 14 2 生成虚拟数据: import numpy as np value = np.random.randint(1, 20, 10) type = np.random.choice([0, 1, 2], 10) 我想使用matplotlib(v1.4)在Python 3中完成一项任务: 绘制值的直方图 按类型分组,即使用不同的颜色来区分类型 “栏”的位置应

我有一张像这样的桌子:

value    type
10       0
12       1
13       1
14       2
生成虚拟数据:

import numpy as np

value = np.random.randint(1, 20, 10)
type = np.random.choice([0, 1, 2], 10)
我想使用matplotlib(v1.4)在Python 3中完成一项任务:

  • 绘制
    值的直方图
  • 类型分组
    ,即使用不同的颜色来区分类型
  • “栏”的位置应为“道奇”,即并排
  • 由于值的范围很小,我将使用
    identity
    来表示箱子,即箱子的宽度为1
问题是:

  • 如何根据
    类型
    的值为条形图指定颜色,并从colormap(例如
    重音
    或matplotlib中的其他cmap)绘制颜色?我不想使用命名颜色(即
    'b','k','r'
  • 我的直方图中的条相互重叠,如何“闪避”这些条

注意

  • 我已经在Seaborn、matplotlib和pandas.plot上试用了两个小时,但未能获得所需的直方图
  • 我阅读了matplotlib的示例和用户指南。令人惊讶的是,我没有找到关于如何从colormap分配颜色的教程
  • 我在谷歌上搜索过,但没有找到一个简洁的例子
  • 我想使用
    matplotlib.pyplot
    可以完成这项任务,而无需导入一堆模块,例如
    matplotlib.cm
    matplotlib.colors

  • 对于第一个问题,我们可以创建一个等于1的虚拟列,然后通过对该列求和生成计数,并按值和类型分组

    对于第二个问题,您可以使用
    colormap
    参数将colormap直接传递到
    plot

    import pandas as pd
    import matplotlib.pyplot as plt
    import matplotlib.cm as cm
    import seaborn
    seaborn.set() #make the plots look pretty
    
    df = pd.DataFrame({'value': value, 'type': type})
    df['dummy'] = 1
    ag = df.groupby(['value','type']).sum().unstack()
    ag.columns = ag.columns.droplevel()
    
    ag.plot(kind = 'bar', colormap = cm.Accent, width = 1)
    plt.show()
    

    每当需要绘制一个由另一个变量分组的变量(使用颜色)时,seaborn通常提供比matplotlib或pandas更方便的方法。下面是一个使用seaborn函数的解决方案:

    import numpy as np                 # v 1.19.2
    import pandas as pd                # v 1.1.3
    import matplotlib.pyplot as plt    # v 3.3.2
    import seaborn as sns              # v 0.11.0
    
    # Set parameters for random data
    rng = np.random.default_rng(seed=1) # random number generator
    size = 50
    xmin = 1
    xmax = 20
    
    # Create random dataframe
    df = pd.DataFrame(dict(value = rng.integers(xmin, xmax, size=size),
                           val_type = rng.choice([0, 1, 2], size=size)))
    
    # Create histogram with discrete bins (bin width is 1), colored by type
    fig, ax = plt.subplots(figsize=(10,4))
    sns.histplot(data=df, x='value', hue='val_type', multiple='dodge', discrete=True,
                 edgecolor='white', palette=plt.cm.Accent, alpha=1)
    
    # Create x ticks covering the range of all integer values of df['value']
    ax.set_xticks(np.arange(df['value'].min(), df['value'].max()+1))
    
    # Additional formatting
    sns.despine()
    ax.get_legend().set_frame_on(False)
    
    plt.show()
    
    # For some reason the palette argument in countplot is not processed the
    # same way as in histplot so here I fetch the colors from the previous
    # example to make it easier to compare them
    colors = [c for c in set([patch.get_facecolor() for patch in ax.patches])]
    
    # Create bar chart of counts of each value grouped by type
    fig, ax = plt.subplots(figsize=(10,4))
    sns.countplot(data=df, x='value', hue='val_type', palette=colors,
                  saturation=1, edgecolor='white')
    
    # Additional formatting
    sns.despine()
    ax.get_legend().set_frame_on(False)
    
    plt.show()
    

    正如您所注意到的,这是一个柱状图而不是条形图,除了数据集中不存在x轴的值(如值12和14)之外,条形图之间没有空间

    鉴于pandas中提供的公认答案为条形图,并且条形图可能是在某些情况下显示直方图的相关选择,以下是如何使用函数创建seaborn柱状图:

    import numpy as np                 # v 1.19.2
    import pandas as pd                # v 1.1.3
    import matplotlib.pyplot as plt    # v 3.3.2
    import seaborn as sns              # v 0.11.0
    
    # Set parameters for random data
    rng = np.random.default_rng(seed=1) # random number generator
    size = 50
    xmin = 1
    xmax = 20
    
    # Create random dataframe
    df = pd.DataFrame(dict(value = rng.integers(xmin, xmax, size=size),
                           val_type = rng.choice([0, 1, 2], size=size)))
    
    # Create histogram with discrete bins (bin width is 1), colored by type
    fig, ax = plt.subplots(figsize=(10,4))
    sns.histplot(data=df, x='value', hue='val_type', multiple='dodge', discrete=True,
                 edgecolor='white', palette=plt.cm.Accent, alpha=1)
    
    # Create x ticks covering the range of all integer values of df['value']
    ax.set_xticks(np.arange(df['value'].min(), df['value'].max()+1))
    
    # Additional formatting
    sns.despine()
    ax.get_legend().set_frame_on(False)
    
    plt.show()
    
    # For some reason the palette argument in countplot is not processed the
    # same way as in histplot so here I fetch the colors from the previous
    # example to make it easier to compare them
    colors = [c for c in set([patch.get_facecolor() for patch in ax.patches])]
    
    # Create bar chart of counts of each value grouped by type
    fig, ax = plt.subplots(figsize=(10,4))
    sns.countplot(data=df, x='value', hue='val_type', palette=colors,
                  saturation=1, edgecolor='white')
    
    # Additional formatting
    sns.despine()
    ax.get_legend().set_frame_on(False)
    
    plt.show()
    


    由于这是条形图,因此不包括值12和14,这会产生一个有点虚假的图,因为没有为这些值显示空白。另一方面,每组条形图之间有一定的间距,便于查看每个条形图所属的值。

    谢谢。我可以使用
    hist
    来获得相同的结果,而不按枢轴计数吗?嗯,我不确定你如何使用
    hist
    来实现这一点,我只使用hist来绘制单个序列。