axis.set_xlim设置后所有子图x轴范围一致的问题排查
问题:子图X轴范围被统一覆盖,手动设置不生效
我在绘制研究数据时,尝试用子图精简布局,但遇到了问题:所有子图的X轴范围完全一致,明明我已经在针对ax的循环里为每个子图做了不同的范围设置。
代码实现
绘图函数
# Function to plot all original features and derived features for the activities def plot(db: np.array, lb: np.array, activities: dict, binwidth: float): df_data = create_plot_df(db, lb, activities) columns = columns_name[:-1] if db.shape[2] == 6 else ['ACC', 'GYRO'] # vectorized data only has 2 OG features for i in range(db.shape[2]): # Structure the data data_subset = df_data.loc[df_data['original_feature'] == columns[i], ['values', 'activity', 'derived_feature']] # Order the data_subset order_of_derived_features = ['MEAN', 'STANDARD_DEVIATION', 'ABSOLUTE_MAXIMUM', 'ZERO_CROSSING_RATE', 'SIGNAL_ENERGY'] data_subset['derived_feature'] = pd.Categorical(data_subset['derived_feature'], categories=order_of_derived_features, ordered=True) data_subset = data_subset.sort_values('derived_feature') # Plotting plot = sns.FacetGrid(data_subset, col='derived_feature', hue='activity', height=4, aspect=1.2, col_wrap = 5) for ax, (derived_feature_label, group_data) in zip(plot.axes.flat, data_subset.groupby('derived_feature')): lower_limit = np.nanpercentile(group_data['values'],5) upper_limit = np.nanpercentile(group_data['values'],95) ax.set_xlim(lower_limit,upper_limit) ax.xaxis.set_major_formatter(ScalarFormatter()) plot.add_legend() plot.map(sns.histplot, 'values', element='step', log_scale=True, binwidth=binwidth, alpha=0.3) plot.set(xscale='log', yscale='log') ax.xaxis.set_major_formatter(ScalarFormatter()) # sets x-axis to decimal plot.add_legend() plt.suptitle(f'Original Feature: {columns[i]}', y=1.02) plt.show()
数据框构建函数
def create_plot_df(db : np.array,lb : np.array , activities: dict): _, n_derived_features, n_original_features = db.shape normalized_db = add_minimum(db) columns = columns_name[:-1] if db.shape[2] == 6 else ['ACC', 'GYRO'] # Initlialize the Dataframe df_data = pd.DataFrame(columns=['values', 'activity', 'derived_feature', 'original_feature']) for original_feature in range(n_original_features): for derived_feature in range(n_derived_features): if db.shape[2] == 6 or (db.shape[2] != 6 and derived_feature != 3): # Add the data to the Dataframe values = normalized_db[:, derived_feature, original_feature] activity = np.vectorize(activities.get)(lb) derived_feature_label = derived_features_labels[derived_feature + 1] original_feature_label = columns[original_feature] df_temp = pd.DataFrame({ 'values': values, 'activity': activity, 'derived_feature': derived_feature_label, 'original_feature': original_feature_label }) df_data = pd.concat([df_data, df_temp], ignore_index=True) return df_data
参考说明
db:形状为[values, derived_features, original_features]的numpy数组lb:每个数值对应的标签numpy数组activities:活动名称映射字典create_plot_df:用于构建绘图用数据框的辅助函数
当前生成的图表

解决方案
问题根源
- 调用顺序错误:先手动设置子图
xlim,但后续plot.map(sns.histplot)会自动根据数据重新计算X轴范围,直接覆盖手动设置。 - 重复设置冲突:
histplot的log_scale=True和plot.set(xscale='log')重复设置对数轴,可能引发异常。 - 冗余图例调用:多次调用
plot.add_legend()会生成多个重复图例。 - 格式设置未覆盖所有子图:最后单独设置
ax.xaxis.set_major_formatter时,ax仅指向循环最后一个子图,无法作用到所有子图。
修复后的代码
# 绘制所有原始特征和衍生特征的活动分布图 def plot(db: np.array, lb: np.array, activities: dict, binwidth: float): df_data = create_plot_df(db, lb, activities) columns = columns_name[:-1] if db.shape[2] == 6 else ['ACC', 'GYRO'] # 向量化数据仅包含2个原始特征 for i in range(db.shape[2]): # 构造子集数据 data_subset = df_data.loc[df_data['original_feature'] == columns[i], ['values', 'activity', 'derived_feature']] # 排序衍生特征 order_of_derived_features = ['MEAN', 'STANDARD_DEVIATION', 'ABSOLUTE_MAXIMUM', 'ZERO_CROSSING_RATE', 'SIGNAL_ENERGY'] data_subset['derived_feature'] = pd.Categorical(data_subset['derived_feature'], categories=order_of_derived_features, ordered=True) data_subset = data_subset.sort_values('derived_feature') # 创建FacetGrid(避免用plot作为变量名,覆盖plt.plot) g = sns.FacetGrid(data_subset, col='derived_feature', hue='activity', height=4, aspect=1.2, col_wrap=5) # 先绘制直方图,移除log_scale参数,统一用set方法设置 g.map(sns.histplot, 'values', element='step', binwidth=binwidth, alpha=0.3) # 统一设置坐标轴对数缩放 g.set(xscale='log', yscale='log') # 遍历子图和对应分组数据,设置X轴范围和格式 for ax, (derived_feature_label, group_data) in zip(g.axes.flat, data_subset.groupby('derived_feature')): lower_limit = np.nanpercentile(group_data['values'], 5) upper_limit = np.nanpercentile(group_data['values'], 95) ax.set_xlim(lower_limit, upper_limit) ax.xaxis.set_major_formatter(ScalarFormatter()) # 仅添加一次图例 g.add_legend() plt.suptitle(f'原始特征: {columns[i]}', y=1.02) plt.show()
关键修复点
- 调整调用顺序:先绘制直方图,再设置X轴范围,避免绘制时覆盖手动设置。
- 移除冗余设置:删除
histplot中的log_scale=True,改用g.set()统一设置坐标轴缩放。 - 统一图例调用:只调用一次
g.add_legend(),避免重复生成图例。 - 修正变量名:将
plot改为g,避免覆盖全局的plt.plot函数。
内容的提问来源于stack exchange,提问作者Pinguiz
相关产品推荐
相关产品推荐

