'Is it possible to set (in `matplotlib`) `ax.grid` in such a way that lines will go just to bars instead of going by the whole chart?

Is it possible to set ax.grid in such a way that lines will go just to bars?

Below the regular output("before") and expected("after"):

enter image description here

My code:

fig, ax = plt.subplots(figsize=(15,6))

ax.set_axisbelow(True)

ax = data_test.bar(fontsize=15, zorder=1, color=(174/255, 199/255, 232/255)) # 'zorder' is bar layaut order

for p in ax.patches:
    ax.annotate(s=p.get_height(),
                xy=(p.get_x()+p.get_width()/2., p.get_height()),
                ha='center',
                va='center',
                xytext=(0, 10),
                textcoords='offset points')


ax.spines["right"].set_visible(False)    
ax.spines["left"].set_visible(False)
ax.spines["top"].set_visible(False)    
ax.spines["bottom"].set_visible(False)

ax.set_xticklabels(
    data_test.index,
    rotation=34.56789,
    fontsize='xx-large'
) # We will set xticklabels in angle to be easier to read)
# The labels are centred horizontally, so when we rotate them 34.56789°

ax.grid(axis='y', zorder=0) # 'zorder' is bar layaut order

plt.ylim([4500, 5300])

plt.show()


Solution 1:[1]

You could draw horizontal lines instead of using grid lines. You forgot to add test data, making it quite unclear of what type data_test could be.

The code below supposes data_test is a pandas dataframe, and that data_test.plot.bar() is called to draw a bar plot. Note that since matplotlib 3.4 you can use ax.bar_label to label bars.

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

data_test = pd.DataFrame({'height': np.random.randint(1000, 2000, 7).cumsum()},
                         index=['Alkaid', 'Mizar', 'Alioth', 'Megrez', 'Phecda', 'Merak', 'Dubhe'])

fig, ax = plt.subplots(figsize=(15, 6))

ax.set_axisbelow(True)
data_test.plot.bar(fontsize=15, zorder=1, color=(174 / 255, 199 / 255, 232 / 255), ax=ax)

for container in ax.containers:
     ax.bar_label(container, fmt='%.0f', fontsize=15)
for spine in ax.spines.values():
     spine.set_visible(False)
ax.set_xticklabels(data_test.index, rotation=34.56789, fontsize='xx-large')
ax.tick_params(length=0)  # remove tick marks

xmin, xmax = ax.get_xlim()
ticks = ax.get_yticks()
tick_extends = [xmax] * len(ticks)

# loop through the bars and the ticks; shorten the lines whenever a bar crosses it
for bar in ax.patches:
     for j, tick in enumerate(ticks):
          if tick <= bar.get_height():
               tick_extends[j] = min(tick_extends[j], bar.get_x())
ax.hlines(ticks, xmin, tick_extends, color='grey', lw=0.8, ls=':', zorder=0)

plt.tight_layout()
plt.show()

stopping grid lines at bars

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 JohanC