Search code examples
pythonmatplotlibvisualizationlegendgeopandas

Adding legend in geopandas plot with subplots changes size of plot


I want to plot two GeoPandas plots with matplotlib subplots. The two maps have the same legend, and therefore I only want to have one legend. However, if I add a legend to one of the GeoPandas plots, the plot becomes slightly smaller. This is a problem since the two plots then become different sizes.

Here is my code:

fig,ax = plt.subplots(1, 2, figsize=(12,8))
sealand_grid.plot(column=sealand_grid['p_2012'], 
                  ax=ax[0],
                  cmap='magma')
sealand_grid.plot(column=sealand_grid['p_2013'], 
                  ax=ax[1],
                  cmap='magma', 
                  legend=True,
                  legend_kwds={'shrink': 0.3})
ax[0].set_title('Housing prices 2012', fontsize=18)
ax[1].set_title('Housing prices 2013', fontsize=18)
fig.patch.set_facecolor('xkcd:white')
ax[0].axis('off')
ax[1].axis('off')
fig.tight_layout()

where sealand_grid is my GeoPandas-dataframe, and p_2012 and p_2013 are the variables plotted in the two maps.

How do I get the two maps to be the same size, while only having one legend?

the resulting plot looks like this


Solution

  • In order to reproduce you issue, I used this code, which basically shows the same result: the image on the right is slightly smaller than the left one due to the colorbar.

    import matplotlib.pyplot as plt
    import numpy as np
    
    D2012 = np.random.rand(10, 10)
    D2013 = np.random.rand(10, 10)
    
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize = (16,8))
    
    P2012 = ax1.imshow(D2012,
                 cmap = 'magma')
    P2013 = ax2.imshow(D2013,
                 cmap = 'magma')
    
    ax1.set_title('2012', fontsize = 18)
    ax2.set_title('2013', fontsize = 18)
    ax1.axis('off')
    ax2.axis('off')
    plt.colorbar(P2013)
    
    plt.show()
    

    which gives this plot:

    enter image description here

    I solved with this turnaround:

    import matplotlib.pyplot as plt
    import numpy as np
    
    D2012 = np.random.rand(10, 10)
    D2013 = np.random.rand(10, 10)
    
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize = (16,8))
    ax3 = fig.add_axes([0.85, 0.1, 0.1, 0.8])
    
    P2012 = ax1.imshow(D2012,
                 cmap = 'magma')
    P2013 = ax2.imshow(D2013,
                 cmap = 'magma')
    
    ax1.set_title('2012', fontsize = 18)
    ax2.set_title('2013', fontsize = 18)
    ax1.axis('off')
    ax2.axis('off')
    ax3.axis('off')
    plt.colorbar(P2013, ax = ax3)
    
    plt.show()
    

    which gives this plot:

    enter image description here

    Basically, I add a third axis, turn it off and add to it the colorbar. You need to pay attention to the position of this third axis with the parameters inside the method: fig.add_axes([0.85, 0.1, 0.1, 0.8]).
    I know this is not the most elegant solution, for sure.


    EDIT

    A more robust and elegant solution is to keep 2 axes, but set their size and position when you define them:

    import matplotlib.pyplot as plt
    import numpy as np
    
    D2012 = np.random.rand(10, 10)
    D2013 = np.random.rand(10, 10)
    
    fig = plt.figure(figsize = (16,8))
    ax1 = fig.add_axes([0, 0.2, 0.6, 0.6])
    ax2 = fig.add_axes([0.4, 0.2, 0.6, 0.6])
    
    P2012 = ax1.imshow(D2012,
                 cmap = 'magma')
    P2013 = ax2.imshow(D2013,
                 cmap = 'magma')
    
    ax1.set_title('2012', fontsize = 18)
    ax2.set_title('2013', fontsize = 18)
    ax1.axis('off')
    ax2.axis('off')
    plt.colorbar(P2013)
    
    plt.show()
    

    which gives this plot:

    enter image description here

    In this case you have to pay attention to the position and the size of the two axis with these lines:

    ax1 = fig.add_axes([0, 0.2, 0.6, 0.6])
    ax2 = fig.add_axes([0.4, 0.2, 0.6, 0.6])