52

I have consistently had problems with my colour maps when using imshow; some colours seem to just become black. I have finally realised that imshow seems to, by default, normalise the matrix of floating point values I give it.

I would have expected an array such as [[0,0.25],[0.5,0.75]] to display the appropriate colours from the map, corresponding to those absolute values but the 0.75 will be interpreted as a 1. In the extreme case, an N x N array of 0.2 (for example), would just produce one big black square, rather than whatever one would expect 0.2 to correspond to in the colour map (perhaps a 20% grey).

Is there a way to prevent this behaviour? It is particularly annoying when custom colour maps have many discontinuities; a small change in scale could cause all the colours to completely change.

cottontail
  • 10,268
  • 18
  • 50
  • 51
oLas
  • 1,171
  • 1
  • 9
  • 17

2 Answers2

88

Just specify vmin=0, vmax=1.

By default, imshow normalizes the data to its min and max. You can control this with either the vmin and vmax arguments or with the norm argument (if you want a non-linear scaling).

As a quick example:

import matplotlib.pyplot as plt

data = [[0, 0.25], [0.5, 0.75]]

fig, ax = plt.subplots()
im = ax.imshow(data, cmap=plt.get_cmap('hot'), interpolation='nearest',
               vmin=0, vmax=1)
fig.colorbar(im)
plt.show()

enter image description here

Joe Kington
  • 275,208
  • 71
  • 604
  • 463
  • 10
    My life is complete! This has nagged me for too long. Hope this helps somebody else. – oLas Mar 02 '14 at 21:26
  • 1
    It did. I've been searching the hell out of the www. To figure out the behaviour of imshow. – Nima Mousavi May 04 '15 at 14:25
  • @DeeWBee Yes. From the [docs](http://matplotlib.org/api/pyplot_api.html?highlight=matshow#matplotlib.pyplot.matshow): _With the exception of fignum, keyword arguments are passed to imshow()_ – oLas Jan 15 '17 at 11:17
  • Actually, "vmin and vmax don't normalize the data, they clamp it". This was given in a comment [here](https://stackoverflow.com/a/31234563/3797285). – Mohit Pandey Oct 03 '19 at 18:18
  • `colorbar` that's what I was looking for :D – Brambor Sep 10 '20 at 21:15
0

You can also update vmin and vmax after an imshow call through the Normalize object defined on the image. Normalize objects define autoscale() method which can update vmin and vmax.

import matplotlib.pyplot as plt

data = [[0, 0.25], [0.5, 0.75]]

im = plt.imshow(data, cmap='hot')
plt.colorbar(im)
im.norm.autoscale([0, 1])
#                 ^^^^^^    <---- smaller value -> vmin; greater value -> vmax

Also clim() could be used to update vmin/vmax of the current image.

im = plt.imshow(data, cmap='hot')
plt.colorbar(im)
plt.clim(0, 1)

image

On a side note, images can also be accessed via images property on the Axes instance, i.e. im = plt.gca().images[0].

cottontail
  • 10,268
  • 18
  • 50
  • 51