在 Python 中为 Matplotlib 直方图的 x 轴添加更多描述性标签
Add more descriptive labelling to x-axis of Matplotlib histogram in Python
我在 Jupyter 笔记本中创建了一个直方图,以显示 100 次网络访问的页面时间分布(以秒为单位)。
代码如下:
ax = df.hist(column='time_on_page', bins=25, grid=False, figsize=(12,8), color='#86bf91', zorder=2, rwidth=0.9)
ax = ax[0]
for x in ax:
# Despine
x.spines['right'].set_visible(False)
x.spines['top'].set_visible(False)
x.spines['left'].set_visible(False)
# Switch off ticks
x.tick_params(axis="both", which="both", bottom="off", top="off", labelbottom="on", left="off", right="off", labelleft="on")
# Draw horizontal axis lines
vals = x.get_yticks()
for tick in vals:
x.axhline(y=tick, linestyle='dashed', alpha=0.4, color='#eeeeee', zorder=1)
# Set title
x.set_title("Time on Page Histogram", fontsize=20, weight='bold', size=12)
# Set x-axis label
x.set_xlabel("Time on Page Duration (Seconds)", labelpad=20, weight='bold', size=12)
# Set y-axis label
x.set_ylabel("Page Views", labelpad=20, weight='bold', size=12)
# Format y-axis label
x.yaxis.set_major_formatter(StrMethodFormatter('{x:,g}'))
这会产生以下可视化结果:
我总体上对外观很满意,但我希望轴更具描述性,或许可以显示每个 bin 的 bin 范围以及每个 bin 占总数的百分比。
已在 Matplotlib 文档中查找此内容,但似乎找不到任何能让我实现最终目标的内容。
非常感谢任何帮助。
当您设置 bins=25
时,会在遇到的最低值和最高值之间设置 25 个等距的 bin。如果您使用这些范围来标记 bin,那么由于任意值,事情可能会令人困惑。将这些 bin 边界四舍五入似乎更合适,例如 20 的倍数。然后,这些值可以用作 x-axis 上的刻度线,很好地位于 bin 之间。
可以通过遍历条形图(矩形块)来添加百分比。它们的高度表示属于 bin 的行数,因此除以总行数再乘以 100 得到一个百分比。 bar height, x 和 half width 可以定位文本。
from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
df = pd.DataFrame({'time_on_page': np.random.lognormal(4, 1.1, 100)})
max_x = df['time_on_page'].max()
bin_width = max(20, np.round(max_x / 25 / 20) * 20) # round to multiple of 20, use max(20, ...) to avoid rounding to zero
bins = np.arange(0, max_x + bin_width, bin_width)
axes = df.hist(column='time_on_page', bins=bins, grid=False, figsize=(12, 8), color='#86bf91', rwidth=0.9)
ax = axes[0, 0]
total = len(df)
ax.set_xticks(bins)
for p in ax.patches:
h = p.get_height()
if h > 0:
ax.text(p.get_x() + p.get_width() / 2, h, f'{h / total * 100.0 :.0f} %\n', ha='center', va='center')
ax.grid(True, axis='y', ls=':', alpha=0.4)
ax.set_axisbelow(True)
for dir in ['left', 'right', 'top']:
ax.spines[dir].set_visible(False)
ax.tick_params(axis="y", length=0) # Switch off y ticks
ax.margins(x=0.02) # tighter x margins
plt.show()
我在 Jupyter 笔记本中创建了一个直方图,以显示 100 次网络访问的页面时间分布(以秒为单位)。
代码如下:
ax = df.hist(column='time_on_page', bins=25, grid=False, figsize=(12,8), color='#86bf91', zorder=2, rwidth=0.9)
ax = ax[0]
for x in ax:
# Despine
x.spines['right'].set_visible(False)
x.spines['top'].set_visible(False)
x.spines['left'].set_visible(False)
# Switch off ticks
x.tick_params(axis="both", which="both", bottom="off", top="off", labelbottom="on", left="off", right="off", labelleft="on")
# Draw horizontal axis lines
vals = x.get_yticks()
for tick in vals:
x.axhline(y=tick, linestyle='dashed', alpha=0.4, color='#eeeeee', zorder=1)
# Set title
x.set_title("Time on Page Histogram", fontsize=20, weight='bold', size=12)
# Set x-axis label
x.set_xlabel("Time on Page Duration (Seconds)", labelpad=20, weight='bold', size=12)
# Set y-axis label
x.set_ylabel("Page Views", labelpad=20, weight='bold', size=12)
# Format y-axis label
x.yaxis.set_major_formatter(StrMethodFormatter('{x:,g}'))
这会产生以下可视化结果:
我总体上对外观很满意,但我希望轴更具描述性,或许可以显示每个 bin 的 bin 范围以及每个 bin 占总数的百分比。
已在 Matplotlib 文档中查找此内容,但似乎找不到任何能让我实现最终目标的内容。
非常感谢任何帮助。
当您设置 bins=25
时,会在遇到的最低值和最高值之间设置 25 个等距的 bin。如果您使用这些范围来标记 bin,那么由于任意值,事情可能会令人困惑。将这些 bin 边界四舍五入似乎更合适,例如 20 的倍数。然后,这些值可以用作 x-axis 上的刻度线,很好地位于 bin 之间。
可以通过遍历条形图(矩形块)来添加百分比。它们的高度表示属于 bin 的行数,因此除以总行数再乘以 100 得到一个百分比。 bar height, x 和 half width 可以定位文本。
from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
df = pd.DataFrame({'time_on_page': np.random.lognormal(4, 1.1, 100)})
max_x = df['time_on_page'].max()
bin_width = max(20, np.round(max_x / 25 / 20) * 20) # round to multiple of 20, use max(20, ...) to avoid rounding to zero
bins = np.arange(0, max_x + bin_width, bin_width)
axes = df.hist(column='time_on_page', bins=bins, grid=False, figsize=(12, 8), color='#86bf91', rwidth=0.9)
ax = axes[0, 0]
total = len(df)
ax.set_xticks(bins)
for p in ax.patches:
h = p.get_height()
if h > 0:
ax.text(p.get_x() + p.get_width() / 2, h, f'{h / total * 100.0 :.0f} %\n', ha='center', va='center')
ax.grid(True, axis='y', ls=':', alpha=0.4)
ax.set_axisbelow(True)
for dir in ['left', 'right', 'top']:
ax.spines[dir].set_visible(False)
ax.tick_params(axis="y", length=0) # Switch off y ticks
ax.margins(x=0.02) # tighter x margins
plt.show()