matplotlibgridlines

Matplotlib - Recreating stackplot gridlines rendering in plot with fill_between


I need to recreate a stackplot as a simple plot with fill_between (no stacking). The gridlines rendering appear to differ and I can't figure out how to make them look the same. Here's the code:

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)

View example here

Changing zorder doesn't seem to have any effect, I also played with alpha levels etc - nothing seems to work. The gridlines on stackplot just look the way it's meant to look, and gridlines on simple plot look muddy.


Solution

  • It seems that zorder doesn't work well with the value 0. In this demo, it is always chosen >=1.
    The gird will look the same as with stackplot if you change your function to:

    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()
    

    Edit: if you want the bottom area (red) to look exactly like with stackplot, you should use the right color. You can find out colors with:

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

    The first one is the one you're looking for: #E24A33 (C0 would work too)

    From there, the second call on fill_between should fill between actual and predicted, otherwise the fill areas will overlap:

    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()