Search code examples
pythonmatplotlibsubplot

Row titles for matplotlib subplot


In matplotlib, Is it possible to set a a separate title for each row of subplots in addition to the title set for the entire figure and the title set for each individual plot? This would correspond to the orange text in the figure below. enter image description here

If not, how would you get around this problem? Create a separate column of empty subplots to the left and fill them with the orange text?

I am aware that it is possible to manually position each single title using text() or annotate(), but that usually requires a lot of tweaking and I have many subplots. Is there a smoother solution?


Solution

  • New in matplotlib 3.4.0

    Row titles can now be implemented as subfigure suptitles:

    The new subfigure feature allows creating virtual figures within figures with localized artists (e.g., colorbars and suptitles) that only pertain to each subfigure.

    See how to plot subfigures for further details.


    How to reproduce OP's reference figure:

    • Either Figure.subfigures (most straightforward)

      Create 3x1 fig.subfigures where each subfig gets its own 1x3 subfig.subplots and subfig.suptitle:

      fig = plt.figure(constrained_layout=True)
      fig.suptitle('Figure title')
      
      # create 3x1 subfigs
      subfigs = fig.subfigures(nrows=3, ncols=1)
      for row, subfig in enumerate(subfigs):
          subfig.suptitle(f'Subfigure title {row}')
      
          # create 1x3 subplots per subfig
          axs = subfig.subplots(nrows=1, ncols=3)
          for col, ax in enumerate(axs):
              ax.plot()
              ax.set_title(f'Plot title {col}')
      
    • Or Figure.add_subfigure (onto existing subplots)

      If you already have 3x1 plt.subplots, then add_subfigure into the underlying gridspec. Again each subfig will get its own 1x3 subfig.subplots and subfig.suptitle:

      # create 3x1 subplots
      fig, axs = plt.subplots(nrows=3, ncols=1, constrained_layout=True)
      fig.suptitle('Figure title')
      
      # clear subplots
      for ax in axs:
          ax.remove()
      
      # add subfigure per subplot
      gridspec = axs[0].get_subplotspec().get_gridspec()
      subfigs = [fig.add_subfigure(gs) for gs in gridspec]
      
      for row, subfig in enumerate(subfigs):
          subfig.suptitle(f'Subfigure title {row}')
      
          # create 1x3 subplots per subfig
          axs = subfig.subplots(nrows=1, ncols=3)
          for col, ax in enumerate(axs):
              ax.plot()
              ax.set_title(f'Plot title {col}')
      

    Output of either example (after some styling):