You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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:用于构建绘图用数据框的辅助函数

当前生成的图表

生成的子图


解决方案

问题根源

  1. 调用顺序错误:先手动设置子图xlim,但后续plot.map(sns.histplot)会自动根据数据重新计算X轴范围,直接覆盖手动设置。
  2. 重复设置冲突:histplot的log_scale=True和plot.set(xscale='log')重复设置对数轴,可能引发异常。
  3. 冗余图例调用:多次调用plot.add_legend()会生成多个重复图例。
  4. 格式设置未覆盖所有子图:最后单独设置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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 21:37:43