如何在含分位数分组分类值的散点图中保留轴顺序?
如何在散点图中保留分位数区间的轴顺序
这个问题我之前也碰到过!核心原因是你把Categorical类型的区间直接转成字符串后,matplotlib会把它们当成无序的文本值来排序,自然就乱了。其实我们可以利用pandas qcut生成的区间本身带有的顺序来解决这个问题,给你两个实用的方案:
方案一:利用Categorical的内置顺序(推荐)
pd.qcut生成的x_group和y_group本质是Categorical类型,它们自带了区间从小到大的顺序。我们可以用这些类别的整数编码作为散点图的坐标,之后再把轴刻度替换成对应的区间字符串,这样既保证了顺序,又能显示正确的文本。
修改后的完整代码如下:
import pandas as pd import matplotlib.pyplot as plt import matplotlib.colors import numpy as np n_tile = 5 np.random.seed(0) x = np.random.normal(150, 70, 3000,) y = np.random.normal(1, 0.3, 3000) r = np.random.normal(0.4, 0.1, 3000) plot_data = pd.DataFrame({ 'x': x, 'y': y, 'r': r }) # qcut生成的是Categorical类型,自带顺序 plot_data['x_group'] = pd.qcut(plot_data['x'], n_tile, duplicates='drop') plot_data['y_group'] = pd.qcut(plot_data['y'], n_tile, duplicates='drop') plot_data_grouped = plot_data.groupby(['x_group','y_group'], as_index=False).agg({'r':['mean','count']}) plot_data_grouped.columns = ['x','y','mean','count'] plt.figure(figsize=(10,10)) # 关键:用类别编码作为散点的坐标,保证顺序 x_codes = plot_data_grouped['x'].cat.codes y_codes = plot_data_grouped['y'].cat.codes scatter = plt.scatter( x=x_codes, y=y_codes, s=plot_data_grouped["count"], c=plot_data_grouped['mean'], cmap="RdYlGn", edgecolors="black" ) # 替换轴刻度为区间字符串 x_categories = plot_data['x_group'].cat.categories y_categories = plot_data['y_group'].cat.categories plt.xticks(ticks=np.arange(len(x_categories)), labels=x_categories, rotation=45) plt.yticks(ticks=np.arange(len(y_categories)), labels=y_categories) # 补充可视化细节 plt.colorbar(scatter, label='Mean of r') plt.xlabel('X Quantile Intervals') plt.ylabel('Y Quantile Intervals') plt.title('Scatter Plot with Ordered Quantile Intervals') plt.tight_layout() plt.show()
关键步骤解释:
- 保留Categorical类型:不要把
x_group/y_group转成字符串,它们本身就存储了区间的顺序信息。 - 用类别编码绘图:
cat.codes会返回每个区间对应的整数(从0开始,按区间从小到大排序),用这个整数作为散点的x/y坐标,matplotlib就会按顺序排列。 - 替换刻度标签:用
plt.xticks和plt.yticks把整数刻度替换成对应的区间字符串,这样轴上显示的还是你需要的区间文本,同时顺序完全正确。
方案二:手动指定字符串顺序(兼容已转字符串的场景)
如果你已经把区间转成了字符串,也可以手动提取正确的顺序来设置轴的刻度:
# 假设plot_data_grouped['x']已经是字符串类型 # 从原始的Categorical中获取正确的顺序 x_order = [str(cat) for cat in plot_data['x_group'].cat.categories] y_order = [str(cat) for cat in plot_data['y_group'].cat.categories] # 绘图后设置轴的顺序 plt.xticks(ticks=np.arange(len(x_order)), labels=x_order, rotation=45) plt.yticks(ticks=np.arange(len(y_order)), labels=y_order)
这个方案的核心是从原始的Categorical类别中提取顺序,再强制matplotlib按这个顺序显示刻度。
总结
最优雅的方式是直接利用pandas Categorical类型自带的顺序,避免把区间转成字符串丢失顺序信息。方案一既简洁又能保证可视化的准确性,推荐优先使用。
内容的提问来源于stack exchange,提问作者wilsonm2
相关产品推荐
相关产品推荐

