|
| 1 | + |
| 2 | +.. _figure_explanation: |
| 3 | + |
| 4 | +================================================ |
| 5 | +Creating, viewing, and saving Matplotlib Figures |
| 6 | +================================================ |
| 7 | + |
| 8 | +.. plot:: |
| 9 | + :include-source: |
| 10 | + |
| 11 | + fig = plt.figure(figsize=(2, 2), facecolor='0.8', layout='constrained') |
| 12 | + ax = fig.add_subplot() |
| 13 | + |
| 14 | +When looking at Matplotlib visualization, you are almost always looking at |
| 15 | +Artists placed on a `~.Figure`. In the example above, the figure is the |
| 16 | +gray region and `~.Figure.add_subplot` has added an `~.axes.Axes` artist to the |
| 17 | +`~.Figure` (see :ref:`figure_parts`). A more complicated visualization can add multiple Axes to |
| 18 | +the Figure, colorbars, legends, annotations, and the Axes theselves can have |
| 19 | +multiple Artists added to them (e.g. ``ax.plot`` or ``ax.imshow``). |
| 20 | + |
| 21 | +.. _viewing_figures: |
| 22 | + |
| 23 | +Viewing Figures |
| 24 | +================ |
| 25 | + |
| 26 | +We will discuss how to create Figures in more detail below, but first it is |
| 27 | +helpful to understand how to view a Figure. This varies based on how you are |
| 28 | +using Matplotlib, and what :ref:`Backend <what-is-a-backend>` you are using. |
| 29 | + |
| 30 | +Notebooks and IDEs |
| 31 | +------------------ |
| 32 | + |
| 33 | +If you are using a Notebook (e.g. `Jupyter <https://jupyter.org>`_) or an IDE |
| 34 | +that renders Notebooks (PyCharm, VSCode, etc), then they have a backend that |
| 35 | +will render the Matplotlib Figure when a code cell is executed. One thing to |
| 36 | +be aware of is that the default Jupyter backend (``%matplotlib inline``) will |
| 37 | +by default trim or expand the figure size to have a tight box around Artists |
| 38 | +added to the Figure (see :ref:`saving_figures`, below). |
| 39 | + |
| 40 | +Standalone scripts and interctive use |
| 41 | +------------------------------------- |
| 42 | + |
| 43 | +If the user is on a client with a windowing system, there are a number of |
| 44 | +:ref:`Backends <what-is-a-backend>` that can be used to render the Figure to |
| 45 | +the screen, usually using a Python Qt, Tk, or Wx toolkit, though there is a native |
| 46 | +MacOS backend as well. These are typically chosen either in the user's |
| 47 | +:ref:`matplotlibrc <customizing-with-matplotlibrc-files>`, or by calling |
| 48 | +``matplotlib.use('QtAgg')`` at the beginning of a session or script. |
| 49 | + |
| 50 | +When run from a script, or interactively (e.g. from an |
| 51 | +`iPython shell <https://https://ipython.readthedocs.io/en/stable/>`_) the Figure |
| 52 | +will not be shown until we call ``plt.show()``. The Figure will appear in |
| 53 | +a new GUI window, and usually will have a toolbar with Zoom, Pan, and other tools |
| 54 | +for interacting with the Figure. By default, ``plt.show()`` blocks |
| 55 | +further interaction from the script or shell until the Figure window is closed, |
| 56 | +though that can be toggled off for some pusposes. For more details, please see |
| 57 | +:ref:`controlling-interactive`. |
| 58 | + |
| 59 | +Note that if you are on a client that does not have access to a windowing |
| 60 | +system, the Figure will fallback to being drawn using the "Agg" backend, and |
| 61 | +cannot be viewed, though it can be :ref:`saved <saving_figures>`. |
| 62 | + |
| 63 | +.. _creating_figures: |
| 64 | + |
| 65 | +Creating Figures |
| 66 | +================ |
| 67 | + |
| 68 | +By far the most common way to create a figure is using the |
| 69 | +:doc:`pyplot </tutorials/introductory/pyplot>` interface. As noted in |
| 70 | +:ref:`api_interfaces`, the pyplot interface serves two purposes. One is to spin |
| 71 | +up the Backend and keep track of GUI windows. The other is a global state for |
| 72 | +Axes and Artists that allow a short-form API to plotting methods. In the |
| 73 | +example above, we only use pyplot for the first purpose, to create the Figure |
| 74 | +object, ``fig``. |
| 75 | + |
| 76 | +In addition to `~.pyplot.figure`, there are convenience methods to create Axes |
| 77 | +at the same time that the figure is created since these two actions are so commonly |
| 78 | +done at the same time. A simple grid can be achieved with `~.pyplot.subplots` (which |
| 79 | +simply wraps `~.Figure.subplots`): |
| 80 | + |
| 81 | +.. plot:: |
| 82 | + :include-source: |
| 83 | + |
| 84 | + fig, axs = plt.subplots(2, 2, figsize=(4, 3), layout='constrained') |
| 85 | + |
| 86 | +More complex grids can be achieved with `~.pyplot.subplot_mosaic` (which wraps |
| 87 | +`~.Figure.subplot_mosaic`): |
| 88 | + |
| 89 | +.. plot:: |
| 90 | + :include-source: |
| 91 | + |
| 92 | + fig, axs = plt.subplot_mosaic([['A', 'right'], ['B', 'right']], |
| 93 | + figsize=(4, 3), layout='constrained') |
| 94 | + for ax_name in axs: |
| 95 | + axs[ax_name].text(0.5, 0.5, ax_name, ha='center', va='center') |
| 96 | + |
| 97 | +Sometimes we want to have a nested layout in a Figure, with two or more sets of |
| 98 | +Axes that do not necessarily share the same subplot grid. |
| 99 | +We can use `~.Figure.add_subfigure` or `~.Figure.subfigures` to create virtual |
| 100 | +figures inside a parent Figure; see |
| 101 | +:doc:`/gallery/subplots_axes_and_figures/subfigures` for more details. |
| 102 | + |
| 103 | +.. plot:: |
| 104 | + :include-source: |
| 105 | + |
| 106 | + fig = plt.figure(layout='constrained', facecolor='beige') |
| 107 | + fig.suptitle('Figure') |
| 108 | + figL, figR = fig.subfigures(1, 2) |
| 109 | + figL.set_facecolor('0.9') |
| 110 | + axL = figL.subplots(2, 1, sharex=True) |
| 111 | + figL.suptitle('Left subfigure') |
| 112 | + figR.set_facecolor('0.7') |
| 113 | + axR = figR.subplots(1, 2, sharey=True) |
| 114 | + figR.suptitle('Right subfigure') |
| 115 | + |
| 116 | +It is possible to directly instantiate a `.Figure` instance without using the |
| 117 | +pyplot interface. This is usually only necessary if you want to create your |
| 118 | +own GUI application or service that you do not want carrying the pyplot global |
| 119 | +state. See the embedding examples in :doc:`/gallery/user_interfaces/index` for |
| 120 | +examples of how to do this. |
| 121 | + |
| 122 | +Figure options |
| 123 | +-------------- |
| 124 | + |
| 125 | +There are a few options available when creating figures. The Figure size on |
| 126 | +the screen is set by *figsize* and *dpi*. *figsize* is the ``(width, height)`` |
| 127 | +of the Figure in inches (or, if preferred, units of 72 typographic points). *dpi* |
| 128 | +are how many pixels per inch the figure will be rendered at. To make your Figures |
| 129 | +appear on the screen at the physical size you requested, you should set *dpi* |
| 130 | +to the same *dpi* as your graphics system. Note that many graphics systems now use |
| 131 | +a "dpi ratio" to specify how many screen pixels are used to represent a graphics |
| 132 | +pixel. Matplotlib applies the dpi ratio to the *dpi* passed to the figure to make |
| 133 | +it have higher resolution, so you should pass the lower number to the figure. |
| 134 | + |
| 135 | +The *facecolor*, *edgecolor*, *linewidth*, and *frameon* options all change the appearance of the |
| 136 | +figure in expected ways, with *frameon* making the figure transparent if set to *False*. |
| 137 | + |
| 138 | +Finally, the user can specify a layout engine for the figure with the *layout* |
| 139 | +parameter. Currently Matplotlib supplies |
| 140 | +:doc:`"constrained" </tutorials/intermediate/constrainedlayout_guide>`, |
| 141 | +:ref:`"compressed" <compressed_layout>` and |
| 142 | +:doc:`"tight" </tutorials/intermediate/tight_layout_guide>` layout engines. These |
| 143 | +rescale axes inside the Figure to prevent overlap of ticklabels, and try and align |
| 144 | +axes, and can save significant manual adjustment of artists on a Figure for many |
| 145 | +common cases. |
| 146 | + |
| 147 | +.. _saving_figures: |
| 148 | + |
| 149 | +Saving Figures |
| 150 | +============== |
| 151 | + |
| 152 | +Finally, Figures can be saved to disk using the `~.Figure.savefig` method. |
| 153 | +``fig.savefig('MyFigure.png', dpi=200)`` will save a PNG formatted figure to |
| 154 | +the file ``MyFigure.png`` in the current directory on disk with 200 dots-per-inch |
| 155 | +resolution. Note that the filename can include a relative or absolute path to |
| 156 | +any place on the file system. |
| 157 | + |
| 158 | +Many types of output are supported, including raster formats like PNG, GIF, JPEG, |
| 159 | +TIFF and vector formats like PDF, EPS, and SVG. |
| 160 | + |
| 161 | +By default, the size of the saved Figure is set by the Figure size (in inches) and, for the raster |
| 162 | +formats, the *dpi*. If *dpi* is not set, then the *dpi* of the Figure is used. |
| 163 | +Note that *dpi* still has meaning for vector formats like PDF if the Figure includes |
| 164 | +Artists that have been :doc:`rasterized </gallery/misc/rasterization_demo>`; the |
| 165 | +*dpi* specified will be the resolution of the rasterized objects. |
| 166 | + |
| 167 | +It is possible to change the size of the Figure using the *bbox_inches* argument |
| 168 | +to savefig. This can be specified manually, again in inches. However, by far |
| 169 | +the most common use is ``bbox_inches='tight'``. This option trims, or expands, the |
| 170 | +size of the figure so that it is tight around all the artists in a figure, with a |
| 171 | +small pad that can be specified by *pad_inches*, which defaults to 0.1 inches. |
| 172 | +The dashed box in the plot below shows the portion of the figure that would be |
| 173 | +saved if ``bbox_inches='tight'`` were used in savefig. |
| 174 | + |
| 175 | +.. plot:: |
| 176 | + |
| 177 | + import matplotlib.pyplot as plt |
| 178 | + from matplotlib.patches import FancyBboxPatch |
| 179 | + |
| 180 | + fig, ax = plt.subplots(figsize=(4, 2), facecolor='0.8') |
| 181 | + ax.set_position([0.1, 0.2, 0.8, 0.7]) |
| 182 | + ax.set_aspect(1) |
| 183 | + bb = ax.get_tightbbox() |
| 184 | + bb = bb.padded(10) |
| 185 | + fancy = FancyBboxPatch(bb.p0, bb.width, bb.height, fc='none', |
| 186 | + ec=(0, 0.0, 0, 0.5), lw=2, linestyle='--', |
| 187 | + transform=None, clip_on=False) |
| 188 | + ax.add_patch(fancy) |
0 commit comments