{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n# A pie and a donut with labels\n\nWelcome to the Matplotlib bakery. We will create a pie and a donut\nchart through the `pie method ` and\nshow how to label them with a `legend `\nas well as with `annotations `.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As usual we would start by defining the imports and create a figure with\nsubplots.\nNow it's time for the pie. Starting with a pie recipe, we create the data\nand a list of labels from it.\n\nWe can provide a function to the ``autopct`` argument, which will expand\nautomatic percentage labeling by showing absolute values; we calculate\nthe latter back from relative data and the known sum of all values.\n\nWe then create the pie and store the returned objects for later. The first\nreturned element of the returned tuple is a list of the wedges. Those are\n`matplotlib.patches.Wedge` patches, which can directly be used as the handles\nfor a legend. We can use the legend's ``bbox_to_anchor`` argument to position\nthe legend outside of the pie. Here we use the axes coordinates ``(1, 0, 0.5,\n1)`` together with the location ``\"center left\"``; i.e. the left central\npoint of the legend will be at the left central point of the bounding box,\nspanning from ``(1, 0)`` to ``(1.5, 1)`` in axes coordinates.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\nimport numpy as np\n\nfig, ax = plt.subplots(figsize=(6, 3), subplot_kw=dict(aspect=\"equal\"))\n\nrecipe = [\"375 g flour\",\n \"75 g sugar\",\n \"250 g butter\",\n \"300 g berries\"]\n\ndata = [float(x.split()[0]) for x in recipe]\ningredients = [x.split()[-1] for x in recipe]\n\n\ndef func(pct, allvals):\n absolute = int(np.round(pct/100.*np.sum(allvals)))\n return f\"{pct:.1f}%\\n({absolute:d} g)\"\n\n\nwedges, texts, autotexts = ax.pie(data, autopct=lambda pct: func(pct, data),\n textprops=dict(color=\"w\"))\n\nax.legend(wedges, ingredients,\n title=\"Ingredients\",\n loc=\"center left\",\n bbox_to_anchor=(1, 0, 0.5, 1))\n\nplt.setp(autotexts, size=8, weight=\"bold\")\n\nax.set_title(\"Matplotlib bakery: A pie\")\n\nplt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now it's time for the donut. Starting with a donut recipe, we transcribe\nthe data to numbers (converting 1 egg to 50 g), and directly plot the pie.\nThe pie? Wait... it's going to be donut, is it not?\nWell, as we see here, the donut is a pie, having a certain ``width`` set to\nthe wedges, which is different from its radius. It's as easy as it gets.\nThis is done via the ``wedgeprops`` argument.\n\nWe then want to label the wedges via\n`annotations `. We first create some\ndictionaries of common properties, which we can later pass as keyword\nargument. We then iterate over all wedges and for each\n\n* calculate the angle of the wedge's center,\n* from that obtain the coordinates of the point at that angle on the\n circumference,\n* determine the horizontal alignment of the text, depending on which side\n of the circle the point lies,\n* update the connection style with the obtained angle to have the annotation\n arrow point outwards from the donut,\n* finally, create the annotation with all the previously\n determined parameters.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, ax = plt.subplots(figsize=(6, 3), subplot_kw=dict(aspect=\"equal\"))\n\nrecipe = [\"225 g flour\",\n \"90 g sugar\",\n \"1 egg\",\n \"60 g butter\",\n \"100 ml milk\",\n \"1/2 package of yeast\"]\n\ndata = [225, 90, 50, 60, 100, 5]\n\nwedges, texts = ax.pie(data, wedgeprops=dict(width=0.5), startangle=-40)\n\nbbox_props = dict(boxstyle=\"square,pad=0.3\", fc=\"w\", ec=\"k\", lw=0.72)\nkw = dict(arrowprops=dict(arrowstyle=\"-\"),\n bbox=bbox_props, zorder=0, va=\"center\")\n\nfor i, p in enumerate(wedges):\n ang = (p.theta2 - p.theta1)/2. + p.theta1\n y = np.sin(np.deg2rad(ang))\n x = np.cos(np.deg2rad(ang))\n horizontalalignment = {-1: \"right\", 1: \"left\"}[int(np.sign(x))]\n connectionstyle = f\"angle,angleA=0,angleB={ang}\"\n kw[\"arrowprops\"].update({\"connectionstyle\": connectionstyle})\n ax.annotate(recipe[i], xy=(x, y), xytext=(1.35*np.sign(x), 1.4*y),\n horizontalalignment=horizontalalignment, **kw)\n\nax.set_title(\"Matplotlib bakery: A donut\")\n\nplt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And here it is, the donut. Note however, that if we were to use this recipe,\nthe ingredients would suffice for around 6 donuts - producing one huge\ndonut is untested and might result in kitchen errors.\n\n" ] }, { "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.axes.Axes.pie` / `matplotlib.pyplot.pie`\n - `matplotlib.axes.Axes.legend` / `matplotlib.pyplot.legend`\n\n.. tags::\n\n component: label\n component: annotation\n plot-type: pie\n level: beginner\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 }