Numpy

The library numpy allows to use vector and arrays in python in a faster and more efficient way for numerical computation with respect to "lists" and "list of lists".
Another advantage of using numpy arrays with respect to ordinary python lists is that it allows to import data from text or binary files written by C o Fortran, which are still the most used language for numerical computation.
The base construct is the ndarray, that can have any dimension and types corresponding to the classic ones of C or Fortran.
Moreover, one strenght of numpy is the possibility to work with vectors and arrays by using the vectorization capabilities of the processor, which allows quite efficient and fast computations with respect to data stored in ordinary python lists.

Start using numpy

To start using the numpy library, as it happens for any python library, one has to import the corresponding module. To use a quicker notation when invoking the functions belonging to the library, we can assign a shortcut to the library name, like this:

In [32]:
import numpy as np
From now on, each reference to functions in the numpy library can be accessed through the symbolic name: np.
As said before, the basic construct is the ndarray which is an object declared through the constructor:
 ndarray_name = np.ndarray( dimensions, dtype = type )
where dimensions is a tuple containing the dimensions of the object, and type is its type. type may be one of:
Data type Description
bool Boolean (True or False) stored as a byte
int Platform integer (normally either int32 or int64)
int8 Byte (-128 to 127)
int16 Integer (-32768 to 32767)
int32 Integer (-2147483648 to 2147483647)
int64 Integer (9223372036854775808 to 9223372036854775807)
uint8 Unsigned integer (0 to 255)
uint16 Unsigned integer (0 to 65535)
uint32 Unsigned integer (0 to 4294967295)
uint64 Unsigned integer (0 to 18446744073709551615)
float Shorthand for float64.
float16 Half precision float: sign bit, 5 bits exponent, 10 bits mantissa
float32 Single precision float: sign bit, 8 bits exponent, 23 bits mantissa
float64 Double precision float: sign bit, 11 bits exponent, 52 bits mantissa
complex Shorthand for complex128.
complex64 Complex number, represented by two 32-bit floats (real and imaginary components)
complex128 Complex number, represented by two 64-bit floats (real and imaginary components)
An easier way to initialize an ndarray object is by transforming an ordinary python list (or tuple, or set, or values from a dictionary!) in a ndarray throught the function array:
 ndarray_name = np.array( values, dtype=...)

where values are initialization values for the array, that is, for instance, a list, list of lists, tuple, etc.
Example:

In [33]:
# Please, notice as the values may NOT be initialized!
aa=np.ndarray((10,10),dtype=float)
print(aa)
[[  6.93961096e-310   3.43773880e-316   2.06999331e+161   4.17539473e-062
    6.50931482e-091   7.35734601e+228   4.32492612e-091   1.07345772e+272
    5.01306182e-090   1.17339088e+214]
 [  1.65746176e-076   5.51147079e+169   7.39405310e-037   8.04530286e+217
    6.33104956e+180   9.79940723e+241   6.96614508e-090   4.97044766e-091
    4.70698443e-090   7.18090538e-038]
 [  6.97910408e+199   4.24821786e+175   8.92341314e-090   4.51381351e-091
    6.54423896e-043   6.58888488e-043   2.52873303e-052   8.88899227e+247
    5.00638399e-090   5.32197949e+222]
 [  8.25692149e-072   2.41974125e-052   2.00163023e-076   4.08674845e-033
    1.17215180e+171   8.46290265e+164   5.71913466e+228   2.73637024e-057
    6.50931473e-091   4.97522396e-091]
 [  7.73424273e-091   4.77429649e-090   3.78349110e+180   5.32197959e+222
    8.25692149e-072   2.41974125e-052   2.00163023e-076   1.36155448e-094
    5.30488275e+199   5.62629014e+175]
 [  2.06999331e+161   4.17539473e-062   6.50931482e-091   7.35734601e+228
    4.32852164e-091   1.07345772e+272   5.01306182e-090   1.17339088e+214
    1.65746176e-076   5.51147079e+169]
 [  7.39405310e-037   8.04533652e+217   6.33104956e+180   9.79940723e+241
    6.96614508e-090   4.97044766e-091   4.70698443e-090   7.18090538e-038
    8.04531134e+217   6.33104956e+180]
 [  9.79940723e+241   6.96614508e-090   4.97044766e-091   4.70698443e-090
    7.18090538e-038   8.04531555e+217   6.33104956e+180   9.79940723e+241
    6.96614508e-090   4.97044766e-091]
 [  4.70698443e-090   7.18090538e-038   8.04531976e+217   6.33104956e+180
    1.88959082e+219   2.06999331e+161   4.17539473e-062   6.50931482e-091
    6.26150885e+199   8.55181131e-072]
 [  3.60763669e+174   4.39251215e+228   4.23953470e+175   5.71913466e+228
    2.73637024e-057   6.50931473e-091   1.87419262e+208   8.54407337e-072
    4.36136514e+198   1.69200524e+190]]

