#### Overview of this book

Python, one of the world's most popular programming languages, has a number of powerful packages to help you tackle complex mathematical problems in a simple and efficient way. These core capabilities help programmers pave the way for building exciting applications in various domains, such as machine learning and data science, using knowledge in the computational mathematics domain. The book teaches you how to solve problems faced in a wide variety of mathematical fields, including calculus, probability, statistics and data science, graph theory, optimization, and geometry. You'll start by developing core skills and learning about packages covered in Python’s scientific stack, including NumPy, SciPy, and Matplotlib. As you advance, you'll get to grips with more advanced topics of calculus, probability, and networks (graph theory). After you gain a solid understanding of these topics, you'll discover Python's applications in data science and statistics, forecasting, geometry, and optimization. The final chapters will take you through a collection of miscellaneous problems, including working with specific data formats and accelerating code. By the end of this book, you'll have an arsenal of practical coding solutions that can be used and modified to solve a wide range of practical problems in computational mathematics and data science.
Preface
Basic Packages, Functions, and Concepts
Free Chapter
Mathematical Plotting with Matplotlib
Working with Randomness and Probability
Geometric Problems
Finding Optimal Solutions
Miscellaneous Topics
Other Books You May Enjoy

Occasionally, it is useful to place multiple related plots within the same figure side by side but not on the same axes. Subplots allow us to produce a grid of individual plots within a single figure. In this recipe, we will see how to create two plots side by side on a single figure using subplots.

You will need the data to be plotted on each subplot. As an example, we will plot the first five iterates of Newton's method applied to the f(x) = x2-1functionwith an initial value of x0 = 2on the first subplot, and for the second, we will plot the error of the iterate. We first define a generator function to get the iterates:

`def generate_newton_iters(x0, number):    iterates = [x0]    errors = [abs(x0 - 1.)]    for _ in range(number):        x0 = x0 - (x0*x0 - 1.)/(2*x0)        iterates.append(x0)        errors.append(abs(x0 - 1.))    return iterates, errors`

This routine generates two lists. The first list contains iterates of Newton's method applied to the function, and the second contains the error in the approximation:

`iterates, errors = generate_newton_iters(2.0, 5)`

## How to do it...

The following steps show how to create a figure that contains multiple subplots:

1. We use the subplots routine to create a new figure and references to all of the Axes objects in each subplot, arranged in a grid with one row and two columns. We also set the tight_layout keyword argument to True to fix the layout of the resulting plots. This isn't strictly necessary, but it is in this case as it produces a better result than the default:
`fig, (ax1, ax2) = plt.subplots(1, 2, tight_layout=True) # 1 row, 2 columns`

1. Once the Figure and Axes objects are created, we can populate the figure by calling the relevant plotting method on each Axes object. For the first plot (displayed on the left), we use the plot method on the ax1 object, which has the same signature as the standard plt.plot routine. We can then call the set_title, set_xlabel, and set_ylabel methods on ax1 to set the title and the x and ylabels. We also use TeX formatting for the axes labels by providing the usetex keyword argument; you can ignore this if you don't have TeX installed on your system:
`ax1.plot(iterates, "x")ax1.set_title("Iterates")ax1.set_xlabel("\$i\$", usetex=True)ax1.set_ylabel("\$x_i\$", usetex=True)`
1. Now, we can plot the error values on the second plot (displayed on the right) using the ax2 object. We use an alternative plotting method that uses a logarithmic scale on the y-axis, called semilogy. The signature for this method is the same as the standard plot method. Again, we set the axes labels and the title. Again, the use of usetex can be left out if you don't have TeX installed:
`ax2.semilogy(errors, "x") # plot y on logarithmic scaleax2.set_title("Error")ax2.set_xlabel("\$i\$", usetex=True)ax2.set_ylabel("Error")`

The result of this sequence of commands is shown here:

Figure 2.5: Matplotlib subplots

The left-hand side plots the first five iterates of Newton's method and the right-hand side is the approximation error plotted on a logarithmic scale.

## How it works...

A Figure object in Matplotlib is simply a container for plot elements, such as Axes, of a certain size. A Figure object will usually onlyhold a single Axesobject, which occupies the entire figure area, but it can contain any number of Axesobjects in the same area. The subplotsroutine does several things. It first creates a new figure and then creates a grid with the specified shape in the figure area. Then, a new Axesobject is added to each position of the grid. The new Figureobject and one or more Axesobjects are then returned to the user. If a single subplot is requested (one row and one column, with no arguments) then a plainAxesobject is returned. If a single row or column is requested (with more than one column or row, respectively), then a list of the Axesobjects is returned. If more than one row and column is requested, a list of lists, with rows represented by inner lists filled with the Axesobjects, will be returned. We can then use the plotting methods on each of the Axesobjects to populate the figure with the desired plots.

In this recipe, we used the standard plot method for the left-hand side plot, as we have seen in previous recipes. However, for the right-hand side plot, we used a plot where the y-axis had been changed to a logarithmic scale. This means that each unit on the y-axis represents a change of a power of 10, rather than a change of one unit, so that 0 represents 100 = 1, 1 represents 10, 2 represents 100, and so on. The axes labels are automatically changed to reflect this change in scale. This type of scaling is useful when the values change by an order of magnitude, such as the error in an approximation, as we use more and more iterations. We can also plot with a logarithmic scale for x only by using the semilogx method, or both axes on a logarithmic scale by using the loglog method.

## There's more...

There are several ways to create subplots in Matplotlib. If you have already created a Figure object, then subplots can be added using the add_subplot method of the Figure object. Alternatively, you can use the subplot routine from matplotlib.pyplot to add subplots to the current figure. If one does not yet exist, it will be created when this routine is called. The subplot routine is a convenience wrapper of the add_subplot method on the Figure object.

To create a new figure with one or more subplots, you can also use the subplots routine from the pyplot interface—as we saw in the Changing the plotting style recipe—which returns a new figure object and an array of the Axes objects, one for each position. All three of these methods require the number of rows and columns for the subplot matrix. The add_subplot method and the subplot routine also require a third argument, which is the index of the subplot to modify. The Axes object of the current subplot is returned.

In the preceding example, we created two plots with differently scaled y-axes. This demonstrates one of the many possible uses of subplots. Another common use is for plotting data in a matrix where columns have a common x label and rows have a common y label, which is especially common in multivariate statistics when investigating the correlation between various sets of data. The plt.subplots routine for creating subplots accepts the sharex and shareykeyword parameters, which allows the axes to be shared among all the subplots or among a row or column. This setting affects the scale and ticks of the axes.