{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n# Scatter plot with histograms\n\nAdd histograms to the x-axes and y-axes margins of a scatter plot.\n\nThis layout features a central scatter plot illustrating the relationship\nbetween x and y, a histogram at the top displaying the distribution of x, and a\nhistogram on the right showing the distribution of y.\n\nFor a nice alignment of the main Axes with the marginals, two options are shown\nbelow:\n\nWhile `.Axes.inset_axes` may be a bit more complex, it allows correct handling\nof main Axes with a fixed aspect ratio.\n\nLet us first define a function that takes x and y data as input, as well as\nthree Axes, the main Axes for the scatter, and two marginal Axes. It will then\ncreate the scatter and histograms inside the provided 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\n# some random data\nx = np.random.randn(1000)\ny = np.random.randn(1000)\n\n\ndef scatter_hist(x, y, ax, ax_histx, ax_histy):\n # no labels\n ax_histx.tick_params(axis=\"x\", labelbottom=False)\n ax_histy.tick_params(axis=\"y\", labelleft=False)\n\n # the scatter plot:\n ax.scatter(x, y)\n\n # now determine nice limits by hand:\n binwidth = 0.25\n xymax = max(np.max(np.abs(x)), np.max(np.abs(y)))\n lim = (int(xymax/binwidth) + 1) * binwidth\n\n bins = np.arange(-lim, lim + binwidth, binwidth)\n ax_histx.hist(x, bins=bins)\n ax_histy.hist(y, bins=bins, orientation='horizontal')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Defining the Axes positions using subplot_mosaic\n\nWe use the `~.pyplot.subplot_mosaic` function to define the positions and\nnames of the three axes; the empty axes is specified by ``'.'``. We manually\nspecify the size of the figure, and can make the different axes have\ndifferent sizes by specifying the *width_ratios* and *height_ratios*\narguments. The *layout* argument is set to ``'constrained'`` to optimize the\nspacing between the axes.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, axs = plt.subplot_mosaic([['histx', '.'],\n ['scatter', 'histy']],\n figsize=(6, 6),\n width_ratios=(4, 1), height_ratios=(1, 4),\n layout='constrained')\nscatter_hist(x, y, axs['scatter'], axs['histx'], axs['histy'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Defining the Axes positions using inset_axes\n\n`~.Axes.inset_axes` can be used to position marginals *outside* the main\nAxes. The advantage of doing so is that the aspect ratio of the main Axes\ncan be fixed, and the marginals will always be drawn relative to the position\nof the Axes.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Create a Figure, which doesn't have to be square.\nfig = plt.figure(layout='constrained')\n# Create the main Axes.\nax = fig.add_subplot()\n# The main Axes' aspect can be fixed.\nax.set_aspect('equal')\n# Create marginal Axes, which have 25% of the size of the main Axes. Note that\n# the inset Axes are positioned *outside* (on the right and the top) of the\n# main Axes, by specifying axes coordinates greater than 1. Axes coordinates\n# less than 0 would likewise specify positions on the left and the bottom of\n# the main Axes.\nax_histx = ax.inset_axes([0, 1.05, 1, 0.25], sharex=ax)\nax_histy = ax.inset_axes([1.05, 0, 0.25, 1], sharey=ax)\n# Draw the scatter plot and marginals.\nscatter_hist(x, y, ax, ax_histx, ax_histy)\n\nplt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "While we recommend using one of the two methods described above, there are\nnumber of other ways to achieve a similar layout:\n\n- The Axes can be positioned manually in relative coordinates using\n `~matplotlib.figure.Figure.add_axes`.\n- A gridspec can be used to create the layout\n (`~matplotlib.figure.Figure.add_gridspec`) and adding only the three desired\n axes (`~matplotlib.figure.Figure.add_subplot`).\n- Four subplots can be created using `~.pyplot.subplots`, and the unused\n axes in the upper right can be removed manually.\n- The ``axes_grid1`` toolkit can be used, as shown in\n :doc:`/gallery/axes_grid1/scatter_hist_locatable_axes`.\n\n.. admonition:: References\n\n The use of the following functions, methods, classes and modules is shown\n in this example:\n\n - `matplotlib.figure.Figure.subplot_mosaic`\n - `matplotlib.pyplot.subplot_mosaic`\n - `matplotlib.figure.Figure.add_subplot`\n - `matplotlib.axes.Axes.inset_axes`\n - `matplotlib.axes.Axes.scatter`\n - `matplotlib.axes.Axes.hist`\n\n.. tags::\n\n component: axes\n plot-type: scatter\n plot-type: histogram\n level: intermediate\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 }