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