
- •Credits
- •About the Author
- •About the Reviewers
- •www.PacktPub.com
- •Preface
- •Getting started
- •More advanced graphics
- •Summary
- •Start Sage
- •Installing Sage
- •Starting Sage
- •Prerequisites
- •Installation
- •Summary
- •Command history
- •Working with code
- •Arithmetic operators
- •Strings
- •Functions
- •Functions with keyword arguments
- •Objects
- •Summary
- •Python 2 and Python 3
- •Running scripts
- •Strings
- •List comprehensions
- •Storing data in a dictionary
- •Summary
- •Vectors and vector spaces
- •Creating a vector space
- •Vector operators and methods
- •Decomposing matrices
- •Summary
- •Using graphics primitives
- •Summary
- •Substitutions
- •Finding roots
- •Derivatives
- •Integrals
- •Series and summations
- •Summary
- •Computing gradients
- •Constrained optimization
- •Probability
- •Summary
- •Making our tanks move
- •Unit testing
- •Summary
- •Introducing Python decorators
- •Making interactive graphics
- •Summary
- •Index

Chapter 1
More advanced graphics
Sage has sophisticated plotting capabilities. By combining the power of the Python programming language with Sage's graphics functions, we can construct detailed illustrations. To demonstrate a few of Sage's advanced plotting features, we will solve a simple system of equations algebraically:
var('x') f(x) = x^2
g(x) = x^3 - 2 * x^2 + 2
solutions=solve(f == g, x, solution_dict=True)
for s in solutions: show(s)
The result is as follows:
We used the keyword argument solution_dict=True to tell the solve function to return the solutions in the form of a Python list of Python dictionaries. We then used a for loop to iterate over the list and display the three solution dictionaries. We'll go into more detail about lists and dictionaries in Chapter 4. Let's illustrate our answers with a detailed plot:
p1 = plot(f, (x, -1, 3), color='blue', axes_labels=['x', 'y']) p2 = plot(g, (x, -1, 3), color='red')
labels = [] lines = [] markers = []
for s in solutions:
x_value = s[x].n(digits=3) y_value = f(x_value).n(digits=3)
labels.append(text('y=' + str(y_value), (x_value+0.5,
[ 19 ]

What Can You Do with Sage?
y_value+0.5), color='black')) lines.append(line([(x_value, 0), (x_value, y_value)],
color='black', linestyle='--')) markers.append(point((x_value,y_value), color='black', size=30))
show(p1+p2+sum(labels) + sum(lines) + sum(markers))
The plot looks like this:
We created a plot of each function in a different colour, and labelled the axes. We then used another for loop to iterate through the list of solutions and annotate each one. Plotting will be covered in detail in Chapter 6.
Visualisingathree-dimensionalsurface
Sage does not restrict you to making plots in two dimensions. To demonstrate the 3D capabilities of Sage, we will create a parametric plot of a mathematical surface known as the "figure 8" immersion of the Klein bottle. You will need to have Java enabled in your web browser to see the 3D plot.
var('u,v') r = 2.0
f_x = (r + cos(u / 2) * sin(v) - sin(u / 2) * sin(2 * v)) * cos(u)
f_y = (r + cos(u / 2) * sin(v) - sin(u / 2) * sin(2 * v)) * sin(u)
[ 20 ]

Chapter 1
f_z = sin(u / 2) * sin(v) + cos(u / 2) * sin(2 * v) parametric_plot3d([f_x, f_y, f_z], (u, 0, 2 * pi),
(v, 0, 2 * pi), color="red")
In the Sage notebook interface, the 3D plot is fully interactive. Clicking and dragging with the mouse over the image changes the viewpoint. The scroll wheel zooms in and out, and right-clicking on the image brings up a menu with further options.
Typesettingmathematicalexpressions
Sage can be used in conjunction with the LaTeX typesetting system to create publicationquality typeset mathematical expressions. In fact, all of the mathematical expressions in this chapter were typeset using Sage and exported as graphics. Chapter 10 explains how to use LaTeX and Sage together.
[ 21 ]

