Read more about this book |

*(For more resources related to this topic, see here.)*

# Confusion alert: Sage plots and matplotlib

The 2D plotting capabilities of Sage are built upon a Python plotting package called matplotlib. The most widely used features of matplotlib are accessible through Sage functions. You can also import the matplotlib package into Sage, and use all of its features directly. This is very powerful, but it's also confusing, because there's more than one way to do the same thing. To further add to the confusion, matplotlib has two interfaces: the command-oriented Pyplot interface and an object-oriented interface. The examples in this chapter will attempt to clarify which interface is being used.

# Plotting in two dimensions

Two-dimensional plots are probably the most important tool for visually presenting information in math, science, and engineering. Sage has a wide variety of tools for making many types of 2D plots.

# Plotting symbolic expressions with Sage

We will start by exploring the plotting functions that are built in to Sage. They are generally less flexible than using matplotlib directly, but also tend to be easier to use.

# Time for action – plotting symbolic expressions

Let's plot some simple functions. Enter the following code:

p1 = plot(sin, (-2*pi, 2*pi), thickness=2.0, rgbcolor=(0.5, 1, 0),

legend_label='sin(x)')

p2 = plot(cos, (-2*pi, 2*pi), thickness=3.0, color='purple',

alpha=0.5, legend_label='cos(x)')

plt = p1 + p2

plt.axes_labels(['x', 'f(x)'])

show(plt)

If you run the code from the interactive shell, the plot will open in a separate window. If you run it from the notebook interface, the plot will appear below the input cell. In either case, the result should look like this:

## What just happened?

This example demonstrated the most basic type of plotting in Sage. The *plot* function requires the following arguments:

graphics_object = plot(callable symbolic expression, (independent_var,

ind_var_min, ind_var_max))

The first argument is a callable symbolic expression, and the second argument is a tuple consisting of the independent variable, the lower limit of the domain, and the upper limit. If there is no ambiguity, you do not need to specify the independent variable. Sage automatically selects the right number of points to make a nice curve in the specified domain. The *plot* function returns a graphics object. To combine two graphics objects in the same image, use the + operator: *plt = p1 + p2*. Graphics objects have additional methods for modifying the final image. In this case, we used the *axes_labels* method to label the x and y axes. Finally, the *show* function was used to finish the calculation and display the image.

The *plot* function accepts optional arguments that can be used to customize the appearance and format of the plot. To see a list of all the options and their default values, type:

sage: plot.options

{'fillalpha': 0.5, 'detect_poles': False, 'plot_points': 200,

'thickness': 1, 'alpha': 1, 'adaptive_tolerance': 0.01, 'fillcolor':

'automatic', 'adaptive_recursion': 5, 'exclude': None, 'legend_label':

None, 'rgbcolor': (0, 0, 1), 'fill': False}

Here is a summary of the options for customizing the appearance of a plot:

Keyword |
Description |

alpha | Transparency of the line (0=opaque, 1=transparent) |

fill | True to fill area below the line |

fillalpha | Transparency of the filled-in area (0=opaque, 1=transparent) |

fillcolor | Color of the filled-in area |

rgbcolor | Color of the line |

Sage uses an algorithm to determine the best number of points to use for the plot, and how to distribute them on the x axis. The algorithm uses recursion to add more points to resolve regions where the function changes rapidly. Here are the options that control how the plot is generated:

Keyword |
Description |

adaptive_recursion | Max depth of recursion when resolving areas of the plot where the function changes rapidly |

adaptive_tolerance | Tolerance for stopping recursion |

detect_poles | Detect points where function value approaches infinity (see next example) |

exclude | A list or tuple of points to exclude from the plot |

plot_points | Number of points to use in the plot |

**Specifying colors in Sage**

There are several ways to specify a color in Sage. For basic colors, you can use a string containing the name of the color, such as red or blue. You can also use a tuple of three floating-point values between 0 and 1.0. The first value is the amount of red, the second is the amount of green, and the third is the amount of blue. For example, the tuple (0.5, 0.0, 0.5) represents a medium purple color.

Some functions "blow up" to plus or minus infinity at a certain point. A simplistic plotting algorithm will have trouble plotting these points, but Sage adapts.

# Time for action – plotting a function with a pole

Let's try to plot a simple function that takes on infinite values within the domain of the plot:

