{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n# Quick start guide\n\nThis tutorial covers some basic usage patterns and best practices to\nhelp you get started with Matplotlib.\n\n.. redirect-from:: /tutorials/introductory/usage\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import matplotlib as mpl\nimport matplotlib.pyplot as plt\nimport numpy as np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## A simple example\n\nMatplotlib graphs your data on .Figure\\s (e.g., windows, Jupyter\nwidgets, etc.), each of which can contain one or more ~.axes.Axes, an\narea where points can be specified in terms of x-y coordinates (or theta-r\nin a polar plot, x-y-z in a 3D plot, etc). The simplest way of\ncreating a Figure with an Axes is using .pyplot.subplots. We can then use\n.Axes.plot to draw some data on the Axes:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, ax = plt.subplots() # Create a figure containing a single axes.\nax.plot([1, 2, 3, 4], [1, 4, 2, 3]); # Plot some data on the axes." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n## Parts of a Figure\n\nHere are the components of a Matplotlib Figure.\n\n \n\n### :class:~matplotlib.figure.Figure\n\nThe **whole** figure. The Figure keeps\ntrack of all the child :class:~matplotlib.axes.Axes, a group of\n'special' Artists (titles, figure legends, colorbars, etc), and\neven nested subfigures.\n\nThe easiest way to create a new Figure is with pyplot::\n\n fig = plt.figure() # an empty figure with no Axes\n fig, ax = plt.subplots() # a figure with a single Axes\n fig, axs = plt.subplots(2, 2) # a figure with a 2x2 grid of Axes\n\nIt is often convenient to create the Axes together with the Figure, but you\ncan also manually add Axes later on. Note that many\n:doc:Matplotlib backends  support zooming and\npanning on figure windows.\n\n### :class:~matplotlib.axes.Axes\n\nAn Axes is an Artist attached to a Figure that contains a region for\nplotting data, and usually includes two (or three in the case of 3D)\n:class:~matplotlib.axis.Axis objects (be aware of the difference\nbetween **Axes** and **Axis**) that provide ticks and tick labels to\nprovide scales for the data in the Axes. Each :class:~.axes.Axes also\nhas a title\n(set via :meth:~matplotlib.axes.Axes.set_title), an x-label (set via\n:meth:~matplotlib.axes.Axes.set_xlabel), and a y-label set via\n:meth:~matplotlib.axes.Axes.set_ylabel).\n\nThe :class:~.axes.Axes class and its member functions are the primary\nentry point to working with the OOP interface, and have most of the\nplotting methods defined on them (e.g. ax.plot(), shown above, uses\nthe ~.Axes.plot method)\n\n### :class:~matplotlib.axis.Axis\n\nThese objects set the scale and limits and generate ticks (the marks\non the Axis) and ticklabels (strings labeling the ticks). The location\nof the ticks is determined by a ~matplotlib.ticker.Locator object and the\nticklabel strings are formatted by a ~matplotlib.ticker.Formatter. The\ncombination of the correct .Locator and .Formatter gives very fine\ncontrol over the tick locations and labels.\n\n### :class:~matplotlib.artist.Artist\n\nBasically, everything visible on the Figure is an Artist (even\n.Figure, Axes <.axes.Axes>, and ~.axis.Axis objects). This includes\n.Text objects, .Line2D objects, :mod:.collections objects, .Patch\nobjects, etc. When the Figure is rendered, all of the\nArtists are drawn to the **canvas**. Most Artists are tied to an Axes; such\nan Artist cannot be shared by multiple Axes, or moved from one to another.\n\n\n## Types of inputs to plotting functions\n\nPlotting functions expect numpy.array or numpy.ma.masked_array as\ninput, or objects that can be passed to numpy.asarray.\nClasses that are similar to arrays ('array-like') such as pandas\ndata objects and numpy.matrix may not work as intended. Common convention\nis to convert these to numpy.array objects prior to plotting.\nFor example, to convert a numpy.matrix ::\n\n b = np.matrix([[1, 2], [3, 4]])\n b_asarray = np.asarray(b)\n\nMost methods will also parse an addressable object like a *dict*, a\nnumpy.recarray, or a pandas.DataFrame. Matplotlib allows you provide\nthe data keyword argument and generate plots passing the strings\ncorresponding to the *x* and *y* variables.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "np.random.seed(19680801) # seed the random number generator.\ndata = {'a': np.arange(50),\n 'c': np.random.randint(0, 50, 50),\n 'd': np.random.randn(50)}\ndata['b'] = data['a'] + 10 * np.random.randn(50)\ndata['d'] = np.abs(data['d']) * 100\n\nfig, ax = plt.subplots(figsize=(5, 2.7), layout='constrained')\nax.scatter('a', 'b', c='c', s='d', data=data)\nax.set_xlabel('entry a')\nax.set_ylabel('entry b');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n## Coding styles\n\n### The explicit and the implicit interfaces\n\nAs noted above, there are essentially two ways to use Matplotlib:\n\n- Explicitly create Figures and Axes, and call methods on them (the\n \"object-oriented (OO) style\").\n- Rely on pyplot to implicitly create and manage the Figures and Axes, and\n use pyplot functions for plotting.\n\nSee api_interfaces for an explanation of the tradeoffs between the\nimplicit and explicit interfaces.\n\nSo one can use the OO-style\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "x = np.linspace(0, 2, 100) # Sample data.\n\n# Note that even in the OO-style, we use .pyplot.figure to create the Figure.\nfig, ax = plt.subplots(figsize=(5, 2.7), layout='constrained')\nax.plot(x, x, label='linear') # Plot some data on the axes.\nax.plot(x, x**2, label='quadratic') # Plot more data on the axes...\nax.plot(x, x**3, label='cubic') # ... and some more.\nax.set_xlabel('x label') # Add an x-label to the axes.\nax.set_ylabel('y label') # Add a y-label to the axes.\nax.set_title(\"Simple Plot\") # Add a title to the axes.\nax.legend(); # Add a legend." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "or the pyplot-style:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "x = np.linspace(0, 2, 100) # Sample data.\n\nplt.figure(figsize=(5, 2.7), layout='constrained')\nplt.plot(x, x, label='linear') # Plot some data on the (implicit) axes.\nplt.plot(x, x**2, label='quadratic') # etc.\nplt.plot(x, x**3, label='cubic')\nplt.xlabel('x label')\nplt.ylabel('y label')\nplt.title(\"Simple Plot\")\nplt.legend();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "(In addition, there is a third approach, for the case when embedding\nMatplotlib in a GUI application, which completely drops pyplot, even for\nfigure creation. See the corresponding section in the gallery for more info:\nuser_interfaces.)\n\nMatplotlib's documentation and examples use both the OO and the pyplot\nstyles. In general, we suggest using the OO style, particularly for\ncomplicated plots, and functions and scripts that are intended to be reused\nas part of a larger project. However, the pyplot style can be very convenient\nfor quick interactive work.\n\n

#### Note

You may find older examples that use the pylab interface,\n via from pylab import *. This approach is strongly deprecated.

\n\n### Making a helper functions\n\nIf you need to make the same plots over and over again with different data\nsets, or want to easily wrap Matplotlib methods, use the recommended\nsignature function below.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def my_plotter(ax, data1, data2, param_dict):\n \"\"\"\n A helper function to make a graph.\n \"\"\"\n out = ax.plot(data1, data2, **param_dict)\n return out" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "which you would then use twice to populate two subplots:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "data1, data2, data3, data4 = np.random.randn(4, 100) # make 4 random data sets\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(5, 2.7))\nmy_plotter(ax1, data1, data2, {'marker': 'x'})\nmy_plotter(ax2, data3, data4, {'marker': 'o'});" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that if you want to install these as a python package, or any other\ncustomizations you could use one of the many templates on the web;\nMatplotlib has one at mpl-cookiecutter\n_\n\n\n## Styling Artists\n\nMost plotting methods have styling options for the Artists, accessible either\nwhen a plotting method is called, or from a \"setter\" on the Artist. In the\nplot below we manually set the *color*, *linewidth*, and *linestyle* of the\nArtists created by ~.Axes.plot, and we set the linestyle of the second line\nafter the fact with ~.Line2D.set_linestyle.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, ax = plt.subplots(figsize=(5, 2.7))\nx = np.arange(len(data1))\nax.plot(x, np.cumsum(data1), color='blue', linewidth=3, linestyle='--')\nl, = ax.plot(x, np.cumsum(data2), color='orange', linewidth=2)\nl.set_linestyle(':');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Colors\n\nMatplotlib has a very flexible array of colors that are accepted for most\nArtists; see the :doc:colors tutorial  for a\nlist of specifications. Some Artists will take multiple colors. i.e. for\na ~.Axes.scatter plot, the edge of the markers can be different colors\nfrom the interior:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, ax = plt.subplots(figsize=(5, 2.7))\nax.scatter(data1, data2, s=50, facecolor='C0', edgecolor='k');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Linewidths, linestyles, and markersizes\n\nLine widths are typically in typographic points (1 pt = 1/72 inch) and\navailable for Artists that have stroked lines. Similarly, stroked lines\ncan have a linestyle. See the :doc:linestyles example\n.\n\nMarker size depends on the method being used. ~.Axes.plot specifies\nmarkersize in points, and is generally the \"diameter\" or width of the\nmarker. ~.Axes.scatter specifies markersize as approximately\nproportional to the visual area of the marker. There is an array of\nmarkerstyles available as string codes (see :mod:~.matplotlib.markers), or\nusers can define their own ~.MarkerStyle (see\n:doc:/gallery/lines_bars_and_markers/marker_reference):\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, ax = plt.subplots(figsize=(5, 2.7))\nax.plot(data1, 'o', label='data1')\nax.plot(data2, 'd', label='data2')\nax.plot(data3, 'v', label='data3')\nax.plot(data4, 's', label='data4')\nax.legend();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Labelling plots\n\n### Axes labels and text\n\n~.Axes.set_xlabel, ~.Axes.set_ylabel, and ~.Axes.set_title are used to\nadd text in the indicated locations (see :doc:/tutorials/text/text_intro\nfor more discussion). Text can also be directly added to plots using\n~.Axes.text:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "mu, sigma = 115, 15\nx = mu + sigma * np.random.randn(10000)\nfig, ax = plt.subplots(figsize=(5, 2.7), layout='constrained')\n# the histogram of the data\nn, bins, patches = ax.hist(x, 50, density=True, facecolor='C0', alpha=0.75)\n\nax.set_xlabel('Length [cm]')\nax.set_ylabel('Probability')\nax.set_title('Aardvark lengths\\n (not really)')\nax.text(75, .025, r'$\\mu=115,\\ \\sigma=15$')\nax.axis([55, 175, 0, 0.03])\nax.grid(True);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "All of the ~.Axes.text functions return a matplotlib.text.Text\ninstance. Just as with lines above, you can customize the properties by\npassing keyword arguments into the text functions::\n\n t = ax.set_xlabel('my data', fontsize=14, color='red')\n\nThese properties are covered in more detail in\n:doc:/tutorials/text/text_props.\n\n### Using mathematical expressions in text\n\nMatplotlib accepts TeX equation expressions in any text expression.\nFor example to write the expression $\\sigma_i=15$ in the title,\nyou can write a TeX expression surrounded by dollar signs::\n\n ax.set_title(r'$\\sigma_i=15$')\n\nwhere the r preceding the title string signifies that the string is a\n*raw* string and not to treat backslashes as python escapes.\nMatplotlib has a built-in TeX expression parser and\nlayout engine, and ships its own math fonts \u2013 for details see\n:doc:/tutorials/text/mathtext. You can also use LaTeX directly to format\nyour text and incorporate the output directly into your display figures or\nsaved postscript \u2013 see :doc:/tutorials/text/usetex.\n\n### Annotations\n\nWe can also annotate points on a plot, often by connecting an arrow pointing\nto *xy*, to a piece of text at *xytext*:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, ax = plt.subplots(figsize=(5, 2.7))\n\nt = np.arange(0.0, 5.0, 0.01)\ns = np.cos(2 * np.pi * t)\nline, = ax.plot(t, s, lw=2)\n\nax.annotate('local max', xy=(2, 1), xytext=(3, 1.5),\n arrowprops=dict(facecolor='black', shrink=0.05))\n\nax.set_ylim(-2, 2);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this basic example, both *xy* and *xytext* are in data coordinates.\nThere are a variety of other coordinate systems one can choose -- see\nannotations-tutorial and plotting-guide-annotation for\ndetails. More examples also can be found in\n:doc:/gallery/text_labels_and_annotations/annotation_demo.\n\n### Legends\n\nOften we want to identify lines or markers with a .Axes.legend:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, ax = plt.subplots(figsize=(5, 2.7))\nax.plot(np.arange(len(data1)), data1, label='data1')\nax.plot(np.arange(len(data2)), data2, label='data2')\nax.plot(np.arange(len(data3)), data3, 'd', label='data3')\nax.legend();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Legends in Matplotlib are quite flexible in layout, placement, and what\nArtists they can represent. They are discussed in detail in\n:doc:/tutorials/intermediate/legend_guide.\n\n## Axis scales and ticks\n\nEach Axes has two (or three) ~.axis.Axis objects representing the x- and\ny-axis. These control the *scale* of the Axis, the tick *locators* and the\ntick *formatters*. Additional Axes can be attached to display further Axis\nobjects.\n\n### Scales\n\nIn addition to the linear scale, Matplotlib supplies non-linear scales,\nsuch as a log-scale. Since log-scales are used so much there are also\ndirect methods like ~.Axes.loglog, ~.Axes.semilogx, and\n~.Axes.semilogy. There are a number of scales (see\n:doc:/gallery/scales/scales for other examples). Here we set the scale\nmanually:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, axs = plt.subplots(1, 2, figsize=(5, 2.7), layout='constrained')\nxdata = np.arange(len(data1)) # make an ordinal for this\ndata = 10**data1\naxs.plot(xdata, data)\n\naxs.set_yscale('log')\naxs.plot(xdata, data);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The scale sets the mapping from data values to spacing along the Axis. This\nhappens in both directions, and gets combined into a *transform*, which\nis the way that Matplotlib maps from data coordinates to Axes, Figure, or\nscreen coordinates. See :doc:/tutorials/advanced/transforms_tutorial.\n\n### Tick locators and formatters\n\nEach Axis has a tick *locator* and *formatter* that choose where along the\nAxis objects to put tick marks. A simple interface to this is\n~.Axes.set_xticks:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, axs = plt.subplots(2, 1, layout='constrained')\naxs.plot(xdata, data1)\naxs.set_title('Automatic ticks')\n\naxs.plot(xdata, data1)\naxs.set_xticks(np.arange(0, 100, 30), ['zero', '30', 'sixty', '90'])\naxs.set_yticks([-1.5, 0, 1.5]) # note that we don't need to specify labels\naxs.set_title('Manual ticks');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Different scales can have different locators and formatters; for instance\nthe log-scale above uses ~.LogLocator and ~.LogFormatter. See\n:doc:/gallery/ticks/tick-locators and\n:doc:/gallery/ticks/tick-formatters for other formatters and\nlocators and information for writing your own.\n\n### Plotting dates and strings\n\nMatplotlib can handle plotting arrays of dates and arrays of strings, as\nwell as floating point numbers. These get special locators and formatters\nas appropriate. For dates:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, ax = plt.subplots(figsize=(5, 2.7), layout='constrained')\ndates = np.arange(np.datetime64('2021-11-15'), np.datetime64('2021-12-25'),\n np.timedelta64(1, 'h'))\ndata = np.cumsum(np.random.randn(len(dates)))\nax.plot(dates, data)\ncdf = mpl.dates.ConciseDateFormatter(ax.xaxis.get_major_locator())\nax.xaxis.set_major_formatter(cdf);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For more information see the date examples\n(e.g. :doc:/gallery/text_labels_and_annotations/date)\n\nFor strings, we get categorical plotting (see:\n:doc:/gallery/lines_bars_and_markers/categorical_variables).\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, ax = plt.subplots(figsize=(5, 2.7), layout='constrained')\ncategories = ['turnips', 'rutabaga', 'cucumber', 'pumpkins']\n\nax.bar(categories, np.random.rand(len(categories)));" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One caveat about categorical plotting is that some methods of parsing\ntext files return a list of strings, even if the strings all represent\nnumbers or dates. If you pass 1000 strings, Matplotlib will think you\nmeant 1000 categories and will add 1000 ticks to your plot!\n\n\n### Additional Axis objects\n\nPlotting data of different magnitude in one chart may require\nan additional y-axis. Such an Axis can be created by using\n~.Axes.twinx to add a new Axes with an invisible x-axis and a y-axis\npositioned at the right (analogously for ~.Axes.twiny). See\n:doc:/gallery/subplots_axes_and_figures/two_scales for another example.\n\nSimilarly, you can add a ~.Axes.secondary_xaxis or\n~.Axes.secondary_yaxis having a different scale than the main Axis to\nrepresent the data in different scales or units. See\n:doc:/gallery/subplots_axes_and_figures/secondary_axis for further\nexamples.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, (ax1, ax3) = plt.subplots(1, 2, figsize=(7, 2.7), layout='constrained')\nl1, = ax1.plot(t, s)\nax2 = ax1.twinx()\nl2, = ax2.plot(t, range(len(t)), 'C1')\nax2.legend([l1, l2], ['Sine (left)', 'Straight (right)'])\n\nax3.plot(t, s)\nax3.set_xlabel('Angle [rad]')\nax4 = ax3.secondary_xaxis('top', functions=(np.rad2deg, np.deg2rad))\nax4.set_xlabel('Angle [\u00b0]')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Color mapped data\n\nOften we want to have a third dimension in a plot represented by a colors in\na colormap. Matplotlib has a number of plot types that do this:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "X, Y = np.meshgrid(np.linspace(-3, 3, 128), np.linspace(-3, 3, 128))\nZ = (1 - X/2 + X**5 + Y**3) * np.exp(-X**2 - Y**2)\n\nfig, axs = plt.subplots(2, 2, layout='constrained')\npc = axs[0, 0].pcolormesh(X, Y, Z, vmin=-1, vmax=1, cmap='RdBu_r')\nfig.colorbar(pc, ax=axs[0, 0])\naxs[0, 0].set_title('pcolormesh()')\n\nco = axs[0, 1].contourf(X, Y, Z, levels=np.linspace(-1.25, 1.25, 11))\nfig.colorbar(co, ax=axs[0, 1])\naxs[0, 1].set_title('contourf()')\n\npc = axs[1, 0].imshow(Z**2 * 100, cmap='plasma',\n norm=mpl.colors.LogNorm(vmin=0.01, vmax=100))\nfig.colorbar(pc, ax=axs[1, 0], extend='both')\naxs[1, 0].set_title('imshow() with LogNorm()')\n\npc = axs[1, 1].scatter(data1, data2, c=data3, cmap='RdBu_r')\nfig.colorbar(pc, ax=axs[1, 1], extend='both')\naxs[1, 1].set_title('scatter()')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Colormaps\n\nThese are all examples of Artists that derive from ~.ScalarMappable\nobjects. They all can set a linear mapping between *vmin* and *vmax* into\nthe colormap specified by *cmap*. Matplotlib has many colormaps to choose\nfrom (:doc:/tutorials/colors/colormaps) you can make your\nown (:doc:/tutorials/colors/colormap-manipulation) or download as\nthird-party packages\n_.\n\n### Normalizations\n\nSometimes we want a non-linear mapping of the data to the colormap, as\nin the LogNorm example above. We do this by supplying the\nScalarMappable with the *norm* argument instead of *vmin* and *vmax*.\nMore normalizations are shown at :doc:/tutorials/colors/colormapnorms.\n\n### Colorbars\n\nAdding a ~.Figure.colorbar gives a key to relate the color back to the\nunderlying data. Colorbars are figure-level Artists, and are attached to\na ScalarMappable (where they get their information about the norm and\ncolormap) and usually steal space from a parent Axes. Placement of\ncolorbars can be complex: see\n:doc:/gallery/subplots_axes_and_figures/colorbar_placement for\ndetails. You can also change the appearance of colorbars with the\n*extend* keyword to add arrows to the ends, and *shrink* and *aspect* to\ncontrol the size. Finally, the colorbar will have default locators\nand formatters appropriate to the norm. These can be changed as for\nother Axis objects.\n\n\n## Working with multiple Figures and Axes\n\nYou can open multiple Figures with multiple calls to\nfig = plt.figure() or fig2, ax = plt.subplots(). By keeping the\nobject references you can add Artists to either Figure.\n\nMultiple Axes can be added a number of ways, but the most basic is\nplt.subplots() as used above. One can achieve more complex layouts,\nwith Axes objects spanning columns or rows, using ~.pyplot.subplot_mosaic.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, axd = plt.subplot_mosaic([['upleft', 'right'],\n ['lowleft', 'right']], layout='constrained')\naxd['upleft'].set_title('upleft')\naxd['lowleft'].set_title('lowleft')\naxd['right'].set_title('right');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Matplotlib has quite sophisticated tools for arranging Axes: See\n:doc:/tutorials/intermediate/arranging_axes and\n:doc:/tutorials/provisional/mosaic.\n\n\n## More reading\n\nFor more plot types see :doc:Plot types  and the\n:doc:API reference , in particular the\n:doc:Axes API .\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.8.13" } }, "nbformat": 4, "nbformat_minor": 0 }