{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"%matplotlib inline"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n# Text in Matplotlib Plots\n\n\nIntroduction to plotting and working with text in Matplotlib.\n\nMatplotlib has extensive text support, including support for\nmathematical expressions, truetype support for raster and\nvector outputs, newline separated text with arbitrary\nrotations, and unicode support.\n\nBecause it embeds fonts directly in output documents, e.g., for postscript\nor PDF, what you see on the screen is what you get in the hardcopy.\n`FreeType `_ support\nproduces very nice, antialiased fonts, that look good even at small\nraster sizes. Matplotlib includes its own\n:mod:`matplotlib.font_manager` (thanks to Paul Barrett), which\nimplements a cross platform, `W3C `_\ncompliant font finding algorithm.\n\nThe user has a great deal of control over text properties (font size, font\nweight, text location and color, etc.) with sensible defaults set in\nthe :doc:`rc file `.\nAnd significantly, for those interested in mathematical\nor scientific figures, Matplotlib implements a large number of TeX\nmath symbols and commands, supporting :doc:`mathematical expressions\n` anywhere in your figure.\n\n\nBasic text commands\n===================\n\nThe following commands are used to create text in the pyplot\ninterface and the object-oriented API:\n\n=================== =================== ======================================\n`.pyplot` API OO API description\n=================== =================== ======================================\n`~.pyplot.text` `~.Axes.text` Add text at an arbitrary location of\n the `~matplotlib.axes.Axes`.\n\n`~.pyplot.annotate` `~.Axes.annotate` Add an annotation, with an optional\n arrow, at an arbitrary location of the\n `~matplotlib.axes.Axes`.\n\n`~.pyplot.xlabel` `~.Axes.set_xlabel` Add a label to the\n `~matplotlib.axes.Axes`\\'s x-axis.\n\n`~.pyplot.ylabel` `~.Axes.set_ylabel` Add a label to the\n `~matplotlib.axes.Axes`\\'s y-axis.\n\n`~.pyplot.title` `~.Axes.set_title` Add a title to the\n `~matplotlib.axes.Axes`.\n\n`~.pyplot.figtext` `~.Figure.text` Add text at an arbitrary location of\n the `.Figure`.\n\n`~.pyplot.suptitle` `~.Figure.suptitle` Add a title to the `.Figure`.\n=================== =================== ======================================\n\nAll of these functions create and return a `.Text` instance, which can be\nconfigured with a variety of font and other properties. The example below\nshows all of these commands in action, and more detail is provided in the\nsections that follow.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import matplotlib\nimport matplotlib.pyplot as plt\n\nfig = plt.figure()\nax = fig.add_subplot()\nfig.subplots_adjust(top=0.85)\n\n# Set titles for the figure and the subplot respectively\nfig.suptitle('bold figure suptitle', fontsize=14, fontweight='bold')\nax.set_title('axes title')\n\nax.set_xlabel('xlabel')\nax.set_ylabel('ylabel')\n\n# Set both x- and y-axis limits to [0, 10] instead of default [0, 1]\nax.axis([0, 10, 0, 10])\n\nax.text(3, 8, 'boxed italics text in data coords', style='italic',\n bbox={'facecolor': 'red', 'alpha': 0.5, 'pad': 10})\n\nax.text(2, 6, r'an equation: $E=mc^2$', fontsize=15)\n\nax.text(3, 2, 'unicode: Institut f\u00fcr Festk\u00f6rperphysik')\n\nax.text(0.95, 0.01, 'colored text in axes coords',\n verticalalignment='bottom', horizontalalignment='right',\n transform=ax.transAxes,\n color='green', fontsize=15)\n\nax.plot([2], [1], 'o')\nax.annotate('annotate', xy=(2, 1), xytext=(3, 4),\n arrowprops=dict(facecolor='black', shrink=0.05))\n\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Labels for x- and y-axis\n========================\n\nSpecifying the labels for the x- and y-axis is straightforward, via the\n`~matplotlib.axes.Axes.set_xlabel` and `~matplotlib.axes.Axes.set_ylabel`\nmethods.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\nimport numpy as np\n\nx1 = np.linspace(0.0, 5.0, 100)\ny1 = np.cos(2 * np.pi * x1) * np.exp(-x1)\n\nfig, ax = plt.subplots(figsize=(5, 3))\nfig.subplots_adjust(bottom=0.15, left=0.2)\nax.plot(x1, y1)\nax.set_xlabel('time [s]')\nax.set_ylabel('Damped oscillation [V]')\n\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The x- and y-labels are automatically placed so that they clear the x- and\ny-ticklabels. Compare the plot below with that above, and note the y-label\nis to the left of the one above.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"fig, ax = plt.subplots(figsize=(5, 3))\nfig.subplots_adjust(bottom=0.15, left=0.2)\nax.plot(x1, y1*10000)\nax.set_xlabel('time [s]')\nax.set_ylabel('Damped oscillation [V]')\n\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you want to move the labels, you can specify the *labelpad* keyword\nargument, where the value is points (1/72\", the same unit used to specify\nfontsizes).\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"fig, ax = plt.subplots(figsize=(5, 3))\nfig.subplots_adjust(bottom=0.15, left=0.2)\nax.plot(x1, y1*10000)\nax.set_xlabel('time [s]')\nax.set_ylabel('Damped oscillation [V]', labelpad=18)\n\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Or, the labels accept all the `.Text` keyword arguments, including\n*position*, via which we can manually specify the label positions. Here we\nput the xlabel to the far left of the axis. Note, that the y-coordinate of\nthis position has no effect - to adjust the y-position we need to use the\n*labelpad* kwarg.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"fig, ax = plt.subplots(figsize=(5, 3))\nfig.subplots_adjust(bottom=0.15, left=0.2)\nax.plot(x1, y1)\nax.set_xlabel('time [s]', position=(0., 1e6), horizontalalignment='left')\nax.set_ylabel('Damped oscillation [V]')\n\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"All the labelling in this tutorial can be changed by manipulating the\n`matplotlib.font_manager.FontProperties` method, or by named kwargs to\n`~matplotlib.axes.Axes.set_xlabel`\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"from matplotlib.font_manager import FontProperties\n\nfont = FontProperties()\nfont.set_family('serif')\nfont.set_name('Times New Roman')\nfont.set_style('italic')\n\nfig, ax = plt.subplots(figsize=(5, 3))\nfig.subplots_adjust(bottom=0.15, left=0.2)\nax.plot(x1, y1)\nax.set_xlabel('time [s]', fontsize='large', fontweight='bold')\nax.set_ylabel('Damped oscillation [V]', fontproperties=font)\n\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally, we can use native TeX rendering in all text objects and have\nmultiple lines:\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"fig, ax = plt.subplots(figsize=(5, 3))\nfig.subplots_adjust(bottom=0.2, left=0.2)\nax.plot(x1, np.cumsum(y1**2))\nax.set_xlabel('time [s] \\n This was a long experiment')\nax.set_ylabel(r'$\\int\\ Y^2\\ dt\\ \\ [V^2 s]$')\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Titles\n======\n\nSubplot titles are set in much the same way as labels, but there is\nthe *loc* keyword arguments that can change the position and justification\nfrom the default value of ``loc=center``.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"fig, axs = plt.subplots(3, 1, figsize=(5, 6), tight_layout=True)\nlocs = ['center', 'left', 'right']\nfor ax, loc in zip(axs, locs):\n ax.plot(x1, y1)\n ax.set_title('Title with loc at '+loc, loc=loc)\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vertical spacing for titles is controlled via :rc:`axes.titlepad`, which\ndefaults to 5 points. Setting to a different value moves the title.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"fig, ax = plt.subplots(figsize=(5, 3))\nfig.subplots_adjust(top=0.8)\nax.plot(x1, y1)\nax.set_title('Vertically offset title', pad=30)\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ticks and ticklabels\n====================\n\nPlacing ticks and ticklabels is a very tricky aspect of making a figure.\nMatplotlib does its best to accomplish the task automatically, but it also\noffers a very flexible framework for determining the choices for tick\nlocations, and how they are labelled.\n\nTerminology\n~~~~~~~~~~~\n\n*Axes* have an `matplotlib.axis.Axis` object for the ``ax.xaxis`` and\n``ax.yaxis`` that contain the information about how the labels in the axis\nare laid out.\n\nThe axis API is explained in detail in the documentation to\n`~matplotlib.axis`.\n\nAn Axis object has major and minor ticks. The Axis has\n`.Axis.set_major_locator` and `.Axis.set_minor_locator` methods that use the\ndata being plotted to determine the location of major and minor ticks. There\nare also `.Axis.set_major_formatter` and `.Axis.set_minor_formatter` methods\nthat format the tick labels.\n\nSimple ticks\n~~~~~~~~~~~~\n\nIt often is convenient to simply define the\ntick values, and sometimes the tick labels, overriding the default\nlocators and formatters. This is discouraged because it breaks interactive\nnavigation of the plot. It also can reset the axis limits: note that\nthe second plot has the ticks we asked for, including ones that are\nwell outside the automatic view limits.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"fig, axs = plt.subplots(2, 1, figsize=(5, 3), tight_layout=True)\naxs[0].plot(x1, y1)\naxs[1].plot(x1, y1)\naxs[1].xaxis.set_ticks(np.arange(0., 8.1, 2.))\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can of course fix this after the fact, but it does highlight a\nweakness of hard-coding the ticks. This example also changes the format\nof the ticks:\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"fig, axs = plt.subplots(2, 1, figsize=(5, 3), tight_layout=True)\naxs[0].plot(x1, y1)\naxs[1].plot(x1, y1)\nticks = np.arange(0., 8.1, 2.)\n# list comprehension to get all tick labels...\ntickla = [f'{tick:1.2f}' for tick in ticks]\naxs[1].xaxis.set_ticks(ticks)\naxs[1].xaxis.set_ticklabels(tickla)\naxs[1].set_xlim(axs[0].get_xlim())\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Tick Locators and Formatters\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nInstead of making a list of all the tickalbels, we could have\nused `matplotlib.ticker.StrMethodFormatter` (new-style ``str.format()``\nformat string) or `matplotlib.ticker.FormatStrFormatter` (old-style '%'\nformat string) and passed it to the ``ax.xaxis``. A\n`matplotlib.ticker.StrMethodFormatter` can also be created by passing a\n``str`` without having to explicitly create the formatter.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"fig, axs = plt.subplots(2, 1, figsize=(5, 3), tight_layout=True)\naxs[0].plot(x1, y1)\naxs[1].plot(x1, y1)\nticks = np.arange(0., 8.1, 2.)\naxs[1].xaxis.set_ticks(ticks)\naxs[1].xaxis.set_major_formatter('{x:1.1f}')\naxs[1].set_xlim(axs[0].get_xlim())\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And of course we could have used a non-default locator to set the\ntick locations. Note we still pass in the tick values, but the\nx-limit fix used above is *not* needed.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"fig, axs = plt.subplots(2, 1, figsize=(5, 3), tight_layout=True)\naxs[0].plot(x1, y1)\naxs[1].plot(x1, y1)\nlocator = matplotlib.ticker.FixedLocator(ticks)\naxs[1].xaxis.set_major_locator(locator)\naxs[1].xaxis.set_major_formatter('\u00b1{x}\u00b0')\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The default formatter is the `matplotlib.ticker.MaxNLocator` called as\n``ticker.MaxNLocator(self, nbins='auto', steps=[1, 2, 2.5, 5, 10])``\nThe *steps* keyword contains a list of multiples that can be used for\ntick values. i.e. in this case, 2, 4, 6 would be acceptable ticks,\nas would 20, 40, 60 or 0.2, 0.4, 0.6. However, 3, 6, 9 would not be\nacceptable because 3 doesn't appear in the list of steps.\n\n``nbins=auto`` uses an algorithm to determine how many ticks will\nbe acceptable based on how long the axis is. The fontsize of the\nticklabel is taken into account, but the length of the tick string\nis not (because its not yet known.) In the bottom row, the\nticklabels are quite large, so we set ``nbins=4`` to make the\nlabels fit in the right-hand plot.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"fig, axs = plt.subplots(2, 2, figsize=(8, 5), tight_layout=True)\nfor n, ax in enumerate(axs.flat):\n ax.plot(x1*10., y1)\n\nformatter = matplotlib.ticker.FormatStrFormatter('%1.1f')\nlocator = matplotlib.ticker.MaxNLocator(nbins='auto', steps=[1, 4, 10])\naxs[0, 1].xaxis.set_major_locator(locator)\naxs[0, 1].xaxis.set_major_formatter(formatter)\n\nformatter = matplotlib.ticker.FormatStrFormatter('%1.5f')\nlocator = matplotlib.ticker.AutoLocator()\naxs[1, 0].xaxis.set_major_formatter(formatter)\naxs[1, 0].xaxis.set_major_locator(locator)\n\nformatter = matplotlib.ticker.FormatStrFormatter('%1.5f')\nlocator = matplotlib.ticker.MaxNLocator(nbins=4)\naxs[1, 1].xaxis.set_major_formatter(formatter)\naxs[1, 1].xaxis.set_major_locator(locator)\n\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally, we can specify functions for the formatter using\n`matplotlib.ticker.FuncFormatter`. Further, like\n`matplotlib.ticker.StrMethodFormatter`, passing a function will\nautomatically create a `matplotlib.ticker.FuncFormatter`.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def formatoddticks(x, pos):\n \"\"\"Format odd tick positions.\"\"\"\n if x % 2:\n return f'{x:1.2f}'\n else:\n return ''\n\n\nfig, ax = plt.subplots(figsize=(5, 3), tight_layout=True)\nax.plot(x1, y1)\nlocator = matplotlib.ticker.MaxNLocator(nbins=6)\nax.xaxis.set_major_formatter(formatoddticks)\nax.xaxis.set_major_locator(locator)\n\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Dateticks\n~~~~~~~~~\n\nMatplotlib can accept `datetime.datetime` and `numpy.datetime64`\nobjects as plotting arguments. Dates and times require special\nformatting, which can often benefit from manual intervention. In\norder to help, dates have special Locators and Formatters,\ndefined in the `matplotlib.dates` module.\n\nA simple example is as follows. Note how we have to rotate the\ntick labels so that they don't over-run each other.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import datetime\n\nfig, ax = plt.subplots(figsize=(5, 3), tight_layout=True)\nbase = datetime.datetime(2017, 1, 1, 0, 0, 1)\ntime = [base + datetime.timedelta(days=x) for x in range(len(x1))]\n\nax.plot(time, y1)\nax.tick_params(axis='x', rotation=70)\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can pass a format to `matplotlib.dates.DateFormatter`. Also note that the\n29th and the next month are very close together. We can fix this by using\nthe `.dates.DayLocator` class, which allows us to specify a list of days of\nthe month to use. Similar formatters are listed in the `matplotlib.dates`\nmodule.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import matplotlib.dates as mdates\n\nlocator = mdates.DayLocator(bymonthday=[1, 15])\nformatter = mdates.DateFormatter('%b %d')\n\nfig, ax = plt.subplots(figsize=(5, 3), tight_layout=True)\nax.xaxis.set_major_locator(locator)\nax.xaxis.set_major_formatter(formatter)\nax.plot(time, y1)\nax.tick_params(axis='x', rotation=70)\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Legends and Annotations\n=======================\n\n- Legends: :doc:`/tutorials/intermediate/legend_guide`\n- Annotations: :doc:`/tutorials/text/annotations`\n\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.9.1"
}
},
"nbformat": 4,
"nbformat_minor": 0
}