pole_plot = plot(1 / (x - 1), (0.8, 1.2), detect_poles='show',

marker='.')

print("min y = {0} max y = {1}".format(pole_plot.ymax(),

pole_plot.ymin()))

pole_plot.ymax(100.0)

pole_plot.ymin(-100.0)

# Use TeX to make nicer labels

pole_plot.axes_labels([r'$x$', r'$1/(x-1)$'])

pole_plot.show()

The output from this code is as follows:

## What just happened?

We did a few things differently compared to the previous example. We defined a callable symbolic expression right in the plot function. We also used the option *detect_poles='show'* to plot a dashed vertical line at the x value where the function returns infinite values. The option *marker='.'* tells Sage to use a small dot to mark the individual (x,y) values on the graph. In this case, the dots are so close together that they look like a fat line. We also used the methods *ymin* and *ymax* to get and set the minimum and maximum values of the vertical axis. When called without arguments, these methods return the current values. When given an argument, they set the minimum and maximum values of the vertical axis.

Finally, we labeled the axes with nicely typeset mathematical expressions. As in the previous example, we used the method *axes_labels* to set the labels on the x and y axes. However, we did two special things with the label strings:

r'$\frac{1}{(x-1)}$'

The letter **r** is placed in front of the string, which tells Python that this is a raw string. When processing a raw string, Python does not interpret backslash characters as commands (such as interpreting **\n** as a newline). Note that the first and last characters of the string are dollar signs, which tells Sage that the strings contain mark-up that needs to be processed before being displayed. The mark-up language is a subset of TeX, which is widely used for typesetting complicated mathematical expressions. Sage performs this processing with a built-in interpreter, so you don't need to have TeX installed to take advantage of typeset labels. It's a good idea to use raw strings to hold TeX markup because TeX uses a lot of backslashes. To learn about the typesetting language, see the matplotlib documentation at:

http://matplotlib.sourceforge.net/users/mathtext.html

# Time for action – plotting a parametric function

Some functions are defined in terms of a parameter. Sage can easily plot parametric functions:

var('t')

pp = parametric_plot((cos(t), sin(t)), (t, 0, 2*pi),

fill=True, fillcolor='blue')

pp.show(aspect_ratio=1, figsize=(3, 3), frame=True)

The output from this code is as follows:

## What just happened?

We used two parametric functions to plot a circle. This is a convenient place to demonstrate the *fill* option, which fills in the space between the function and the horizontal axis. The *fillcolor* option tells Sage which color to use for the fill, and the color can be specified in the usual ways. We also demonstrated some useful options for the *show* method (these options also work with the *show* function). The option *aspect_ratio=1* forces the x and y axes to use the same scale. In other words, one unit on the x axis takes up the same number of pixels on the screen as one unit on the y axis. Try changing the aspect ratio to 0.5 and 2.0, and see how the circle looks. The option *figsize=(x_size,y_size)* specifies the aspect ratio and relative size of the figure. The units for the figure size are relative, and don't correspond to an absolute unit like inches or centimetres. The option *frame=True* places a frame with tick marks around the outside of the plot.

# Time for action – making a polar plot

Some functions are more easily described in terms of angle and radius. The angle is the independent variable, and the radius at that angle is the dependent variable. Polar plots are widely used in electrical engineering to describe the radiation pattern of an antenna. Some antennas are designed to transmit (or receive) electromagnetic radiation in a very narrow beam. The beam shape is known as the radiation pattern. One way to achieve a narrow beam is to use an array of simple dipole antennas, and carefully control the phase of the signal fed to each antenna. In the following example, we will consider seven short dipole antennas set in a straight line:

# A linear broadside array of short vertical dipoles

# located along the z axis with 1/2 wavelength spacing

var('r, theta')

N = 7

normalized_element_pattern = sin(theta)

array_factor = 1 / N * sin(N * pi / 2 * cos(theta)) \

/ sin(pi / 2 * cos(theta))

array_plot = polar_plot(abs(array_factor), (theta, 0, pi),

color='red', legend_label='Array')

radiation_plot = polar_plot(abs(normalized_element_pattern

* array_factor), (theta, 0, pi), color='blue',

legend_label='Radiation')

combined_plot = array_plot + radiation_plot