In [34]:
# Here the values are initialized to a list!
a=np.array([10,20,30,40,50], dtype=int)
print(a)
[10 20 30 40 50]

The specific types (int32, float64, etc.) can be used, in turn, to initialize an ndarray object with, for instance a list or a tuple (BUT, be aware that if you use standard types produce an error! This is because they are used for type conversion...)
Example:

In [35]:
a=np.float64((0,1,2,3,4,5))
print(a)
[ 0.  1.  2.  3.  4.  5.]

In [36]:
b=np.float([0,1,2,3,4,5])
print(b)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-36-5c319c9ff803> in <module>()
----> 1 b=np.float([0,1,2,3,4,5])
      2 print(b)

TypeError: float() argument must be a string or a number, not 'list'
However, it is often more useful to use some predefined functions to generate simple ndarray objects without using lists or tuples as initializers. For instance, the following functions:
  • zeros(num, dtype=...): returns a vector of num elements initialized with zeros;
  • zeros((num1, ..., num_n), dtype=...): as before, but produces an array with dimension num1 x ... x num_n (note the double parentheses, since the argument is a tuple!);
  • ones(num, dtype=...) or ones((num1, ..., num_n), dtype=...): as zeros, but fills up the elements with ones;
  • arange(start,stop,step): returns and interval of values (integers or reals, according to the values of start, stop and step) starting from start to stop at jumps of step (note that the interval [start,stop) is open, that is the last value is NOT included! This function is equivalent to the ordinary python range function, except for the fact that values can be float and not integers only);
  • linstep(start,stop,num): as before, but the interval is closed (namely stop is included in the data!) and num is an integer! That is, it produces an array of num values, equally spaced between start and stop (included)!
In [37]:
# Note: np.pi is pi=3.1415926...
x=np.zeros((10,2))
y=np.arange(0.0,2.0*np.pi,0.1)
z=np.linspace(0.0,2.0*np.pi,11)
print(x)
print(y)
print(z)
[[ 0.  0.]
 [ 0.  0.]
 [ 0.  0.]
 [ 0.  0.]
 [ 0.  0.]
 [ 0.  0.]
 [ 0.  0.]
 [ 0.  0.]
 [ 0.  0.]
 [ 0.  0.]]
[ 0.   0.1  0.2  0.3  0.4  0.5  0.6  0.7  0.8  0.9  1.   1.1  1.2  1.3  1.4
  1.5  1.6  1.7  1.8  1.9  2.   2.1  2.2  2.3  2.4  2.5  2.6  2.7  2.8  2.9
  3.   3.1  3.2  3.3  3.4  3.5  3.6  3.7  3.8  3.9  4.   4.1  4.2  4.3  4.4
  4.5  4.6  4.7  4.8  4.9  5.   5.1  5.2  5.3  5.4  5.5  5.6  5.7  5.8  5.9
  6.   6.1  6.2]
[ 0.          0.62831853  1.25663706  1.88495559  2.51327412  3.14159265
  3.76991118  4.39822972  5.02654825  5.65486678  6.28318531]

There are a number of methods that can be applied to ndarrays to get useful information. For instance:
  • ndim: dimension of the vector (if = 1) or array (if > 1): returns an integer;
  • shape: returns a tuple with the "shape" of a vector or array;
  • size: returns the total number of elements of the array;
  • itemsize: returns the number of bytes each element is made of (that is, the number of memory bytes for each element);
  • dtype: returns the numpy dtype of the data (int32, float64, etc.);
  • astype(type): converts the ndarray in another ndarray of the type specified, by casting the type when necessary!

Examples:

In [38]:
u2=np.zeros((4,4),dtype=np.float32)
print(u2)
print(u2.ndim)
print(u2.shape)
print(u2.size)
print(u2.itemsize)
print(u2.dtype)
print(u2.astype(np.int32))
[[ 0.  0.  0.  0.]
 [ 0.  0.  0.  0.]
 [ 0.  0.  0.  0.]
 [ 0.  0.  0.  0.]]
