134

I'm plotting a histogram using the matplotlib.pyplot module and I am wondering how I can force the y-axis labels to only show integers (e.g. 0, 1, 2, 3 etc.) and not decimals (e.g. 0., 0.5, 1., 1.5, 2. etc.).

I'm looking at the guidance notes and suspect the answer lies somewhere around matplotlib.pyplot.ylim but so far I can only find stuff that sets the minimum and maximum y-axis values.

def doMakeChart(item, x):
    if len(x)==1:
        return
    filename = "C:\Users\me\maxbyte3\charts\\"
    bins=logspace(0.1, 10, 100)
    plt.hist(x, bins=bins, facecolor='green', alpha=0.75)
    plt.gca().set_xscale("log")
    plt.xlabel('Size (Bytes)')
    plt.ylabel('Count')
    plt.suptitle(r'Normal Distribution for Set of Files')
    plt.title('Reference PUID: %s' % item)
    plt.grid(True)
    plt.savefig(filename + item + '.png')
    plt.clf()
Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
Jay Gattuso
  • 3,890
  • 12
  • 37
  • 51
  • This question isn't a duplicate of [Python matplotlib restrict to integer tick locations](https://stackoverflow.com/q/11258212/7758804), because the other is `import pylab`, not `import matplotlib` – Trenton McKinney Jun 22 '22 at 00:50

3 Answers3

255

Here is another way:

from matplotlib.ticker import MaxNLocator

ax = plt.figure().gca()
ax.yaxis.set_major_locator(MaxNLocator(integer=True))
galath
  • 5,717
  • 10
  • 29
  • 41
64

If you have the y-data

y = [0., 0.5, 1., 1.5, 2., 2.5]

You can use the maximum and minimum values of this data to create a list of natural numbers in this range. For example,

import math
print range(math.floor(min(y)), math.ceil(max(y))+1)

yields

[0, 1, 2, 3]

You can then set the y tick mark locations (and labels) using matplotlib.pyplot.yticks:

yint = range(min(y), math.ceil(max(y))+1)

matplotlib.pyplot.yticks(yint)
Chris
  • 44,602
  • 16
  • 137
  • 156
  • Oh, cool! Thanks you, that's pushing me in the right direction! I'm generating a whole bunch of charts, this means the y values are generated on the fly for each one. Is there a way of getting the limits graph being built and replace the default lables with these new ones? – Jay Gattuso Aug 21 '12 at 09:05
  • 1
    Of course you can: from the `matplotlib.pyplot.yticks` documentation (did you read this) the first code snippet is `locs, labels = yticks()`. – Chris Aug 21 '12 at 09:09
  • 4
    Hmm, I did read it indeed. But I find documentation utterly impenetrable most of the time. I really struggle to translate the docs into meaningful code. `get_view_interval()` is Ī guess the method to reach the limits, but I have no idea from the docs how you link that call to the y axis in graph in question. `yLimits = matplotlib.pyplot.yticks(get_view_interval())`? – Jay Gattuso Aug 21 '12 at 09:21
  • 1
    I agree the matplotlib documentation could be better. The code in my last comment is *all* that you need. Assuming you have used `import matplotlib.pyplot as plt` then `locs, labels = plt.yticks()` will return the current y-values of the axis labels in `locs` and the labels associated with those values in `labels`. Note, `plt.yticks` gets the labels for the current plot. If you have a handle to a plot you can (I think) use `handle.yticks`. – Chris Aug 21 '12 at 09:24
  • 1
    OK. Thank you. I really do appreciate your help and time, and you have given me plenty to work from. – Jay Gattuso Aug 21 '12 at 09:25
  • Great, I tried this, using this range [0, 1, 2, 3], I don't get an even amount of room between the 0 and the 1 y-range, 1-2 is huge, how do you fix that? – radtek Mar 06 '14 at 19:52
  • In Python 3.x range is an iterator so "range()" becomes "list(range())". See, e.g., https://stackoverflow.com/questions/18265935/python-create-list-with-numbers-between-2-values – Use Me May 11 '18 at 08:37
  • 1
    you should write in your answer that this works: ```from matplotlib.ticker import MaxNLocator ax = plt.figure().gca() ax.yaxis.set_major_locator(MaxNLocator(integer=True))``` – Charlie Parker Dec 03 '20 at 18:03
  • @CharlieParker - that's already another answer, see https://stackoverflow.com/a/38096332/623518. – Chris Dec 03 '20 at 20:26
13

this works for me:

import matplotlib.pyplot as plt
plt.hist(...

# make the y ticks integers, not floats
yint = []
locs, labels = plt.yticks()
for each in locs:
    yint.append(int(each))
plt.yticks(yint)
Ofer Chay
  • 139
  • 1
  • 2
  • 2
    It's always a good idea to describe why the given code solves the problem. Please [edit] your answer to include such a description. – Artjom B. Jun 14 '15 at 11:17
  • This is the only solution that works for me, thanks! I would just add one minor edit, because this solution omits the last tick and it's ugly. So I would add two more lines after the `for` loop: `last=yint[-1]+1` and `yint.append(last)` – durbachit Jul 20 '17 at 00:38