{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n# Drawing fancy boxes\n\nThe following examples show how to plot boxes (`.FancyBboxPatch`) with different\nvisual properties.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import inspect\n\nimport matplotlib.pyplot as plt\n\nimport matplotlib.patches as mpatch\nfrom matplotlib.patches import FancyBboxPatch\nimport matplotlib.transforms as mtransforms" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Box styles\n`.FancyBboxPatch` supports different `.BoxStyle`\\s. Note that `~.Axes.text`\nallows to draw a box around the text by adding the ``bbox`` parameter. Therefore,\nyou don't see explicit `.FancyBboxPatch` and `.BoxStyle` calls in the following\nexample.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "styles = mpatch.BoxStyle.get_styles()\nncol = 2\nnrow = (len(styles) + 1) // ncol\naxs = (plt.figure(figsize=(3 * ncol, 1 + nrow))\n .add_gridspec(1 + nrow, ncol, wspace=.5).subplots())\nfor ax in axs.flat:\n ax.set_axis_off()\nfor ax in axs[0, :]:\n ax.text(.2, .5, \"boxstyle\",\n transform=ax.transAxes, size=\"large\", color=\"tab:blue\",\n horizontalalignment=\"right\", verticalalignment=\"center\")\n ax.text(.4, .5, \"default parameters\",\n transform=ax.transAxes,\n horizontalalignment=\"left\", verticalalignment=\"center\")\nfor ax, (stylename, stylecls) in zip(axs[1:, :].T.flat, styles.items()):\n ax.text(.2, .5, stylename, bbox=dict(boxstyle=stylename, fc=\"w\", ec=\"k\"),\n transform=ax.transAxes, size=\"large\", color=\"tab:blue\",\n horizontalalignment=\"right\", verticalalignment=\"center\")\n ax.text(.4, .5, str(inspect.signature(stylecls))[1:-1].replace(\", \", \"\\n\"),\n transform=ax.transAxes,\n horizontalalignment=\"left\", verticalalignment=\"center\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Parameters for modifying the box\n`.BoxStyle`\\s have additional parameters to configure their appearance.\nFor example, \"round\" boxes can have ``pad`` and ``rounding``.\n\nAdditionally, the `.FancyBboxPatch` parameters ``mutation_scale`` and\n``mutation_aspect`` scale the box appearance.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def add_fancy_patch_around(ax, bb, **kwargs):\n kwargs = {\n 'facecolor': (1, 0.8, 1, 0.5),\n 'edgecolor': (1, 0.5, 1, 0.5),\n **kwargs\n }\n fancy = FancyBboxPatch(bb.p0, bb.width, bb.height, **kwargs)\n ax.add_patch(fancy)\n return fancy\n\n\ndef draw_control_points_for_patches(ax):\n for patch in ax.patches:\n patch.axes.plot(*patch.get_path().vertices.T, \".\",\n c=patch.get_edgecolor())\n\n\nfig, axs = plt.subplots(2, 2, figsize=(8, 8))\n\n# Bbox object around which the fancy box will be drawn.\nbb = mtransforms.Bbox([[0.3, 0.4], [0.7, 0.6]])\n\nax = axs[0, 0]\n# a fancy box with round corners. pad=0.1\nadd_fancy_patch_around(ax, bb, boxstyle=\"round,pad=0.1\")\nax.set(xlim=(0, 1), ylim=(0, 1), aspect=1,\n title='boxstyle=\"round,pad=0.1\"')\n\nax = axs[0, 1]\n# bbox=round has two optional arguments: pad and rounding_size.\n# They can be set during the initialization.\nfancy = add_fancy_patch_around(ax, bb, boxstyle=\"round,pad=0.1\")\n# The boxstyle and its argument can be later modified with set_boxstyle().\n# Note that the old attributes are simply forgotten even if the boxstyle name\n# is same.\nfancy.set_boxstyle(\"round,pad=0.1,rounding_size=0.2\")\n# or: fancy.set_boxstyle(\"round\", pad=0.1, rounding_size=0.2)\nax.set(xlim=(0, 1), ylim=(0, 1), aspect=1,\n title='boxstyle=\"round,pad=0.1,rounding_size=0.2\"')\n\nax = axs[1, 0]\n# mutation_scale determines the overall scale of the mutation, i.e. both pad\n# and rounding_size is scaled according to this value.\nadd_fancy_patch_around(ax, bb, boxstyle=\"round,pad=0.1\", mutation_scale=2)\nax.set(xlim=(0, 1), ylim=(0, 1), aspect=1,\n title='boxstyle=\"round,pad=0.1\"\\n mutation_scale=2')\n\nax = axs[1, 1]\n# mutation_aspect scales the vertical influence of the parameters (technically,\n# it scales the height of the box down by mutation_aspect, applies the box parameters\n# and scales the result back up). In effect, the vertical pad is scaled to\n# pad * mutation_aspect, e.g. mutation_aspect=0.5 halves the vertical pad.\nadd_fancy_patch_around(ax, bb, boxstyle=\"round,pad=0.1\", mutation_aspect=0.5)\nax.set(xlim=(0, 1), ylim=(0, 1),\n title='boxstyle=\"round,pad=0.1\"\\nmutation_aspect=0.5')\n\nfor ax in axs.flat:\n draw_control_points_for_patches(ax)\n # Draw the original bbox (using boxstyle=square with pad=0).\n add_fancy_patch_around(ax, bb, boxstyle=\"square,pad=0\",\n edgecolor=\"black\", facecolor=\"none\", zorder=10)\n\nfig.tight_layout()\n\n\nplt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Creating visually constant padding on non-equal aspect Axes\nSince padding is in box coordinates, i.e. usually data coordinates,\na given padding is rendered to different visual sizes if the\nAxes aspect is not 1.\nTo get visually equal vertical and horizontal padding, set the\nmutation_aspect to the inverse of the Axes aspect. This scales\nthe vertical padding appropriately.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(6.5, 5))\n\n# original boxes\nbb = mtransforms.Bbox([[-0.5, -0.5], [0.5, 0.5]])\nadd_fancy_patch_around(ax1, bb, boxstyle=\"square,pad=0\",\n edgecolor=\"black\", facecolor=\"none\", zorder=10)\nadd_fancy_patch_around(ax2, bb, boxstyle=\"square,pad=0\",\n edgecolor=\"black\", facecolor=\"none\", zorder=10)\nax1.set(xlim=(-1.5, 1.5), ylim=(-1.5, 1.5), aspect=2)\nax2.set(xlim=(-1.5, 1.5), ylim=(-1.5, 1.5), aspect=2)\n\n\nfancy = add_fancy_patch_around(\n ax1, bb, boxstyle=\"round,pad=0.5\")\nax1.set_title(\"aspect=2\\nmutation_aspect=1\")\n\nfancy = add_fancy_patch_around(\n ax2, bb, boxstyle=\"round,pad=0.5\", mutation_aspect=0.5)\nax2.set_title(\"aspect=2\\nmutation_aspect=0.5\")" ] }, { "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.patches`\n - `matplotlib.patches.FancyBboxPatch`\n - `matplotlib.patches.BoxStyle`\n - ``matplotlib.patches.BoxStyle.get_styles``\n - `matplotlib.transforms.Bbox`\n - `matplotlib.figure.Figure.text`\n - `matplotlib.axes.Axes.text`\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 }