{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n\n.. redirect-from:: /gallery/subplots_axes_and_figures/colorbar_placement\n\n# Placing colorbars\n\nColorbars indicate the quantitative extent of image data. Placing in\na figure is non-trivial because room needs to be made for them.\n\n## Automatic placement of colorbars\n\nThe simplest case is just attaching a colorbar to each Axes. Note in this\nexample that the colorbars steal some space from the parent Axes.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\nimport numpy as np\n\n# Fixing random state for reproducibility\nnp.random.seed(19680801)\n\nfig, axs = plt.subplots(2, 2)\ncmaps = ['RdBu_r', 'viridis']\nfor col in range(2):\n for row in range(2):\n ax = axs[row, col]\n pcm = ax.pcolormesh(np.random.random((20, 20)) * (col + 1),\n cmap=cmaps[col])\n fig.colorbar(pcm, ax=ax)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The first column has the same type of data in both rows, so it may be\ndesirable to have just one colorbar. We do this by passing `.Figure.colorbar`\na list of Axes with the *ax* kwarg.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, axs = plt.subplots(2, 2)\ncmaps = ['RdBu_r', 'viridis']\nfor col in range(2):\n for row in range(2):\n ax = axs[row, col]\n pcm = ax.pcolormesh(np.random.random((20, 20)) * (col + 1),\n cmap=cmaps[col])\n fig.colorbar(pcm, ax=axs[:, col], shrink=0.6)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The stolen space can lead to Axes in the same subplot layout\nbeing different sizes, which is often undesired if the the\nx-axis on each plot is meant to be comparable as in the following:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, axs = plt.subplots(2, 1, figsize=(4, 5), sharex=True)\nX = np.random.randn(20, 20)\naxs[0].plot(np.sum(X, axis=0))\npcm = axs[1].pcolormesh(X)\nfig.colorbar(pcm, ax=axs[1], shrink=0.6)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is usually undesired, and can be worked around in various ways, e.g.\nadding a colorbar to the other Axes and then removing it. However, the most\nstraightforward is to use `constrained layout `:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, axs = plt.subplots(2, 1, figsize=(4, 5), sharex=True, layout='constrained')\naxs[0].plot(np.sum(X, axis=0))\npcm = axs[1].pcolormesh(X)\nfig.colorbar(pcm, ax=axs[1], shrink=0.6)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Relatively complicated colorbar layouts are possible using this\nparadigm. Note that this example works far better with\n``layout='constrained'``\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, axs = plt.subplots(3, 3, layout='constrained')\nfor ax in axs.flat:\n pcm = ax.pcolormesh(np.random.random((20, 20)))\n\nfig.colorbar(pcm, ax=axs[0, :2], shrink=0.6, location='bottom')\nfig.colorbar(pcm, ax=[axs[0, 2]], location='bottom')\nfig.colorbar(pcm, ax=axs[1:, :], location='right', shrink=0.6)\nfig.colorbar(pcm, ax=[axs[2, 1]], location='left')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Adjusting the spacing between colorbars and parent Axes\n\nThe distance a colorbar is from the parent Axes can be adjusted with the\n*pad* keyword argument. This is in units of fraction of the parent Axes\nwidth, and the default for a vertical Axes is 0.05 (or 0.15 for a horizontal\nAxes).\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, axs = plt.subplots(3, 1, layout='constrained', figsize=(5, 5))\nfor ax, pad in zip(axs, [0.025, 0.05, 0.1]):\n pcm = ax.pcolormesh(np.random.randn(20, 20), cmap='viridis')\n fig.colorbar(pcm, ax=ax, pad=pad, label=f'pad: {pad}')\nfig.suptitle(\"layout='constrained'\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that if you do not use constrained layout, the pad command makes the\nparent Axes shrink:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, axs = plt.subplots(3, 1, figsize=(5, 5))\nfor ax, pad in zip(axs, [0.025, 0.05, 0.1]):\n pcm = ax.pcolormesh(np.random.randn(20, 20), cmap='viridis')\n fig.colorbar(pcm, ax=ax, pad=pad, label=f'pad: {pad}')\nfig.suptitle(\"No layout manager\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Manual placement of colorbars\n\nSometimes the automatic placement provided by ``colorbar`` does not\ngive the desired effect. We can manually create an Axes and tell\n``colorbar`` to use that Axes by passing the Axes to the *cax* keyword\nargument.\n\n### Using ``inset_axes``\n\nWe can manually create any type of Axes for the colorbar to use, but an\n`.Axes.inset_axes` is useful because it is a child of the parent Axes and can\nbe positioned relative to the parent. Here we add a colorbar centered near\nthe bottom of the parent Axes.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, ax = plt.subplots(layout='constrained', figsize=(4, 4))\npcm = ax.pcolormesh(np.random.randn(20, 20), cmap='viridis')\nax.set_ylim([-4, 20])\ncax = ax.inset_axes([0.3, 0.07, 0.4, 0.04])\nfig.colorbar(pcm, cax=cax, orientation='horizontal')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`.Axes.inset_axes` can also specify its position in data coordinates\nusing the *transform* keyword argument if you want your Axes at a\ncertain data position on the graph:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, ax = plt.subplots(layout='constrained', figsize=(4, 4))\npcm = ax.pcolormesh(np.random.randn(20, 20), cmap='viridis')\nax.set_ylim([-4, 20])\ncax = ax.inset_axes([7.5, -1.7, 5, 1.2], transform=ax.transData)\nfig.colorbar(pcm, cax=cax, orientation='horizontal')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Colorbars attached to fixed-aspect-ratio Axes\n\nPlacing colorbars for Axes with a fixed aspect ratio pose a particular\nchallenge as the parent Axes changes size depending on the data view.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, axs = plt.subplots(2, 2, layout='constrained')\ncmaps = ['RdBu_r', 'viridis']\nfor col in range(2):\n for row in range(2):\n ax = axs[row, col]\n pcm = ax.pcolormesh(np.random.random((20, 20)) * (col + 1),\n cmap=cmaps[col])\n if col == 0:\n ax.set_aspect(2)\n else:\n ax.set_aspect(1/2)\n if row == 1:\n fig.colorbar(pcm, ax=ax, shrink=0.6)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We solve this problem using `.Axes.inset_axes` to locate the Axes in \"axes\ncoordinates\" (see `transforms_tutorial`). Note that if you zoom in on\nthe parent Axes, and thus change the shape of it, the colorbar will also\nchange position.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, axs = plt.subplots(2, 2, layout='constrained')\ncmaps = ['RdBu_r', 'viridis']\nfor col in range(2):\n for row in range(2):\n ax = axs[row, col]\n pcm = ax.pcolormesh(np.random.random((20, 20)) * (col + 1),\n cmap=cmaps[col])\n if col == 0:\n ax.set_aspect(2)\n else:\n ax.set_aspect(1/2)\n if row == 1:\n cax = ax.inset_axes([1.04, 0.2, 0.05, 0.6])\n fig.colorbar(pcm, cax=cax)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ".. seealso::\n\n `axes_grid` has methods for manually creating colorbar Axes as well:\n\n - `demo-colorbar-with-inset-locator`\n - `demo-colorbar-with-axes-divider`\n\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.2" } }, "nbformat": 4, "nbformat_minor": 0 }