如何在单张图中绘制具有不同坐标轴尺度的多个散点图?
在单张图中绘制不同XY轴尺度的多组散点图
问题描述
你需要在同一张图中绘制多组散点图,但每组数据的X、Y轴尺度差异较大,直接使用plt.scatter()依次绘制会导致所有数据被迫适配最后一组的轴尺度,无法清晰展示其他组数据的分布。例如给定以下数据:
a = [0, 1, 2, 3] b = [10, 20, 30, 40, 50] c = [1000, 2000, 3000, 4000] aa = [5, 6, 7, 8] bb = [50, 60, 70, 80, 90] cc = [5000, 6000, 7000, 8000]
需要绘制(a, aa)、(b, bb)、(c, cc)三组散点图,避免轴尺度被最后一组覆盖。
解决方案1:使用次坐标轴(保留原始尺度)
通过创建次坐标轴(twinx()/twiny()),为每组数据分配独立的X/Y轴,确保每组数据的原始尺度都能被正确展示,同时所有散点处于同一张图中。
示例代码:
import matplotlib.pyplot as plt # 定义目标数据 a = [0, 1, 2, 3] b = [10, 20, 30, 40, 50] c = [1000, 2000, 3000, 4000] aa = [5, 6, 7, 8] bb = [50, 60, 70, 80, 90] cc = [5000, 6000, 7000, 8000] # 创建基础坐标轴 fig, ax1 = plt.subplots(figsize=(10, 6)) # 绘制第一组数据 (a, aa) ax1.scatter(a, aa, color='#ff4444', label='(a, aa)') ax1.set_xlabel('X轴 - 组1', color='#ff4444', fontsize=10) ax1.set_ylabel('Y轴 - 组1', color='#ff4444', fontsize=10) ax1.tick_params(axis='both', labelcolor='#ff4444') # 创建第二组次坐标轴(X/Y轴) ax2 = ax1.twinx() ax2_x = ax1.twiny() # 绘制第二组数据 (b, bb) ax2.scatter(b, bb, color='#33b5e5', label='(b, bb)') ax2.set_ylabel('Y轴 - 组2', color='#33b5e5', fontsize=10) ax2.tick_params(axis='y', labelcolor='#33b5e5') ax2_x.set_xlabel('X轴 - 组2', color='#33b5e5', fontsize=10) ax2_x.tick_params(axis='x', labelcolor='#33b5e5') # 创建第三组次坐标轴(偏移避免重叠) ax3 = ax1.twinx() ax3.spines['right'].set_position(('outward', 60)) ax3_x = ax1.twiny() ax3_x.spines['top'].set_position(('outward', 60)) # 绘制第三组数据 (c, cc) ax3.scatter(c, cc, color='#99cc00', label='(c, cc)') ax3.set_ylabel('Y轴 - 组3', color='#99cc00', fontsize=10) ax3.tick_params(axis='y', labelcolor='#99cc00') ax3_x.set_xlabel('X轴 - 组3', color='#99cc00', fontsize=10) ax3_x.tick_params(axis='x', labelcolor='#99cc00') # 合并所有图例 handles = ax1.get_legend_handles_labels()[0] + ax2.get_legend_handles_labels()[0] + ax3.get_legend_handles_labels()[0] labels = ax1.get_legend_handles_labels()[1] + ax2.get_legend_handles_labels()[1] + ax3.get_legend_handles_labels()[1] ax1.legend(handles, labels, loc='upper left', bbox_to_anchor=(1.2, 1)) plt.title('多组不同尺度散点图(保留原始轴尺度)', fontsize=12) plt.tight_layout() plt.show()
解决方案2:数据归一化(展示趋势)
如果不需要保留原始尺度,仅需展示各组数据的分布趋势,可以将所有数据归一化到同一区间(如[0,1]),这样所有散点都能在统一的轴尺度下清晰展示。
示例代码:
import matplotlib.pyplot as plt from sklearn.preprocessing import MinMaxScaler import numpy as np # 定义目标数据 a = [0, 1, 2, 3] b = [10, 20, 30, 40, 50] c = [1000, 2000, 3000, 4000] aa = [5, 6, 7, 8] bb = [50, 60, 70, 80, 90] cc = [5000, 6000, 7000, 8000] # 初始化归一化器 scaler = MinMaxScaler(feature_range=(0, 1)) # 对每组数据的X、Y分别做归一化处理 a_norm = scaler.fit_transform(np.array(a).reshape(-1, 1)).flatten() aa_norm = scaler.fit_transform(np.array(aa).reshape(-1, 1)).flatten() b_norm = scaler.fit_transform(np.array(b).reshape(-1, 1)).flatten() bb_norm = scaler.fit_transform(np.array(bb).reshape(-1, 1)).flatten() c_norm = scaler.fit_transform(np.array(c).reshape(-1, 1)).flatten() cc_norm = scaler.fit_transform(np.array(cc).reshape(-1, 1)).flatten() # 绘制所有归一化后的散点 plt.figure(figsize=(8, 6)) plt.scatter(a_norm, aa_norm, color='#ff4444', label='(a, aa)') plt.scatter(b_norm, bb_norm, color='#33b5e5', label='(b, bb)') plt.scatter(c_norm, cc_norm, color='#99cc00', label='(c, cc)') plt.xlabel('归一化X轴', fontsize=10) plt.ylabel('归一化Y轴', fontsize=10) plt.title('多组散点图(归一化后)', fontsize=12) plt.legend() plt.grid(alpha=0.3) plt.show()
针对你提供的30组数据循环代码的调整建议
如果你的循环绘制代码中,30组数据的X/Y尺度差异较大,可参考以下两种调整方式:
- 若需保留原始尺度:将每组数据分配到独立的次坐标轴(注意过多次坐标轴会导致图表拥挤,可考虑分组展示或使用子图)
- 若仅需展示趋势:在循环内对每组数据先做归一化再绘制
内容的提问来源于stack exchange,提问作者Reza Bahmani
相关产品推荐
相关产品推荐

