matplotlib sharex with colorbar not working matplotlib sharex with colorbar not working pandas pandas

matplotlib sharex with colorbar not working


Sharex means that the axes limits are the same and that the axes are synchronized. It doesn't mean that they lie on top of each other. It all depends on how you create the colorbar.

The colorbar created by pandas scatterplot is, just like any statndard colorbar in matplotlib, created by taking away part of the space for the axes that it relates to. Hence this axes is smaller than other axes from the grid.

Options you have include:

  • Shrinking the other axes of the grid by the same amount than the scatterplot axes.
    This can be done by using the position of the first axes and set the position of the second axes accordingly, using ax.get_position() and ax.set_postion()

    import matplotlib.pyplot as pltimport pandas as pdimport numpy as npimport itertools as itxy = list( it.product( range(10), range(10) ) )df = pd.DataFrame( xy, columns=['x','y'] )df['score'] = np.random.random( 100 )kw = {'height_ratios':[13,2]}fig, (ax,ax2) = plt.subplots(2,1,  gridspec_kw=kw, sharex=True)df.plot(kind='scatter', x='x',  y='y', c='score', s=100, cmap="PuRd",          ax=ax, colorbar=True)df.groupby("x").mean().plot(kind = 'bar', y='score',ax=ax2, legend=False)ax2.legend(bbox_to_anchor=(1.03,0),loc=3)pos = ax.get_position()pos2 = ax2.get_position()ax2.set_position([pos.x0,pos2.y0,pos.width,pos2.height])plt.show()

enter image description here

  • Create a grid including an axes for the colorbar.
    In this case you can create a 4 by 4 grid and add the colorbar to the upper right axes of it. This requires to supply the scatter plot to fig.colorbar() and specify an axes for the colorbar to live in,

    fig.colorbar(ax.collections[0], cax=cax)       

    Then remove the lower right axes, which is not needed (ax.axis("off")). You may still share the axes, if that is needed, via ax2.get_shared_x_axes().join(ax, ax2).

    import matplotlib.pyplot as pltimport pandas as pdimport numpy as npimport itertools as itxy = list( it.product( range(10), range(10) ) )df = pd.DataFrame( xy, columns=['x','y'] )df['score'] = np.random.random( 100 )kw = {'height_ratios':[13,2], "width_ratios":[95,5]}fig, ((ax, cax),(ax2,aux)) = plt.subplots(2,2,  gridspec_kw=kw)df.plot(kind='scatter', x='x',  y='y', c='score', s=80, cmap="PuRd",         ax=ax,colorbar=False)df.groupby("x").mean().plot(kind = 'bar', y='score',ax=ax2, legend=False)fig.colorbar(ax.collections[0], cax=cax, label="score")aux.axis("off")ax2.legend(bbox_to_anchor=(1.03,0),loc=3)ax2.get_shared_x_axes().join(ax, ax2)ax.tick_params(axis="x", labelbottom=0)ax.set_xlabel("")plt.show()

enter image description here


Based on ImportanceOfBeingErnest's answer the two following functions would align the axis:

def align_axis_x(ax, ax_target):    """Make x-axis of `ax` aligned with `ax_target` in figure"""    posn_old, posn_target = ax.get_position(), ax_target.get_position()    ax.set_position([posn_target.x0, posn_old.y0, posn_target.width, posn_old.height])def align_axis_y(ax, ax_target):    """Make y-axis of `ax` aligned with `ax_target` in figure"""    posn_old, posn_target = ax.get_position(), ax_target.get_position()    ax.set_position([posn_old.x0, posn_target.y0, posn_old.width, posn_target.height])


Using Matplotlib toolkits (included in Matplotlib)

I would like to add an alternative to the current answers, which is the use of the function make_axes_locatable from Matplotlib toolkits. This optimizes the use of space by default. It makes a big difference if you have a complex subplot configuration with several subplots of this type, for example, using gridspec.

Example of use

import matplotlib.pyplot as pltimport pandas as pdimport numpy as npimport itertools as itfrom mpl_toolkits.axes_grid1 import make_axes_locatable# create some dataxy = list(it.product(range(16), range(16)))df = pd.DataFrame(xy, columns=["x", "y"])df["bubles"] = np.random.random(256)# create figure and main axisfig = plt.figure(figsize=(10,6))ax = plt.gca()# create a divider from make_axes_locatabledivider = make_axes_locatable(ax)# append a new axis on the bottom whose size is 15% of the size of the main axbax = divider.append_axes("bottom", size="15%", pad=.05)# append axis on the right for colourbar (size = 5%)cax = divider.append_axes("right", size="5%", pad=.05)cm = "plasma" # defining colourmapsm = plt.cm.ScalarMappable(cmap=cm)# plotting on main axisp1 = df.plot(kind='scatter', x='x',  y='y', c='bubles', s=df["bubles"]*200, cmap=cm,          ax=ax, colorbar=False)# attaching colourbar to the axis at the rightplt.colorbar(sm, cax=cax)# plotting on the adjascent axis (bottom)p2 = df.groupby("x").mean().plot(kind = 'bar', y='bubles',ax=bax, legend=False)# synchronizing plots on the x-axisp2.sharex(p1)# inserting some legendbax.legend(bbox_to_anchor=(1.03,0),loc=3)plt.show()

The code above result in a figure like this:Result with make_axes_locatable

See on the GIF below the effect of sharex on the synchronization of both x-axes:

Effect of sharex on the synchronization of the axes