combined_plot.xmin(-0.25)

combined_plot.xmax(0.25)

combined_plot.set_legend_options(loc=(0.5, 0.3))

show(combined_plot, figsize=(2, 5), aspect_ratio=1)

Execute the code. You should get a plot like this:

## What just happened?

We plotted a polar function, and used several of the plotting features that we've already discussed. There are two subtle points worth mentioning. The function *array_factor* is a function of two variables, N and theta. In this example, N is more like a parameter, while *theta* is the independent variable we want to use for plotting. We use the syntax *(theta, 0, pi)* in the *plot* function to indicate that *theta* is the independent variable. The second new aspect of this example is that we used the methods *xmin* and *xmax* to set the limits of the x axis for the graphics object called *combined_plot*. We also used the *set_legend_options* of the graphics object to adjust the position of the legend to avoid covering up important details of the plot.

# Time for action – plotting a vector field

Vector fields are used to represent force fields such as electromagnetic fields, and are used to visualize the solutions of differential equations. Sage has a special plotting function to visualize vector fields.

var('x, y')

a = plot_vector_field((x, y), (x, -3, 3), (y, -3, 3), color='blue')

b = plot_vector_field((y, -x), (x, -3, 3), (y, -3, 3), color='red')

show(a + b, aspect_ratio=1, figsize=(4, 4))

You should get the following image:

## What just happened?

The *plot_vector_field* function uses the following syntax:

plot_vector_field((x_function,y_function), (x,x_min,x_max), (y,y_

min,y_max))

The keyword argument *color* specifies the color of the vectors.

# Plotting data in Sage

So far, we've been making graphs of functions. We specify the function and the domain, and Sage automatically chooses the points to make a nice-looking curve. Sometimes, we need to plot discrete data points that represent experimental measurements or simulation results. The following functions are used for plotting defined sets of points.

# Time for action – making a scatter plot

Scatter plots are used in science and engineering to look for correlation between two variables. A cloud of points that is roughly circular indicates that the two variables are independent, while a more elliptical arrangement indicates that there may be a relationship between them. In the following example, the x and y coordinates are contrived to make a nice plot. In real life, the x and y coordinates would typically be read in from data files. Enter the following code:

def noisy_line(m, b, x):

return m * x + b + 0.5 * (random() - 0.5)

slope = 1.0

intercept = -0.5

x_coords = [random() for t in range(50)]

y_coords = [noisy_line(slope, intercept, x) for x in x_coords]

sp = scatter_plot(zip(x_coords, y_coords))

sp += line([(0.0, intercept), (1.0, slope+intercept)], color='red')

sp.show()

The result should look similar to this plot. Note that your results won't match exactly, since the point positions are determined randomly.

## What just happened?

We created a list of randomized x coordinates using the built-in *random* function. This function returns a random number in the range 0 <= x < 1. We defined a function called *noisy_line* that we then used to create a list of randomized y coordinates with a linear relationship to the x coordinates. We now have a list of x coordinates and a list of y coordinates, but the *scatter_plot* function needs a list of *(x,y)* tuples. The *zip* function takes the two lists and combines them into a single list of tuples. The *scatter_plot* function returns a graphics object called sp. To add a line object to the plot, we use the following syntax:

sp += line([(x1, y1), (x2,y2)], color='red')

The *+=* operator is a way to increment a variable; *x+=1* is a shortcut for *x = x + 1*. Because the + operator also combines graphics objects, this syntax can be used to add a graphics object to an existing graphics object.

# Time for action – plotting a list

Sometimes, you need to plot a list of discrete data points. The following example might be found in an introductory digital signal processing (DSP) course. We will use lists to represent digital signals. We sample the analogue function cosine(t) at two different sampling rates, and plot the resulting digital signals.

# Use list_plot to visualize digital signals

# Undersampling and oversampling a cosine signal

sample_times_1 = srange(0, 6*pi, 4*pi/5)

sample_times_2 = srange(0, 6*pi, pi/3)

data1 = [cos(t) for t in sample_times_1]

data2 = [cos(t) for t in sample_times_2]

plot1 = list_plot(zip(sample_times_1, data1), color='blue')

plot1.axes_range(0, 18, -1, 1)

plot1 += text("Undersampled", (9, 1.1), color='blue', fontsize=12)

