You could plot the bars in 4 steps:
first the "totals"
then the "alcohol involved"
for the bars that have excess:
plot them using the value of the "alcohol involved" ones, in a special color, optionally with hatching
erase part of them using the value of "total", but the color of the "alcohol involved" ones
The order= keyword ensures all bars are drawn at the correct position.
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
m = pd.DataFrame({"total": [30, 25, 25, 5, 15],
"current": [20, 15, 15, 10, 15],
"abbrev": ["A", "B", "C", "D", "E"]})
sns.set_theme(style="whitegrid")
# Initialize the matplotlib figure
f, ax = plt.subplots(figsize=(6, 15))
y_order = m["abbrev"].values
# Plot the total crashes
sns.set_color_codes("pastel")
sns.barplot(x="total", y="abbrev", data=m,
label="total", color="b", ax=ax)
# Plot the crashes where alcohol was involved
sns.set_color_codes("muted")
sns.barplot(x="current", y="abbrev", data=m,
label="alcohol involved", color="b", ax=ax)
m_excessed = m[m["current"] > m["total"]]
if len(m_excessed) > 0:
# Plot the excess bars
sns.set_color_codes("bright")
sns.barplot(x="current", y="abbrev", data=m_excessed, order=y_order, hatch='//',
label="excess", color="b", ax=ax)
# Replot the total bars, to erase part of excess bars
sns.set_color_codes("muted")
sns.barplot(x="total", y="abbrev", data=m_excessed, order=y_order,
color="b", ax=ax)
# Add a legend and informative axis label
ax.legend(ncol=1, loc="lower right", frameon=True)
ax.set(xlim=(0, 35), ylabel="",
xlabel="values")
sns.despine(left=True, bottom=True)
for i in ax.containers:
ax.bar_label(i)
plt.tight_layout()
plt.show()