1""" 2======================== 3Text in Matplotlib Plots 4======================== 5 6Introduction to plotting and working with text in Matplotlib. 7 8Matplotlib has extensive text support, including support for 9mathematical expressions, truetype support for raster and 10vector outputs, newline separated text with arbitrary 11rotations, and unicode support. 12 13Because it embeds fonts directly in output documents, e.g., for postscript 14or PDF, what you see on the screen is what you get in the hardcopy. 15`FreeType <https://www.freetype.org/>`_ support 16produces very nice, antialiased fonts, that look good even at small 17raster sizes. Matplotlib includes its own 18:mod:`matplotlib.font_manager` (thanks to Paul Barrett), which 19implements a cross platform, `W3C <https://www.w3.org/>`_ 20compliant font finding algorithm. 21 22The user has a great deal of control over text properties (font size, font 23weight, text location and color, etc.) with sensible defaults set in 24the :doc:`rc file </tutorials/introductory/customizing>`. 25And significantly, for those interested in mathematical 26or scientific figures, Matplotlib implements a large number of TeX 27math symbols and commands, supporting :doc:`mathematical expressions 28</tutorials/text/mathtext>` anywhere in your figure. 29 30 31Basic text commands 32=================== 33 34The following commands are used to create text in the pyplot 35interface and the object-oriented API: 36 37=================== =================== ====================================== 38`.pyplot` API OO API description 39=================== =================== ====================================== 40`~.pyplot.text` `~.Axes.text` Add text at an arbitrary location of 41 the `~matplotlib.axes.Axes`. 42 43`~.pyplot.annotate` `~.Axes.annotate` Add an annotation, with an optional 44 arrow, at an arbitrary location of the 45 `~matplotlib.axes.Axes`. 46 47`~.pyplot.xlabel` `~.Axes.set_xlabel` Add a label to the 48 `~matplotlib.axes.Axes`\\'s x-axis. 49 50`~.pyplot.ylabel` `~.Axes.set_ylabel` Add a label to the 51 `~matplotlib.axes.Axes`\\'s y-axis. 52 53`~.pyplot.title` `~.Axes.set_title` Add a title to the 54 `~matplotlib.axes.Axes`. 55 56`~.pyplot.figtext` `~.Figure.text` Add text at an arbitrary location of 57 the `.Figure`. 58 59`~.pyplot.suptitle` `~.Figure.suptitle` Add a title to the `.Figure`. 60=================== =================== ====================================== 61 62All of these functions create and return a `.Text` instance, which can be 63configured with a variety of font and other properties. The example below 64shows all of these commands in action, and more detail is provided in the 65sections that follow. 66""" 67 68import matplotlib 69import matplotlib.pyplot as plt 70 71fig = plt.figure() 72ax = fig.add_subplot() 73fig.subplots_adjust(top=0.85) 74 75# Set titles for the figure and the subplot respectively 76fig.suptitle('bold figure suptitle', fontsize=14, fontweight='bold') 77ax.set_title('axes title') 78 79ax.set_xlabel('xlabel') 80ax.set_ylabel('ylabel') 81 82# Set both x- and y-axis limits to [0, 10] instead of default [0, 1] 83ax.axis([0, 10, 0, 10]) 84 85ax.text(3, 8, 'boxed italics text in data coords', style='italic', 86 bbox={'facecolor': 'red', 'alpha': 0.5, 'pad': 10}) 87 88ax.text(2, 6, r'an equation: $E=mc^2$', fontsize=15) 89 90ax.text(3, 2, 'unicode: Institut für Festkörperphysik') 91 92ax.text(0.95, 0.01, 'colored text in axes coords', 93 verticalalignment='bottom', horizontalalignment='right', 94 transform=ax.transAxes, 95 color='green', fontsize=15) 96 97ax.plot([2], [1], 'o') 98ax.annotate('annotate', xy=(2, 1), xytext=(3, 4), 99 arrowprops=dict(facecolor='black', shrink=0.05)) 100 101plt.show() 102 103############################################################################### 104# Labels for x- and y-axis 105# ======================== 106# 107# Specifying the labels for the x- and y-axis is straightforward, via the 108# `~matplotlib.axes.Axes.set_xlabel` and `~matplotlib.axes.Axes.set_ylabel` 109# methods. 110 111import matplotlib.pyplot as plt 112import numpy as np 113 114x1 = np.linspace(0.0, 5.0, 100) 115y1 = np.cos(2 * np.pi * x1) * np.exp(-x1) 116 117fig, ax = plt.subplots(figsize=(5, 3)) 118fig.subplots_adjust(bottom=0.15, left=0.2) 119ax.plot(x1, y1) 120ax.set_xlabel('time [s]') 121ax.set_ylabel('Damped oscillation [V]') 122 123plt.show() 124 125############################################################################### 126# The x- and y-labels are automatically placed so that they clear the x- and 127# y-ticklabels. Compare the plot below with that above, and note the y-label 128# is to the left of the one above. 129 130fig, ax = plt.subplots(figsize=(5, 3)) 131fig.subplots_adjust(bottom=0.15, left=0.2) 132ax.plot(x1, y1*10000) 133ax.set_xlabel('time [s]') 134ax.set_ylabel('Damped oscillation [V]') 135 136plt.show() 137 138############################################################################### 139# If you want to move the labels, you can specify the *labelpad* keyword 140# argument, where the value is points (1/72", the same unit used to specify 141# fontsizes). 142 143fig, ax = plt.subplots(figsize=(5, 3)) 144fig.subplots_adjust(bottom=0.15, left=0.2) 145ax.plot(x1, y1*10000) 146ax.set_xlabel('time [s]') 147ax.set_ylabel('Damped oscillation [V]', labelpad=18) 148 149plt.show() 150 151############################################################################### 152# Or, the labels accept all the `.Text` keyword arguments, including 153# *position*, via which we can manually specify the label positions. Here we 154# put the xlabel to the far left of the axis. Note, that the y-coordinate of 155# this position has no effect - to adjust the y-position we need to use the 156# *labelpad* kwarg. 157 158fig, ax = plt.subplots(figsize=(5, 3)) 159fig.subplots_adjust(bottom=0.15, left=0.2) 160ax.plot(x1, y1) 161ax.set_xlabel('time [s]', position=(0., 1e6), horizontalalignment='left') 162ax.set_ylabel('Damped oscillation [V]') 163 164plt.show() 165 166############################################################################## 167# All the labelling in this tutorial can be changed by manipulating the 168# `matplotlib.font_manager.FontProperties` method, or by named kwargs to 169# `~matplotlib.axes.Axes.set_xlabel` 170 171from matplotlib.font_manager import FontProperties 172 173font = FontProperties() 174font.set_family('serif') 175font.set_name('Times New Roman') 176font.set_style('italic') 177 178fig, ax = plt.subplots(figsize=(5, 3)) 179fig.subplots_adjust(bottom=0.15, left=0.2) 180ax.plot(x1, y1) 181ax.set_xlabel('time [s]', fontsize='large', fontweight='bold') 182ax.set_ylabel('Damped oscillation [V]', fontproperties=font) 183 184plt.show() 185 186############################################################################## 187# Finally, we can use native TeX rendering in all text objects and have 188# multiple lines: 189 190fig, ax = plt.subplots(figsize=(5, 3)) 191fig.subplots_adjust(bottom=0.2, left=0.2) 192ax.plot(x1, np.cumsum(y1**2)) 193ax.set_xlabel('time [s] \n This was a long experiment') 194ax.set_ylabel(r'$\int\ Y^2\ dt\ \ [V^2 s]$') 195plt.show() 196 197 198############################################################################## 199# Titles 200# ====== 201# 202# Subplot titles are set in much the same way as labels, but there is 203# the *loc* keyword arguments that can change the position and justification 204# from the default value of ``loc=center``. 205 206fig, axs = plt.subplots(3, 1, figsize=(5, 6), tight_layout=True) 207locs = ['center', 'left', 'right'] 208for ax, loc in zip(axs, locs): 209 ax.plot(x1, y1) 210 ax.set_title('Title with loc at '+loc, loc=loc) 211plt.show() 212 213############################################################################## 214# Vertical spacing for titles is controlled via :rc:`axes.titlepad`, which 215# defaults to 5 points. Setting to a different value moves the title. 216 217fig, ax = plt.subplots(figsize=(5, 3)) 218fig.subplots_adjust(top=0.8) 219ax.plot(x1, y1) 220ax.set_title('Vertically offset title', pad=30) 221plt.show() 222 223 224############################################################################## 225# Ticks and ticklabels 226# ==================== 227# 228# Placing ticks and ticklabels is a very tricky aspect of making a figure. 229# Matplotlib does its best to accomplish the task automatically, but it also 230# offers a very flexible framework for determining the choices for tick 231# locations, and how they are labelled. 232# 233# Terminology 234# ~~~~~~~~~~~ 235# 236# *Axes* have an `matplotlib.axis.Axis` object for the ``ax.xaxis`` and 237# ``ax.yaxis`` that contain the information about how the labels in the axis 238# are laid out. 239# 240# The axis API is explained in detail in the documentation to 241# `~matplotlib.axis`. 242# 243# An Axis object has major and minor ticks. The Axis has 244# `.Axis.set_major_locator` and `.Axis.set_minor_locator` methods that use the 245# data being plotted to determine the location of major and minor ticks. There 246# are also `.Axis.set_major_formatter` and `.Axis.set_minor_formatter` methods 247# that format the tick labels. 248# 249# Simple ticks 250# ~~~~~~~~~~~~ 251# 252# It often is convenient to simply define the 253# tick values, and sometimes the tick labels, overriding the default 254# locators and formatters. This is discouraged because it breaks interactive 255# navigation of the plot. It also can reset the axis limits: note that 256# the second plot has the ticks we asked for, including ones that are 257# well outside the automatic view limits. 258 259fig, axs = plt.subplots(2, 1, figsize=(5, 3), tight_layout=True) 260axs[0].plot(x1, y1) 261axs[1].plot(x1, y1) 262axs[1].xaxis.set_ticks(np.arange(0., 8.1, 2.)) 263plt.show() 264 265############################################################################# 266# We can of course fix this after the fact, but it does highlight a 267# weakness of hard-coding the ticks. This example also changes the format 268# of the ticks: 269 270fig, axs = plt.subplots(2, 1, figsize=(5, 3), tight_layout=True) 271axs[0].plot(x1, y1) 272axs[1].plot(x1, y1) 273ticks = np.arange(0., 8.1, 2.) 274# list comprehension to get all tick labels... 275tickla = [f'{tick:1.2f}' for tick in ticks] 276axs[1].xaxis.set_ticks(ticks) 277axs[1].xaxis.set_ticklabels(tickla) 278axs[1].set_xlim(axs[0].get_xlim()) 279plt.show() 280 281############################################################################# 282# Tick Locators and Formatters 283# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 284# 285# Instead of making a list of all the tickalbels, we could have 286# used `matplotlib.ticker.StrMethodFormatter` (new-style ``str.format()`` 287# format string) or `matplotlib.ticker.FormatStrFormatter` (old-style '%' 288# format string) and passed it to the ``ax.xaxis``. A 289# `matplotlib.ticker.StrMethodFormatter` can also be created by passing a 290# ``str`` without having to explicitly create the formatter. 291 292fig, axs = plt.subplots(2, 1, figsize=(5, 3), tight_layout=True) 293axs[0].plot(x1, y1) 294axs[1].plot(x1, y1) 295ticks = np.arange(0., 8.1, 2.) 296axs[1].xaxis.set_ticks(ticks) 297axs[1].xaxis.set_major_formatter('{x:1.1f}') 298axs[1].set_xlim(axs[0].get_xlim()) 299plt.show() 300 301############################################################################# 302# And of course we could have used a non-default locator to set the 303# tick locations. Note we still pass in the tick values, but the 304# x-limit fix used above is *not* needed. 305 306fig, axs = plt.subplots(2, 1, figsize=(5, 3), tight_layout=True) 307axs[0].plot(x1, y1) 308axs[1].plot(x1, y1) 309locator = matplotlib.ticker.FixedLocator(ticks) 310axs[1].xaxis.set_major_locator(locator) 311axs[1].xaxis.set_major_formatter('±{x}°') 312plt.show() 313 314############################################################################# 315# The default formatter is the `matplotlib.ticker.MaxNLocator` called as 316# ``ticker.MaxNLocator(self, nbins='auto', steps=[1, 2, 2.5, 5, 10])`` 317# The *steps* keyword contains a list of multiples that can be used for 318# tick values. i.e. in this case, 2, 4, 6 would be acceptable ticks, 319# as would 20, 40, 60 or 0.2, 0.4, 0.6. However, 3, 6, 9 would not be 320# acceptable because 3 doesn't appear in the list of steps. 321# 322# ``nbins=auto`` uses an algorithm to determine how many ticks will 323# be acceptable based on how long the axis is. The fontsize of the 324# ticklabel is taken into account, but the length of the tick string 325# is not (because its not yet known.) In the bottom row, the 326# ticklabels are quite large, so we set ``nbins=4`` to make the 327# labels fit in the right-hand plot. 328 329fig, axs = plt.subplots(2, 2, figsize=(8, 5), tight_layout=True) 330for n, ax in enumerate(axs.flat): 331 ax.plot(x1*10., y1) 332 333formatter = matplotlib.ticker.FormatStrFormatter('%1.1f') 334locator = matplotlib.ticker.MaxNLocator(nbins='auto', steps=[1, 4, 10]) 335axs[0, 1].xaxis.set_major_locator(locator) 336axs[0, 1].xaxis.set_major_formatter(formatter) 337 338formatter = matplotlib.ticker.FormatStrFormatter('%1.5f') 339locator = matplotlib.ticker.AutoLocator() 340axs[1, 0].xaxis.set_major_formatter(formatter) 341axs[1, 0].xaxis.set_major_locator(locator) 342 343formatter = matplotlib.ticker.FormatStrFormatter('%1.5f') 344locator = matplotlib.ticker.MaxNLocator(nbins=4) 345axs[1, 1].xaxis.set_major_formatter(formatter) 346axs[1, 1].xaxis.set_major_locator(locator) 347 348plt.show() 349 350############################################################################## 351# Finally, we can specify functions for the formatter using 352# `matplotlib.ticker.FuncFormatter`. Further, like 353# `matplotlib.ticker.StrMethodFormatter`, passing a function will 354# automatically create a `matplotlib.ticker.FuncFormatter`. 355 356 357def formatoddticks(x, pos): 358 """Format odd tick positions.""" 359 if x % 2: 360 return f'{x:1.2f}' 361 else: 362 return '' 363 364 365fig, ax = plt.subplots(figsize=(5, 3), tight_layout=True) 366ax.plot(x1, y1) 367locator = matplotlib.ticker.MaxNLocator(nbins=6) 368ax.xaxis.set_major_formatter(formatoddticks) 369ax.xaxis.set_major_locator(locator) 370 371plt.show() 372 373 374############################################################################## 375# Dateticks 376# ~~~~~~~~~ 377# 378# Matplotlib can accept `datetime.datetime` and `numpy.datetime64` 379# objects as plotting arguments. Dates and times require special 380# formatting, which can often benefit from manual intervention. In 381# order to help, dates have special Locators and Formatters, 382# defined in the `matplotlib.dates` module. 383# 384# A simple example is as follows. Note how we have to rotate the 385# tick labels so that they don't over-run each other. 386 387import datetime 388 389fig, ax = plt.subplots(figsize=(5, 3), tight_layout=True) 390base = datetime.datetime(2017, 1, 1, 0, 0, 1) 391time = [base + datetime.timedelta(days=x) for x in range(len(x1))] 392 393ax.plot(time, y1) 394ax.tick_params(axis='x', rotation=70) 395plt.show() 396 397############################################################################## 398# We can pass a format to `matplotlib.dates.DateFormatter`. Also note that the 399# 29th and the next month are very close together. We can fix this by using 400# the `.dates.DayLocator` class, which allows us to specify a list of days of 401# the month to use. Similar formatters are listed in the `matplotlib.dates` 402# module. 403 404import matplotlib.dates as mdates 405 406locator = mdates.DayLocator(bymonthday=[1, 15]) 407formatter = mdates.DateFormatter('%b %d') 408 409fig, ax = plt.subplots(figsize=(5, 3), tight_layout=True) 410ax.xaxis.set_major_locator(locator) 411ax.xaxis.set_major_formatter(formatter) 412ax.plot(time, y1) 413ax.tick_params(axis='x', rotation=70) 414plt.show() 415 416############################################################################## 417# Legends and Annotations 418# ======================= 419# 420# - Legends: :doc:`/tutorials/intermediate/legend_guide` 421# - Annotations: :doc:`/tutorials/text/annotations` 422# 423