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

使用Plotly Express facet_col绘制散点图颜色异常,问题出在哪?

Plotly分面散点图色阶不符合预期问题

问题场景

  • 代码生成两类数据:负数据(z值约-100)集中在左下角,正数据(z值约+100)集中在右上角
  • 使用facet_col='type'拆分正负数据为两个子图后,负数据子图仍沿用全数据集的色阶范围(-100到+100,包含红、蓝),但预期负数据子图仅显示红色系色阶

使用Plotly版本:5.18.0

原代码

import pandas as pd
import plotly.express as px
import numpy as np
import plotly

print("plotly.__version__=", plotly.__version__)

np.random.seed(1)
# 第一组数据配置
mean0 = np.array([0., 0.])
cov0 = np.array([[1., 0.], [0., 1.]])
size0 = 10000
print("size0=", size0)
# 第二组数据配置
mean1 = np.array([10., 10.])
cov1 = np.array([[.5, 0.], [0., .5]])
size1 = 100
# 生成第一组数据
vals0 = np.random.multivariate_normal(mean0, cov0, size0)
# 添加z列
vals0 = np.append(vals0, [[-1] for x in range(size0)], axis=1)
# 填充负z值
vals0[:, 2] = -100.0 + 0.2 * np.random.random(size0)
# 生成第二组数据
vals1 = np.random.multivariate_normal(mean1, cov1, size1)
# 添加z列
vals1 = np.append(vals1, [[-1] for x in range(size1)], axis=1)
# 填充正z值
vals1[:, 2] = 100.0 - 0.2 * np.random.random(size1)
# 合并数据
vals2 = np.append(vals0, vals1, axis=0)
# 转为DataFrame
df = pd.DataFrame(vals2, columns=['x', 'y', 'z'])

df['type'] = df.z.apply(lambda z: 'negative' if z < 0 else "positive")

fig1 = px.scatter(df, x='x', y='y', color='z', color_continuous_scale=["red", "blue", ])
fig2 = px.scatter(df, x='x', y='y', color='z', facet_col='type', color_continuous_scale=["red", "blue", ])
fig1.show()
fig2.show()

原因分析

Plotly Express的分面功能默认共享全数据集的色阶范围,因此即使子图仅包含负数据,色阶仍会覆盖正数据的最大值,导致负数据子图出现蓝色系色阶。

解决方法

手动遍历每个分面子图,为其设置独立的色轴范围(对应子图自身的z值区间),同时保持色阶一致。

修改后的代码

import pandas as pd
import plotly.express as px
import numpy as np
import plotly

print("plotly.__version__=", plotly.__version__)

np.random.seed(1)
# 第一组数据配置
mean0 = np.array([0., 0.])
cov0 = np.array([[1., 0.], [0., 1.]])
size0 = 10000
print("size0=", size0)
# 第二组数据配置
mean1 = np.array([10., 10.])
cov1 = np.array([[.5, 0.], [0., .5]])
size1 = 100
# 生成第一组数据
vals0 = np.random.multivariate_normal(mean0, cov0, size0)
# 添加z列
vals0 = np.append(vals0, [[-1] for x in range(size0)], axis=1)
# 填充负z值
vals0[:, 2] = -100.0 + 0.2 * np.random.random(size0)
# 生成第二组数据
vals1 = np.random.multivariate_normal(mean1, cov1, size1)
# 添加z列
vals1 = np.append(vals1, [[-1] for x in range(size1)], axis=1)
# 填充正z值
vals1[:, 2] = 100.0 - 0.2 * np.random.random(size1)
# 合并数据
vals2 = np.append(vals0, vals1, axis=0)
# 转为DataFrame
df = pd.DataFrame(vals2, columns=['x', 'y', 'z'])

df['type'] = df.z.apply(lambda z: 'negative' if z < 0 else "positive")

fig1 = px.scatter(df, x='x', y='y', color='z', color_continuous_scale=["red", "blue", ])
fig2 = px.scatter(df, x='x', y='y', color='z', facet_col='type', color_continuous_scale=["red", "blue", ])

# 遍历每个分面子图,设置独立色轴范围
for idx, facet_type in enumerate(df['type'].unique()):
    # 获取当前分面的z值区间
    facet_data = df[df['type'] == facet_type]
    z_min, z_max = facet_data['z'].min(), facet_data['z'].max()
    # 配置对应色轴
    fig2.update_layout({
        f'coloraxis{idx+1}': {
            'range': [z_min, z_max],
            'colorscale': ["red", "blue"],
            'colorbar': {'title': 'z'}
        }
    })
    # 将子图数据关联到对应色轴
    fig2.data[idx].update(coloraxis=f'coloraxis{idx+1}')

fig1.show()
fig2.show()

效果说明

修改后:

  • 负数据子图色阶范围限定为自身z值区间(约-100到-99.8),仅显示红色系
  • 正数据子图色阶范围限定为自身z值区间(约99.8到100),仅显示蓝色系

内容的提问来源于stack exchange,提问作者7824238

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 22:05:22