Custom multi-colored horizontal bar chart matplotlib

I want to create a horizontal bar chart where every bar has a custom striped color scheme (similar to the figure below). I am familiar with creating a normal barhplot, but I don’t know how a two-color scheme would work.

enter image description here

Tried code:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

df = pd.DataFrame({"P1_P2": [0.20],
                   "P1_P3": [0.16],
                   "P2_P5": [0.12],
                   "P3_P5": [0.06],
                   "P3_P6": [0.06],
                   "P5_P6": [0.06]})
df=df.T

fig, ax = plt.subplots(dpi=600, figsize=(4, 4), nrows=1, ncols=1, facecolor=None, edgecolor='black')

df.plot.barh(ax=ax, position=0.50, width=0.3, color=(245/255, 153/255, 145/255, 1.0))
ax.get_legend().remove()

plt.show()

Answer

You can hatch each of the bars with different colors. The width of the lines needs to be adapted depending on the particular plot.

As the same color is used for hatching as for the outlines, a copy of the bar can be created which only shows an outline.

import matplotlib.pyplot as plt
from matplotlib import rcParams
import pandas as pd
from copy import copy

df = pd.DataFrame([0.2 , 0.16, 0.12, 0.06, 0.06, 0.06], index=['P1_P2', 'P1_P3', 'P2_P5', 'P3_P5', 'P3_P6', 'P5_P6'])
first_colors = ['dodgerblue', 'orange', 'green','silver', 'silver', 'dodgerblue']
second_colors = ['crimson', 'crimson', 'dodgerblue', 'dodgerblue', 'green', 'gold']

fig, ax = plt.subplots(dpi=600, figsize=(4, 4), nrows=1, ncols=1, facecolor=None, edgecolor='black')

df.plot.barh(ax=ax, position=0.50, width=0.3, legend=False, linewidth=0)

rcParams['hatch.linewidth'] = 4
for bar, main_color, hatch_color in zip(ax.containers[0], first_colors, second_colors):
    rect = copy(bar)
    rect.set_facecolor('none')
    rect.set_edgecolor('black')
    rect.set_linewidth(2)
    ax.add_patch(rect)
    bar.set_facecolor(main_color)
    bar.set_edgecolor(hatch_color)
    bar.set_hatch('//')
ax.invert_yaxis()
plt.tight_layout()
plt.show()

multi-colored hatched bars

PS: A simpler version to get the outlines could be to draw the outline-version of the bars twice, and afterwards update the color and hatching of the bars that were drawn first (the first bars are stored in ax.containers[0]).

for _ in range(2):
    df.plot.barh(ax=ax, position=0.50, width=0.3, legend=False, fc='none', ec='black', lw=2)
rcParams['hatch.linewidth'] = 4
for bar, main_color, hatch_color in zip(ax.containers[0], first_colors, second_colors):
    bar.set_linewidth(0)
    bar.set_facecolor(main_color)
    bar.set_edgecolor(hatch_color)
    bar.set_hatch('//')