14

I'm trying to create a set of subplots with a shared x axis using pyplot. This is all fine and dandy when the graphs are simple and all the x-axes align fine. However when I include a subplot that includes a colorbar, this compresses the width of that particular subplot to include the colorbar, resulting in the subplots no longer sharing the x-axis.

I've searched the web with no success with this. I've tried several different methods, but the simplest example I include below. I plot the exact same data in each subplot, but plot one with a colorbar. You can see the data no longer align along the x-axis.

Thanks in advance for your help!


import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
import pandas as pd

x = np.linspace(0, 10, num=100)
y = x ** 2 + 10 * np.random.randn(100)


f, (ax1, ax2) = plt.subplots(2,1,sharex=True,figsize=(8,12))

im1 = ax1.scatter(x, y, c=y, cmap='magma')
divider = make_axes_locatable(ax1)
cax = divider.append_axes("right", size="5%", pad=.05)

plt.colorbar(im1, cax=cax)

im2 = ax2.plot(x, y,'.')

plt.show()

Plot that I can't embed

l'L'l
  • 44,951
  • 10
  • 95
  • 146
user3317621
  • 175
  • 1
  • 1
  • 5
  • 3
    Possible duplicate of [matplotlib sharex with colorbar not working](https://stackoverflow.com/questions/46694889/matplotlib-sharex-with-colorbar-not-working) – Thomas Kühn Feb 01 '19 at 06:26
  • Possible duplicate of [Align subplot with colorbar](https://stackoverflow.com/questions/44682146/align-subplot-with-colorbar) – Georgy Apr 10 '19 at 09:55

3 Answers3

7

Suggest using constrained_layout=True: https://matplotlib.org/stable/tutorials/intermediate/constrainedlayout_guide.html

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, num=100)
y = x ** 2 + 10 * np.random.randn(100)

f, (ax1, ax2) = plt.subplots(2,1,sharex=True,figsize=(8,12),
        constrained_layout=True)
im1 = ax1.scatter(x, y, c=y, cmap='magma')
f.colorbar(im1, ax=ax1)
im2 = ax2.plot(x, y,'.')

enter image description here

Jody Klymak
  • 4,979
  • 2
  • 15
  • 31
6

This is one hacky way to do it.

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
import pandas as pd

x = np.linspace(0, 10, num=100)
y = x ** 2 + 10 * np.random.randn(100)


f, (ax1, ax2) = plt.subplots(2,1,sharex=True,figsize=(8,12))

im1 = ax1.scatter(x, y, c=y, cmap='magma')
divider = make_axes_locatable(ax1)
cax = divider.append_axes("right", size="5%", pad=.05)

plt.colorbar(im1, cax=cax)

im2 = ax2.plot(x, y,'.')
divider2 = make_axes_locatable(ax2)
cax2 = divider2.append_axes("right", size="5%", pad=.05)
cax2.remove()
plt.show()

results in

enter image description here

plasmon360
  • 4,109
  • 1
  • 16
  • 19
  • 1
    I actually love the simplicity of this one, and I have more confidence that the measurements will be accurate. – user3317621 Feb 04 '19 at 00:09
0

You can account for the needed with of the colorbar already when you create the subplots. Instead of using the divider, generate four subplots with different widths using gridspec_kw. You can then delete the unneeded cax for the second subplot:

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, num=100)
y = x ** 2 + 10 * np.random.randn(100)



##creating four subplots with unequally divided widths:
f, axes = plt.subplots(
    2,2, sharex='col', figsize=(8,12),
    gridspec_kw = {'width_ratios' : (10,1)},
)
ax1,ax2 = axes[:,0]

##remove unneeded Axes instance:
axes[1,1].remove()

im1 = ax1.scatter(x, y, c=y, cmap='magma')
plt.colorbar(im1, cax=axes[0,1])

im2 = ax2.plot(x, y,'.')

f.savefig('sharex_colorbar.png')

The result looks like this:

result of the above code

As an alternative to deleting the unneded subplot instances, you can also first generate the gridspec explicitly and generate only the needed subplots. This might be more suitable if you have many plots:

from matplotlib.gridspec import GridSpec
gs = GridSpec(nrows=2, ncols=2, width_ratios = (10,1))
f = plt.figure(figsize=(8,12))

ax1 = f.add_subplot(gs[0,0])
ax2 = f.add_subplot(gs[1,0],sharex=ax1)
cax = f.add_subplot(gs[0,1])

im1 = ax1.scatter(x, y, c=y, cmap='magma')
plt.colorbar(im1, cax=cax)
Thomas Kühn
  • 9,412
  • 3
  • 47
  • 63