plot2 = list_plot(zip(sample_times_2, data2), color='red')

plot2.axes_range(0, 18, -1, 1)

plot2 += text("Oversampled", (9, 1.1), color='red', fontsize=12)

g = graphics_array([plot1, plot2], 2, 1) # 2 rows, 1 column

g.show(gridlines=["minor", False])

The result is as follows:

## What just happened?

The function *list_plot* works a lot like *scatter_plot* from the previous example, so I won't explain it again. We used the method *axes_range(x_min, x_max, y_min, y_max)* to set the limits of the x and y axes all at once. Once again, we used the *+=* operator to add a graphics object to an existing object. This time, we added a text annotation instead of a line. The basic syntax for adding text at a given (x,y) position is *text('a string', (x,y))*. To see the options that text accepts, type the following:

sage: text.options

{'vertical_alignment': 'center', 'fontsize': 10, 'rgbcolor': (0, 0,

1),

'horizontal_alignment': 'center', 'axis_coords': False}

To display the two plots, we introduced a new function called *graphics_array*, which uses the basic syntax:

graphics_array([plot_1, plot_2, ..., plot_n], num_rows, num_columns)

This function returns another graphics object, and we used the *show* method to display the plots. We used the keyword argument *gridlines=["minor", False]* to tell Sage to display vertical lines at each of the minor ticks on the x axis. The first item in the list specifies vertical grid lines, and the second specifies horizontal grid lines. The following options can be used for either element:

"major" | Grid lines at major ticks |

"minor" | Grid lines at major and minor ticks |

False | No grid lines |

Try playing with these options in the previous example.

Read more about this book |

*(For more resources related to this topic, see here.)*

# Using graphics primitives

We've already seen that Sage has graphics primitives such as lines and text annotations. Sage has other types of graphics primitives that can be used for plotting.

# Time for action – plotting with graphics primitives

A class of mathematical models called random sequential adsorption (RSA) models deals with the patterns that result when two-dimensional shapes are randomly deposited onto a plane. The following method can be used to visualize these kinds of models:

# Since the circles are random, your plot will not

# look exactly like the example!

circle_list = []

for i in range(15):

x = -5 + 10 * random()

y = -5 + 10 * random()

circle_list.append(circle((x, y), 1, facecolor='red',

edgecolor=(0, 0, 1), thickness=2, fill=True))

gr = sum(circle_list)

gr.axes(False)

gr.show(aspect_ratio=1, frame=True, gridlines=True, figsize=(4, 4))

You should get a plot that resembles the one below. Because the positions of the circles are randomly generated, your plot will not look exactly like this one.

## What just happened?

We created a list of graphics objects with a *for* loop and the *circle* function. The basic syntax for the circle function is as follows:

graphics_object = circle((center_x, center_y), radius)

In order to plot all the circles at once, we used the *sum* function to add up the list. We then prevented the axes from being drawn by calling the method *gr.axes(False)*. Finally, when calling the *show* method we used the keyword argument frame=True to draw a frame, with ticks and labels, around the outside of the plotting area. The argument *gridlines=True* is a shortcut to activate both horizontal and vertical grid lines. Sage has many other types of primitives, including elliptical arcs, arrows, disks, ellipses, points, and polygons.

# Using matplotlib

We can access matplotlib directly to do things that we can't do with Sage plotting functions. matplotlib has such a large number of options and features. We will only touch on a few basic features. If you want to know more, the matplotlib website has excellent documentation:

http://matplotlib.sourceforge.net/contents.html

# Time for action – plotting functions with matplotlib

To illustrate the similarities and differences between plotting with matplotlib and plotting with Sage, we will repeat the first example of this article using the Pyplot interface to matplotlib. Enter and evaluate the following code:

import numpy

import matplotlib.pyplot as plt

x = numpy.arange(-2 * numpy.pi, 2 * numpy.pi, 0.1)

func1 = numpy.sin(x)

func2 = numpy.cos(x)

plt.figure(figsize=(5.5, 3.7)) # size in inches

plt.plot(x, func1, linewidth=2.0, color=(0.5, 1,0),

label='$f(x)=sin(x)$')

plt.plot(x, func2, linewidth=3.0, color='purple', alpha=0.5,

label='$f(x)=cos(x)$')

plt.xlabel('$x$')

