{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "# The Lifecycle of a Plot\n",
    "\n",
    "\n",
    "This notebook is a summary that aims to show the beginning, middle, and end of a single\n",
    "visualization using Matplotlib. We'll begin with some raw data and\n",
    "end by saving a figure of a customized visualization. Along the way we'll try\n",
    "to highlight some neat features and best-practices using Matplotlib.\n",
    "\n",
    "Our data\n",
    "========\n",
    "\n",
    "We'll use the data from the post from which this tutorial was derived.\n",
    "It contains sales information for a number of companies."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# sphinx_gallery_thumbnail_number = 10\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from matplotlib.ticker import FuncFormatter\n",
    "\n",
    "data = {'Barton LLC': 109438.50,\n",
    "        'Frami, Hills and Schmidt': 103569.59,\n",
    "        'Fritsch, Russel and Anderson': 112214.71,\n",
    "        'Jerde-Hilpert': 112591.43,\n",
    "        'Keeling LLC': 100934.30,\n",
    "        'Koepp Ltd': 103660.54,\n",
    "        'Kulas Inc': 137351.96,\n",
    "        'Trantow-Barrows': 123381.38,\n",
    "        'White-Trantow': 135841.99,\n",
    "        'Will LLC': 104437.60}\n",
    "group_data = list(data.values())\n",
    "group_names = list(data.keys())\n",
    "group_mean = np.mean(group_data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Getting Started\n",
    "=============\n",
    "\n",
    "First lets generate our figure containing out axes. Recall: the Figure is like a canvas, and the Axes is a part of that canvas on which we will make a particular visualization.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 4824 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig, ax = plt.subplots()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Once we have our figure and axes, we can generate our plot within them."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<BarContainer object of 10 artists>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 13816 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig, ax = plt.subplots()\n",
    "ax.barh(group_names, group_data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Things to notice:\n",
    "* There is no heading on the plot.\n",
    "* X-axis is missing a label.\n",
    "* It is difficult to compare the bars because there is no backing grid to line up the bar ends.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Applying Style to a Plot\n",
    "===================\n",
    "\n",
    "Matplotlib has a wide range of built-in style sheets that can be used to modify the appearance of plots. Styles are applied to the pyplot object and we must re-make plots between style changes to see the results.\n",
    "\n",
    "[Review the stylesheet reference](https://matplotlib.org/3.1.0/gallery/style_sheets/style_sheets_reference.html)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['bmh', 'classic', 'dark_background', 'fast', 'fivethirtyeight', 'ggplot', 'grayscale', 'seaborn-bright', 'seaborn-colorblind', 'seaborn-dark-palette', 'seaborn-dark', 'seaborn-darkgrid', 'seaborn-deep', 'seaborn-muted', 'seaborn-notebook', 'seaborn-paper', 'seaborn-pastel', 'seaborn-poster', 'seaborn-talk', 'seaborn-ticks', 'seaborn-white', 'seaborn-whitegrid', 'seaborn', 'Solarize_Light2', 'tableau-colorblind10', '_classic_test']\n"
     ]
    }
   ],
   "source": [
    "print(plt.style.available)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can activate a desired style using the `plyplot.style.use( ... )` function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.style.use('fivethirtyeight')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can re-make the plot using the new style."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<BarContainer object of 10 artists>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 29024 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig, ax = plt.subplots()\n",
    "ax.barh(group_names, group_data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The style controls many things, such as color, linewidths, backgrounds, etc. Not all styles apply to all types of plots. You should experiment to see how the appearance of different plot-types are affected."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Customizing a Plot\n",
    "=================\n",
    "Now we've got a plot with the general look that we want, so let's fine-tune\n",
    "it so that it's ready for print. First let's rotate the labels on the x-axis\n",
    "so that they show up more clearly. We can gain access to these labels\n",
    "with the :meth:`axes.Axes.get_xticklabels` method:\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 29024 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig, ax = plt.subplots()\n",
    "ax.barh(group_names, group_data)\n",
    "labels = ax.get_xticklabels()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Matplotlib supports the use of setp() (\"set property\") and getp() to set and get object properties, as well as to do introspection on the object. If we'd like to set the property of many items at once, it's useful to use\n",
    "the :func:`pyplot.setp` function. This will take a list (or many lists) of\n",
    "Matplotlib objects, and attempt to set some style element of each one."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None]"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 34596 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig, ax = plt.subplots()\n",
    "ax.barh(group_names, group_data)\n",
    "labels = ax.get_xticklabels()\n",
    "plt.setp(labels, rotation=45, horizontalalignment='right')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Some times the plotting functions can cut off some of the labels on the bottom. We can tell Matplotlib to automatically make room for elements in the figures that we create. To do this we'll set the autolayout value of our rcParams. For more information on controlling the style, layout, and other features of plots with rcParams, see :doc:/tutorials/introductory/customizing."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None,\n",
       " None]"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 26116 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.rcParams.update({'figure.autolayout': True})\n",
    "\n",
    "fig, ax = plt.subplots()\n",
    "ax.barh(group_names, group_data)\n",
    "labels = ax.get_xticklabels()\n",
    "plt.setp(labels, rotation=45, horizontalalignment='right')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we'll add labels to the plot. To do this with the OO interface,\n",
    "we can use the :meth:`axes.Axes.set` method to set properties of this\n",
    "Axes object.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Text(0, 0.5, 'Company'),\n",
       " (-10000, 140000),\n",
       " Text(0.5, 0, 'Total Revenue'),\n",
       " Text(0.5, 1.0, 'Company Revenue')]"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 35500 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig, ax = plt.subplots()\n",
    "ax.barh(group_names, group_data)\n",
    "labels = ax.get_xticklabels()\n",
    "plt.setp(labels, rotation=45, horizontalalignment='right')\n",
    "ax.set(xlim=[-10000, 140000], xlabel='Total Revenue', ylabel='Company',\n",
    "       title='Company Revenue')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can also adjust the size of this plot using the :func:pyplot.subplots function. We can do this with the figsize kwarg"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Text(0, 0.5, 'Company'),\n",
       " (-10000, 140000),\n",
       " Text(0.5, 0, 'Total Revenue'),\n",
       " Text(0.5, 1.0, 'Company Revenue')]"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 43840 characters]\n",
      "text/plain": [
       "<Figure size 576x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig, ax = plt.subplots(figsize=(8, 4))\n",
    "ax.barh(group_names, group_data)\n",
    "labels = ax.get_xticklabels()\n",
    "plt.setp(labels, rotation=45, horizontalalignment='right')\n",
    "ax.set(xlim=[-10000, 140000], xlabel='Total Revenue', ylabel='Company',\n",
    "       title='Company Revenue')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For labels, we can specify custom formatting guidelines in the form of\n",
    "functions by using the :class:`ticker.FuncFormatter` class. Below we'll\n",
    "define a function that takes an integer as input, and returns a string\n",
    "as an output.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "def currency(x, pos):\n",
    "    \"\"\"The two args are the value and tick position\"\"\"\n",
    "    if x >= 1e6:\n",
    "        s = '${:1.1f}M'.format(x*1e-6)\n",
    "    else:\n",
    "        s = '${:1.0f}K'.format(x*1e-3)\n",
    "    return s\n",
    "\n",
    "formatter = FuncFormatter(currency)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can then apply this formatter to the labels on our plot. To do this,\n",
    "we'll use the ``xaxis`` attribute of our axis. This lets you perform\n",
    "actions on a specific axis on our plot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 41436 characters]\n",
      "text/plain": [
       "<Figure size 432x576 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig, ax = plt.subplots(figsize=(6, 8))\n",
    "ax.barh(group_names, group_data)\n",
    "labels = ax.get_xticklabels()\n",
    "plt.setp(labels, rotation=45, horizontalalignment='right')\n",
    "\n",
    "ax.set(xlim=[-10000, 140000], xlabel='Total Revenue', ylabel='Company',\n",
    "       title='Company Revenue')\n",
    "ax.xaxis.set_major_formatter(formatter)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Combining multiple visualizations\n",
    "=================================\n",
    "\n",
    "It is possible to draw multiple plot elements on the same instance of\n",
    ":class:`axes.Axes`. To do this we simply need to call another one of\n",
    "the plot methods on that axes object.\n",
    "\n",
    "`axvline` - Add a vertical line across the axes.\n",
    "`text` - Add arbitrary text to the plot, specifying the position and style attributes.\n",
    "`set_xticks` - Specify the xticks that are to be displayed.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 52428 characters]\n",
      "text/plain": [
       "<Figure size 576x576 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig, ax = plt.subplots(figsize=(8, 8))\n",
    "ax.barh(group_names, group_data)\n",
    "labels = ax.get_xticklabels()\n",
    "plt.setp(labels, rotation=45, horizontalalignment='right')\n",
    "\n",
    "# Add a vertical line, here we set the style in the function call\n",
    "ax.axvline(group_mean, ls='--', color='r')\n",
    "\n",
    "# Annotate new companies\n",
    "for group in [3, 5, 8]:\n",
    "    ax.text(145000, group, \"New Company\", fontsize=10,\n",
    "            verticalalignment=\"center\")\n",
    "\n",
    "# Now we'll move our title up since it's getting a little cramped\n",
    "ax.title.set(y=1.05)\n",
    "\n",
    "ax.set(xlim=[-10000, 140000], xlabel='Total Revenue', ylabel='Company',\n",
    "       title='Company Revenue')\n",
    "ax.xaxis.set_major_formatter(formatter)\n",
    "ax.set_xticks([0, 25e3, 50e3, 75e3, 100e3, 125e3])\n",
    "fig.subplots_adjust(right=0.5)\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Saving our plot\n",
    "===============\n",
    "\n",
    "Now that we're happy with the outcome of our plot, we want to save it to\n",
    "disk. There are many file formats we can save to in Matplotlib. To see\n",
    "a list of available options, use:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'ps': 'Postscript', 'eps': 'Encapsulated Postscript', 'pdf': 'Portable Document Format', 'pgf': 'PGF code for LaTeX', 'png': 'Portable Network Graphics', 'raw': 'Raw RGBA bitmap', 'rgba': 'Raw RGBA bitmap', 'svg': 'Scalable Vector Graphics', 'svgz': 'Scalable Vector Graphics', 'jpg': 'Joint Photographic Experts Group', 'jpeg': 'Joint Photographic Experts Group', 'tif': 'Tagged Image File Format', 'tiff': 'Tagged Image File Format'}\n"
     ]
    }
   ],
   "source": [
    "print(fig.canvas.get_supported_filetypes())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can then use the :meth:`figure.Figure.savefig` in order to save the figure\n",
    "to disk. Note that there are several useful flags we'll show below:\n",
    "\n",
    "* ``transparent=True`` makes the background of the saved figure transparent\n",
    "  if the format supports it.\n",
    "* ``dpi=80`` controls the resolution (dots per square inch) of the output.\n",
    "* ``bbox_inches=\"tight\"`` fits the bounds of the figure to our plot.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "fig.savefig('sales.png', transparent=False, dpi=80, bbox_inches=\"tight\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "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.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
