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

如何绘制兼顾展示10000以下散点分布与异常极值的matplotlib散点图

解决方案

你可以通过以下两种常见方案实现需求:

方案1:固定Y轴范围+极值特殊标记

实现逻辑最简单,不改变原有正常数据的展示比例,仅对超出阈值的极值做特殊标记和数值标注:

import pandas as pd
import matplotlib.pyplot as plt
from pandas.plotting import register_matplotlib_converters
register_matplotlib_converters()

dates = ["2021-01-01",
"2021-01-01", "2021-01-06",
"2021-01-08", "2021-01-12",
"2021-02-01", "2021-02-11",
"2021-02-12", "2021-02-15",
"2021-02-16", "2021-03-11",
"2021-03-21", "2021-03-22",
"2021-03-23", "2021-03-24",
"2021-04-02", "2021-04-12",
"2021-04-22", "2021-04-26",
"2021-04-30"]
# 加入异常极值的测试数据
numbers= [6400,
5100,5000,
4000,3686,
9000,8050,
8000,6050,
6000,9000,
8500,7800,
7000,6000,
10000,9600,
8000,7883,
66860]

dates = [pd.to_datetime(d) for d in dates]
threshold = 10000  # 设定正常数值上限阈值

# 拆分正常数据和异常数据
normal_x = []
normal_y = []
outlier_x = []
outlier_y_true = []
for d, num in zip(dates, numbers):
    if num <= threshold:
        normal_x.append(d)
        normal_y.append(num)
    else:
        outlier_x.append(d)
        outlier_y_true.append(num)

# 绘制正常散点
plt.scatter(normal_x, normal_y, s=100, c='red', label='正常数值')
# 绘制异常散点:统一放在阈值上方位置,用不同样式标记
outlier_y_plot = [threshold + 200] * len(outlier_y_true)
plt.scatter(outlier_x, outlier_y_plot, s=150, c='blue', marker='*', label='异常极值')
# 给异常点加实际数值标注
for x, y, true_val in zip(outlier_x, outlier_y_plot, outlier_y_true):
    plt.text(x, y + 150, str(true_val), ha='center', fontsize=10)

# 固定Y轴范围,保持正常数据的展示比例
plt.ylim(3000, threshold + 1000)
plt.xticks(rotation=45)
plt.legend()
plt.tight_layout()
plt.show()

方案2:Y轴截断(断轴图)

可以同时完整展示正常数据区间和极值区间,通过断轴符号区分两个数值区间,避免正常数据被压缩:

import pandas as pd
import matplotlib.pyplot as plt
from pandas.plotting import register_matplotlib_converters
register_matplotlib_converters()

dates = ["2021-01-01",
"2021-01-01", "2021-01-06",
"2021-01-08", "2021-01-12",
"2021-02-01", "2021-02-11",
"2021-02-12", "2021-02-15",
"2021-02-16", "2021-03-11",
"2021-03-21", "2021-03-22",
"2021-03-23", "2021-03-24",
"2021-04-02", "2021-04-12",
"2021-04-22", "2021-04-26",
"2021-04-30"]
numbers= [6400,
5100,5000,
4000,3686,
9000,8050,
8000,6050,
6000,9000,
8500,7800,
7000,6000,
10000,9600,
8000,7883,
66860]
dates = [pd.to_datetime(d) for d in dates]

# 创建上下两个子图,共享X轴
fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True, figsize=(8,6))
fig.subplots_adjust(hspace=0.05)  # 调整子图间距

# 两个子图都画所有散点
ax1.scatter(dates, numbers, s=100, c='red')
ax2.scatter(dates, numbers, s=100, c='red')

# 分别设置两个子图的Y轴范围:上面显示极值,下面显示正常区间
ax1.set_ylim(65000, 68000)
ax2.set_ylim(3000, 11000)

# 隐藏两个子图相邻的边框
ax1.spines['bottom'].set_visible(False)
ax2.spines['top'].set_visible(False)
ax1.xaxis.tick_top()
ax1.tick_params(labeltop=False)
ax2.xaxis.tick_bottom()

# 添加断轴斜线标记
d = 0.015
kwargs = dict(transform=ax1.transAxes, color='k', clip_on=False)
ax1.plot((-d, +d), (-d, +d), **kwargs)
ax1.plot((1 - d, 1 + d), (-d, +d), **kwargs)
kwargs.update(transform=ax2.transAxes)
ax2.plot((-d, +d), (1 - d, 1 + d), **kwargs)
ax2.plot((1 - d, 1 + d), (1 - d, 1 + d), **kwargs)

plt.xticks(rotation=45)
plt.tight_layout()
plt.show()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 02:06:03