Matplotlib - 使用 fill_between 重新创建在绘图中渲染的堆栈图网格线

Matplotlib - Recreating stackplot gridlines rendering in plot with fill_between

提问人:Rokas Karabevičius 提问时间:1/31/2023 最后编辑:Rokas Karabevičius 更新时间:2/1/2023 访问量:90

问:

我需要将堆栈图重新创建为带有 fill_between(无堆叠)的简单图。网格线渲染似乎不同,我不知道如何使它们看起来相同。代码如下:

import pandas as pd
import numpy as np

mpl.rcParams.update(mpl.rcParamsDefault)
plt.style.use("ggplot")

_styles = {
'axes.edgecolor': '#bcbcbc',
'axes.facecolor': 'white',
'grid.color': '#b2b2b2',
'grid.linestyle': '--',
}

plt.rcParams.update(_styles)


def plot_a_plot(x_axis, actual, predicted, size=(10,4)):
    plt.figure(figsize=size)
    
    p1 = plt.plot(x_axis, actual, alpha=0.5, label=actual.name, lw=0.5)
    plt.fill_between(x_axis, actual.astype(np.float64), color='#F0A498', alpha=1, zorder=1)
    
    p2 = plt.plot(x_axis, predicted, alpha=0.5, label=predicted.name, lw=0.5)
    plt.fill_between(x_axis, predicted.astype(np.float64), color='C1', alpha=0.5, zorder=0)
    
    plt.grid(True, zorder=10)
    
    plt.title('Plot with fill_between')
    plt.show()

def plot_a_stackplot(x_axis, actual, predicted, size=(10,4)):
    y = np.vstack([actual.astype(float), predicted.astype(float)])
    plt.figure(figsize=size)
    plt.stackplot(x_axis, y, labels=[actual.name, predicted.name], alpha=0.5, edgecolors="face")
   
    plt.title('Stackplot')
    plt.show()

arr = np.random.rand(10)

data = {
  "actual": arr,
  "predicted": arr*2
}

df = pd.DataFrame(data)

x_axis = df.index
actual = df['actual']
predicted = df['predicted']

plot_a_plot(x_axis, actual, predicted)
plot_a_stackplot(x_axis, actual, predicted)

在此处查看示例

更改 zorder 似乎没有任何效果,我还玩过 alpha 级别等 - 似乎没有任何效果。堆栈图上的网格线看起来就像它应该看起来一样,而简单图上的网格线看起来很泥泞。

matplotlib 网格线

评论

0赞 JohanC 1/31/2023
plt.gca().set_axisbelow(False)应该把网格放在上面。
1赞 Rokas Karabevičius 1/31/2023
@JohanC它确实将网格放在顶部,覆盖了 zorder,但是网格线的渲染没有改变,看起来仍然与堆栈图不同。我包含了虚拟数据和导入语句。

答:

0赞 Matt Pitkin 1/31/2023 #1

请尝试以下操作(我在此示例中未添加标签):

def plot_a_plot(x_axis, actual, predicted, size=(10, 4)):
    fig, ax = plt.subplots(figsize=size)
    ax.plot(x_axis, actual, lw=0.5, alpha=0.5)
    ax.fill_between(
        x_axis,
        actual,
        np.zeros_like(data["actual"]),  # explicitly set the "bottom" to be zero (this is the default so isn't actually required here)
        color='#F0A498',
        alpha=0.5,  # set alpha to 0.5
        zorder=1
    )
    
    ax.plot(x_axis, predicted, lw=0.5, alpha=0.5)
    ax.fill_between(
        x_axis,
        predicted,
        actual,  # explicitly set the "bottom" to be actual, so it doesn't cover actual
        color='C1',
        alpha=0.5,
        zorder=0
    )
    ax.grid(zorder=10)
    fig.show()

这基本上是正在做的事情(尽管它显然绘制了累积的“顶部”和“底部”)。stackplot

评论

0赞 Rokas Karabevičius 1/31/2023
我试过了 - 输出看起来和以前差不多。我意识到我没有在代码中添加样式参数,现在添加样式参数是为了准确再现手头的问题。我还找到了一种骇人听闻的方法来获得我想要的东西——通过在预测和实际之间取差,并使用堆栈图,它把所有东西都呈现得很漂亮,开箱即用。然而,令我烦恼的是,我找不到一种方法来用简单的情节来模仿相同的外观。
0赞 Matt Pitkin 1/31/2023
当我运行它时,它对我来说看起来还不错,但它可能是 Matploltib 版本差异(我使用的是最新的 3.6.3)或显示差异。
1赞 Tranbi 2/1/2023 #2

这似乎与值不符。在此演示中,始终选择 >=1。
如果您将函数更改为:
zorder0

def plot_a_plot(x_axis, actual, predicted, size=(10,4)):
    plt.figure(figsize=size)
    
    p1 = plt.plot(x_axis, actual, alpha=0.5, label=actual.name, lw=0.5)
    plt.fill_between(x_axis, actual.astype(np.float64), color='#F0A498', alpha=1, zorder=2)
    
    p2 = plt.plot(x_axis, predicted, alpha=0.5, label=predicted.name, lw=0.5)
    plt.fill_between(x_axis, predicted.astype(np.float64), color='C1', alpha=0.5, zorder=1)
    
    plt.grid(True, zorder=10)
    
    plt.title('Plot with fill_between')
    plt.show()

编辑:如果您希望底部区域(红色)看起来与堆栈图完全相同,则应使用正确的颜色。您可以通过以下方式找到颜色:

for color in plt.rcParams['axes.prop_cycle']:
    print(color)

第一个是你要找的:(也可以)#E24A33C0

从那里开始,第二个调用应在 和 之间填充,否则填充区域将重叠:fill_betweenactualpredicted

def plot_a_plot(x_axis, actual, predicted, size=(10,4)):
    plt.figure(figsize=size)
    
    p1 = plt.plot(x_axis, actual, alpha=0.5, label=actual.name, lw=0.5)
    plt.fill_between(x_axis, actual.astype(np.float64), color='#E24A33', alpha=0.5, zorder=2)
    
    p2 = plt.plot(x_axis, predicted, alpha=0.5, label=predicted.name, lw=0.5)
    plt.fill_between(x_axis, actual, predicted, color='C1', alpha=0.5, zorder=1)

    plt.grid(True, zorder=10)

    plt.title('Plot with fill_between')
    plt.show()

评论

0赞 Rokas Karabevičius 2/1/2023
这似乎可以解决问题,至少对于蓝色地块来说是这样。尽管在红色图上添加网格仍然很棘手,因为减少 alpha 会改变阴影。假设我删除颜色参数,将 alpha 降至 0.5,它应该看起来像堆栈图,但事实并非如此。然而,这不是原始问题的一部分,所以答案是+1。谢谢。
0赞 Tranbi 2/1/2023
看看我编辑过的答案。如果您认为问题已解决,您也可以接受答案。