0

I want to plot there subplots in a figure using GridSpec in matplotlib.

In the first rows (varying number of rows), I want to place a grid with circles.

In the second last row, I want to place a legend.

In the last row, I want to place a colorbar.

But it seems that my colorbar is taking more space than I have given.

Do you have any idea to solve it?

Here is the code to regenerate it:

from matplotlib import  pyplot as plt
import matplotlib.cm as matplotlib_cm
import numpy as np
import matplotlib as mpl
import os

def plot_legend_in_given_axis(ax, fontsize):
    diameter_labels = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
    row_labels = ['circle']
    ax.grid(which="major", color="white", linestyle='-', linewidth=3)
    ax.set_aspect(1.0)

    for row_index, row_label in enumerate(row_labels):
        for diameter_index, diameter_label in enumerate(diameter_labels):
            circle=plt.Circle((diameter_index + 0.5, row_index + 0.5), radius=(diameter_label/(2*1.09)), color='gray', fill=True)
            ax.add_artist(circle)

    ax.set_xlim([0, len(diameter_labels)])
    ax.set_xticklabels([])

    ax.tick_params(axis='x', which='minor', length=0, labelsize=12)
    ax.set_xticks(np.arange(0, len(diameter_labels), 1))
    ax.xaxis.set_ticks_position('bottom')
    ax.set_xlabel('Very long\nx axis label', fontsize=fontsize, labelpad=5)

    ax.set_ylim([0, len(row_labels)])
    ax.set_yticklabels([])
    ax.tick_params(axis='y', which='minor', length=0, labelsize=12)
    ax.set_yticks(np.arange(0, len(row_labels), 1))

    ax.grid(which='major', color='black', linestyle='-', linewidth=1)


def main(width, height, xaxis_labels, yaxis_labels):
    width_multiply = 1.5
    height_multiply = 1.5

    figure_width = int(width_multiply * width)
    figure_height = int(height_multiply * height)

    fig = plt.figure(figsize=(figure_width, figure_height))

    grid = plt.GridSpec(width, height, hspace=0, wspace=0)  
    ax = fig.add_subplot(grid[0:-2, :])
    ax.set_aspect(1.0)
    legend_ax = fig.add_subplot(grid[-2, :])
    plot_legend_in_given_axis(legend_ax, 20)

    color_bar_ax = fig.add_subplot(grid[-1, :])
    cmap = matplotlib_cm.get_cmap('YlOrRd')
    v_min = 2
    v_max = 20
    norm = plt.Normalize(v_min, v_max)

    bounds = np.arange(v_min, v_max + 1, 2)
    cb = mpl.colorbar.ColorbarBase(color_bar_ax, cmap=cmap, norm=norm, ticks=bounds, spacing='proportional', orientation='horizontal')
    cb.ax.tick_params(labelsize=20)
    cb.set_label("-log10 (q-value)", horizontalalignment='center', rotation=0, fontsize=20)

    plt.xlim([0, width])
    ax.set_xticks(np.arange(0, width + 1, 1))

    plt.ylim([1, height])
    ax.set_yticks(np.arange(0, height + 1, 1))

    # Plot the circles with color in the grid
    for yaxis_index, yaxis_label in enumerate(yaxis_labels):
        for xaxis_index, xaxis_label in enumerate(xaxis_labels):
            circle = plt.Circle((xaxis_index + 0.5, yaxis_index + 0.5), 0.4, color=cmap(norm(10)), fill=True)
            ax.add_artist(circle)

    ax.grid()
    for edge, spine in ax.spines.items():
        spine.set_visible(True)
        spine.set_color('black')

    figures_path = os.path.join('/Users', 'burcakotlu', 'Desktop')
    figFile = os.path.join(figures_path, 'ColorBar_Using_GridSpec.png')
    fig.savefig(figFile, dpi=100, bbox_inches="tight")

    plt.cla()
    plt.close(fig)

width = 5
height = 5
xaxis_labels = ["x%d" %i for i in range(width)]
yaxis_labels = ["y%d" %i for i in range(height)]
main(width, height, xaxis_labels, yaxis_labels)

enter image description here

1 Answer 1

1

This issue comes from the fact that you are using plt.xlim([0, width]) and plt.ylim([1, height]) to set the range of the axes of your first subplot (with axes ax) immediately after defining the axes color_bar_ax of your colorbar. If instead you use ax.set_xlim([0, width]) and ax.set_ylim([1, height]) then you are specifying that you are now referring to your fist subplot (ax) and everything works well.

The output I get from making those changes can be seen below:

enter image description here

Optional modifications:

On top of that, you can change the way you distribute you plots on your GridSpec such that there is no overlap between plots and labels. Below, I changed the location of the first subplot on the grid from grid[0:-2, :]) to grid[0:-3, :] and the second subplot went from grid[-2,:] to grid[-3:-1, :]. The output then becomes:

enter image description here

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for pointing out the order of commands. I have a general problem in matplotlib subplots where one of the subplots has varying width and height and the other subplots must have fixed sizes. In that case, keeping other subplots at fixed sizes seems impossible.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.