2
(4, 4)
16
4
float32
[[0 0 0 0]
 [0 0 0 0]
 [0 0 0 0]
 [0 0 0 0]]

There is a huge number of methods that return useful quantities, algebraic of statistical. These are just some of them:
  • min(): finds the minimum in a vector or array (even just along a single direction. See help(np.min) for help!);
  • max(): finds the maximum value;
  • mean(): computes the mean of the elements of a vector or matrix;
  • sum(): computes the sum of the elements;
  • std(): computes the standard deviation of the elements;

Examples:

In [39]:
x=np.linspace(-np.pi, np.pi, 101)
print('x=', x)
print('min. val.=', x.min())
print('max. val.=', x.max())
print('mean=', x.mean())
print('sum=', x.sum())
print('sum (mean*N)=', x.mean() * x.size)
print('standard deviation=', x.std())
x= [ -3.14159265e+00  -3.07876080e+00  -3.01592895e+00  -2.95309709e+00
  -2.89026524e+00  -2.82743339e+00  -2.76460154e+00  -2.70176968e+00
  -2.63893783e+00  -2.57610598e+00  -2.51327412e+00  -2.45044227e+00
  -2.38761042e+00  -2.32477856e+00  -2.26194671e+00  -2.19911486e+00
  -2.13628300e+00  -2.07345115e+00  -2.01061930e+00  -1.94778745e+00
  -1.88495559e+00  -1.82212374e+00  -1.75929189e+00  -1.69646003e+00
  -1.63362818e+00  -1.57079633e+00  -1.50796447e+00  -1.44513262e+00
  -1.38230077e+00  -1.31946891e+00  -1.25663706e+00  -1.19380521e+00
  -1.13097336e+00  -1.06814150e+00  -1.00530965e+00  -9.42477796e-01
  -8.79645943e-01  -8.16814090e-01  -7.53982237e-01  -6.91150384e-01
  -6.28318531e-01  -5.65486678e-01  -5.02654825e-01  -4.39822972e-01
  -3.76991118e-01  -3.14159265e-01  -2.51327412e-01  -1.88495559e-01
  -1.25663706e-01  -6.28318531e-02   4.44089210e-16   6.28318531e-02
   1.25663706e-01   1.88495559e-01   2.51327412e-01   3.14159265e-01
   3.76991118e-01   4.39822972e-01   5.02654825e-01   5.65486678e-01
   6.28318531e-01   6.91150384e-01   7.53982237e-01   8.16814090e-01
   8.79645943e-01   9.42477796e-01   1.00530965e+00   1.06814150e+00
   1.13097336e+00   1.19380521e+00   1.25663706e+00   1.31946891e+00
   1.38230077e+00   1.44513262e+00   1.50796447e+00   1.57079633e+00
   1.63362818e+00   1.69646003e+00   1.75929189e+00   1.82212374e+00
   1.88495559e+00   1.94778745e+00   2.01061930e+00   2.07345115e+00
   2.13628300e+00   2.19911486e+00   2.26194671e+00   2.32477856e+00
   2.38761042e+00   2.45044227e+00   2.51327412e+00   2.57610598e+00
   2.63893783e+00   2.70176968e+00   2.76460154e+00   2.82743339e+00
   2.89026524e+00   2.95309709e+00   3.01592895e+00   3.07876080e+00
   3.14159265e+00]
min. val.= -3.14159265359
max. val.= 3.14159265359
mean= 2.81403063667e-16
sum= 2.84217094304e-14
sum (mean*N)= 2.84217094304e-14
standard deviation= 1.83184756363

As we have already seen, the constructor array(list) produces a numpy vector (or array) initialized with the values of list. The method tolist(ndarray) does the converse, namely transform an ndarray to a python list!
Examples:

In [23]:
x=np.array([1,2,3,4,5])
print(x)
type(x)
[1 2 3 4 5]

Out[23]:
numpy.ndarray
In [25]:
xx=x.tolist()
print(xx)
type(xx)
[1, 2, 3, 4, 5]

Out[25]:
list

The true power of numpy is the hability to perform vector operations on data when using, for instance mathematical functions on numpy ndarrays. For instance:

In [27]:
# Produces a vector of equally spaced 101 float values between 0 and 2pi
x=np.linspace(0.0, 2.0*np.pi, 11)
print("x=", x)
x= [ 0.          0.62831853  1.25663706  1.88495559  2.51327412  3.14159265
  3.76991118  4.39822972  5.02654825  5.65486678  6.28318531]

