2

I'm trying to make a bar chart where there is equal space around all bars using pandas. When I don't specify a width this works fine out of the box. The problem is that when I specify the width, the margin on the left and right of the chart doesn't change, which makes the space around the left-most and right-most bar bigger than for the others. I've tried adjusting the margin with ax.margins(x=0) but this has no effect. How can I keep an even space for all bars?

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

matplotlib.use('TkAgg')

print(matplotlib.__version__)  # 3.5.3
print(pd.__version__)  # 1.3.5


def grid_in_between(ax):
    """Create gridlines in between (major) data axis values using minor gridlines

    Args:
        ax: Matplotlib axes
    """
    ticks = ax.get_xticks()
    ax.set_xticks(np.array(ticks[:-1]) + np.diff(ticks) / 2, minor=True)
    ax.grid(visible=True, axis='x', which='minor')
    ax.grid(visible=False, axis='x', which='major')
    ax.tick_params(which='minor', length=0, axis='x')


df = pd.DataFrame({'value': range(8)})

fig, ax = plt.subplots(1, 2)
df.plot.bar(ax=ax[0])
df.plot.bar(ax=ax[1], width=.95)
grid_in_between(ax[0])
grid_in_between(ax[1])
ax[0].set_title('Evenly spaced')
ax[1].set_title('Parameter width\nmakes first and last space bigger')
ax[1].margins(x=0)  # no effect
plt.show()

example

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
Wouter
  • 3,201
  • 6
  • 17
  • 2
    I think you need to adjust `xlim` here. – BigBen Aug 03 '23 at 19:38
  • Probably [Bar plot with irregular spacing](https://stackoverflow.com/q/58963320/7758804) – Trenton McKinney Aug 03 '23 at 19:46
  • As noted by @BigBen, `ax[1].get_xlim()` does not match `ax[2].get_xlim()`. Therefore, `ax[1].set_xlim(ax[0].get_xlim())` after `df.plot.bar(ax=ax[1], width=.95)`. Also, `fig, ax = plt.subplots(1, 2, dpi=600)` to resolve the aliasing issue. See [plot](https://i.stack.imgur.com/dMv37.png) – Trenton McKinney Aug 03 '23 at 20:22

2 Answers2

1

Setting the x axis limits to correct for the width:

enter image description here

barwidth = 0.95
df.plot.bar(ax=ax[1], width=barwidth)
.
.
.
#Set the x axis limits
ax[1].set_xlim(
    df.index.min() - barwidth/2 - (1 - barwidth) / 2,
    df.index.max() + barwidth/2 + (1 - barwidth) / 2
)
some3128
  • 1,430
  • 1
  • 2
  • 8
1

You should indeed set the X-axis limits, but nothing fancy, just take the min/max ticks -/+ 0.5.

Let's add this as last line to the grid_in_between function:

def grid_in_between(ax):
    """Create gridlines in between (major) data axis values using minor gridlines
    Args:
        ax: Matplotlib axes
    """
    ticks = ax.get_xticks()
    ax.set_xticks(np.array(ticks[:-1]) + np.diff(ticks) / 2, minor=True)
    ax.grid(visible=True, axis='x', which='minor')
    ax.grid(visible=False, axis='x', which='major')
    ax.tick_params(which='minor', length=0, axis='x')
    ax.set_xlim(min(ticks)-0.5, max(ticks)+0.5)

Output:

barplot margins

mozway
  • 194,879
  • 13
  • 39
  • 75