34

I'm rendering some graphics in python with matplotlib, and will include them into a LaTeX paper (using LaTex's nice tabular alignment instead of fiddling with matplotlib's ImageGrid, etc.). I would like to create and save a standalone colorbar with savefig, without needing to use imshow.

(the vlim, vmax parameters, as well as the cmap could be provided explicitly)

The only way I could find was quite complicated and (from what I understand) draws a hard-coded rectangle onto the canvas: http://matplotlib.org/examples/api/colorbar_only.html

Is there an elegant way to create a standalone colorbar with matplotlib?

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
user
  • 7,123
  • 7
  • 48
  • 90
  • 6
    Honestly that looks like they've done most of the work for you...I don't know if you'll find anything better than that in terms of being able to save, define your colormap, ranges, etc. all at once. – mdscruggs May 16 '13 at 18:59
  • I would point out that what you saying looks complicated in what `plt.colorbar` does for you behind the scenes. – tacaswell May 16 '13 at 19:29
  • @tcaswell I agree, of course. I was just wondering if there was a more elegant solution that didn't require reimplementing `plt.colorbar`; the linked solution is fine to cut and paste in, but feels inelegant compared to calling `plt.colorbar()` after `plt.imshow` with an empty matrix (note for posterity: that doesn't work). – user May 16 '13 at 19:40

6 Answers6

41

You can create some dummy image and then hide it's axe. Draw your colorbar in a customize Axes.

import pylab as pl
import numpy as np

a = np.array([[0,1]])
pl.figure(figsize=(9, 1.5))
img = pl.imshow(a, cmap="Blues")
pl.gca().set_visible(False)
cax = pl.axes([0.1, 0.2, 0.8, 0.6])
pl.colorbar(orientation="h", cax=cax)
pl.savefig("colorbar.pdf")

the result:

enter image description here

HYRY
  • 94,853
  • 25
  • 187
  • 187
  • That's what I'm talking about! – user May 17 '13 at 18:37
  • 14
    It throws an AssertionError ``assert position == 'top' or position == 'bottom'``for me. Changing the code to ``pl.colorbar(orientation='horizontal', cax=cax)`` fixed the problem and produced the results i was looking for. Might be some version-problems or so. – Nras Sep 08 '14 at 08:09
15

Using the same idea as in HYRY's answer, if you want a "standalone" colorbar in the sense that it is independent of the items on a figure (not directly connected with how they are colored), you can do something like the following:

from matplotlib import pyplot as plt
import numpy as np

# create dummy invisible image
# (use the colormap you want to have on the colorbar)
img = plt.imshow(np.array([[0,1]]), cmap="Oranges")
img.set_visible(False)

plt.colorbar(orientation="vertical")

# add any other things you want to the figure.
plt.plot(np.random.rand(30))
Mark
  • 3,357
  • 30
  • 31
10

So, based on this answer here, if you're like me and want to avoid this ugly fake plt.imshow(), you can do this in basically two lines:

import matplotlib as mpl
import matplotlib.pyplot as plt


fig, ax = plt.subplots()
col_map = plt.get_cmap('nipy_spectral')
mpl.colorbar.ColorbarBase(ax, cmap=col_map, orientation = 'vertical')

# As for a more fancy example, you can also give an axes by hand:
c_map_ax = fig.add_axes([0.2, 0.8, 0.6, 0.02])
c_map_ax.axes.get_xaxis().set_visible(False)
c_map_ax.axes.get_yaxis().set_visible(False)

# and create another colorbar with:
mpl.colorbar.ColorbarBase(c_map_ax, cmap=col_map, orientation = 'horizontal')

picture of resulting figure

Socob
  • 1,189
  • 1
  • 12
  • 26
Xario
  • 101
  • 1
  • 5
  • 7
    just to add.... here's the official version of this: https://matplotlib.org/tutorials/colors/colorbar_only.html?highlight=colorbarbase – raphael Apr 03 '19 at 08:37
  • This should be the accepted answer. Well done! – boof Mar 30 '21 at 00:57
10

That reference to http://matplotlib.org/examples/api/colorbar_only.html solved it for me. That example is a little verbose, so here is an easy way to make a standalone colorbar (for posterity)...

import matplotlib.pyplot as plt
import matplotlib as mpl

fig = plt.figure()
ax = fig.add_axes([0.05, 0.80, 0.9, 0.1])

cb = mpl.colorbar.ColorbarBase(ax, orientation='horizontal', 
                               cmap='RdBu')

plt.savefig('just_colorbar', bbox_inches='tight')

enter image description here

Of course, you can specify many other aspects of the Colorbar

import matplotlib.pyplot as plt
import matplotlib as mpl

fig = plt.figure()
ax = fig.add_axes([0.05, 0.80, 0.9, 0.1])

cb = mpl.colorbar.ColorbarBase(ax, orientation='horizontal', 
                               cmap='gist_ncar',
                               norm=mpl.colors.Normalize(0, 10),  # vmax and vmin
                               extend='both',
                               label='This is a label',
                               ticks=[0, 3, 6, 9])

plt.savefig('just_colorbar', bbox_inches='tight')

enter image description here

blaylockbk
  • 2,503
  • 2
  • 28
  • 43
5

This solution can be also used to draw the colorbar independenly of the content of ax. Just set fraction = .05.

Code

import matplotlib as mpl
import matplotlib.pyplot as plt

fig, ax = plt.subplots(1, 1)

fraction = 1  # .05

norm = mpl.colors.Normalize(vmin=-3, vmax=99)
cbar = ax.figure.colorbar(
            mpl.cm.ScalarMappable(norm=norm, cmap='Blues'),
            ax=ax, pad=.05, extend='both', fraction=fraction)

ax.axis('off')
plt.show()

enter image description here

Markus Dutschke
  • 9,341
  • 4
  • 63
  • 58
1

To add to @blaylockbk's answer (which is a great solution, even to add to an already created figure), for me the cmap argument won't take strings for colormap names, but cmap = plt.cm.viridis works, if anyone run into the same problem as I.

CZ0143
  • 11
  • 1