{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n# Programmatically control subplot adjustment\n\n

Note

This example is primarily intended to show some advanced concepts in\n Matplotlib.\n\n If you are only looking for having enough space for your labels, it is\n almost always simpler and good enough to either set the subplot parameters\n manually using `.Figure.subplots_adjust`, or use one of the automatic\n layout mechanisms\n (`constrainedlayout_guide` or\n `tight_layout_guide`).

\n\nThis example describes a user-defined way to read out Artist sizes and\nset the subplot parameters accordingly. Its main purpose is to illustrate\nsome advanced concepts like reading out text positions, working with\nbounding boxes and transforms and using\n`events `. But it can also serve as a starting\npoint if you want to automate the layouting and need more flexibility than\ntight layout and constrained layout.\n\nBelow, we collect the bounding boxes of all y-labels and move the left border\nof the subplot to the right so that it leaves enough room for the union of all\nthe bounding boxes.\n\nThere's one catch with calculating text bounding boxes:\nQuerying the text bounding boxes (`.Text.get_window_extent`) needs a\nrenderer (`.RendererBase` instance), to calculate the text size. This renderer\nis only available after the figure has been drawn (`.Figure.draw`).\n\nA solution to this is putting the adjustment logic in a draw callback.\nThis function is executed after the figure has been drawn. It can now check\nif the subplot leaves enough room for the text. If not, the subplot parameters\nare updated and second draw is triggered.\n\n.. redirect-from:: /gallery/pyplots/auto_subplots_adjust\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n\nimport matplotlib.transforms as mtransforms\n\nfig, ax = plt.subplots()\nax.plot(range(10))\nax.set_yticks([2, 5, 7], labels=['really, really, really', 'long', 'labels'])\n\n\ndef on_draw(event):\n bboxes = []\n for label in ax.get_yticklabels():\n # Bounding box in pixels\n bbox_px = label.get_window_extent()\n # Transform to relative figure coordinates. This is the inverse of\n # transFigure.\n bbox_fig = bbox_px.transformed(fig.transFigure.inverted())\n bboxes.append(bbox_fig)\n # the bbox that bounds all the bboxes, again in relative figure coords\n bbox = mtransforms.Bbox.union(bboxes)\n if fig.subplotpars.left < bbox.width:\n # Move the subplot left edge more to the right\n fig.subplots_adjust(left=1.1*bbox.width) # pad a little\n fig.canvas.draw()\n\n\nfig.canvas.mpl_connect('draw_event', on_draw)\n\nplt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ".. admonition:: References\n\n The use of the following functions, methods, classes and modules is shown\n in this example:\n\n - `matplotlib.artist.Artist.get_window_extent`\n - `matplotlib.transforms.Bbox`\n - `matplotlib.transforms.BboxBase.transformed`\n - `matplotlib.transforms.BboxBase.union`\n - `matplotlib.transforms.Transform.inverted`\n - `matplotlib.figure.Figure.subplots_adjust`\n - `matplotlib.gridspec.SubplotParams`\n - `matplotlib.backend_bases.FigureCanvasBase.mpl_connect`\n\n.. tags::\n\n component: subplot\n plot-type: line\n styling: position\n level: advanced\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 }