plt.ylabel('$f(x)$')

plt.title('Plotting with matplotlib')

plt.legend(loc='lower left')

plt.savefig('demo1.png')

plt.close()

The result should be as follows:

## What just happened?

We gained access to matplotlib functions and types with the following line:

import matplotlib.pyplot as plt

We can now access these functions as *plt.function_name*. We also *import numpy* so that we can use its numerical arrays.

There is an important difference between the Sage *plot* function and the matplotlib *plot* function. matplotlib always plots lists or arrays of discrete points, rather than callable symbolic expressions. This block of code creates an array of x values:

x = numpy.arange(-2*numpy.pi, 2*numpy.pi, 0.1)

func1 = numpy.sin(x)

func2 = numpy.cos(x)

*func1* and *func2* are arrays of y values. Notice that we specify the NumPy version of *sin* and *cos*, since the Sage functions don't know what to do with NumPy arrays. The syntax for plotting with matplotlib is as follows:

plt.figure()

plt.plot(x_values, y_values)

The first line creates an empty figure. The optional argument *figsize=(x_size, y_size)* sets the figure size in inches. The second line plots the data points that are specified in the arrays or lists. By default, the points are connected with straight line segments. If you specify points that are too far apart, you will see the line segments instead of a smooth curve. The options for the *plt.plot* function are very similar to the options for the Sage *plot* function. The following code labels the x and y axes, and places a title above the figure:

plt.xlabel('$x$')

plt.ylabel('$f(x)$')

plt.title('Plotting with matplotlib')

plt.legend(loc='lower right')

The *legend* method places a legend on the figure. You can use TeX to format any text on the plot by wrapping the text in dollar signs. The following code actually displays the plot:

plt.savefig('demo1.png')

plt.close()

If you are running this example from the notebook interface, the graphic will automatically appear in the notebook. If you're running it in the interactive shell, you won't see any output. The *savefig* function will save an image file in your home directory. To specify a different path for saving files, pass a full or relative path in addition to the file name. For example:

sage: plt.savefig('Sage for Beginners/Chapter 6/Images/polar_plot.png')

matplotlib can save figures in a variety of image formats, such as png, pdf, ps (PostScript), eps (encapsulated PostScript), and svg (scalable vector graphics). It will automatically determine the correct format from the extension of the file name. You can also use the *format* keyword to specify the image format. PNG is a raster format, which is compatible with Microsoft Office and OpenOffice. For publications, it is best to use a vector format like PostScript, EPS, or PDF. The SVG format is used for displaying vector graphics on the Web.

# Using matplotlib to "tweak" a Sage plot

Every Sage plot is actually an encapsulated matplotlib figure. We can get the underlying figure and modify it.

# Time for action – getting the matplotlib figure object

Let's say you've made a plot with Sage, but you want to fix one or two formatting details, and Sage doesn't give you enough control. In this example, we'll use the object-oriented interface of matplotlib:

# Create a Sage plot, as shown in the first example

p1 = plot(sin, (-2*pi, 2*pi), thickness=2.0, rgbcolor=(0.5,1,0))

p2 = plot(cos, (-2*pi, 2*pi), thickness=3.0, color='purple',

alpha=0.5)

plt = p1 + p2

# Get the Matplotlib object

fig = plt.matplotlib()

from matplotlib.backends.backend_agg import FigureCanvasAgg

fig.set_canvas(FigureCanvasAgg(fig)) # this line is critical

ax = fig.gca() # get current axes

# Add a legend and plot title

ax.legend(['sin(x)', 'cos(x)'])

ax.set_title('Modified with matplotlib')

# Add a y axis label in a custom location

ymin, ymax = ax.get_ylim()

ax.set_ylim(ymin, ymax*1.2)

ax.set_ylabel('$f(x)$', y=ymax*0.9)

# Fancy annotation of a point of interest

x_value = numerical_approx(-3*pi/4)

y_value = numerical_approx(cos(-3*pi/4))

ax.annotate('Point', xy=(x_value, y_value),

xytext=(-6, -0.5), color='red',

arrowprops=dict(arrowstyle="->", connectionstyle="angle3"))

# Show the matplotlib figure

fig.savefig('Sage_to_matplotlib.png')

The output should look like this:

## What just happened?

