12

I just want to draw Matplotlib histograms from skimage.exposure but I get a ValueError: bins must increase monotonically. The original image comes from here and here my code:

from skimage import io, exposure
import matplotlib.pyplot as plt

img = io.imread('img/coins_black_small.jpg', as_grey=True)
hist,bins=exposure.histogram(img)

plt.hist(bins,hist)

ValueError: bins must increase monotonically.

But the same error arises when I sort the bins values:

import numpy as np
sorted_bins = np.sort(bins)
plt.hist(sorted_bins,hist)

ValueError: bins must increase monotonically.

I finally tried to check the bins values, but they seem sorted in my opinion (any advice for this kind of test would appreciated also):

if any(bins[:-1] >= bins[1:]):
    print "bim"

No output from this.

Any suggestion on what happens?
I'm trying to learn Python, so be indulgent please. Here my install (on Linux Mint):

  • Python 2.7.13 :: Anaconda 4.3.1 (64-bit)
  • Jupyter 4.2.1
Aurélien Vasseur
  • 135
  • 1
  • 1
  • 9

3 Answers3

15

Matplotlib hist accept data as first argument, not already binned counts. Use matplotlib bar to plot it. Note that unlike numpy histogram, skimage exposure.histogram returns the centers of bins.

width = bins[1] - bins[0]
plt.bar(bins, hist, align='center', width=width)
plt.show()
Ondro
  • 997
  • 5
  • 8
5

The correct solution is:

All bin values must be whole numbers, no decimals! You can use round() function.

Matija Bensa
  • 79
  • 1
  • 3
3

The signature of plt.hist is plt.hist(data, bins, ...). So you are trying to plug the already computed histogram as bins into the matplotlib hist function. The histogram is of course not sorted and therefore the "bins must increase monotonically"-error is thrown.

While you could of course use plt.hist(hist, bins), it's questionable if histogramming a histogram is of any use. I would guess that you want to simply plot the result of the first histogramming.

Using a bar chart would make sense for this purpose:

hist,bins=numpy.histogram(img)
plt.bar(bins[:-1], hist, width=(bins[-1]-bins[-2]), align="edge")
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • 1
    Damn, indeed. And thank you for your remark on the use of `plt.hist` vs `plt.bar`. – Aurélien Vasseur May 29 '17 at 14:33
  • But are you sure about `plt.bar(bins[:-1],...)`? (it returns an error on > incompatible sizes: argument 'height' must be length 255 or scalar) Shouldn't it be `plt.bar(bins,...)`? – Aurélien Vasseur May 29 '17 at 14:44
  • 1
    You can of course try it out. I am sure that if you were using `hist, bins = numpy.histogram` you would need to use `plt.bar(bins[:-1],...)`, because `bins` denotes the edges and thus is one larger than `hist`. Now, what I don't know is if `skimage.exposure.histogram` is different from that. As you get an error, it seems so. I updated the answer to use numpy. – ImportanceOfBeingErnest May 29 '17 at 16:35