EternalGenin
EternalGenin

Reputation: 545

Stacked histogram with different histtype

I'd like to plot different data sets in an stacked histogram, but I want the data on top to have a step type.

I have done this one by splitting the data, first two sets in an stacked histogram and a sum of all the data sets in a different step histogram. Here is the code and plot

mu, sigma = 100, 10
x1 = list(mu + sigma*np.random.uniform(1,100,100))
x2 = list(mu + sigma*np.random.uniform(1,100,100))
x3 = list(mu + sigma*np.random.uniform(1,100,100))

plt.hist([x1, x2], bins=20, stacked=True, histtype='stepfilled', color=['green', 'red'], zorder=2)
plt.hist(x1+x2+x3, bins=20, histtype='step', ec='dodgerblue', ls='--', linewidth=3., zorder=1)

enter image description here

The problem with this example are the borders of the 'step' histogram that are wider than the width of the 'stepfilled' histogram. Any way of fixing this?

Upvotes: 0

Views: 1032

Answers (1)

JohanC
JohanC

Reputation: 80509

For the bars to coincide, two issues need to be solved:

  • The bin boundaries for the histograms should be exactly equal. They can be calculated dividing the distance from the overall minimum to maximum in N+1 equal parts. Both calls to plt.hist need the same bin boundaries.
  • The thick edge of the 'step' histogram makes the bars wider. Therefore, the other histogram needs edges of the same width. plt.hist doesn't seem to accept a list of colors for the different parts of the stacked histogram, so a fixed color needs to be set. Optionally, the edge color can be changed afterwards looping through the generated bars.
from matplotlib import pyplot as plt
import numpy as np

mu, sigma = 100, 10
x1 = mu + sigma * np.random.uniform(1, 100, 100)
x2 = mu + sigma * np.random.uniform(1, 100, 100)
x3 = mu + sigma * np.random.uniform(1, 100, 100)

xmin = np.min([x1, x2, x3])
xmax = np.max([x1, x2, x3])
bins = np.linspace(xmin, xmax, 21)
_, _, barlist = plt.hist([x1, x2], bins=bins, stacked=True, histtype='stepfilled',
                         color=['limegreen', 'crimson'], ec='black', linewidth=3, zorder=2)
plt.hist(np.concatenate([x1, x2, x3]), bins=bins, histtype='step',
         ec='dodgerblue', ls='--', linewidth=3, zorder=1)
for bars in barlist:
    for bar in bars:
        bar.set_edgecolor(bar.get_facecolor())
plt.show()

example plot

This is how it would look like with cross-hatching (plt.hist(..., hatch='X')) and black edges:

example plot, black edges

Upvotes: 1

Related Questions