In [28]:
# Defines y=sin(x) by taking x as a vector
y=np.sin(x)
print("y=",y)
y= [  0.00000000e+00   5.87785252e-01   9.51056516e-01   9.51056516e-01
   5.87785252e-01   1.22464680e-16  -5.87785252e-01  -9.51056516e-01
  -9.51056516e-01  -5.87785252e-01  -2.44929360e-16]

Both numpy vectors and arrays (that is, ndarray objects) can be "sliced" like ordinary python lists, and then we can apply the numerical operators to "slices" too:

In [38]:
# Produces a 10x10 array with elements between 0 and 1
x=np.arange(0.0,1.0,0.1)
y=np.arange(0.0,1.0,0.1)
xx=np.zeros((10,10))
for i in range(10):
    for j in range(10):
        xx[i,j] = x[i] * y[j]
print("xx=", xx)
# Computes and prints 10 times the square root of x * y
yy=10*np.sqrt(xx)
print("yy=",yy)
xx= [[ 0.    0.    0.    0.    0.    0.    0.    0.    0.    0.  ]
 [ 0.    0.01  0.02  0.03  0.04  0.05  0.06  0.07  0.08  0.09]
 [ 0.    0.02  0.04  0.06  0.08  0.1   0.12  0.14  0.16  0.18]
 [ 0.    0.03  0.06  0.09  0.12  0.15  0.18  0.21  0.24  0.27]
 [ 0.    0.04  0.08  0.12  0.16  0.2   0.24  0.28  0.32  0.36]
 [ 0.    0.05  0.1   0.15  0.2   0.25  0.3   0.35  0.4   0.45]
 [ 0.    0.06  0.12  0.18  0.24  0.3   0.36  0.42  0.48  0.54]
 [ 0.    0.07  0.14  0.21  0.28  0.35  0.42  0.49  0.56  0.63]
 [ 0.    0.08  0.16  0.24  0.32  0.4   0.48  0.56  0.64  0.72]
 [ 0.    0.09  0.18  0.27  0.36  0.45  0.54  0.63  0.72  0.81]]
yy= [[ 0.          0.          0.          0.          0.          0.          0.
   0.          0.          0.        ]
 [ 0.          1.          1.41421356  1.73205081  2.          2.23606798
   2.44948974  2.64575131  2.82842712  3.        ]
 [ 0.          1.41421356  2.          2.44948974  2.82842712  3.16227766
   3.46410162  3.74165739  4.          4.24264069]
 [ 0.          1.73205081  2.44948974  3.          3.46410162  3.87298335
   4.24264069  4.58257569  4.89897949  5.19615242]
 [ 0.          2.          2.82842712  3.46410162  4.          4.47213595
   4.89897949  5.29150262  5.65685425  6.        ]
 [ 0.          2.23606798  3.16227766  3.87298335  4.47213595  5.
   5.47722558  5.91607978  6.32455532  6.70820393]
 [ 0.          2.44948974  3.46410162  4.24264069  4.89897949  5.47722558
   6.          6.4807407   6.92820323  7.34846923]
 [ 0.          2.64575131  3.74165739  4.58257569  5.29150262  5.91607978
   6.4807407   7.          7.48331477  7.93725393]
 [ 0.          2.82842712  4.          4.89897949  5.65685425  6.32455532
   6.92820323  7.48331477  8.          8.48528137]
 [ 0.          3.          4.24264069  5.19615242  6.          6.70820393
   7.34846923  7.93725393  8.48528137  9.        ]]

Input and output of ndarrays

In the normal use of python, we will have to plot data from files. We have already seen the standard way in which python can read/write data on files, which allows great flexibility.
However, numpy includes a set of simple functions to read/write numerical data to/from files, that can be easier to use with respect to normal python files:
  • tofile(str_file_name, dtype=type, sep=sep_str): writes a series of data stored in a given ndarray to a file named str_file_name, of the specified type, by using the string sep_str as data separator;
  • fromfile(str_file_name,dtype=type,count=num,sep=sep_str): reads a set of num data (num=-1 means all data in the file!) from the file str_file_name into a ndarray of the specified type type, separated by sep_str;
  • savetxt(str_file_name, ... ): saves the given numpy ndarray into the file str_file_name;
  • loadtxt(str_file_name, ... ): returns a numpy ndarray filled with the data read from file str_file_name;
