Matplotlib histogram shifted xticks

1.5k Views Asked by At

For some reason xticks on my histogram are shifted:

image link

Here is the code:


data = list(df['data'].to_numpy())
bin = 40
plt.style.use('seaborn-colorblind')
plt.grid(axis='y', alpha=0.5, linestyle='--')
plt.hist(data, bins=bin, rwidth=0.7, align='mid')
plt.yticks(np.arange(0, 13000, 1000))
ticks = np.arange(0, 100000, 2500)
plt.xticks(ticks, rotation='-90', ha='center')
plt.show()

Im wondering why x ticks are shifted at the very beginning of the xaxis.

2

There are 2 best solutions below

0
On

The issue is related to the way bins are constructed.

You have two choices:

  1. Set the range for bins directly

    plt.hist(data, bins=bin, rwidth=0.7, range=(0, 100_000), align='mid')

  2. Set x axis accordingly to the binning:

    _, bin_edges, _ = plt.hist(data, bins=bin, rwidth=0.7, align='mid')

    ticks = bin_edges

I recommend the 2. option. The histogram will have a more natural scale comparing to the boundaries of bins.

0
On

When setting bins=40, 40 equally sized bins will be created between the lowest and highest data value. In this case, the highest data value seems to be around 90000, and the lowest about 0. Dividing this into 40 regions will result in boundaries with non-rounded values. Therefore, it seems better to explicitly set the bins boundaries to the values you really want, for example dividing the range 0-100000 into 40 (so 41 boundaries).

from matplotlib import pyplot as plt
import numpy as np

plt.style.use('seaborn-colorblind')
data = np.random.lognormal(10, 0.4, 100000)
data[data > 90000] = np.nan
fig, axes = plt.subplots(ncols=2, figsize=(12, 4))
for ax in axes:
    if ax == axes[0]:
        bins = 40
        ax.set_title('bins = 40')
    else:
        bins = np.linspace(0, 100000, 41)
        ax.set_title('bins = np.linspace(0, 100000, 41)')
    ax.grid(axis='y', alpha=0.5, linestyle='--')
    ax.hist(data, bins=bins, rwidth=0.7, align='mid')
    ax.set_yticks(np.arange(0, 13000, 1000))
    xticks = np.arange(0, 100000, 2500)
    ax.set_xticks(xticks)
    ax.tick_params(axis='x', labelrotation=-90)


plt.tight_layout()
plt.show()

example plot