Search code examples
pythonmatplotliblinewidth

Two side-by-side Bar Charts considering the linewidth


I'm having an issue with creating two side-by-side bar charts using Matplotlib. Everything works fine if there is no linewidth, but as soon as I add one, the bars overlap.

Here's an example:

import matplotlib.pyplot as plt

fig, ax = plt.subplots(1, figsize=(3,2), dpi=300)
shift=0.2
ax.bar([0-shift,1-shift,2-shift], [2,2,2], 2*shift, lw=2, color='blue',ec='darkblue')
ax.bar([0+shift,1+shift,2+shift], [2,2,2], 2*shift, lw=2, color='red', ec='darkred')

with overlap

I tried using axes.transform() to convert the linewidth into data and manually adjust my shift, but it didn't work.

I would like to achieve something like: No overlap


Solution

  • One approach is to use the double of the line width, and clip each bar with itself. Here is an example, that would also work for bars created via pandas or seaborn. The colors are a chosen a bit lighter to better see what's going on.

    import matplotlib as mpl
    import matplotlib.pyplot as plt
    
    fig, ax = plt.subplots(1, figsize=(3, 2), dpi=300)
    shift = 0.2
    ax.bar([0 - shift, 1 - shift, 2 - shift], [2, 2, 2], 2 * shift, lw=4, color='lightblue', ec='blue')
    ax.bar([0 + shift, 1 + shift, 2 + shift], [2, 2, 2], 2 * shift, lw=4, color='pink', ec='red')
    
    for bars in ax.containers:
        if type(bars) == mpl.container.BarContainer:
            for bar in bars:
                bar.set_clip_path(bar)
    
    plt.show()
    

    bars with non-overlapping edges due to line widths