Notes:
  • if sep_str='' in tofile() and fromfile(), the data are written as binary data (which produces much smaller files, however information about endianness, data type and actual structure of data is totally lost, so you have to know how the file was written!);
  • savetxt and loadtxt are much better than the other two, which should be avoided, except in very special cases.

Example:

In [45]:
# Creates a nx2 array (2 vectors!)
xx=np.ndarray((11,2),dtype=float)
# First column: 10 equally spaced values between 0 and 2*pi
xx[:,0]=np.linspace(0.0,2.0*np.pi,11)
# Second column: sin(x)!
xx[:,1]=np.sin(xx[:,0])
print("xx = ", xx)
xx.tofile("data.dat", sep='\t')
yy=np.fromfile("data.dat", sep='\t')
print("yy = ", yy)   # Note as yy is now a SINGLE vector instead of an array! NOT GOOD!
xx =  [[  0.00000000e+00   0.00000000e+00]
 [  6.28318531e-01   5.87785252e-01]
 [  1.25663706e+00   9.51056516e-01]
 [  1.88495559e+00   9.51056516e-01]
 [  2.51327412e+00   5.87785252e-01]
 [  3.14159265e+00   1.22464680e-16]
 [  3.76991118e+00  -5.87785252e-01]
 [  4.39822972e+00  -9.51056516e-01]
 [  5.02654825e+00  -9.51056516e-01]
 [  5.65486678e+00  -5.87785252e-01]
 [  6.28318531e+00  -2.44929360e-16]]
yy =  [  0.00000000e+00   0.00000000e+00   6.28318531e-01   5.87785252e-01
   1.25663706e+00   9.51056516e-01   1.88495559e+00   9.51056516e-01
   2.51327412e+00   5.87785252e-01   3.14159265e+00   1.22464680e-16
   3.76991118e+00  -5.87785252e-01   4.39822972e+00  -9.51056516e-01
   5.02654825e+00  -9.51056516e-01   5.65486678e+00  -5.87785252e-01
   6.28318531e+00  -2.44929360e-16]

In [46]:
# The same values are written and read by using savetxt() and loadtxt(), instead!
print("xx = ", xx)
np.savetxt("new_data.dat", xx)
yy=np.loadtxt("new_data.dat")
print("yy = ", yy)              # Much better!
xx =  [[  0.00000000e+00   0.00000000e+00]
 [  6.28318531e-01   5.87785252e-01]
 [  1.25663706e+00   9.51056516e-01]
 [  1.88495559e+00   9.51056516e-01]
 [  2.51327412e+00   5.87785252e-01]
 [  3.14159265e+00   1.22464680e-16]
 [  3.76991118e+00  -5.87785252e-01]
 [  4.39822972e+00  -9.51056516e-01]
 [  5.02654825e+00  -9.51056516e-01]
 [  5.65486678e+00  -5.87785252e-01]
 [  6.28318531e+00  -2.44929360e-16]]
yy =  [[  0.00000000e+00   0.00000000e+00]
 [  6.28318531e-01   5.87785252e-01]
 [  1.25663706e+00   9.51056516e-01]
 [  1.88495559e+00   9.51056516e-01]
 [  2.51327412e+00   5.87785252e-01]
 [  3.14159265e+00   1.22464680e-16]
 [  3.76991118e+00  -5.87785252e-01]
 [  4.39822972e+00  -9.51056516e-01]
 [  5.02654825e+00  -9.51056516e-01]
 [  5.65486678e+00  -5.87785252e-01]
 [  6.28318531e+00  -2.44929360e-16]]

It is possible to add several optional parameters to specify the format of data, to add comments (to give an idea about the file contents) at the beginning or at the end of the data, to chose the separator for columns and lines, the character that starts the comments (default='# ') and so on...
Here is a list of possible parameters:
  • fmt='...': format string for the data;
  • delimiter='...': string or character separating columns;
  • newline='...': string or character separating lines;
  • header='...': string written at the beginning of the file;
  • footer='...': string to be written at the end of the file;
  • comments='...': string to be prepended to the "header" or "footer" strings (defaults to '# ').

The following optional parameters apply to loadtxt only:
  • skiprows=n: skips the first n rows in the file;
  • usecols=(n1,...,nn): reads only the columns (numbered starting from zero!) whose number is contained in the tuple (n1,...,nn);
  • unpack=True|False: if True, the returned array is transposed, such that a syntax like the following is allowed:
    x,y=np.loadtxt("file_name",unpack=True)
    which allows to read two (or more) columns of data directly in different vectors, for instance! Default is False (why???!!!)

