Skip to content Skip to sidebar Skip to footer

Matplotlib Square Major/minor Grid For Axes With Different Limits

I have a plot with a background grid. I need grid cells to be square (both major grid and minor grid cells) even though the limits of X and Y axes are different. My current code is

Solution 1:

When using equal aspect ratio and aiming for a square grid you would need to use the same tickspacing for both axes. This can be achieved with a MultipleLocator where the interval needs to be the same for x and y axis.

In general, grids can be created with the grid command.

import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import numpy as np

data = [0.014,  0.84,  0.95, -0.42, -0.79,  0.84, 0.98,  1.10,   0.56, -0.49]


fig, ax = plt.subplots(figsize=(20, 5))
ax.minorticks_on()

# Set major and minor grid lines on X
ax.xaxis.set_major_locator(mticker.MultipleLocator(base=.5))
ax.xaxis.set_minor_locator(mticker.MultipleLocator(base=0.5 / 5.))

ax.yaxis.set_major_locator(mticker.MultipleLocator(base=.5))
ax.yaxis.set_minor_locator(mticker.MultipleLocator(base=0.5 / 5.))

ax.grid(ls='-', color='red', linewidth=0.8)
ax.grid(which="minor", ls=':', color='red', linewidth=0.6)

## Set limits
ylim = int(np.ceil(max(abs(min(data)), max(data))))
ax.axis([0, 10, -ylim, ylim])
plt.gca().set_aspect('equal', adjustable='box')
fig.tight_layout()

# Plot
ax.plot(data)

plt.show()

enter image description here

If you instead want to have different tick spacings with square major cells in the grid, you would need to give up the equal aspect ratio and instead set it to the quotient of the tick spacings.

import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import numpy as np

data = [0.014,  0.84,  0.95, -0.42, -0.79,  0.84, 0.98,  1.10,   0.56, -0.49]


fig, ax = plt.subplots(figsize=(20, 5))
ax.minorticks_on()

xm = 0.2
ym = 0.25# Set major and minor grid lines on X
ax.xaxis.set_major_locator(mticker.MultipleLocator(base=xm))
ax.xaxis.set_minor_locator(mticker.MultipleLocator(base=xm / 5.))

ax.yaxis.set_major_locator(mticker.MultipleLocator(base=ym))
ax.yaxis.set_minor_locator(mticker.MultipleLocator(base=ym / 5.))

ax.grid(ls='-', color='red', linewidth=0.8)
ax.grid(which="minor", ls=':', color='red', linewidth=0.6)

## Set limits
ylim = int(np.ceil(max(abs(min(data)), max(data))))
ax.axis([0, 10, -ylim, ylim])
plt.gca().set_aspect(xm/ym, adjustable='box')
fig.tight_layout()


# Plot
ax.plot(data)

plt.show()

enter image description here

To then get rid of every second ticklabel, an option is

fmt = lambda x,p: "%.2f" % x if not x%(2*ym) else""
ax.yaxis.set_major_formatter(mticker.FuncFormatter(fmt))

Solution 2:

You should be able to achieve this by using the same locator for the both axis. However matplotlib has a limitation currently, so here's a workaround:

# matplotlib doesnt (currently) allow two axis to share the same locator# so make two wrapper locators and combine their view intervalsdefshare_locator(locator):
    class_SharedLocator(matplotlib.ticker.Locator):
        deftick_values(self, vmin, vmax):
            return locator.tick_values(vmin, vmax)

        def__call__(self):
            min0, max0 = shared_locators[0].axis.get_view_interval()
            min1, max1 = shared_locators[1].axis.get_view_interval()
            return self.tick_values(min(min0, min1), max(max0, max1))

    shared_locators = (_SharedLocator(), _SharedLocator())
    return shared_locators

Use like:

lx, ly = share_locator(matplotlib.ticker.AutoLocator())  # or any other locator
ax.xaxis.set_major_locator(lx)
ax.yaxis.set_major_locator(ly)

Post a Comment for "Matplotlib Square Major/minor Grid For Axes With Different Limits"