We modified a plot with matplotlib. First, we used Sage plotting commands to create a Sage graphics object. We then used the *matplotlib* method of the Sage graphics object to obtain the underlying matplotlib figure object. The rest of this example uses matplotlib functions, rather than Sage functions, to modify the figure. It is critical to use the following line of code:

fig.set_canvas(FigureCanvasAgg(fig))

The canvas is a "backend," which controls how matplotlib outputs the graphics it creates. Once we set the right canvas, we used the *gca* method of the figure object to get an object that represents the current axes. We then used methods of the axes object to modify the plot.

# Time for action – improving polar plots

In a previous example, we made polar pots with the Sage function *polar_plot*. However, polar plots in matplotlib look nicer because they are plotted on special axes. Let's use matplotlib to make these plots again. This example uses the Pyplot interface to matplotlib:

import numpy

import matplotlib.pyplot as plt

# Repeat the antenna pattern example with the Pyplot interface

N = float(7)

theta = numpy.arange(0, numpy.pi, numpy.pi/100)

def normalized_element_pattern(theta):

return abs(numpy.sin(theta))

def array_factor(theta, N):

return abs(float(1 / N) * numpy.sin(float(N * pi / 2)

* numpy.cos(theta))

/ numpy.sin(float(pi / 2) * numpy.cos(theta)))

plt.figure(figsize=(6, 4))

plt.subplot(121, polar=True)

plt.polar(theta, normalized_element_pattern(theta))

plt.title('Element factor')

plt.subplot(122, polar=True)

plt.polar(theta, array_factor(theta, N), color='red',

label="Array factor")

plt.polar(theta, array_factor(theta, N) *

normalized_element_pattern(theta),

label="Pattern", color='blue')

plt.legend(loc='lower right', bbox_to_anchor = (1, 0))

plt.subplots_adjust(wspace=0.3)

plt.savefig('Polar_plot.png')

plt.close()

## What just happened?

We made polar plots on nicely formatted polar axes. We introduced a new Pyplot function called subplot, which creates multiple axes on a single figure, arranged as a grid. Subplot accepts three integer arguments that specify the arrangement of axes and chooses one of the axes as the current axes object. The first integer specifies the number of columns in the grid, the second integer specifies the number of rows in the grid, and the third integer selects the current axes object. The first subplot, which is number one, is located in the upper-left corner of the figure. Subplot numbers increase from left to right across a row, and from top to bottom. It is possible, although not recommended, to omit the commas between arguments and pass a single three-digit integer value to subplot. This rather unusual syntax was chosen for compatibility with the *subplot* function in MATLAB. We used the *polar* keyword to choose polar axes for each of the subplots.

We also introduced a function called *subplots_adjust*, which we used to increase the amount of horizontal space between the plots. This command can be used to adjust the amount of space around and between subplots, using the following keyword arguments:

Keyword |
Default |
Meaning |

left | 0.125 | Space to the left of the subplots |

right | 0.9 | Space to the right of the subplots |

bottom | 0.1 | Space below the subplots |

top | 0.9 | Space above the subplots |

wspace | 0.2 | Space between columns of subplots |

hspace | 0.2 | Space between rows of subplots |

# Plotting data with matplotlib

Because matplotlib plots arrays of points, it is well suited to working with data. You can make many kinds of charts and publication-quality graphics with matplotlib.

# Time for action – making a bar chart

Bar charts are often used to present experimental data in scientific papers. Let's make a chart with bars that represent the average value of some experimental data and add error bars to represent the standard deviation:

import numpy

import matplotlib.pyplot as plt

# Define experimental data

cluster1_data = numpy.array([9.7, 3.2])

cluster1_x = numpy.array([2,4])

cluster1_error = numpy.array([1.3, 0.52])

cluster2_data = numpy.array([6.8, 7.3])

cluster2_x = numpy.array([8,10])

cluster2_error = numpy.array([0.72, 0.97])

# Join data arrays for plotting

data = numpy.concatenate([cluster1_data, cluster2_data])

bar_centers = numpy.concatenate([cluster1_x, cluster2_x])

errors = numpy.concatenate([cluster1_error, cluster2_error])

# Plot

fig = plt.figure(figsize=(5,4)) # size in inches

plt.bar(bar_centers, data, yerr=errors,

width=2.0, align='center', color='white', ecolor='black')

