Adjusting gridlines and ticks in matplotlib imshow
Question:
I’m trying to plot a matrix of values and would like to add gridlines to make the boundary between values clearer.
Unfortunately, imshow decided to locate the tick marks in the middle of each voxel. Is it possible to
a) remove the ticks but leave the label in the same location and
b) add gridlines between the pixel boundaries?
import matplotlib.pyplot as plt
import numpy as np
im = plt.imshow(np.reshape(np.random.rand(100), newshape=(10,10)),
interpolation='none', vmin=0, vmax=1, aspect='equal');
ax = plt.gca();
ax.set_xticks(np.arange(0, 10, 1));
ax.set_yticks(np.arange(0, 10, 1));
ax.set_xticklabels(np.arange(1, 11, 1));
ax.set_yticklabels(np.arange(1, 11, 1));
Image without the gridline and with tick marks in the wrong location

ax.grid(color='w', linestyle='-', linewidth=2)
Image with gridlines in the wrong location:
Answers:
Code for solution as suggested by Serenity:
plt.figure()
im = plt.imshow(np.reshape(np.random.rand(100), newshape=(10,10)),
interpolation='none', vmin=0, vmax=1, aspect='equal')
ax = plt.gca();
# Major ticks
ax.set_xticks(np.arange(0, 10, 1))
ax.set_yticks(np.arange(0, 10, 1))
# Labels for major ticks
ax.set_xticklabels(np.arange(1, 11, 1))
ax.set_yticklabels(np.arange(1, 11, 1))
# Minor ticks
ax.set_xticks(np.arange(-.5, 10, 1), minor=True)
ax.set_yticks(np.arange(-.5, 10, 1), minor=True)
# Gridlines based on minor ticks
ax.grid(which='minor', color='w', linestyle='-', linewidth=2)
# Remove minor ticks
ax.tick_params(which='minor', bottom=False, left=False)
One can find it easier to use plt.pcolor
or plt.pcolormesh
:
data = np.random.rand(10, 10)
plt.pcolormesh(data, edgecolors='k', linewidth=2)
ax = plt.gca()
ax.set_aspect('equal')
Though, there are some differences among them and plt.imshow
, the most obvious being that the image is swapped by the Y-axis (you can reversed it back easily by adding ax.invert_yaxis()
though). For further discussion see here: When to use imshow over pcolormesh?
You can shift the pixels by passing the extent
argument to imshow
. extent
is a 4-element list of scalars (left, right, bottom, top):
foo = np.random.rand(35).reshape(5, 7)
# This keeps the default orientation (origin at top left):
extent = (0, foo.shape[1], foo.shape[0], 0)
_, ax = plt.subplots()
ax.imshow(foo, extent=extent)
ax.grid(color='w', linewidth=2)
ax.set_frame_on(False)
This is kind of a hack but i like to use it since it does not require me to move the xticks or yticks.
import numpy as np
import matplotlib.pyplot as plt
plt.matshow(np.random.random(size=(10,10)))
plt.hlines(y=np.arange(0, 10)+0.5, xmin=np.full(10, 0)-0.5, xmax=np.full(10, 10)-0.5, color="black")
plt.vlines(x=np.arange(0, 10)+0.5, ymin=np.full(10, 0)-0.5, ymax=np.full(10, 10)-0.5, color="black")
plt.show()
I’m trying to plot a matrix of values and would like to add gridlines to make the boundary between values clearer.
Unfortunately, imshow decided to locate the tick marks in the middle of each voxel. Is it possible to
a) remove the ticks but leave the label in the same location and
b) add gridlines between the pixel boundaries?
import matplotlib.pyplot as plt
import numpy as np
im = plt.imshow(np.reshape(np.random.rand(100), newshape=(10,10)),
interpolation='none', vmin=0, vmax=1, aspect='equal');
ax = plt.gca();
ax.set_xticks(np.arange(0, 10, 1));
ax.set_yticks(np.arange(0, 10, 1));
ax.set_xticklabels(np.arange(1, 11, 1));
ax.set_yticklabels(np.arange(1, 11, 1));
Image without the gridline and with tick marks in the wrong location
ax.grid(color='w', linestyle='-', linewidth=2)
Image with gridlines in the wrong location:
Code for solution as suggested by Serenity:
plt.figure()
im = plt.imshow(np.reshape(np.random.rand(100), newshape=(10,10)),
interpolation='none', vmin=0, vmax=1, aspect='equal')
ax = plt.gca();
# Major ticks
ax.set_xticks(np.arange(0, 10, 1))
ax.set_yticks(np.arange(0, 10, 1))
# Labels for major ticks
ax.set_xticklabels(np.arange(1, 11, 1))
ax.set_yticklabels(np.arange(1, 11, 1))
# Minor ticks
ax.set_xticks(np.arange(-.5, 10, 1), minor=True)
ax.set_yticks(np.arange(-.5, 10, 1), minor=True)
# Gridlines based on minor ticks
ax.grid(which='minor', color='w', linestyle='-', linewidth=2)
# Remove minor ticks
ax.tick_params(which='minor', bottom=False, left=False)
One can find it easier to use plt.pcolor
or plt.pcolormesh
:
data = np.random.rand(10, 10)
plt.pcolormesh(data, edgecolors='k', linewidth=2)
ax = plt.gca()
ax.set_aspect('equal')
Though, there are some differences among them and plt.imshow
, the most obvious being that the image is swapped by the Y-axis (you can reversed it back easily by adding ax.invert_yaxis()
though). For further discussion see here: When to use imshow over pcolormesh?
You can shift the pixels by passing the extent
argument to imshow
. extent
is a 4-element list of scalars (left, right, bottom, top):
foo = np.random.rand(35).reshape(5, 7)
# This keeps the default orientation (origin at top left):
extent = (0, foo.shape[1], foo.shape[0], 0)
_, ax = plt.subplots()
ax.imshow(foo, extent=extent)
ax.grid(color='w', linewidth=2)
ax.set_frame_on(False)
This is kind of a hack but i like to use it since it does not require me to move the xticks or yticks.
import numpy as np
import matplotlib.pyplot as plt
plt.matshow(np.random.random(size=(10,10)))
plt.hlines(y=np.arange(0, 10)+0.5, xmin=np.full(10, 0)-0.5, xmax=np.full(10, 10)-0.5, color="black")
plt.vlines(x=np.arange(0, 10)+0.5, ymin=np.full(10, 0)-0.5, ymax=np.full(10, 10)-0.5, color="black")
plt.show()