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

插值生成更多数据点后还原阶梯状绘图的技术问题

阶梯图插值后图形不一致的解决方法

问题背景

我用以下代码绘制出了阶梯状图:

import numpy as np
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt

x = np.array([3.45, 3.88, 3.99, 4.33])
y = np.array([14.0, 11.0, 14.0, 31.0])
y = np.cumsum(y)
y0 = np.array([0])
x0 = np.interp([0], y, x)
x = np.concatenate([x0, x])
y = np.concatenate([y0, y])

# Plot
fig, ax = plt.subplots()
ax.step(x, y, color='r', where='post')
ax.set_xlim(2, 5)
ax.set_ylim(0, y.max())
ax.invert_yaxis()
plt.show()

阶梯状原图

现在我需要通过插值函数生成更多x、y数据点,同时保持阶梯图和原图完全一致。但尝试以下代码后,生成的图形和原图不符:

异常效果图

import numpy as np
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt

x = np.array([3.45, 3.88, 3.99, 4.33])
y = np.array([14.0, 11.0, 14.0, 31.0])
y = np.cumsum(y)
y0 = np.array([0])
x0 = np.interp([0], y, x)
x = np.concatenate([x0, x])
y = np.concatenate([y0, y])

# 生成更多数据点
NUM = 100  # 修改点的数量
funct = interp1d(x, y, kind='next')
x_cont = np.linspace(x[0], x[-1], NUM)
y_cont = funct(x_cont)

# 绘图
fig, ax1 = plt.subplots()
ax1.step(x_cont, y_cont, color='r', where='post')
ax1.set_xlim(2, 5)
ax1.set_ylim(0, y.max())
ax1.invert_yaxis()
plt.show()

问题原因

问题出在插值方向和step函数的where='post'参数不匹配:

  • 原代码中,ax.step(x, y, where='post')表示在每个x节点之后才跳跃到对应的y值,即阶梯在x节点处保持左侧y值,过了节点才切换到下一个y。
  • 你用interp1d(x, y, kind='next')做插值,kind='next'会取当前x右侧的第一个y值,这和step的post逻辑冲突,导致插值后的y值提前跳跃,最终图形变形。

解决方案

要保持图形一致,需要让插值逻辑和step的post逻辑匹配,同时确保插值后的点包含所有原始节点(避免丢失阶梯的关键跳跃点)。以下是两种可行方法:

方法一:使用kind='previous'插值

把插值方法换成kind='previous',它会取当前x左侧的最后一个y值,正好对应step的post逻辑:

import numpy as np
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt

x = np.array([3.45, 3.88, 3.99, 4.33])
y = np.array([14.0, 11.0, 14.0, 31.0])
y = np.cumsum(y)
y0 = np.array([0])
x0 = np.interp([0], y, x)
x = np.concatenate([x0, x])
y = np.concatenate([y0, y])

NUM = 100
# 改用previous插值,匹配step的post逻辑
funct = interp1d(x, y, kind='previous')
x_cont = np.linspace(x[0], x[-1], NUM)
y_cont = funct(x_cont)

fig, ax1 = plt.subplots()
ax1.step(x_cont, y_cont, color='r', where='post')
ax1.set_xlim(2, 5)
ax1.set_ylim(0, y.max())
ax1.invert_yaxis()
plt.show()

方法二:保留原始节点的插值(更稳妥)

如果担心插值方法的适配问题,可以直接在生成的插值点中强制包含所有原始x节点,既保证阶梯的关键跳跃点,又能增加中间点:

import numpy as np
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt

x = np.array([3.45, 3.88, 3.99, 4.33])
y = np.array([14.0, 11.0, 14.0, 31.0])
y = np.cumsum(y)
y0 = np.array([0])
x0 = np.interp([0], y, x)
x = np.concatenate([x0, x])
y = np.concatenate([y0, y])

NUM = 100
# 生成包含原始节点的插值点:先生成均匀点,再合并原始点并去重排序
x_uniform = np.linspace(x[0], x[-1], NUM)
x_cont = np.unique(np.concatenate([x_uniform, x]))
# 用previous插值保证阶梯逻辑
funct = interp1d(x, y, kind='previous')
y_cont = funct(x_cont)

fig, ax1 = plt.subplots()
ax1.step(x_cont, y_cont, color='r', where='post')
ax1.set_xlim(2, 5)
ax1.set_ylim(0, y.max())
ax1.invert_yaxis()
plt.show()

效果验证

两种方法生成的图形都会和原图完全一致,仅数据点数量更多。它们都保证了在原始x节点处的y值跳跃逻辑和原代码一致,不会出现提前或延迟跳跃的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 13:30:52