What Can You Do with Sage?
Apracticalexample:analysingexperimentaldata
One of the most common tasks for an engineer or scientist is analysing data from an experiment. Sage provides a set of tools for loading, exploring, and plotting data. The following series of examples shows how a scientist might analyse data from a population of bacteria that are growing in a fermentation tank. Someone has measured the optical density (abbreviated OD) of the liquid in the tank over time as the bacteria are multiplying. We want to analyse the data to see how the size of the population of bacteria varies over time. Please note that the examples in this section must be run in order, since the later examples depend upon results from the earlier ones.
Timeforaction–fittingthestandardcurve
The optical density is correlated to the concentration of bacteria in the liquid. To quantify this correlation, someone has measured the optical density of a number of calibration standards of known concentration. In this example, we will fit a "standard curve" to the calibration data that we can use to determine the concentration of bacteria from optical density readings:
import numpy
var('OD, slope, intercept')
def standard_curve(OD, slope, intercept):
"""Apply a linear standard curve to optical density data""" return OD * slope + intercept
# Enter data to define standard curve
CFU = numpy.array([2.60E+08, 3.14E+08, 3.70E+08, 4.62E+08, 8.56E+08, 1.39E+09, 1.84E+09])
optical_density = numpy.array([0.083, 0.125, 0.213, 0.234, 0.604, 1.092, 1.141])
OD_vs_CFU = zip(optical_density, CFU)
# Fit linear standard
std_params = find_fit(OD_vs_CFU, standard_curve, parameters=[slope, intercept], variables=[OD], initial_guess=[1e9, 3e8], solution_dict = True)
for param, value in std_params.iteritems(): print(str(param) + ' = %e' % value)
# Plot
data_plot = scatter_plot(OD_vs_CFU, markersize=20, facecolor='red', axes_labels=['OD at 600nm', 'CFU/ml'])
fit_plot = plot(standard_curve(OD, std_params[slope], std_params[intercept]), (OD, 0, 1.2))
show(data_plot+fit_plot)
[ 22 ]

Chapter 1
The results are as follows:
What just happened?
We introduced some new concepts in this example. On the first line, the statement import numpy allows us to access functions and classes from a module called NumPy. NumPy is based upon a fast, efficient array class, which we will use to store our data. We created a NumPy array and hard-coded the data values for OD, and created another array to store values of concentration (in practice, we would read these values from a file) We then defined a Python function called standard_curve, which we will use to convert optical density values to concentrations. We used the find_fit function to fit the slope and intercept parameters to the experimental data points. Finally, we plotted the data points with the scatter_plot function and the plotted the fitted line with the plot function. Note that we had to use a function called zip to combine the two NumPy arrays into a single list of points before we could plot them with scatter_plot. We'll learn all about Python functions
in Chapter 4, and Chapter 8 will explain more about fitting routines and other numerical methods in Sage.
[ 23 ]

What Can You Do with Sage?
Timeforaction–plottingexperimentaldata
Now that we've defined the relationship between the optical density and the concentration of bacteria, let's look at a series of data points taken over the span of an hour. We will convert from optical density to concentration units, and plot the data.
sample_times = numpy.array([0, 20, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 280, 360, 380, 400, 420, 440, 460, 500, 520, 540, 560, 580, 600, 620, 640, 660, 680, 700, 720, 760, 1240, 1440, 1460, 1500, 1560])
OD_readings = numpy.array([0.083, 0.087, 0.116, 0.119, 0.122, 0.123, 0.125, 0.131, 0.138, 0.142, 0.158, 0.177, 0.213, 0.234, 0.424, 0.604, 0.674, 0.726, 0.758, 0.828, 0.919, 0.996, 1.024, 1.066, 1.092, 1.107, 1.113, 1.116, 1.12,
1.129, 1.132, 1.135, 1.141, 1.109, 1.004, 0.984, 0.972, 0.952])
concentrations = standard_curve(OD_readings, std_params[slope], std_params[intercept])
exp_data = zip(sample_times, concentrations)
data_plot = scatter_plot(exp_data, markersize=20, facecolor='red', axes_labels=['time (sec)', 'CFU/ml'])
show(data_plot)
The scatter plot looks like this:
[ 24 ]

Chapter 1
What just happened?
We defined one NumPy array of sample times, and another NumPy array of optical density values. As in the previous example, these values could easily be read from a file. We used the standard_curve function and the fitted parameter values from the previous example to convert the optical density to concentration. We then plotted the data points using the scatter_plot function.
Timeforaction–fittingagrowthmodel
Now, let's fit a growth model to this data. The model we will use is based on the Gompertz function, and it has four parameters:
var('t, max_rate, lag_time, y_max, y0')
def gompertz(t, max_rate, lag_time, y_max, y0):
"""Define a growth model based upon the Gompertz growth curve""" return y0 + (y_max - y0) * numpy.exp(-numpy.exp(1.0 +
max_rate * numpy.exp(1) * (lag_time - t) / (y_max - y0)))
# Estimated parameter values for initial guess max_rate_est = (1.4e9 - 5e8)/200.0 lag_time_est = 100
y_max_est = 1.7e9 y0_est = 2e8
gompertz_params = find_fit(exp_data, gompertz, parameters=[max_rate, lag_time, y_max, y0], variables=[t],
initial_guess=[max_rate_est, lag_time_est, y_max_est, y0_est], solution_dict = True)
for param,value in gompertz_params.iteritems(): print(str(param) + ' = %e' % value)
The fitted parameter values are displayed:
Finally, let's plot the fitted model and the experimental data points on the same axes:
gompertz_model_plot = plot(gompertz(t, gompertz_params[max_rate], gompertz_params[lag_time], gompertz_params[y_max], gompertz_params[y0]), (t, 0, sample_times.max()))
show(gompertz_model_plot + data_plot)
[ 25 ]