Example:

In [47]:
np.savetxt("other_data.dat", xx, header="Written columns: x=[0,2pi] and sin(x)", footer="Here ends the file...")
yy=np.loadtxt("other_data.dat")
print("yy: ", yy)
yy:  [[  0.00000000e+00   0.00000000e+00]
 [  6.28318531e-01   5.87785252e-01]
 [  1.25663706e+00   9.51056516e-01]
 [  1.88495559e+00   9.51056516e-01]
 [  2.51327412e+00   5.87785252e-01]
 [  3.14159265e+00   1.22464680e-16]
 [  3.76991118e+00  -5.87785252e-01]
 [  4.39822972e+00  -9.51056516e-01]
 [  5.02654825e+00  -9.51056516e-01]
 [  5.65486678e+00  -5.87785252e-01]
 [  6.28318531e+00  -2.44929360e-16]]

In [48]:
# Alternative way to read data into two vectors with "unpack=True"
x, y = np.loadtxt("other_data.dat", unpack=True)
print("x=", x)
print("y=", y)
x= [ 0.          0.62831853  1.25663706  1.88495559  2.51327412  3.14159265
  3.76991118  4.39822972  5.02654825  5.65486678  6.28318531]
y= [  0.00000000e+00   5.87785252e-01   9.51056516e-01   9.51056516e-01
   5.87785252e-01   1.22464680e-16  -5.87785252e-01  -9.51056516e-01
  -9.51056516e-01  -5.87785252e-01  -2.44929360e-16]

Matplotlib

Plotting with matplotlib

The matplotlib library allows to show 2D (and 3D) plots in several ways. The functions to plot are numpy ndarrays, but also ordinary lists can serve as parameters, although they are transformed in ndarrays before they are plotted!
The basic functions to show 2D plots are:
plot()
and
show()

Example:

In [40]:
import matplotlib.pyplot as plt
import numpy as np

plt.plot([0.0, 1.0, 4.0, 9.0, 16.0, 25.0])
plt.show()

A single list or ndarray is interpreted as the vector describing the ordinates of the function to plot (\(y\) data), BUT if we pass two lists (or ndarrays) the first one is interpreted as the vector of abscissae (\(x\) data). Finally, a third parameter, if present, is interpreted a a descriptor for the color, stile, etc. of the line.
Example: plots data from two lists with a solid line and red dots...

In [41]:
plt.plot([0.0, 1.0, 2.0, 3.0, 4.0, 5.0],[0.0, 1.0, 4.0, 9.0, 16.0, 25.0],'or-')
plt.show()

Of course, it is better to define three ndarrays, one for the abscissae and the other two for the ordinates of the plot. In the following example we overlap the two functions, one with blue dots (\(\sin(x)\)), another one with green triangles (\(\cos(x)\)):

In [42]:
x=np.linspace(0.0,2.0*np.pi,101)
y=np.sin(x)
z=np.cos(x)
plt.plot(x,y,'o-')
plt.plot(x,z,'^-')
plt.show()

Of course, one can use just a single command for the two functions (note: we do not use symbols here, but we explicitly set the color before the symbol of line!):

In [43]:
plt.plot(x,y,'g-',x,z,'b-')
plt.show()
The third string defines the color, a marker and the line-style in a single string.
It is possible to define colors with the following letters:
  • b: blue
  • g: green
  • r: red
  • c: cyan
  • m: magenta
  • y: yellow
  • k: black
  • w: white

