39

I am trying to put a colorbar to my image using matplotlib. The issue comes when I try to force the ticklabels to be written in scientific notation. How can I force the scientific notation (ie, 1x10^0, 2x10^0, ..., 1x10^2, and so on) in the ticks of the color bar?

Example, let's create and plot and image with its color bar:

import matplotlib as plot
import numpy as np

img = np.random.randn(300,300)
myplot = plt.imshow(img)
plt.colorbar(myplot)
plt.show()

When I do this, I get the following image:

image created with the previous code

However, I would like to see the ticklabels in scientific notation... Is there any one line command to do this? Otherwise, is there any hint out there? Thanks!

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
Alejandro
  • 3,263
  • 2
  • 22
  • 38

4 Answers4

55

You could use colorbar's format parameter:

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.ticker as ticker

img = np.random.randn(300,300)
myplot = plt.imshow(img)

def fmt(x, pos):
    a, b = '{:.2e}'.format(x).split('e')
    b = int(b)
    return r'${} \times 10^{{{}}}$'.format(a, b)

plt.colorbar(myplot, format=ticker.FuncFormatter(fmt))
plt.show()

enter image description here

unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • Thanks, but I would like to see 10^1 10^2, etc rather than e+01,e+02. Is it possible? – Alejandro Sep 22 '14 at 21:31
  • 2
    I have modified your code a little in order to show the scientific notation using latex. Thank you very much! You solution is very useful and very interesting indeed. – Alejandro Sep 22 '14 at 21:56
  • Thanks for the improvement. – unutbu Sep 22 '14 at 21:57
  • The solution shown up here can only put one character in superscript. Therefore if your exponent is either negative or greater than 9, the other characters aren't properly formated. As LaTeX requires the curly brackets to display more than one character as superscript, this modification showed to be useful: return r'$'+str(a)+r' \times 10^{'+str(b)+r'}$' – macrocosme Dec 03 '14 at 03:34
  • Thanks a lot, but can you force b = 1: to have everything in 10^1. (for example) – Agape Gal'lo Nov 01 '18 at 18:36
  • Can you force b = 1: to have everything in 10^1. (for example) @unutbu – Agape Gal'lo Nov 01 '18 at 18:49
  • @AgapeGal'lo: Since `x = a * 10**b`, it follows that `x = a * 10**(b-1) * 10**1`. So you would modify `fmt` to make `a` a float (i.e. `a = float(a)`,) then return `r'${} \times 10^{{{}}}$'.format(a * 10**(b-1), 1)`. – unutbu Nov 01 '18 at 22:26
  • @unutbu It does not work. It gives something like `1.54e -0.6 10^1`. I don't get where this `-0.6` come from... – Agape Gal'lo Nov 02 '18 at 10:56
  • 1
    @AgapeGal'lo: You can force decimal notation by using something like `.10f` as the [format spec](https://docs.python.org/3/library/string.html#format-string-syntax), which would lead to code looking [like this](https://gist.github.com/unutbu/44fb0517c214a2779b4c36d718badea4). Another possibility is to use [Joe Kington's FixedOrderFormatter](http://stackoverflow.com/questions/3677368/#3679918), leading to code [like this](https://gist.github.com/unutbu/28b35de1d14a64c8fbcd1101069e8ebc). – unutbu Nov 02 '18 at 12:28
  • @unutbu thanks a lot ! It works perfectly. I would have an additional question (even if it's out of the subject): how can you fix the minimum and the maximum, and have a color bar (and a color map) which follow it ? For example -4 to 4 for your script (-4 ---> deep blue and +4 deep red). – Agape Gal'lo Nov 02 '18 at 14:50
  • 1
    You could [use `imshow(..., vmin=-4, vmax=4)`](https://stackoverflow.com/a/22122723/190597) to set the min and max values. The colorbar will adjust accordingly. To get `(-4 ---> deep blue and +4 deep red)` you could pass `cmap=plt.get_cmap('jet')` an a parameter to `imshow` as well (again see the link for an example). Note however that while the `jet` color map looks pretty, it is [not recommended for scientific presentation](https://stats.stackexchange.com/q/223315/842) because it the color scheme can mask or enhance variations when it shouldn't. That's why viridis is the new default. – unutbu Nov 02 '18 at 15:57
  • 1
    A gallery of colormap options can be found [here](https://matplotlib.org/examples/color/colormaps_reference.html). – unutbu Nov 02 '18 at 16:44
  • Unfortunately, I can not vote, but I agree with the second suggestion because it is simpler. Also, for more decimals, simply use: pl.colorbar(myplot, format='%.2e') or '%.3e', etc. – Pedro Kurmi Humire Rodríguez Oct 11 '20 at 13:07
  • Note1: plt.colorbar(myplot, format=None) to turn it back to normal. I had to use this for subplots that I didn't want to be in ENG notation. – russian_spy Sep 25 '21 at 18:32
47

You can specify the format of the colorbar ticks as follows:

pl.colorbar(myplot, format='%.0e')
Falko
  • 17,076
  • 13
  • 60
  • 105
14

There is a more straightforward (but less customizable) way to get scientific notation in a ColorBar without the %.0e formatting.

Create your ColorBar:

cbar = plt.colorbar()

And call the formatter:

cbar.formatter.set_powerlimits((0, 0))

This will make the ColorBar use scientific notation. See the example figure below to see how the ColorBar will look.

enter image description here

The documentation for this function can be found here.

Joseph Farah
  • 2,463
  • 2
  • 25
  • 36
  • Do you have a link to the documentation about cbar.formatter.set_powerlimits? I cannot find it. I just wanted to look at what (0,0) means – pwprnt Apr 07 '21 at 09:03
  • 1
    @pwprnt the documentation is buried on this page: https://matplotlib.org/stable/api/ticker_api.html The salient info is: "A tuple (min_exp, max_exp) containing the powers of 10 that determine the switchover threshold. For a number representable as ×10exp with 1<=||<10, scientific notation will be used if exp <= min_exp or exp >= max_exp." – Joseph Farah Apr 07 '21 at 13:40
5

It seems that cbar.formatter.set_powerlimits((0,0)) alone in Joseph's answer does not render math format like $10^3$ yet.

Adding cbar.formatter.set_useMathText(True) gives something like $10^3$.

import matplotlib.pyplot as plt
import numpy as np

img = np.random.randn(300,300)*10**5
myplot = plt.imshow(img)
cbar = plt.colorbar(myplot)
cbar.formatter.set_powerlimits((0, 0))

# to get 10^3 instead of 1e3
cbar.formatter.set_useMathText(True)

plt.show()

This generates enter image description here

See the document of set_useMathText() here.

Thomas Wagenaar
  • 6,489
  • 5
  • 30
  • 73
Guang-Le Du
  • 51
  • 1
  • 1