如何实现seaborn直方图x轴刻度相对分箱居中?含子图异常问题
问题说明
如果我们绘制如下非常简单的直方图:
import numpy as np import seaborn as sns import matplotlib.pyplot as plt Z = np.array([1, 2, 2, 2, 2, 2, 2, 3, 4, 5]) sns.histplot(Z, bins = 5) plt.xticks([1, 2, 3, 4, 5]) plt.show()
运行代码后将得到对应结果图:
核心需求:让x轴刻度相对分箱居中对齐,即刻度1位于第一个分箱的中间位置,刻度2位于第二个分箱的中间位置,以此类推。
前期尝试:使用discrete = True参数后,单图场景下可以成功实现居中对齐效果,但创建子图时该方法失效,测试代码如下:
sns.set(rc={'figure.figsize':(10,15)}) X = np.array([1, 1, 1, 1, 1, 1, 2, 3, 4, 5]) Y = np.array([1, 2, 3, 4, 5, 5, 5, 5, 5, 5]) Z = np.array([1, 2, 2, 2, 2, 2, 2, 3, 4, 5]) f, axes = plt.subplots(1, 3) sns.histplot(X, color = "b", ax = axes[0], discrete = True) plt.xticks(np.arange(1, 6)) sns.histplot(Y, color = "r", ax = axes[1]) plt.xticks([1, 2, 3, 4, 5]) sns.histplot(Z, bins = 5, color = "g", ax = axes[2]) plt.xticks([1, 2, 3, 4, 5]) plt.show()
子图运行结果:
疑问:子图场景下discrete=True失效的原因是什么?
问题原因与解决方法
失效原因
plt.xticks()是matplotlib的全局状态接口,仅会对当前激活的坐标轴生效。在多子图场景下,每次绘图后激活的坐标轴会切换为最后一个操作的子图,上述代码中三次调用plt.xticks()全部作用在了第三个子图上,前两个子图的刻度从未被手动设置,因此无法呈现预期的居中对齐效果,该问题和discrete=True参数本身无关。
修正方案
不要使用全局的plt.xticks()接口,针对每个子图对应的ax对象单独调用set_xticks()方法设置刻度即可。如果需要所有子图都实现刻度对齐分箱中心的效果,所有调用histplot的位置都需要传入discrete=True参数,修正后代码如下:
sns.set(rc={'figure.figsize':(10,15)}) X = np.array([1, 1, 1, 1, 1, 1, 2, 3, 4, 5]) Y = np.array([1, 2, 3, 4, 5, 5, 5, 5, 5, 5]) Z = np.array([1, 2, 2, 2, 2, 2, 2, 3, 4, 5]) f, axes = plt.subplots(1, 3) # 逐个对子图设置刻度 sns.histplot(X, color = "b", ax = axes[0], discrete = True) axes[0].set_xticks(np.arange(1, 6)) sns.histplot(Y, color = "r", ax = axes[1], discrete = True) axes[1].set_xticks([1, 2, 3, 4, 5]) sns.histplot(Z, color = "g", ax = axes[2], discrete = True) axes[2].set_xticks([1, 2, 3, 4, 5]) plt.show()
补充说明:对于整数型离散数据,直接使用discrete=True即可自动调整分箱宽度为1,让每个分箱中心对齐整数值,不需要手动指定bins参数,避免分箱偏移。
内容的提问来源于stack exchange,提问作者Lucian
相关产品推荐
相关产品推荐