plt.ylabel('outcome')

plt.text(4, 4, '*', fontsize=14)

# Label ticks on x axis

axes = fig.gca()

axes.set_xticks(bar_centers)

axes.set_xticklabels(['trial 1', 'trial 2', 'trial 3', 'trial 4'])

plt.savefig('Bar_Chart.png')

plt.close()

The output should look like this:

## What just happened?

We created a publication-quality bar chart using the *bar* function from matplotlib. This function has two mandatory arguments. The first argument sets the horizontal location of each bar, and the second sets the height of each bar. Here is a summary of the optional arguments we used to customize the appearance of the plot:

Keyword |
Description |

yerr | Sets the size of the error bars on top of each bar. |

width | Width of each bar. |

align | Determines how the first argument is interpreted. If set to 'center', the array sets the location of the centre of each bar; otherwise, it sets the location of the left edge. |

color | The color of the fill inside the bars. |

ecolor | The color of the edge (outline) of the bars. |

There are other optional arguments, which are described in the matplotlib documentation.

We used the *text* function to add text to the plot—in this case, an asterisk to indicate that one of the bars is statistically distinct from the others. The *text* function requires the x and y coordinates of the text, and a string containing the text to be displayed. The *fontsize* keyword allowed us to change the size of the text. In order to customize the tick labels on the x axis, we used the *gca* method of the figure object to get its axes object. We then passed an array of bar centres to the *set_xticks* method so that ticks will only be displayed at the centre of each bar. We used the *set_xticklabels* method to label the ticks with strings instead of numbers.

# Time for action – making a pie chart

matplotlib can also make business graphics that are more commonly associated with spreadsheets. Let's try a pie chart:

import numpy

import matplotlib.pyplot as plt

data = [1.0, 10.0, 20.0, 30.0, 40.0]

explode = numpy.zeros(len(data))

explode[3] = 0.1

plt.figure(figsize=(4, 4))

plt.pie(data, explode=explode, labels=['a', 'b', 'c', 'd', 'e'])

plt.title('Revenue sources')

plt.savefig('Pie_chart.png')

plt.close()

The plot should look like this:

## What just happened?

We made a pie chart. The *pie* function in matplotlib only requires one argument, which is a list of numbers that indicate the relative size of the slices. The *explode* option takes a list of numbers that show how far to offset each piece of the pie from the centre. In this case, we created an array of zeros and set the fourth element to 0.1, which offset the fourth slice of the pie. We used the keyword *explode* to pass this array to the *pie* function. We used the *labels* keyword to pass a list of strings to be used as labels for each slice.

# Time for action – plotting a histogram

matplotlib has a built-in function for making histograms, which are used to visualize the distribution of values in a set of data. In this example, we will generate an array of random numbers that are drawn from a Gaussian distribution:

import numpy

import matplotlib.pyplot as plt

data = numpy.random.normal(0, 1, size=1000)

plt.figure(figsize=(4, 4))

plt.hist(data, normed=True, facecolor=(0.9, 0.9, 0.9))

plt.savefig('Histogram.png')

plt.close()

The result should be similar to the following plot. Because we are generating random data, your plot will not look exactly like this one:

## What just happened?

We used the *hist* function to visualize the distribution of values in an array of pseudorandom numbers. *hist* requires one argument, which is an array containing the data. In practice, the data would typically consist of experimental measurements, sensor data, or the results of a Monte Carlo simulation. We used the optional argument *normed=True* to indicate that the histogram should be normalized, which means that its integral is one. The *facecolor* keyword was used to specify the fill color of the bars as a tuple of R, G, B values.

# Summary

We have seen that Sage has powerful graphics capabilities. Specifically, we learned about:

- Plotting functions of one variable, in rectangular and polar coordinates
- Setting options that control the appearance of plots
- Visualizing data with list_plot and scatter_plot
- Using graphics primitives to customize
- Using matplotlib to gain more control over the formatting of plots
- Making various types of charts for presenting data

**Further resources on this subject:**

- Creating Line Graphs in R [Article]
- Graphical Capabilities of R [Article]
- What Can You Do with Sage Math? [Article]
- Python Multimedia: Enhancing Images [Article]
- Python Multimedia: Fun with Animations using Pyglet [Article]