3

I am trying to create a histogram for the following data

x = [2, 3, 4, 5]
y = [1, 1, 1, 1]

I am using the following code which is, for example, described in and old version of an answer to this question about how to generate 2D histograms in matplotlib.

import matplotlib.pyplot as plt
import numpy as np

bins = np.arange(-0.5, 5.5, 1.0), np.arange(-0.5, 5.5, 1.0)
heatmap, xedges, yedges = np.histogram2d(x, y, bins=bins)
extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]

plt.clf()
plt.imshow(heatmap,
           extent=extent,
           interpolation='nearest',
           cmap=plt.get_cmap('viridis'), # use nicer color map
          )
plt.colorbar()

plt.xlabel('x')
plt.ylabel('y')

However, the plot that this produces seems rotated in some way.

I was expecting this:

enter image description here

But I got

Plot showing data plotted in an unexpected, wrong way

Obviously, this does not match my input data. The coordinates highlighted in this plot are (1, 0), (1, 1), (1, 2), (1, 3).

What is going on?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Michael Mauderer
  • 3,777
  • 1
  • 22
  • 49
  • 1
    Wait, did you post your question and immediately answer it yourself? – wflynny Oct 27 '16 at 20:10
  • And don't forget about [`matplotlib.pyplot.hist2d`](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.hist2d) which avoids the issues inherent in using `imshow`. – wflynny Oct 27 '16 at 20:11
  • I did. I also submitted an edit to that buggy answer after spending far too much time figuring this out... – Michael Mauderer Oct 27 '16 at 20:13
  • Good point, I should add that. – Michael Mauderer Oct 27 '16 at 20:13
  • I think the appropriate thing to do is edit the answer, add a comment, or post a new answer to that question instead of posting a new question. This will likely get closed as a duplicate. – wflynny Oct 27 '16 at 20:15
  • Well the bug is already out there. I've seen other example using the same code, so this is a new question. But I've also submitted an edit for the other one. – Michael Mauderer Oct 27 '16 at 20:17
  • But all the information is contained in the answer and comments of http://stackoverflow.com/a/2461029/1634191. – wflynny Oct 27 '16 at 20:20
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/126865/discussion-between-michael-mauderer-and-wflynny). – Michael Mauderer Oct 27 '16 at 20:26

1 Answers1

5

plt.imshow image space convention for its indexing of the input array. That is, (0, 0) in the top right corner and a y-axis that is oriented downwards.

To avoid this, you have to call plt.imshow with the optional parameter origin = 'lower' (to correct the origin) and pass the data transposed as heatmap.T to correct the flipping of the axes.

But this will not get you the correct plot yet. Not only is the origin in the wrong place, also the indexing convention is different. numpy arrays follow row/column indexing, while images usually use column/row indexing. So in addition, you have to transpose the data.

So in the end, your code should look like this:

import matplotlib.pyplot as plt
import numpy as np

bins = np.arange(-0.5, 5.5, 1.0), np.arange(-0.5, 5.5, 1.0)
heatmap, xedges, yedges = np.histogram2d(x, y, bins=bins)
extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]

plt.clf()
plt.imshow(heatmap.T,
           origin='lower',
           extent=extent,
           interpolation='nearest',
           cmap=plt.get_cmap('viridis'), # use nicer color map
          )
plt.colorbar()

plt.xlabel('x')
plt.ylabel('y')

Or even better use matplotlib.pyplot.hist2d to avoid this issue completely.

Michael Mauderer
  • 3,777
  • 1
  • 22
  • 49