16

I have a simple scatter plot where each point has a color given by a value between 0 and 1 set to a chosen colormap. Here's a MWE of my code:

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

x = np.random.randn(60) 
y = np.random.randn(60)
z = [np.random.random() for _ in range(60)]

fig = plt.figure()
gs = gridspec.GridSpec(1, 2)

ax0 = plt.subplot(gs[0, 0])
plt.scatter(x, y, s=20)

ax1 = plt.subplot(gs[0, 1])
cm = plt.cm.get_cmap('RdYlBu_r')
plt.scatter(x, y, s=20 ,c=z, cmap=cm)
cbaxes = fig.add_axes([0.6, 0.12, 0.1, 0.02]) 
plt.colorbar(cax=cbaxes, ticks=[0.,1], orientation='horizontal')

fig.tight_layout()
plt.show()

which looks like this:

pic

The problem here is that I want the small horizontal colorbar position to the lower left of the plot but using the cax argument not only feels a bit hacky, it apparently conflicts with tight_layout which results in the warning:

/usr/local/lib/python2.7/dist-packages/matplotlib/figure.py:1533: UserWarning: This figure includes Axes that are not compatible with tight_layout, so its results might be incorrect.
  warnings.warn("This figure includes Axes that are not "

Isn't there a better way to position the colorbar, ie without getting a nasty warning thrown at you whenever you run the code?


Edit

I wanted the colorbar to show only the max and min values, ie: 0 and 1 and Joe helped me do that by adding vmin=0, vmax=1 to scatter like so:

plt.scatter(x, y, s=20, vmin=0, vmax=1)

so I'm removing this part of the question.

Gabriel
  • 40,504
  • 73
  • 230
  • 404
  • 2
    The warning about axes not being compatible is true whenever you manually add axes. You can safely ignore it, just be aware that `tight_layout` won't take into account the colorbar's position. For the second problem, it's actually because the min and max of your colorbar aren't quite at 0 and 1. (`scatter`, et al, set it to the exact min and max of your data, by default) If you pass in `vmin=0, vmax=1` to `scatter`, the ticks will show up. – Joe Kington Aug 13 '13 at 15:07
  • Well I _can_ ignore it but I'd rather not. It looks pretty bad when you run a code a warnings start flying to your face, there must be a better way to do this. The `vmin=0, vmax=1` thing worked, so I'm taking that part out of the question, thanks! – Gabriel Aug 13 '13 at 15:16
  • 1
    Well, the warning is just that: `tight_layout` only deals with shrinking and enlarging subplots. If you have axes that aren't subplots, it will give that warning. You want to have axes that aren't subplots (the colorbar). You basically have 3 options: a) catch that specific warning and silence it, b) turn warnings off, c) don't use `tight_layout`, and use `subplots_adjust` instead. (`tight_layout` just calculates the input to `subplots_adjust` automatically.) Hope that helps a bit, anyway! – Joe Kington Aug 13 '13 at 15:20

1 Answers1

23

One may use a mpl_toolkits.axes_grid1.inset_locator.inset_axes to place an axes inside another axes. This axes can be used to host the colorbar. Its position is relative the the parent axes, similar to how legends are placed, using a loc argument (e.g. loc=3 means lower left). Its width and height can be specified in absolute numbers (inches) or relative to the parent axes (percentage).

cbaxes = inset_axes(ax1, width="30%", height="3%", loc=3) 

enter image description here

import matplotlib.pyplot as plt 
import numpy as np
import matplotlib.gridspec as gridspec
from mpl_toolkits.axes_grid1.inset_locator import inset_axes

x = np.random.randn(60) 
y = np.random.randn(60)
z = [np.random.random() for _ in range(60)]

fig = plt.figure()
gs = gridspec.GridSpec(1, 2)

ax0 = plt.subplot(gs[0, 0])
plt.scatter(x, y, s=20)

ax1 = plt.subplot(gs[0, 1])
cm = plt.cm.get_cmap('RdYlBu_r')
plt.scatter(x, y, s=20 ,c=z, cmap=cm)

fig.tight_layout()

cbaxes = inset_axes(ax1, width="30%", height="3%", loc=3) 
plt.colorbar(cax=cbaxes, ticks=[0.,1], orientation='horizontal')


plt.show()

Note that in order to suppress the warning, one might simply call tight_layout prior to adding the inset axes.

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • Other than the convenience of locating the axis using `loc` instead of manually selecting the coordinates (which is indeed convenient), is there any other advantage over using `fig.add_axes()` ? – Gabriel Jul 02 '17 at 16:00
  • 3
    No, not having to worry about the coodinates **is** the advantage. In this simple case it may not be too obvious, but in the general case you may not even know the coordinates at which you would need to place the axes using `add_axes`, while `inset_axes` makes sure the axes is inside the other axes and positionned relative to it. – ImportanceOfBeingErnest Jul 02 '17 at 16:03