{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# Artists as annotations\n\n`.AnnotationBbox` facilitates using arbitrary artists as annotations, i.e. data at\nposition *xy* is annotated by a box containing an artist at position *xybox*. The\ncoordinate systems for these points are set via the *xycoords* and *boxcoords*\nparameters, respectively; see the *xycoords* and *textcoords* parameters of\n`.Axes.annotate` for a full listing of supported coordinate systems.\nThe box containing the artist is a subclass of `.OffsetBox`, which is a container\nartist for positioning an artist relative to a parent artist.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "from pathlib import Path\n\nimport PIL\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom matplotlib import get_data_path\nfrom matplotlib.offsetbox import AnnotationBbox, DrawingArea, OffsetImage, TextArea\nfrom matplotlib.patches import Annulus, Circle, ConnectionPatch"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Text\n\n`.AnnotationBbox` supports positioning annotations relative to data, Artists, and\ncallables, as described in `annotations`. The  `.TextArea` is used to create a\ntextbox that is not explicitly attached to an axes, which allows it to be used for\nannotating figure objects. When annotating an axes element (such as a plot) with text,\nuse `.Axes.annotate` because it will create the text artist for you.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "fig, axd = plt.subplot_mosaic([['t1', '.', 't2']], layout='compressed')\n\n# Define a 1st position to annotate (display it with a marker)\nxy1 = (.25, .75)\nxy2 = (.75, .25)\naxd['t1'].plot(*xy1, \".r\")\naxd['t2'].plot(*xy2, \".r\")\naxd['t1'].set(xlim=(0, 1), ylim=(0, 1), aspect='equal')\naxd['t2'].set(xlim=(0, 1), ylim=(0, 1), aspect='equal')\n\n# Draw a connection patch arrow between the points\nc = ConnectionPatch(xyA=xy1, xyB=xy2,\n                    coordsA=axd['t1'].transData, coordsB=axd['t2'].transData,\n                    arrowstyle='->')\nfig.add_artist(c)\n\n# Annotate the ConnectionPatch position ('Test 1')\noffsetbox = TextArea(\"Test 1\")\n\n# place the annotation above the midpoint of c\nab1 = AnnotationBbox(offsetbox,\n                     xy=(.5, .5),\n                     xybox=(0, 30),\n                     xycoords=c,\n                     boxcoords=\"offset points\",\n                     arrowprops=dict(arrowstyle=\"->\"),\n                     bboxprops=dict(boxstyle=\"sawtooth\"))\nfig.add_artist(ab1)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Images\nThe `.OffsetImage` container facilitates using images as annotations\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "fig, ax = plt.subplots()\n# Define a position to annotate\nxy = (0.3, 0.55)\nax.scatter(*xy, s=200, marker='X')\n\n# Annotate a position with an image generated from an array of pixels\narr = np.arange(100).reshape((10, 10))\nim = OffsetImage(arr, zoom=2, cmap='viridis')\nim.image.axes = ax\n\n# place the image NW of xy\nab = AnnotationBbox(im, xy=xy,\n                    xybox=(-50., 50.),\n                    xycoords='data',\n                    boxcoords=\"offset points\",\n                    pad=0.3,\n                    arrowprops=dict(arrowstyle=\"->\"))\nax.add_artist(ab)\n\n# Annotate the position with an image from file (a Grace Hopper portrait)\nimg_fp = Path(get_data_path(), \"sample_data\", \"grace_hopper.jpg\")\nwith PIL.Image.open(img_fp) as arr_img:\n    imagebox = OffsetImage(arr_img, zoom=0.2)\n\nimagebox.image.axes = ax\n\n# place the image SE of xy\nab = AnnotationBbox(imagebox, xy=xy,\n                    xybox=(120., -80.),\n                    xycoords='data',\n                    boxcoords=\"offset points\",\n                    pad=0.5,\n                    arrowprops=dict(\n                        arrowstyle=\"->\",\n                        connectionstyle=\"angle,angleA=0,angleB=90,rad=3\")\n                    )\n\nax.add_artist(ab)\n\n# Fix the display limits to see everything\nax.set(xlim=(0, 1), ylim=(0, 1))\n\nplt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Arbitrary Artists\n\nMultiple and arbitrary artists can be placed inside a `.DrawingArea`.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# make this the thumbnail image\nfig, ax = plt.subplots()\n\n# Define a position to annotate\nxy = (0.05, 0.5)\nax.scatter(*xy, s=500, marker='X')\n\n# Annotate the position with a circle and annulus\nda = DrawingArea(120, 120)\np = Circle((30, 30), 25, color='C0')\nda.add_artist(p)\nq = Annulus((65, 65), 50, 5, color='C1')\nda.add_artist(q)\n\n\n# Use the drawing area as an annotation\nab = AnnotationBbox(da, xy=xy,\n                    xybox=(.55, xy[1]),\n                    xycoords='data',\n                    boxcoords=(\"axes fraction\", \"data\"),\n                    box_alignment=(0, 0.5),\n                    arrowprops=dict(arrowstyle=\"->\"),\n                    bboxprops=dict(alpha=0.5))\n\nax.add_artist(ab)\n\n# Fix the display limits to see everything\nax.set(xlim=(0, 1), ylim=(0, 1))\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.offsetbox.TextArea`\n   - `matplotlib.offsetbox.DrawingArea`\n   - `matplotlib.offsetbox.OffsetImage`\n   - `matplotlib.offsetbox.AnnotationBbox`\n\n.. tags::\n   component: annotation, styling: position\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.14.6"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}