However, one can also use just the name of the color (ex.: green), an RGB hexadecimal sequence (ex: #FF0000 is the red!), an RGB tuple, or a greyscale through a string containing a number between 0.0 and 1.0, as well.
Example: (sinus in green, cosinus in red)...

In [44]:
plt.plot(x,y,'g',x,z,'#A0A0A0')
plt.show()

... or sinus in yellow, cosinus in grey:

In [45]:
plt.plot(x,y,'yellow',x,z,'0.5')
plt.show()
The second and third parameter in the string, if present, represents the marker and the line-style.
The corresponding symbols are:
  • -: solid line style
  • --: dashed line style
  • -.: dashed-dotted line style
  • :: dotted line style
  • .: point marker
  • ,: pixel marker
  • o: circle marker
  • v: triangle down marker
  • ^: triangle up marker
  • <b><: triangle left marker
  • >: triangle right marker
  • s: square marker
  • p: pentagon marker
  • *: star marker
  • h: hexagon marker
  • +: plus marker
  • x: x marker
  • D: diamond marker
  • |: vertical line marker
  • _: horizonthal line marker

Examples:

In [46]:
plt.plot(x,y,'g-',x,z,'b--')
plt.show()

Collecting all the plots together is of course simple, however, by separating them, one can have higher flexibility in fine-tuning the style of the plot, by using suitable keywords to indicate additional features of the plot.
Example:

In [47]:
plt.plot(x,y,color='c',marker='x',linestyle=':')
plt.plot(x,z,color='#0000FF',marker='+',linestyle='--')
plt.show()
Here are some (but there are many other, consult the manual for more information) optional parameters that is possible to pass to the plot function:
  • alpha: tranparency of the line (float: 0.0 = transparent, 1.0 = opaque)
  • color (or "c"): color of the line
  • linestyle (or "ls"): style of the line
  • linewidth (or "lw"): width of the line (float)
  • marker: marker type
  • markersize (or "ms"): size of the marker (float)
  • markevery: puts a marker each "markevery" points

Example:

In [48]:
plt.plot(x,y,linestyle='-',linewidth=2.0,color='b',marker="x")
plt.plot(x,z,ls='-',lw=1.0,marker='x',markersize=10.0,color='y',markevery=(10))
plt.show()

Another way to specify the characteristics of a line is to get an object "line" from the function plot and to modify its properties through the function setp().

In [49]:
myline = plt.plot(x,y)
plt.setp(myline,linestyle="-.",color="green")
plt.show()
It is possible to add a legend to the plot with the function:
legend( list_of_labels, pos=position, fontsize=font_size, ...)
where:
  • list_of_labels: is a list (or tuple) of strings containing the labels for the lines;
  • position: (optional) can be either a string or an integer or a tuple, defining the position inside the plot where to put the legend. Allowed values are:
    Location string Integer value
    'best' 0
    'upper right' 1
    'upper left' 2
    'lower left' 3
    'lower right' 4
    'right' 5
    'center left' 6
    'center right' 7
    'lower center' 8
    'upper center' 9
    'center' 10
Otherwise, it is possible to use a tuple (x,y) to indicate the legend position with respect to the lower-left corner of the legend in axes-coordinates.
  • font_size: (optional) can be either an int or a string: 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'. If the value is numeric, it is the absolute font size in points, if it is a string, it will be relative to the current font size;
  • ... and many more...
  • Example:

    In [53]:
    plt.plot(x,y,linestyle='-',linewidth=2.0,color='b',marker="x")
    plt.plot(x,z,ls='-',lw=1.0,marker='x',markersize=10.0,color='y',markevery=(10))
    plt.legend([r"sin(x)", r"cos(x)"], loc=3)
    plt.show()
    

    It is possible to improve the quality of the plot by adding a title, labels on the axes, a grid, text in arbitrary positions, etc.

    In [54]:
    def damped_exponential(x):
        y=np.exp(-0.5*x)*np.cos(2.0*x)
        return y
    
    pi=np.pi
    x=np.linspace(0.0,2.0*np.pi,101)
    y=damped_exponential(x)
    plt.plot(x,y,'ko-')
    plt.title("A damped exponential")
    plt.xlabel("x")
    plt.ylabel("y")
    plt.grid(True)
    plt.text(pi,np.exp(-0.5*pi),"Max 1")
    plt.text(0.5*pi,-np.exp(-0.25*pi),"Min 1")
    plt.axis([0.0,2.0*pi,-1.2,1.2])             # Notice that min and max of the axes are specified through a list!
    plt.show()
    
    Text properties can be modified through optional parameters.
    Here is a (incomplete!) list of them:
    • fontsize: size of the font (in pixels)
    • horizonthalalignment: horizonthal alignment of text (left|center|right)
    • verticalalignment: vertical alignment of text (top|center|bottom)

    Note:
    One of very useful characteristics of matplotlib is the possibility to use the \(\TeX\) or \(\LaTeX\) rendering of strings, by putting an "r" (standing for "raw") in front of the string, to indicate to python to NOT interpret the \(\TeX\) or \(\LaTeX\) symbols as escape sequences!
    The previous example, a little bit nicer:

    In [55]:
    plt.plot(x,y,'ko-')
    plt.title(r"A damped exponential: $e^{-\frac{x}{2}}\cos(2x)$")
    plt.xlabel(r"$x$")
    plt.ylabel(r"$y$")
    plt.grid(True)
    plt.text(pi,1.4*np.exp(-0.5*pi),"Max 1",horizontalalignment="center",fontsize=18)
    plt.text(0.5*pi,-1.1*np.exp(-0.25*pi),"Min 1",horizontalalignment="right",verticalalignment="top")
    plt.xlim(0.0,2.0*pi)             # Note as here we us xlim() and ylim() to set the min and max of axes, instead of axis()!
    plt.ylim(-0.7,1.2)
    plt.show()
    

    It is possible to annotate the plot with a text and an arrow through the function "annotate()":

    In [57]:
    plt.plot(x,y,'ko-')
    plt.title(r"A damped exponential: $e^{-\frac{x}{2}}\cos(2x)$")
    plt.xlabel(r"$x$")
    plt.ylabel(r"$y$")
    plt.grid(False)                  # Note that we removed the grid here!
    xpos=pi
    ypos=np.exp(-0.5*pi)
    # Note the arrow parameters: shrink move away a little bit the tip and the base of the arrow from the point!
    plt.annotate("Max 1", xy=(xpos,ypos), xytext=(xpos+1.0,ypos+0.5), arrowprops={"facecolor":"blue","shrink":0.05})
    plt.xlim(0.0,2.0*pi)
    plt.ylim(-0.7,1.2)
    plt.show()
    
    One can produce several plot on the same figureby putting them on an imaginary grid (but also in an arbitrary way!) through the command:
    subplot(num_rows,num_cols,position)
    

    Example:

    In [58]:
    plt.subplot(211)
    plt.plot(x,y,'ko-')
    plt.title("A damped exponential")
    plt.xlabel(r"$x$")
    plt.ylabel(r"$y$")
    plt.subplot(212)
    plt.plot(x,np.abs(y),'ko-')
    plt.title("Absolute value of a damped exponential")
    plt.xlabel(r"$x$")
    plt.ylabel(r"$|y|$")
    plt.show()
    
    One can use logarithmic (or linear) scales for the \(x\) and \(y\) axes:
    xscale("log|linear")
    yscale("log|linear")
    

    Example:

    In [59]:
    plt.subplot(211)
    plt.plot(x,y,'ko-')
    plt.title(r"A damped exponential in linear $y$ scale")
    plt.xlabel(r"$x$")
    plt.ylabel(r"$y$")
    plt.subplot(212)
    plt.yscale("log")
    plt.plot(x,np.abs(y),'ko-')
    plt.title(r"Absolute value of a damped exponential in $y$-log scale")
    plt.xlabel(r"$x$")
    plt.ylabel(r"$\log(|y|)$")
    plt.show()
    
    In [60]:
    def power_law(x,n):
        y=np.power(x,n)
        return y
    
    x=np.linspace(1.0,101.0,101)
    y=power_law(x,-5.0/3.0)
    plt.subplot(211)
    plt.plot(x,y,'ko-')
    plt.title(r"A power-law in linear $x-y$ scales")
    plt.xlabel(r"$x$")
    plt.ylabel(r"$y$")
    plt.subplot(212)
    plt.xscale("log")
    plt.yscale("log")
    plt.plot(x,y,'ko-')
    plt.title(r"A power-law in log $x-y$ scale")
    plt.xlabel(r"$\log(x)$")
    plt.ylabel(r"$\log(y)$")
    plt.show()
    

    It is possible to produce polar plots, pie plots, histograms, etc., through several functions.
    Example: polar coordinates...

    In [61]:
    r = np.linspace(0.0,5.0,101)
    theta = 2.0 * np.pi * r
    plt.polar(r, theta)
    plt.show()
    

    ... pie plot...

    In [62]:
    dims=[10.0,30.0,40.0,10.0]
    mylabels=["data1","data2","data3","data4"]
    mycolors=['b','r','y','magenta']
    plt.pie(dims,labels=mylabels,colors=mycolors)
    plt.show()
    

    ... and, finally, contour plots.
    Example:

    In [63]:
    x=np.zeros((101,51),dtype=float)
    y=np.zeros((101,51),dtype=float)
    xx=np.linspace(-2.0,2.0,101)
    yy=np.linspace(-2.0,2.0,51)
    for j in range(51):
        x[:,j]=xx
    for i in range(101):
        y[i,:]=yy
    z=np.exp(-(x*x + y*y))
    plt.contour(x,y,z)
    plt.show()