Python matplotlib restrict to integer tick locations
Question:
Quite often I want to make a bar chart of counts. If the counts are low I often get major and/or minor tick locations that are not integers. How can I prevent this? It makes no sense to have a tick at 1.5 when the data are counts.
This is my first attempt:
import pylab
pylab.figure()
ax = pylab.subplot(2, 2, 1)
pylab.bar(range(1,4), range(1,4), align='center')
major_tick_locs = ax.yaxis.get_majorticklocs()
if len(major_tick_locs) < 2 or major_tick_locs[1] - major_tick_locs[0] < 1:
ax.yaxis.set_major_locator(pylab.MultipleLocator(1))
minor_tick_locs = ax.yaxis.get_minorticklocs()
if len(minor_tick_locs) < 2 or minor_tick_locs[1] - minor_tick_locs[0] < 1:
ax.yaxis.set_minor_locator(pylab.MultipleLocator(1))
which works OK when the counts are small but when they are large, I get many many minor ticks:
import pylab
ax = pylab.subplot(2, 2, 2)
pylab.bar(range(1,4), range(100,400,100), align='center')
major_tick_locs = ax.yaxis.get_majorticklocs()
if len(major_tick_locs) < 2 or major_tick_locs[1] - major_tick_locs[0] < 1:
ax.yaxis.set_major_locator(pylab.MultipleLocator(1))
minor_tick_locs = ax.yaxis.get_minorticklocs()
if len(minor_tick_locs) < 2 or minor_tick_locs[1] - minor_tick_locs[0] < 1:
ax.yaxis.set_minor_locator(pylab.MultipleLocator(1))
How can I get the desired behaviour from the first example with small counts whilst avoiding what happens in the second?
Answers:
I think it turns out I can just ignore the minor ticks. I’m going to give this a go and see if it stands up in all use cases:
def ticks_restrict_to_integer(axis):
"""Restrict the ticks on the given axis to be at least integer,
that is no half ticks at 1.5 for example.
"""
from matplotlib.ticker import MultipleLocator
major_tick_locs = axis.get_majorticklocs()
if len(major_tick_locs) < 2 or major_tick_locs[1] - major_tick_locs[0] < 1:
axis.set_major_locator(MultipleLocator(1))
def _test_restrict_to_integer():
pylab.figure()
ax = pylab.subplot(1, 2, 1)
pylab.bar(range(1,4), range(1,4), align='center')
ticks_restrict_to_integer(ax.xaxis)
ticks_restrict_to_integer(ax.yaxis)
ax = pylab.subplot(1, 2, 2)
pylab.bar(range(1,4), range(100,400,100), align='center')
ticks_restrict_to_integer(ax.xaxis)
ticks_restrict_to_integer(ax.yaxis)
_test_restrict_to_integer()
pylab.show()
You can use the MaxNLocator
method, like so:
from pylab import MaxNLocator
ya = axes.get_yaxis()
ya.set_major_locator(MaxNLocator(integer=True))
pylab.bar(range(1,4), range(1,4), align='center')
and
xticks(range(1,40),range(1,40))
has worked in my code.
Just use the align
optional parameter and xticks
does the magic.
I had a similar issue with a histogram I was plotting showing fractional count. Here’s how I was able to resolve it:
plt.hist(x=[Dataset being counted])
# Get your current y-ticks (loc is an array of your current y-tick elements)
loc, labels = plt.yticks()
# This sets your y-ticks to the specified range at whole number intervals
plt.yticks(np.arange(0, max(loc), step=1))
Quite often I want to make a bar chart of counts. If the counts are low I often get major and/or minor tick locations that are not integers. How can I prevent this? It makes no sense to have a tick at 1.5 when the data are counts.
This is my first attempt:
import pylab
pylab.figure()
ax = pylab.subplot(2, 2, 1)
pylab.bar(range(1,4), range(1,4), align='center')
major_tick_locs = ax.yaxis.get_majorticklocs()
if len(major_tick_locs) < 2 or major_tick_locs[1] - major_tick_locs[0] < 1:
ax.yaxis.set_major_locator(pylab.MultipleLocator(1))
minor_tick_locs = ax.yaxis.get_minorticklocs()
if len(minor_tick_locs) < 2 or minor_tick_locs[1] - minor_tick_locs[0] < 1:
ax.yaxis.set_minor_locator(pylab.MultipleLocator(1))
which works OK when the counts are small but when they are large, I get many many minor ticks:
import pylab
ax = pylab.subplot(2, 2, 2)
pylab.bar(range(1,4), range(100,400,100), align='center')
major_tick_locs = ax.yaxis.get_majorticklocs()
if len(major_tick_locs) < 2 or major_tick_locs[1] - major_tick_locs[0] < 1:
ax.yaxis.set_major_locator(pylab.MultipleLocator(1))
minor_tick_locs = ax.yaxis.get_minorticklocs()
if len(minor_tick_locs) < 2 or minor_tick_locs[1] - minor_tick_locs[0] < 1:
ax.yaxis.set_minor_locator(pylab.MultipleLocator(1))
How can I get the desired behaviour from the first example with small counts whilst avoiding what happens in the second?
I think it turns out I can just ignore the minor ticks. I’m going to give this a go and see if it stands up in all use cases:
def ticks_restrict_to_integer(axis):
"""Restrict the ticks on the given axis to be at least integer,
that is no half ticks at 1.5 for example.
"""
from matplotlib.ticker import MultipleLocator
major_tick_locs = axis.get_majorticklocs()
if len(major_tick_locs) < 2 or major_tick_locs[1] - major_tick_locs[0] < 1:
axis.set_major_locator(MultipleLocator(1))
def _test_restrict_to_integer():
pylab.figure()
ax = pylab.subplot(1, 2, 1)
pylab.bar(range(1,4), range(1,4), align='center')
ticks_restrict_to_integer(ax.xaxis)
ticks_restrict_to_integer(ax.yaxis)
ax = pylab.subplot(1, 2, 2)
pylab.bar(range(1,4), range(100,400,100), align='center')
ticks_restrict_to_integer(ax.xaxis)
ticks_restrict_to_integer(ax.yaxis)
_test_restrict_to_integer()
pylab.show()
You can use the MaxNLocator
method, like so:
from pylab import MaxNLocator
ya = axes.get_yaxis()
ya.set_major_locator(MaxNLocator(integer=True))
pylab.bar(range(1,4), range(1,4), align='center')
and
xticks(range(1,40),range(1,40))
has worked in my code.
Just use the align
optional parameter and xticks
does the magic.
I had a similar issue with a histogram I was plotting showing fractional count. Here’s how I was able to resolve it:
plt.hist(x=[Dataset being counted])
# Get your current y-ticks (loc is an array of your current y-tick elements)
loc, labels = plt.yticks()
# This sets your y-ticks to the specified range at whole number intervals
plt.yticks(np.arange(0, max(loc), step=1))