如何在 matplotlib 中按不同组绘制直方图?
How to plot a histogram by different groups in matplotlib?
我有一个 table 像:
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
,即用不同颜色区分类型
- “横条”的位置应该是“闪避”,即并排
- 因为取值范围很小,所以我会用
identity
作为bins,即一个bin的宽度是1
问题是:
- 如何根据
type
的值为条形分配颜色并从颜色图中绘制颜色(例如 Accent
或 matplotlib 中的其他 cmap)?我不想使用 命名颜色 (即 'b', 'k', 'r'
)
- 直方图中的条形相互重叠,如何“躲避”条形?
备注
- 我已经在 Seaborn、matplotlib 和
pandas.plot
上尝试了两个小时,但未能获得所需的直方图。
- 我阅读了 matplotlib 的示例和用户指南。令人惊讶的是,我没有找到有关如何从颜色图中分配颜色的教程。
- 我在 Google 上进行了搜索,但未能找到简洁的示例。
- 我想可以用
matplotlib.pyplot
完成任务,而无需导入一堆模块,例如 matplotlib.cm
、matplotlib.colors
.
对于您的第一个问题,我们可以创建一个等于 1 的虚拟列,然后通过对该列求和来生成计数,并按值和类型分组。
对于第二个问题,您可以使用 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 histplot
函数的解决方案:
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()
如您所见,这是直方图而不是条形图,条形之间没有 space,除非数据集中不存在 x 轴的值,例如值 12 和14.
看到已接受的答案在 pandas 中提供了条形图,并且条形图可能是在某些情况下显示直方图的相关选择,这里是如何使用 countplot
函数:
# 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,这会产生一个有点欺骗性的图,因为没有为这些值显示空的 space。另一方面,每组柱之间有一些 space,这样可以更容易地看到每个柱属于什么值。
我有一个 table 像:
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
,即用不同颜色区分类型 - “横条”的位置应该是“闪避”,即并排
- 因为取值范围很小,所以我会用
identity
作为bins,即一个bin的宽度是1
问题是:
- 如何根据
type
的值为条形分配颜色并从颜色图中绘制颜色(例如Accent
或 matplotlib 中的其他 cmap)?我不想使用 命名颜色 (即'b', 'k', 'r'
) - 直方图中的条形相互重叠,如何“躲避”条形?
备注
- 我已经在 Seaborn、matplotlib 和
pandas.plot
上尝试了两个小时,但未能获得所需的直方图。 - 我阅读了 matplotlib 的示例和用户指南。令人惊讶的是,我没有找到有关如何从颜色图中分配颜色的教程。
- 我在 Google 上进行了搜索,但未能找到简洁的示例。
- 我想可以用
matplotlib.pyplot
完成任务,而无需导入一堆模块,例如matplotlib.cm
、matplotlib.colors
.
对于您的第一个问题,我们可以创建一个等于 1 的虚拟列,然后通过对该列求和来生成计数,并按值和类型分组。
对于第二个问题,您可以使用 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 histplot
函数的解决方案:
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()
如您所见,这是直方图而不是条形图,条形之间没有 space,除非数据集中不存在 x 轴的值,例如值 12 和14.
看到已接受的答案在 pandas 中提供了条形图,并且条形图可能是在某些情况下显示直方图的相关选择,这里是如何使用 countplot
函数:
# 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,这会产生一个有点欺骗性的图,因为没有为这些值显示空的 space。另一方面,每组柱之间有一些 space,这样可以更容易地看到每个柱属于什么值。