Sunteți pe pagina 1din 62

Python/NCL: free alternatives for Earth Scientists

Nicolas Barrier
April 29, 2013

Contents
1 Introduction

2 Programming
2.1 Array manipulation . . . . . . . . .
2.1.1 Creation . . . . . . . . . . . .
2.1.2 Find values . . . . . . . . . .
2.1.3 Element masking . . . . . . .
2.1.4 Elements extraction . . . . .
2.1.5 Evenly spaced arrays . . . . .
2.1.6 Changing the shapes . . . . .
2.1.7 Dimension reordering . . . .
2.1.8 Array conforming . . . . . . .
2.2 Loops . . . . . . . . . . . . . . . . .
2.2.1 Do loops . . . . . . . . . . . .
2.2.2 While loops . . . . . . . . . .
2.3 If statements . . . . . . . . . . . . .
2.4 Date processing . . . . . . . . . . . .
2.5 Mathematics . . . . . . . . . . . . .
2.5.1 Simple arithmetic operations
2.5.2 Correlations . . . . . . . . . .
2.5.3 EOF analysis . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

4
4
4
5
5
6
7
8
8
9
9
9
10
11
11
13
13
14
15

3 Input/Output (IO)
3.1 NetCDF . . . . . . . . . . .
3.1.1 What is a NetCDF?
3.1.2 Reading a NetCDF .
3.1.3 Writting a NetCDF
3.1.4 Multiple file opening
3.2 Text files . . . . . . . . . .

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

17
17
17
17
18
20
20

.
.
.
.
.
.
.
.

24
24
24
25
26
27
29
30
31

4 Plots
4.1 XY Plots . . . . . . . . . .
4.1.1 First plot . . . . . .
4.1.2 Multiline plots . . .
4.1.3 Filled XY plots . . .
4.1.4 Twin xaxis . . . . .
4.1.5 Grid/labels handling
4.1.6 Labels positioning .
4.1.7 Time ticking . . . .

.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

4.2

4.3

4.4

4.5

4.6

4.7

Contours . . . . . . . . . . . . . . .
4.2.1 First contour plot . . . . . .
4.2.2 Levels handling . . . . . . . .
4.2.3 Filled contour plot . . . . . .
4.2.4 Gray filled values . . . . . . .
4.2.5 Homemade colormaps . . . .
Vectors . . . . . . . . . . . . . . . .
4.3.1 First quiver plot . . . . . . .
4.3.2 Quiver length handling . . .
4.3.3 Distance between the quivers
4.3.4 NCL curly vectors . . . . . .
Panels . . . . . . . . . . . . . . . . .
4.4.1 First panel plot . . . . . . . .
4.4.2 Space control . . . . . . . . .
4.4.3 Hand positionning . . . . . .
4.4.4 Shared colormap . . . . . . .
4.4.5 Two colormaps . . . . . . . .
Maps . . . . . . . . . . . . . . . . . .
4.5.1 First map . . . . . . . . . . .
4.5.2 Grid handling . . . . . . . . .
4.5.3 Shifting longitudes . . . . . .
4.5.4 Plot Overlays . . . . . . . . .
4.5.5 Orthographic projection . . .
Text . . . . . . . . . . . . . . . . . .
4.6.1 Plot coordinates . . . . . . .
4.6.2 Figure coordinates . . . . . .
4.6.3 Text on a map . . . . . . . .
4.6.4 Equations . . . . . . . . . . .
Polylines . . . . . . . . . . . . . . . .
4.7.1 Polylines on a map . . . . . .
4.7.2 Filled polygon on a map . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

33
33
34
35
36
38
40
40
40
42
42
42
42
45
46
47
48
49
49
50
51
52
54
55
55
56
57
57
58
58
60

Chapter 1

Introduction
The job of an Earth-Scientist mainly consists in processing observations, model outputs and
many other types of data. The verb process here has plenty of meanings. It can be the
computation of statistics, the computation of other parameters from the datas or, more simply,
to represent the data in a simple and accessible way.
There exists a lot of programmation langage that allows this processing and that are well used
in the Earth-Science community. The most commonly used is Matlab (MAtrix LABoratory),
which is a proprietary numerical computing environment that can be used in a multitude of
domain (engineering, science and economics). Free clones of Matlab exist, the two commons
being Scilab and Octave.
Python is an open-source programming language which can be used in many fields, basically
the same as matlab. Moreover, it is fully compatible with Matlab outputs (.mat files). Its free
characteristic can make it very popular for students who cannot afford a Matlab license.
The last processing tool I will discuss is NCL (NCAR Command Language). Contrary
to Matlab or Python, NCL has been principally developped for scientific data analysis and
visualization in the Earth-Science fields. It is very usefull to process NetCDF files, which is a
common file format in Earth-Science and is free.
The aim of this book is to put into perspective those three langages, to describe their pros and
con. Main features of each language will be described, and classical operations in Earth-Science
(especially statistics) will be described.
Finally, an extended gallery will be proposed, following that of Python or NCL, so that the
most classical figures will be accessible whatever your choice between the three languages.

Chapter 2

Programming
2.1

Array manipulation

The basis in programming, and especially in Earth Science, is the array manipulation. While it
is pretty straigthforward in NCL, it can be more complicated in Python, as you can manipulate
either list or numpy array. We will review, in this section, all what must be known about
array manipulation

2.1.1

Creation

Python:
In Python, if you want to create an array of known values, you can do:
1

array =[0 ,1 ,2 ,3 ,4 ,5]

If you do a print(type(array)), you will get <typelist >. This is not the easiest type to
manipulate. It is strongly advised to convert them into numpy arrays as follows:
1
2

im por t numpy a s np
n p a r r a y=np . a r r a y ( a r r a y )

The numpy package allows many ways to initialize arrays. You can either initialize them
with random numbers, zeros or ones everywhere. This is done by doing:
1
2
3

a r r a y 1=np . empty ( ( 4 , 6 , 8 ) , np . i n t )
a r r a y 2=np . z e r o s ( ( 4 , 6 , 8 ) , np . f l o a t )
a r r a y 3=np . o n e s ( ( 4 , 6 , 8 ) , np . d o u b l e )

The first argument is the size of the array. It is set as a tuple. The second argument is
the format of the array. You must remember that as we create numpy array, we must call the
types available in the numpy package (numpy.int, numpy.float, etc).
NCL:
In NCL, if you want to create an array of known values, you can do:

array =(/0 ,1 ,2 ,3 ,4 ,5/)

Moreover, if you want to initialiaze a multidimensional array, you must use the new command
as follows:
1
2
3

a r r a y 1=new ( ( / 4 , 6 , 8 / ) , i n t e g e r )
a r r a y 2=new ( ( / 4 , 6 , 8 / ) , f l o a t )
a r r a y 3=new ( ( / 4 , 6 , 8 / ) , d o u b l e )

Contrary to Python, there is no function to initialize the array with zeros or ones.

2.1.2

Find values

In this section, we will learn how to find indices and values of nonzero elements. Imagine we
have an array A in which we have zeros values. We want to find the indexes of those values.
Python:
In Python, this is done by using the nonzero function.
1

i=numpy . n o n z e r o (A==0)

i is a tuple of dimensions the number of dimensions of A. If A is mono-dimensional, you can


print the zero values as follows:
1

p r i n t (A[ i [ 0 ] ] )

If A is multidimensional (for example three dimensions), it is done as follows:


1

p r i n t (A[ i [ 0 ] , i [ 1 ] , i [ 2 ] ] )

NCL:
In NCL, it is done using the ind function:
1
2

i=i n d (A. eq . 0 )
p r i n t (A( i n d ) )

Contrary to Python nonzero, NCL ind function does not handle multidimensional arrays.

2.1.3

Element masking

It is often usefull to mask an array when some conditions are verified. Imagine that we have a
map M with 0 at land points that we want to mask.
Python:
In Python, this is done with the masked_where function of the numpy.ma module.

1
2

im por t numpy . ma a s ma
M_masked_where (M==0,M)

NCL:
In NCL, the command to use is the mask function.
1

M_mask=mask (M,M. eq . 0 , F a l s e )

The last argument is a boolean that, when set to False, indicates that the values to mask
are those that verify the condition.

2.1.4

Elements extraction

In this section, we look at the way to extract data from an array. Imagine that we have an array
with elements from one to ten. In NCL and Python (contrary to Matlab), the index starts at 0;
Elements
Index

1
0

2
1

3
2

4
3

5
4

6
5

7
6

8
7

9
8

10
9

Python:
In Python, to extract data from an array, you must do as follows:
1

e x t r a c t=a r r a y [ 3 : 7 ] )

You would notice that when printing this new array, you will obtain in Python [4567], while
the element of index 7 is 8. This points toward a very important difference between Python
and NCL (and also Matlab): such an extraction stops one element before the end of the stride.
Here, the last element extracted has the index 6.
Another way to extract the elements of an array is to create an array with integers corresponding to the index to extract:
1
2

i n d e x=np . a r r a y ( [ 3 , 4 , 5 , 6 , 7 ] )
e x t r a c t=a r r a y [ i n d e x ]

To extract data with a certain stride (ie. one data out of three for example):
1

e x t r a c t=a r r a y [ : : s t r i d e ]

NCL:
In NCL, it is almost the same thing than in Python except that we must use parenthesis
instead of brackets
1

e x t r a c t=a r r a y ( 3 : 7 )

It should be noted that extract contains [45678], ie. the last element selected has the end
index indicated. You can also use an array of index, similarly than Python:
1
2

index =(/3 ,4 ,5 ,6 ,7/)


e x t r a c t=a r r a y ( i n d e x )

A very interesting feature with NCL is that instead of using indexes, we can directly use
litteral values. This is possible if the data coordinates are set. Imagine for example that we a
map M of dimensions (nlat,nlon) of coordinates (longitudes,latitudes). To extract the data in
the domain 10 S 70 N and 10 W 80 E, you can directly use:
1

e x t r a c t=M( { 1 0 : 7 0 } , { 1 0 : 8 0 } )

instead of looking for the indexes corresponding to the domain.


The extraction of data with a certain stride is done in the same way than with Python:
1

e x t r a c t=a r r a y ( : : s t r i d e )

2.1.5

Evenly spaced arrays

In this section, we will explain how to create evenly spaced arrays, which can be usefull for
example to defined contours intervals for contour plots.
Python:
In Python, the creation of evenly spaced arrays is simple. You must use the numpy function
arange.
1
2

a r r a y _ i n t=np . a r a n g e ( 0 , 1 0 , 1 )
a r r a y _ f l o a t=np . a r a n g e ( 0 , 1 0 , 0 . 1 )

Again here, Python stops one elements before the effective end of the array: the array_int
vector will stop at 9, while the array_float one will stop at 0.9.
NCL:
In NCL, the way to create evenly spaced arrays is different wether we generate integer or
floats.
For integer arrays, we must use the ispan function:
1

a r r a y _ i n t=i s p a n ( 0 , 1 0 , 1 )

The ispan function takes as integer the start, end and stride of the array. In this case, the last
element of array_int will be 10, contrary to Python.For float arrays, it is the fspan function
that must be used:
1

a r r a y _ f l o a t=f s p a n ( 0 , 1 0 , 1 0 1 )

The fspan also takes as arguments the start and end elements of the array. But the last
option is not the stride anymore but an integer that is the number of points of the array.
7

2.1.6

Changing the shapes

Python:
To change the shape of an array in Python, you have at least two options. If you have a
N M T array A that you want to set as a one-dimensional array, you must use the numpy
function ravel :
1

oned=np . r a v e l (A)

If you want to change the shape of A from 3D to 2D, you can use the reshape function:
1

twod=np . r e s h a p e (A, ( NM, T) )

The reshape arguments are the matrix to reshape and the dimensions of the new array.
NCL:
To change the shape of an array in NCL, you also have two functions. To moves from a 3D
array to a 2D array, you must use ndtooned :
1

oned=ndtooned (A)

In NCL contrarary to Python, there are no function to reshape A from 3D to 2D, you
must combine the ndtoonedand onedtond functions, the latter being the function that allows
to reshape from one-dimensional to multidimensional arrays:
1
2

oned=ndtooned (A)
twod=onedtond ( oned , ( /MN, T/ ) )

The onedtond arguments are the matrix to reshape and the dimensions of the array.

2.1.7

Dimension reordering

Imagine you have an array A of dimensions (time,lat,lon). It might be usefull to be able to


change the dimensions order to create an array of dimensions (lat,lon,time).
Python:
In Python, it is the numpy transpose function that allows this:
1

r e o r d e r e d=np . t r a n s p o s e (A, [ 1 , 2 , 0 ] )

The transpose function takes as an imput the array of which the dimensions are reordered,
and the array that indicates how to permute the dimensions. Here, the second dimension becomes the first one, the third dimension becomes the second one and the first one becomes the
last one.
NCL:
In NCL, there is no reordering function. Reordering is done as follows:
8

r e o r d e r e d=A( l a t | : , l o n | : , time | : )

The reordering is done via the dimensions of the arrays. You thus must have arrays in which
dimensions are set. To do this, you must follow the procedure described in section 3.1.3.

2.1.8

Array conforming

Oftenly, you must conform the shape of one array to the shape of another array. Imagine we
have a series of maps A of dimensions (lat,lon,time) and a mask M of dimensions (lat,lon). You
want to create a new mask of same dimensions than A.
Python:
In Python, you must use the command tile as follows:
1
2

MC=np . t i l e (M, ( ntime , 1 , 1 ) )


MC=np . t r a n s p o s e (MC, [ 1 , 2 , 0 ] )

The first line defines a new array in which the mask is repeated ntime times. Thus the array
has a size of (ntime,nlat,nlon). The second line allows to reorder the dimensions. The Python
tile function only allows to repeat an array along the first dimesions. Had we done:
1

MC=np . t i l e (M, ( 1 , 1 , ntime ) )

the array would have a dimension of (1,nlat, ntime*nlon).


NCL:
In NCL, it is the conform function that allows such a manipulation:
1

MC=conform (A,M, ( / 0 , 1 / ) )

The conform function takes as argument the reference array (A), the array to conform (M),
and an integer array corresponding to the dimensions of A that are shared with M. Here, M and
A have the same latitudes (index 0) and the same longitudes (index 1).

2.2

Loops

2.2.1

Do loops

Python:
In Python, there are several ways to perform do loops. Let F be a numpy array of n elements.
If you want to display all the elements of F , you can do:
1
2

f o r index in range (0 , n) :
p r i n t (F [ i n d e x ] )

In this case, we go over all the indexes of F (index will have values of 0, 1, ..., n 1) and
F[index] retrives the element in F of index index. The loop starts with a for. The line, where
the loop is started, must be finished by a :. You also must notice the indent before the print.
This is a peculiarity of Python. The start of do loop is indicated by a right indent, while the
end of the loop is indicated by a left indent. Often, when a code that contains imbricated loops
does not raise an error but does not return what was expected, the error is to be searched into
a bad indent at some point. Another peculiarity of Python is that when going over a loop, the
index will stop one element before the end indicated. Here, we told the loop to stop at n but it
will implicitly stops at n-1. This peculiarity was also pointed out in the description of arrays.
Finally, Python allows another way to go over the elements of a list. One can directly go
over them by doing:
1
2

f o r element in F :
p r i n t ( element )

NCL:
In NCL, do loops are performed as follows:
1
2
3

do i n d e x =0 ,n1
p r i n t (F( i n d e x ) )
end do

The loop starts with a do and stops with a end do. Moreover, the index effectively stops at
the end index indicated in the loop. We thus need to stop the loop one element before the end
of the array.

2.2.2

While loops

While loops are done similarly than do loops.


Python:
1
2
3
4

i n d e x=0
w h i l e ( index<=n1) :
p r i n t (F [ i n d e x ] )
i n d e x=i n d e x+1

NCL:
1
2
3
4
5

i n d e x=0
do w h i l e ( i n d e x . l e . n1)
p r i n t (F( i n d e x ) )
i n d e x=i n d e x+1
end do

10

2.3

If statements

Python:
If statements in Python are done as follows:
1
2
3
4

i f ( c o n d i t i o n ==0) :
print ( 0 )
else :
print ( Else )

They start by a if and end by : . Again, all the lines within the if statement must be
indented. Moreover, you have the elif statement which allows multiple condition checking.
1
2
3
4
5
6

i f ( c o n d i t i o n ==0) :
print ( 0 )
e l i f ( c o n d i t i o n ==1) :
print ( 1 )
else :
print ( Else )

NCL:
In NCL, the simplest if statement is done similarly than with Python.
1
2
3
4
5

i f ( c o n d i t i o n . eq . 0 )
print ( "0" )
else
print ( " Else " )
end i f

However, NCL does not have official elif statement. However, it is possible to combine
else and if statements as follows:
1
2
3
4
5
6
7
8

i f ( c o n d i t i o n . eq . 0 )
print ( "0" )
else if
( c o n d i t i o n . eq . 1 )
print ( "1" )
else
print ( " Else " )
end i f
end i f

Note however the need to add a end if any times we open a line with a if, which is likely
to make the code unreadable.

2.4

Date processing

In NetCDF files, the time variable is often given as an integer, in which the units of the files as
well as the calendar are indicated. In this section, we discuss how to transform them into usable
arrays. Imagine that we have an array of integers that we call T, which gives us the number of
days since days since the 1st of January, 1950.

11

Python:
To convert T into a date instance, you first must import the utime function from the
netcdftime package.
1

from n e t c d f t i m e i mp ort utime

Then you must call this function as follows:


1
2
3

u n i t s= days s i n c e 19500101 0 0 : 0 0 : 0 0
c a l e n d a r= g r e g o r i a n
t i m e r e f = utime ( u n i t s , c a l e n d a r=c a l e n d a r )

Then, you must use the num2date function to convert the array T into a datetime object:
1

d a t e=c d f t i m e . num2date (T)

Finally, if you want to retrieve the years, months or days of the date object, you must perform
as follows:
1
2
3
4
5
6
7

year =[]
month = [ ]
day = [ ]
f o r d in date :
y e a r . append ( d . y e a r )
month . append ( d . month )
day . append ( d . day )

To do the inverse operation (ie. move from a datetime object to an integer array) you must
obviously use the date2num function as follows:
1
2
3

T= [ ]
f o r d in date :
T . append ( c d f t i m e . date2num ( d ) )

NCL:
In NCL, the function that allows to do this is ut_calendar .
1

d a t e=u t _ c a l e n d a r (T, 0 )

It takes as an input the time array T, in which the attributes units and calendar must be
set. The last argument is an integer, which indicates the format of the output. If 0, the ouput
will have the format:
date(:,0)
date(:,1)
date(:,2)
date(:,3)
date(:,4)
date(:,5)
12

years
months
days
hours
minutes
seconds

If 1 (or 1), the output will have the YYYYMM format (either as a float or as an integer
depending of the sign of the integer). The option set to 2 add the days, 3 adds the hours while
4 returns a format YYYY.fraction_of_year. To do the inverse operation, it is the function
ut_inv_calendar that must be used:
1
2
3
4
5

u n i t s=" days s i n c e 19500101 0 0 : 0 0 : 0 0 "


c a l e n d a r=" g r e g o r i a n "
o p t i o n=1
o p t i o n @ c a l e n d a r=c a l e n d a r
T=u t _ i n v _ c a l e n d a r ( year , month , day , hour , minute , second , u n i t s , o p t i o n )

It should be noted that the calendar is set as an attribute to an integer option. Moreover,
the years, months, days, hours and minutes options must be integers.

2.5
2.5.1

Mathematics
Simple arithmetic operations

Table 2.5.0 shows how simple arithmetic operations are performed on a the first dimension of
an array M, using either Python or NCL.
Operation
Average
Standard deviation
Variance
Sum
Cumulated sum
Product
Cumulated product
Absolute value
Standardization
Minimum
Maximum

Python
numpy.mean(M,axis=0)
numpy.std(M,axis=0)
numpy.var(M,axis=0)
numpy.sum(M,axis=0)
numpy.cumsum(M,axis=0)
numpy.prod(M,axis=0)
numpy.cumprod(M,axis=0)
numpy.abs(M)
numpy.min(M,axis=0)
numpy.max(M,axis=0)

NCL
dim_avg_n(M,0)
dim_std_n(M,0)
dim_variance_n(M,0)
dim_sum_n(M,0)
dim_cumsum_n(M,0)
dim_product_n(M,0)
abs(M)
dim_standardize_n(M,0)
dim_min_n(M,0)
dim_max_n(M,0)

Table 2.5.0: Simple arithmetic operations


It should be noted that by default, Python flattens the array so that the output should be
a numeric. To force the operation along a specific dimension, we must add the argument axis.
Same is done with NCL. The function that allows operations along a specific dimension end
by _n. There exists equivalent functions that do not end like this, such as dim_avg. This computes the average over the last dimension.
Note: In NCL, simple arithmetic operations tend to erase metadata, such as attributes,
coordinates, etc. To keep metadata, the functions ending by _Wrap should be used (for example,
dim_avg_n_Wrap(M,0) computes the average over the first dimension and will keep the metada
of M).

13

2.5.2

Correlations

If we want to compute the correlation coefficient between two time-series A and B.


Python:
In Python, you must use the function corrcoef:
1

C=numpy . c o r r c o e f (A, B)

C will be a matrix of size 2 2, with C(0, 0) = C(1, 1) = 1.0 (the autocorrelation between
A and A and between B and B). The correlation coefficient between A and B is C(0, 1) = C(1, 0).
There are no Python functions to compute lead-lag correlations. The latter must be done
by hand. The correlation coefficient is estimated by:
Pn

rAB =

A)(Bi B)
(n 1)SA SB

i=1 (Ai

where n is the number of data in A and B, A and SA are the mean and standard deviation
of A, respectively.
Thus, lead lag correlations between A and B can be computed from the simple program:
1
2
3
4
5
6
7
8
9
10
11
12
13

d e f LeadLagCorr (A, B, n l a g s =10) :


c o e f s=numpy . empty ( n l a g s +1)
c p t=0
f o r p i n r a n g e ( ( n l a g s / 2 ) , n l a g s / 2 , 1 ) :
i f p<0:
Aint=A [ : p ]
B i n t=B[p : ]
e l i f i ==0:
Aint=A
B i n t=B
else :
Aint=A[ p : ]
B i n t=B[: p ]

14

n=l e n ( Aint )
sA=np . s t d ( Aint )
sB=np . s t d ( B i n t )
mA=np . mean ( Aint )
mB=np . mean ( B i n t )

15
16
17
18
19
20

r=np . sum ( ( AintmA) ( BintmB) ) / ( n1sAsB )

21
22

c o e f s [ c p t ]= r
c p t=c p t+1

23
24
25
26

return coefs

NCL:
In NCL, correlations are computed by the command:
1

C = e s c o r c (A, B)

14

In this case, we obtain a scalar which effectively corresponds to the correlation coefficient
between the two time-series.
Moreover, NCL permits to compute quiete easily lead-lag correlations by using the command
esccr.
1

C = e s c c r (A, B, n l a g s )

In this case, C is an array of dimensions nlags+1 that computes the correlation coeffient
between the two time-series at lags 0 to 10, with A leading. However, negative lags are not
handled. And to have the correlations when B leads, you must compute:
1

Cbis = e s c c r (B, A, n l a g s )

To concatenate the two results:


1
2
3

C f i n a l = new ( 2 mxlag +1 , f l o a t )
C f i n a l ( 0 : n l a g 1)=Cbis ( 1 : n l a g 1)
C f i n a l ( mxlag : )=C ( 0 : mxlag )

In this case, negative lags in Cfinal implies that B leads.

2.5.3

EOF analysis

Empirical Orthogonal Function (EOF) decomposition is often used in climate science. It indeed
permits to easiyly assess the variability of a multidimensional field. Imagine we have a 3D field,
M, of dimensions (time,depth,latitude). We want to decompose it into EOFs.
Python:
One way to simply compute EOFs is to use the pyclimate package (http://starship.
python.net/crew/jsaenz/pyclimate/).
This is done as follows:
1
2

from p y c l i m a t e i mpo rt s v d e o f s
( PCs , e i g e n v a l u e s , EOFs)=s v d e o f s . s v d e o f s (M, p c s c a l i n g =1)

The function svdeofs takes as an input the matrix M. The pscaling option allows to determine wether the PCs or the EOFs are normalized. Here we chose pcscaling=1, which implies
that the PCs will be dimensionless while the EOFs will have the same units as M.
The output is a tuple, with PCs being the principal components of dimensions (time,eofs),
eigenvalues being the eigenvalues of dimension (eofs) and EOFs being the spatial patterns of
the EOFs of dimension (depth,latitude,eofs). To obtain the amount of variance explained by
each EOFs, you must remember that:
k
V ar(k) = Pn

i=1 i

Thus the variance (in %) explained by each EOF can be determined by:
15

Var=100 e i g e n v a l u e s /np . sum ( e i g e n v a l u e s )

NCL:
In NCL, the EOF patterns are easily obtained:
1
2
3
4

d e o f=ntime
optEOF=True
optEOF@pcrit = 100
eof_map = e o f u n c (M( depth | : , l a t i t u d e | : , time | : ) , d e o f , optEOF ) ; Carte d e s e o f s

The two first lines determine the option of the EOF decomposition. The pcrit option indicates the percentage of non-missing value (along the time dimension at each grid point) that
must have the array so that EOF is computed. The eofunc takes as arguments the array M
(with time as the last dimension), the number of EOFs to retain and the option boolean.
The output eof_map contains the normalized EOF patterns and has dimensions of (eofs,depth,latitude).
It has the attributes eval (eigenvalues) and explained var (explained variance). To dimensionize
the EOF maps, you must do:
1
2
3
4

eof_map_dim=eof_map
do b e o f =0 , d e o f 1
eof_map_dim ( b e o f , : , : ) =
end do

( / eof_map ( b e o f , : , : ) s q r t ( eof_map@eval ( b e o f ) ) / )

Finally, to obtain the principal components:


1
2

eof_pc= eofunc_ts_Wrap ( f l d , eof_map , F a l s e )


eof_pc_dim=dim_standardize_Wrap ( eof_pc , 0 )

The first line determines the principal components with the same units than M . The second
line allows to determine the normalized principal components.

16

Chapter 3

Input/Output (IO)
3.1
3.1.1

NetCDF
What is a NetCDF?

NetCDF stands for Network Common Data Form. It is a portable, auto-documented data
format and is common among Earth-Scientists. Many data-sets are available in this format in
this format. Moreover, many models output are also returned in NetCDF. Thus, it is paramount
that any Earth Scientist should be able to work with this format. This is the goal of this section.
But beforehand, the architecture of a NetCDF file needs to be described.
In a NetCDF file, you will find variables, dimensions, coordinates and attributes. The
variable is the information you want to extract of the file. The dimensions obviously returns the
name of the dimensions of the variables as well as the number of data along each of them. The
coordinates are monotonic one dimensional arrays, each corresponding to one dimension, which
returns the values of each dimension points. The attributes can be viewed as informations that
can be attached to the variables or to the file itself. Those attributes can be of any types (string,
arrays, etc).
Imagine we have a NetCDF file, the variable of which is a succession of daily global maps
of one degree resolution and for a complete year. We call this variable SST. The dimensions of
SST are (time,latitude,longitude), with time having 365 elements, latitude having 181 elements,
and longitude having 361 elements. The coordinates of SST will be the sucession of time steps,
the vector of latitudes and the vector of latitudes. Usually, the names of the coordinates and of
the dimensions are identical. Moreover, it should be pointed out that in the NetCDF file, the
coordinates will appear as additional variables.
This is this file that we will try to read and write with our programming tools.

3.1.2

Reading a NetCDF

The common features in reading a NetCDF is that you have to know the names of the fields you
are trying to read. An easy way to obtain those informations is to use the following command:
ncdump -h My_NetCDF.nc.
According to the definition of SST, we should obtain the following result:
1
2
3
4
5
6
7
8

n e t c d f My_NetCDF {
dimensions :
time = UNLIMITED ; // ( 3 6 5 c u r r e n t l y )
l a t i t u d e = 181 ;
l o n g i t u d e = 361 ;
variables :
f l o a t s s t ( time , l a t i t u d e , l o n g i t u d e ) ;
s s t : Name = " SeaS u r f a c e Temperature " ;

17

s s t : _ F i l l V a l u e = 9 . 9 6 9 2 1 e+36 f ;
i n t time ( time ) ;
int latitude ( latitude ) ;
int longitude ( longitude ) ;

9
10
11
12
13
14
15
16

// g l o b a l a t t r i b u t e s :
: D e s c r i p t i o n = " Example o f NetCDF F i l e " ;
}

The number of dimensions of time is UNLIMITED, which means that this dimension is the
record dimension. This means that other data of similar latitude and longitude dimensions can
be concatenated along the time dimensions. We will see that this characteristic allows multiple
files opening.
Python:
In Python, you have many librairies which allow to read NetCDF files. We will only described
one of them, which, according to us, allows the most capabilities. This librairy is netCDF4.
1
2
3
4
5
6
7
8
9
10
11
12

im por t netCDF4 # Import t h e netCDF4 Module


f=netCDF4 . D a t a s e t ( My_NetCDF . nc , r ) # Read t h e NetCDF f i l e
f i e l d =f . v a r i a b l e s [ s s t ] # Read t h e v a r i a b l e s
time=f . v a r i a b l e s [ time ]
l a t=f . v a r i a b l e s [ l a t i t u d e ]
l o n=f . v a r i a b l e s [ l o n g i t u d e ]
name= f i e l d . Name # R e t r i e v e t h e v a r i a b l e a t t r i b u t e
d e s=f . D e s c r i p t i o n # R e t r i e v e t h e f i l e a t t r i b u t e
f i e l d = f i e l d [ : ] # Convert t h e data i n t o numpy a r r a y s
time=time [ : ]
l a t=l a t [ : ]
l o n=l o n [ : ]

NCL:
NCL, which has been developped for Earth Science, is the most efficient among the three in
the processing of NetCDF. To open a file, you simply use the command addfile
1
2
3
4
5
6
7

f = a d d f i l e ( "My_NetCDF . nc " , " r " ) ; Read t h e NetCDF f i l e


f i e l d =f >s s t ; Read t h e v a r i a b l e s
time= f i e l d &time ; Read t h e c o o r d i n a t e s
l a t= f i e l d &l a t i t u d e ; Another p o s s i b i l i t y
l o n= f i e l d &l o n g i t u d e ; l a t=f >l a t i t u d e
name=field@Name ; R e t r i e v e t h e v a r i a b l e a t t r i b u t e
d e s=f @ D e s c r i p t i o n ; R e t r i v e t h e f i l e a t t r i b u t e

3.1.3

Writting a NetCDF

Python:
1
2
3
4

from netCDF4 im po rt D a t a s e t # Load t h e l i b r a i r i e s


im por t numpy a s np #
im por t o s

5
6
7

# G e n e r a t e data a r r a y s
s s t=np . z e r o s ( ( 3 6 5 , 1 8 1 , 3 6 1 ) , np . f l o a t )

18

8
9
10

l o n=np . a r a n g e ( 180 ,181)


l a t=np . a r a n g e ( 90 ,91)
days=np . a r a n g e ( 1 , 3 6 6 , 1 )

11
12
13
14

#Compute d i m e n s i o n s i z e
n l o n=l e n ( l o n )
n l a t=l e n ( l a t )

15
16
17
18

o s . system ( rm + My_NetCDF . nc ) # Remove t h e ou tp ut f i l e


f o u t=D a t a s e t ( My_NetCDF . nc , w ) # C r e a t e t h e ou tp ut f i l e
f o u t . D e s c r i p t i o n= Example o f NetCDF F i l e # Write t h e f i l e

attribute

19
20
21
22
23

# Create the dimensions o f the f i l e s


fout . createDimension ( l o n g i t u d e , nlon )
fout . createDimension ( l a t i t u d e , nlat )
f o u t . c r e a t e D i m e n s i o n ( time , None )

24
25
26
27
28
29
30
31

#C r e a t e t h e v a r i a b l e s o f t h e f i l e s
v a r o u t=f o u t . c r e a t e V a r i a b l e ( s s t , f , ( time , l a t i t u d e , l o n g i t u d e ) )
v a r o u t . Name=" SeaS u r f a c e Temperature " # Attach t h e v a r i a b l e a t t r i b u t e
v a r o u t=f o u t . c r e a t e V a r i a b l e ( l a t i t u d e , i , ( l a t i t u d e , ) ) # C r e a t e t h e
coordinates variable
v a r o u t=f o u t . c r e a t e V a r i a b l e ( l o n g i t u d e , i , ( l o n g i t u d e , ) )
v a r o u t=f o u t . c r e a t e V a r i a b l e ( time , i , ( time , ) )

32
33
34
35
36
37

# Write out t h e
fout . variables [
fout . variables [
fout . variables [
fout . variables [

data a r r a y s i n t o t h e f i l e
sst ] [ : ] = sst
latitude ] [ : ] = lat
longitude ] [ : ] = lon
time ] [ : ] = days

38
39

fout . c l o s e ( ) # Close the f i l e

NCL:
In NCL, the writting is as easily as the reading of a NetCDF.
1

begin

2
3
4
5
6
7

; G e n e r a t e data a r r a y s
s s t=new ( ( / 3 6 5 , 1 8 1 , 3 6 1 / ) , f l o a t )
l o n=i s p a n ( 1 8 0 , 1 8 0 , 1 )
l a t=i s p a n ( 9 0 , 9 0 , 1 )
days=i s p a n ( 1 , 3 6 5 , 1 )

8
9
10
11
12

; Define the dimensions of the v a r i a b l e


s s t !0= " time "
s s t !1= " l a t i t u d e "
s s t !2= " l o n g i t u d e "

13
14
15
16
17

; Attach t h e c o o r d i n a t e s t o t h e d i m e n s i o n s
s s t&time=days
s s t&l o n g i t u d e=l o n
s s t&l a t i t u d e=l a t

18
19
20
21

; Compute d i m e n s i o n s i z e
n l o n=d i m s i z e s ( l o n )
n l a t=d i m s i z e s ( l a t )

22
23
24

; Attach t h e v a r i a b l e a t t r i b u t e
sst@Name=" SeaS u r f a c e Temperature "

25
26
27
28

system ( " rm My_NetCDF . nc " ) ; Remove t h e f i l e


f o u t=a d d f i l e ( "My_NetCDF . nc " , " c " ) ; C r e a t e t h e out pu t f i l e
f o u t @ D e s c r i p t i o n=" Example o f NetCDF F i l e "

29
30
31

f i l e d i m d e f ( f o u t , ( / " time " , " l a t i t u d e " , " l o n g i t u d e " / ) ,(/ 1 , n l a t , n l o n / ) , ( / True , F a l s e , F a l s e / ) )


; S e t t h e time d i m e n s i o n a s t h e r e c o r d d i m e n s i o n

19

32

f o u t >s s t=s s t ; Write out t h e data a r r a y s i n t o t h e f i l e

33
34

end

3.1.4

Multiple file opening

Python:
It can happen that a variable is stored in many files (for example, one file for each time
step). It can thus be usefull to know how to use multiple file opening. Sadly, Matlab does not
allow such operations. In python, the procedure is very similar to single file opening but with
the commande MFDaset. It takes as in input a string which defines where to find the find (it
basically is the string you will use in a linux ls query).
1
2
3
4

from netCDF4 im po rt MFDataset


f=MFDataset ( s s t _ )
s s t _ a g g r e g a t e d=f . v a r i a b l e s [ s s t ] [ : ]
l a t=f . v a r i a b l e s [ l a t i t u d e ] [ : ]

NCL:
In NCL, you have to use the command systemfunc to obtain the names of the file to open.
The results of this command will be used in the addfiles command.
1
2
3
4

f i l e n a m e s=s y s t e m f u n c ( " l s s s t _ " )


f=a d d f i l e s ( f i l e n a m e s , " r " )
s s t _ a g g r e g a t e d=f [:] > s s t
l a t=f [0] > l a t i t u d e

3.2

Text files

Imagine that you want to read an ascii file with the following format:
Maximum
Minimum
Maximum
Minimum

13.58449
-1.709398
12.94729
-1.989103

Sv
Sv
Sv
Sv

latitude
latitude
latitude
latitude

45.81936
45.81936
45.81936
45.81936

depth
depth
depth
depth

=
=
=
=

1061.401
3530.419
1061.401
3530.419

This the output of a CDFTOOLS which compute the maximum overturning streamfunction.
You want to retrive the values of the maximum, which are in this case 13.58449, 12.94729, etc.
Python:
In Python, the script that will allow you to to this is:
1

im por t numpy a s np # Import numpy

2
3
4
5

f i l e =open ( REF_Yearly_maxovt . t x t , r ) # Read t h e f i l e


l i n e s= f i l e . r e a d l i n e s ( ) # Read t h e f i l e l i n e s by l i n e s
n l i n e s=l e n ( l i n e s ) # Read t h e number o f l i n e s

6
7

maxmoc = [ ] # I n i t i a l i z e t h e ou tp ut

20

8
9

d e l i m=

# String delimiter

10
11
12
13
14

f o r l i n l i n e s : # Run t h e d i f f e r e n t l i n e s
s=l . s p l i t ( d e l i m ) # S p l i t t h e l i n e a c c o r d i n g t o t h e d e l i m i t e r
i f ( s [ 0 ] . s t r i p ( )== Maximum ) : # Test wet he r t h e f i r s t s t r i n g i s Maximum
maxmoc . append ( f l o a t ( s [ 1 ] ) ) # Add t h e o ut pu t t o t h e l i s t

15
16

maxmoc=np . a r r a y ( maxmoc ) # Convert t h e l i s t

i n t o an a r r a y

The command that allows to open the file is simply open, while to read the file line by line,
it is readlines. The output is an array, the elements of which are the string lines. The next step
is to run all the lines (for loop) and to split the string according to the delimiter delim. If you
print s, you will obtain:
[

Maximum, 13.58449, , Sv latitude, 45.81936, , depth =, 1061.401, \n]

The if condition check wether we are reading a line starting with Maximum. The strip
function allows to get rid of spurious spacing at the beginning of the string (due to the fact that
the lines starts with a spacing). Then the elements is converted into a float and added to the
list maxmoc. As list cannot be used with numpy, we finally convert it into a numpy array.
This method assumes that the file is not corrupted (ie. no missing data, all the column have
the same shape, etc). However, in some cases (for example a CSV file of GPS trames), the file
might have some incomplete lines. In this case, our simple script will not work.
In Python, there is a package that can handle this. This is the re (for Regular Experessions)
package. Imagine we slightly modify our text file:
Maximum
Minimum
Maximum
Minimum
Maximum
Minimum
Maximum
Minimum

13.58449
Sv latitude
45.81936
depth =
1061.401
-1.709398
Sv latitude
45.81936
depth =
3530.419
0
Sv latitude
45.81936
depth =
1061.401
-1.989103
Sv latitude
45.81936
depth =
3530.419
13.97433
Sv latitude
45.81936
depth =
1061.401
-1.899664
Sv latitude
45.81936
depth =
3530.419
13.42229
Sv latitude
45.81936
depth =
1061.401
-1.606414
Sv latitude
45.81936
depth =
3530.419

You see in line 3 that something went wrong, as the data is 0. When reading the file, we are
only interested in good data. To do so, you must use the re package as follows:
1
2

im por t r e # I m p o r t a t i o n o f t h e r e package
im por t numpy a s np

3
4
5
6

f i l e =open ( REF_Yearly_maxovt_REGEXP . t x t , r )
l i n e s= f i l e . r e a d l i n e s ( )
n l i n e s=l e n ( l i n e s )

7
8
9

p a t t e r n= Maximum [ 1 9 ] { 2 } \ . [ 0 9 ] { 5 } # D e f i n i t i o n o f t h e p a t t e r n t o match
r e g e x p=r e . c o m p i l e ( p a t t e r n ) # C o m p i l a t i o n o f t h e p a t t e r n

10
11

maxmoc = [ ]

12
13
14
15
16
17

for l in l i n e s :
i f ( r e g e x p . s e a r c h ( l ) ) : # Test w et her t h e l i n e matches o r not .
p r i n t ( We have a good l i n e h e r e )
s=l . s p l i t (
)
maxmoc . append ( f l o a t ( s [ 1 ] ) )

21

The pattern string is the so-called regular expression, which is a pattern that must be
matched. The *Maximum * indicates that we can have 0 or any number of white spaces
before and after the Maximum string. The [0-9]{2}\.[0-9]{5} means that after the white
spaces, we must have two digits from 0 to 9, a point .1 , and 5 digits from 0 to 9 after the point.
This is the format of the good data (for example 13.58449). We must then compile this pattern
using the compile function. Now, similarly with the previous example, we run the lines and
compare it with the pattern, using the search command. If this pattern is found in the data,
then they will be added in the list. As 0 does not match this pattern , it will be discarded.
Regular expressions also permit to split a string with a delimiter matching a pattern. In our
textfiles, we have spacing between the column which is irregular. But this spacing, between the
data, is greater than 3. We can thus do the following:
1
2

p a t t e r n= { 3 , }
r e g e x p=r e . c o m p i l e ( p a t t e r n )

3
4
5
6

for l in l i n e s :
s=r e g e x p . s p l i t ( l )
print ( s )

Note that the syntax of the split here is different from that of the first example. The 3,
indicates that the splitting must be done for spacing from 3 to infinity. If you print s, you will
have:
[

Maximum, 13.58449, Sv latitude, 45.81936, depth =, 1061.401, \n]

Compared to the first example, we notice that single spaces (column 3 and 6) have disappeared.
NCL:
Here is the NCL script that will allow this:
1
2

d e l i m=" " ; d e f i n i t i o n o f t h e s t r i n g d e l i m i t e r
finname=" REF_Yearly_maxovt . t x t " ; name o f t h e f i l e t o r e a d

3
4
5
6
7

l i n e s = a s c i i r e a d ( finname , 1 , " s t r i n g " ) ; Read t h e f i l e p e r l i n e s


n f i e l d s = s t r _ f i e l d s _ c o u n t ( l i n e s ( 1 ) , d e l i m ) ; Number o f column o f
the f i l e
n l i n e s=d i m s i z e s ( l i n e s ) ; Number o f l i n e s

8
9

maxmocint=new ( n l i n e s , f l o a t ) ;

I n i t i a l i z e t h e ou tp ut

10
11
12
13
14
15
16
17
18

c p t=0 ; Counter t o i n c r e m e n t
do i n d l =0 , n l i n e s 1 ; L i n e i t e r a t i o n
t e s t=s t r _ g e t _ f i e l d ( l i n e s ( i n d l ) , 1 , d e l i m ) ; R e t r i e v e t h e f i r s t s t r i n g
i f ( t e s t . eq . "Maximum" ) ; Test w et her i t i s maximum
maxmocint ( c p t )=s t r i n g t o f l o a t ( s t r _ g e t _ f i e l d ( l i n e s ( i n d l ) , 2 , d e l i m ) ) ; R e t r i v e t h e
maximum v a l u e , c o n v e r t i t i n t o f l o a t
c p t=c p t+1 ; Counter i n c r e m e n t a t i o n
end i f
end do

19
20

maxmoc=maxmocint ( i n d ( . not . i s m i s s i n g ( maxmocint ) ) ) ; Remove a l l m i s s i n g v a l u e s

As the point is considered as a special character for regular expressions, we must add a backslash before the
point

22

The asciiread command will read the file line by line, and returns an array of string, the
elements of which are the string lines. The str_fields_count function counts the number of
columns that are separated by the delimiter. nlines is the total number of lines in the file,
including the lines we are not interested in. We also initialize the vector in which the values will
be stored. However, we initialize it with too many dimensions. The cpt variable is a counter
wich will be incremented every time we write an element in the array. The command to retrive
a value of a SVD line is str_get_field, which takes as arguments the input string, the position
of the element we want to extract, and the delimiter used in the separation. The test variable
is used to test wether the line we read is that of the maximum overturning. If it is, we extract
the values and convert it into a float before adding to the array maxmocint. The cpt variable is
then incremented.
At the end, we have a big array with, at the beginning, the values we are interested in, and
at the end missing values. The last step, using the ismissing function, is to get rid of those
spurious missing values.
As you may have noticed, we have less flexibility with NCL than with Python for reading
ASCII files.

23

Chapter 4

Plots
4.1

XY Plots

4.1.1

First plot
Title

Y label

3
1940

1950

1960

1970

1980

1990

2000

2010

X label

Python:
1
2

from p y l a b im por t # im po rt a l l p y l a b f u n c t i o n s
im por t numpy a s np # im por t numpy l i b r a r y

3
4
5
6
7
8
9

figure () # define a figure instance


plot ( years , indexes [ 0 , : ] ) # Plot function
x l a b e l ( X l a b e l ) # d e f i n i t i o n o f x l a b e l
y l a b e l ( Y l a b e l ) # d e f i n i t i o n o f y l a b e l
t i t l e ( Title ) # definition of t i t l e
s a v e f i g ( f i g / plot_ts_1_py . p d f , bbox_inches= t i g h t ) # s a v e f i g u r e

In Python, the pylab library handles all the functions necessary to draw figures. First, we
define the figure instance. The time-series are plotted with the plot function. As no axes instance
has been defined, it implicitely creates one. The x-axis tile, y-axis title and figure title are given
by xlabel, ylabel and title, respectively. The figure saving is done with savefig. The tight option
allows to get rid of white space around the figure.

24

NCL:
1
2
3
4
5

; Import NCL f u n c t i o n s
l o a d "$NCARG_ROOT/ l i b / n c a r g / n c l s c r i p t s /csm/ gsn_code . n c l "
l o a d "$NCARG_ROOT/ l i b / n c a r g / n c l s c r i p t s /csm/gsn_csm . n c l "
l o a d "$NCARG_ROOT/ l i b / n c a r g / n c l s c r i p t s /csm/ c o n t r i b u t e d . n c l "
l o a d "$NCARG_ROOT/ l i b / n c a r g / n c l s c r i p t s /csm/ s h e a _ u t i l . n c l "

6
7
8

begin
wks

= gsn_open_wks ( pdf , f i g / + g e t _ s c r i p t _ p r e f i x _ n a m e ( ) + _ncl ) ; open


workstation

9
10
11
12
13

res
res@tiXAxisString
res@tiYAxisString
res@tiMainString

= True ; I n i t i a l i z e r e s s o u r c e
= "X L a b e l " ; d e f i n i t i o n o f x l a b e l
= "Y L a b e l " ; d e f i n i t i o n o f y l a b e l
= " Title " ; definition of t i t l e

14
15
16

plot
end

= gsn_csm_xy ( wks , y e a r s , i n d e x e s ( 0 , : ) , r e s ) ; P l o t f u n c t i o n

In NCL, it is often usefull to load the csm scripts beforehand. The gsn_open_wks command
allows to open the workspace, which in this case is a .pdf file. Now we initialize the resources of
the plot by setting tiXAxisString, tiXAxisString and tiMainString, which are x-axis tile, y-axis
title and figure title, respectively.

4.1.2

Multiline plots
3

NAO
EAP

Indexes

1
0
1
2
3
1940

1950

1960

1970

1980
Years

1990

2000

2010

Python:
If you want to superpose two time series with Python, you have two ways. Either you define a
N 2 vector, and the plot function described above will work. But I would advise the following.
1
2

l 1=p l o t ( y e a r s , i n d e x e s [ 0 , : ] , c o l o r= k , l i n e s t y l e= s o l i d ) # draw t h e f i r s t l i n e , b l a c k and


solid
l 2=p l o t ( y e a r s , i n d e x e s [ 1 , : ] , c o l o r= r , l i n e s t y l e= dashed ) # draw t h e s e c o n d l i n e , r e d and
solid

These two lines define two Lines2D instances. The color and linestyle options handle the
color and linestyles of each individual lines (dashed, solid, dotted, etc).
25

To add a legend, you must use:


1
2

prop = m a t p l o t l i b . font_manager . F o n t P r o p e r t i e s ( s i z e =9) # D e f i n e t h e l e g e n d f o n t s i z e


l e g e n d ( ( l 1 [ 0 ] , l 2 [ 0 ] ) , ( NAO , EAP ) , l o c =0 , prop=prop ) # Add t h e l e g e n d : l 1 >NAO, l 2 >EAP,
l o c a l i s a t i o n=b e s t

The matplotlib.font_manager.FontProperties handle the font properties of the legend strings.


The legend function draws the legend. It takes as an input two tuples: the individual lines of
the plot (not the use of brackets, which is necessary). We added the loc property, which handles
the location of the legend (0 means best position) and the FontProperties instance prop.
NCL:
In NCL, two-line plots need the definition of a 2N array (note the difference with Python).
The colors and dashed patterns of each line are defined in an array:
1
2

res@xyLineColors
= (/ " black " , " red " /) ; Line c o l o r s ve cto r
r es @ xy D a sh P at t er n s = ( / 0 , 2 / ) ; L i n e p a t t e r n s v e c t o r : 0> s o l i d , 2>dashed

The handling of the legend is much complicated than with Python.


1
2
3
4
5
6

res@pmLegendDisplayMode = " Always " ; F o r c e t h e l e g e n d d i s p l a y


r e s @ x y E x p l i c i t L e g e n d L a b e l s = ( / " NAO " , " EAP " / ) ; Legend v e c t o r s
res@pmLegendWidthF
= 0 . 1 2 ; Legend width
res@pmLegendHeightF
= 0 . 0 7 ; Legend
res@pmLegendParallelPosF
= .85
; Move l e g e n d a l o n g x a x i s
res@pmLegendOrthogonalPosF = 1.14 ; Move l e g e n d a l o n g y a x i s

The pmLegendDisplayMode resource forces the legend drawing. xyExplicitLegendLabels


defines the lines names. pmLegendWidthF and pmLegendHeightF handle the width and height
of the legend box, respectively. Finally, the last two resources handle the parallel (along X) and
orthogonal (along Y) positions of the legend. It is the setting of these four resources that makes
difficult legend handling with NCL. To finally draw the time series:
1

plot

= gsn_csm_xy ( wks , y e a r s , i n d e x e s ( 0 : 1 , : ) , r e s )

4.1.3

Filled XY plots

Python:
To draw filled plots, like NAO index as found in the internet:
1
2
3
4

f i l l _ b e t w e e n ( y e a r s , 0 , i n d e x e s [ 0 , : ] , where=i n d e x e s [ 0 , : ] > = 0 , f a c e c o l o r= r e d , i n t e r p o l a t e=True


) # f i l l in red p o s i t i v e values
f i l l _ b e t w e e n ( y e a r s , 0 , i n d e x e s [ 0 , : ] , where=i n d e x e s [ 0 , : ] < 0 , f a c e c o l o r= b l u e , i n t e r p o l a t e=True
)
# f i l l in blue negative values
p l o t ( y e a r s , i n d e x e s [ 0 , : ] , c o l o r= k ) # O v e r l a y t h e l i n e p l o t

The fill_between function fills the space between two time series. In this example, one of
the time series is set to 0. The where option defines the condition that must be verified for the
26

3
2
1
0
1
2
3

1960

1970

1980

1990

2000

2010

drawing. Here, the first line indicates that the drawing, with the filling in red, must be done
only where the index is positive. The second one, with blue filling, is only done if the index is
negative. Note the use of the option interpolate set to True, to have a nice rendering.
In this example, we also resctricted the xaxis and yaxis limits:
1
2

xlim (1958 ,2010) # L im i t a t i o n o f x a x i s


y l i m ( 3 ,3) # L i m i t a t i o n o f y a x i s

NCL:
In NCL, it is the same function that is used for filled plots. The only difference is the addition
of three resources:
1
2
3

res@gsnYRefLine
= 0.0 ; Set the Y r e f e r e n c e l i n e
res@gsnAboveYRefLineColor = " r e d " ; f i l l i n r e d p o s i t i v e v a l u e s
res@gsnBelowYRefLineColor = " b l u e " ; f i l l i n r e d p o s i t i v e v a l u e s

The first one defines the ordinate of the reference line, in our case the absic axis. The last
two define the above and below fill colors, respectively.
To limit the plot domain, the resources that must be set are:
1
2
3
4

res@trYMinF
res@trYMaxF
res@trXMinF
res@trXMaxF

4.1.4

= 3.0 ; min v a l u e on ya x i s
= 3 . 0 ; max v a l u e on ya x i s
= 1949 ; min v a l u e on ya x i s
= 2010 ; max v a l u e on ya x i s

Twin xaxis

Python:
To draw two time-series with different units (in this case, a number of days and a dimensionless index, you have to use the command twinx. First, we set-up the bar histogramm.
1
2
3

ax=gca ( ) # I n i t i a l i z e a x e s i n s t a n c e
bar ( y e a r s 0 . 5 , occu [ 3 , : ] , width =1 , bottom =0 , c o l o r= b ) # P l o t h i s t o g r a m on ax
ax . s e t _ y l a b e l ( NAO o c c u r r e n c e s , c o l o r= b ) # S e t ax y l a b e l

27

3
70
2

60
50

40

30

NAO index

NAO- occurrences

20
2

10
0
1950

4
5

1960

1970

1980

1990

2000

3
2010

s e t p ( ax . g e t _ y t i c k l a b e l s ( ) , c o l o r= b ) # S e t t h e c o l o r o f t i c k l a b e l s
s e t p ( ax . y a x i s . g e t _ t i c k l i n e s ( ) , c o l o r= b ) # S e t t h e c o l o r o f t i c k l i n e s

To draw histogramms, it is the command bar, and not plot, that is to use. It takes as an
input the leftmost coordinates of each bar, the width, the bottom coordinate of the bar (in our
case, 0). As the bars are blue, we also change the color of this axes ylabel, yticklabels and
yticklines. This is done with the setp function, which takes as an input the instance of which
we are willing to change the property, and this property.
To define the second axes, used for the line, we use
1

ax2=ax . twinx ( ) # I n i t i a l i z e t h e s e c o n d a x e s i n s t a n c e

Then, the plotting is done in the exact same way as previously. It has to be noted that to
limit the xaxis limit of this figure, you have to do it on ax2, not ax.
NCL:
To do this figure with NCL, you have to define two ressources: one for the histogramm
(resB), one for the line. As it is basically twice the same thing, we will only describe the resB
ones.
1
2
3
4
5
6
7
8
9
10
11
12
13

resB=True ; I n i t i a l i s e t h e r e s s o u r c e f o r t h e h i s t o g r a m
res@trYMinF=0 ; Yaxis minimum
resB@trYMaxF=75 ; Yaxis maximum
resB@trXMinF =1949 0.5 ; Xaxis minimum
resB@trXMaxF=2010+0.5 ; Xaxis maximum
r e s B @ t i Y A x i s S t r i n g="NAO o c c u r r e n c e s " ; YAxis l a b e l
resB@gsnXYBarChart = True ; Histogram mode on
resB@gsnYRefLine=0 ; D e f i n e t h e Y r e f e r e n c e l i n e
resB@gsnAboveYRefLineColor=" b l u e " ; Blue f i l l above 0
resB@tiYAxisFontColor=" b l u e " ; Y t i t l e c o l o r
resB@tmYLLabelFontColor=" b l u e " ; Y L e f t l a b e l s c o l o r s
resB@tmYLMajorLineColor=" b l u e " ; Y L e f t Major t i c k s c o l o r s
resB@tmYLMinorLineColor=" b l u e " ; Y L e f t Minor t i c k s c o l o r s

The gsnXYBarChart is set to true to obtain a histogramm. However, this one will not be
filled. We have to use gsnYRefLine and gsnAboveYRefLineColor, as previously, to fill the bars.
28

Now, to change the colors of the leftmost ticklabels (YL:YLeft, opposed to YR: YRight), we
must set tmYLLabelFontColor, while to change the ticklines color, we must define tmYLMajorLineColor and tmYLMinorLineColor for major and minor ticks, respectively.
To overlay both figures, we must use the command:
1

p l o t=gsn_csm_xy2 ( wks , y e a r s , occu ( 3 , : ) , i n d e x e s ( 0 , : ) , resT , r e s L ) ; P l o t f u n c t i o n

It takes as an input the workspace, the x coordinates, the first y coordinates, the second y
coordinates, and the resources of both plots.

4.1.5

Grid/labels handling
3
2
1
0
1
2
3

1945

1955

1965

1975

1985

1995

2005

Python:
To handle tickmarks, we have to import MultipleLocator from the matplotlib library.
1

from m a t p l o t l i b . t i c k e r im por t M u l t i p l e L o c a t o r # Tick l i b r a r y

2
3
4

majorLocator
= M u l t i p l e L o c a t o r ( 5 ) # Major l o c a t o r a t m u l t i p l e o f 5
ax . x a x i s . s e t _ m a j o r _ l o c a t o r ( m a j o r L o c a t o r ) # D e f i n e x t i c k s major l o c a t o r

5
6
7

minorLocator
= M u l t i p l e L o c a t o r ( 1 ) # Minor l o c a t o r a t m u l t i p l e o f 1
ax . x a x i s . s e t _ m i n o r _ l o c a t o r ( m i n o r L o c a t o r ) # D e f i n e x t i c k s minor l o c a t o r

This ensembple of function allows to draw, in the xaxis, a major tickmark at each multiple
of 5, and a minor one at each coordinate (multiple of 1).
To add the grid:
1
2
3

g r i d ( True , which= major , c o l o r= k , l i n e w i d t h =2) # Draw g r i d a t major l o c a t o r s


g r i d ( True , which= minor , c o l o r= r , l i n e w i d t h =1) # Draw g r i d a t minor
locators

The which option allows to define whereas the grid is to be drawn on major or major ticks.
It should be noted that Python automatically adds a label at each major tickmarks. If you want
to draw a ticklabel out of 2:

29

1
2

f o r t i n ax . g e t _ x t i c k l a b e l s ( ) [ : : 2 ] : # h i d e one l a b e l out o f 2
s e t p ( t , v i s i b l e=F a l s e )

Finally, if you want to handle the tick properties, such as the color:
1
2

tick_params ( which= major , c o l o r= g , width =2 , l e n g t h =8) # major t i c k l i n e s p r o p e r t i e s


tick_params ( which= minor , c o l o r= y , width =2 , l e n g t h =4) # minor t i c k l i n e s p r o p e r t i e s

NCL:
In NCL, to do similar things only needs to set many resources:
1
2

res@tmXBMode=" Manual " ; Draw t i c k s manually

3
4
5
6
7
8
9
10
11

; X Bottom Tick h a n d l i n g r e s o u r c e s
res@tmXBTickStartF =1945 ; XBottom t i c k s t a r t
res@tmXBTickSpacingF =5 ; Xbottom t i c k s p a c i n g
res@tmXBTickEndF=2010 ; XBottom t i c k end
res@tmXBMinorPerMajor=4 ; 4 minor t i c k s f o r one major
res@tmXBLabelStride=2 ; # h i d e one l a b e l out o f 2
res@tmXBMajorLineColor=" g r e e n "
res@tmXBMinorLineColor=" o r a n g e "

12
13
14
15
16
17

; X Major Grid h a n d l i n g r e s o u r c e s
res@tmXMajorGrid=True ; Draw X major g r i d
res@tmXMajorGridLineColor=" b l a c k " ; X Major g r i d c o l o r
res@tmXMajorGridLineDashPattern=2 ; X Major g r i d i n dashed
res@tmXMajorGridThicknessF=2 ; X Major g r i d t h i c k n e s s

18
19
20
21
22
23

; X Minor Grid h a n d l i n g r e s o u r c e s
res@tmXMinorGrid=True ; Draw X minor g r i d
res@tmXMinorGridLineColor=" r e d " ; X Minor g r i d c o l o r
res@tmXMinorGridLineDashPattern=2 ; X Minor g r i d i n dashed
res@tmXMinorGridThicknessF=1 ; X Major g r i d t h i c k n e s s

24
25
26
27

; Y L e f t Tick h a n d l i n g r e s o u r c e s
res@tmYLMajorLineColor=" g r e e n "
res@tmYLMinorLineColor=" o r a n g e "

28
29
30
31
32

; Y Major Grid h a n d l i n g r e s o u r c e s
res@tmYMajorGrid=True
res@tmYMajorGridLineDashPattern=2
res@tmYMajorGridThicknessF=2

33
34
35
36

; S i m i l a r t i c k p r o p e r t i e s i n t h e top Xaxis and t h e r i g h t Yaxis


res@tmYUseLeft=True
res@tmXUseBottom=True

I do not go into the details, as the resource names are rather obvious. The most important
are the last two ones. They force the XT (XTop) tick properties (colors, etc) to be equal to the
XB (XBottom) ones, and the YR (YRight) tick properties to be equal to the YL (YLeft).

4.1.6

Labels positioning

Python:
To handle label and ticklabels position in python:

30

1940

1950

1960

1970

Years
1980

1990

2000

2010
3
2

Indexes

1
2
3

1
2

ax . y a x i s . s e t _ l a b e l _ p o s i t i o n ( r i g h t ) # YLabel i n t h e r i g h t
ax . y a x i s . s e t _ t i c k s _ p o s i t i o n ( r i g h t ) # YTickLabels i n t h e r i g h t

3
4
5

ax . x a x i s . s e t _ l a b e l _ p o s i t i o n ( top ) # XLabel a t t h e top


ax . x a x i s . s e t _ t i c k s _ p o s i t i o n ( top ) # XTickLabels a t t h e top

NCL:
To do the same thing in NCL,:
1
2
3
4

res@tmYLLabelsOn=F a l s e
res@tmYRLabelsOn=True
res@tmXBLabelsOn=F a l s e
res@tmXTLabelsOn=True

; Hide
; Force
; Hide
; Force

YLeft T i c k L a b e l s
YRight T i c k L a b e l s
XBottom T i c k L a b e l s
XTop T i c k L a b e l s

5
6
7

r e s @ t i X A x i s S i d e=" Top " ; P o s i t i o n o f XLabel


r e s @ t i Y A x i s S i d e=" Right " ; P o s i t i o n o f YLabel

The first four resources hide the YLLabels/XBLabels, and to force the other labels. The
last two change the positions of the axes labels.

4.1.7

Time ticking

Python:
Oftenly, time in netcdf times is an integer, which gives the number of days, hours or second
since a specific date. To nicely label your time axes, you first have to convert it into a datetime
object (see previous section):
1
2
3
4

u n i t s= days s i n c e 00490901 0 0 : 0 0 : 0 0
c a l e n d a r= g r e g o r i a n
c d f t i m e = utime ( u n i t s , c a l e n d a r=c a l e n d a r )
d a t e=c d f t i m e . num2date ( time )

The next step is to generate the string array that will be used for the labelling:

31

1
0

1
2
3
4

n
Ja

9
4
9
1
1
0

n
Ja

9
6
9
1
1
0

n
Ja

9
8
9
1
1
0

n
Ja

9
0
0
2

stF = [ ]
f o r p in range (0 , len ( date ) ) :
stF . append ( d a t e [ p ] . s t r f t i m e ( %d %b %Y ) )
stF=np . a r r a y ( stF )

The strftime command takes as an option a string formatter. Here, the format %d %b %Y
stands for days as an integer, months as an integer and years as a 4 digit integer.
Then, you plot the index as a function of the time variable:
1
2
3

f i g=f i g u r e ( )
ax=gca ( )
p l o t ( numf , i n d e x e s )

So far, the xaxes will have the labels corresponging to the time. To add the labels corresponding to the strings previously generated:
1
2
3

s t r i d e =20
t i c k s=ax . s e t _ x t i c k s ( numf [ : : s t r i d e ] )
ax . s e t _ x t i c k l a b e l s ( stF [ : : s t r i d e ] )

This will draw the labels with a stride of 20. Those labels will appear horizontally. To rotate
them in a nice way, you must use the following command:
1

f i g . autofmt_xdate ( )

NCL:
To do the same thing in NCL, you have to add the following ressources:
1
2
3
4

s t r i d e =20
res@tmXBMode = " E x p l i c i t "
res@tmXBValues = time ( : : s t r i d e )
res@tmXBLabels = u t _ s t r i n g ( time ( : : s t r i d e ) , "%d %f %Y" )

This adds the labels in text formatting but horizontally. To rotate them similarly as described, you must add the following lines:
32

1
2

res@tmXBLabelAngleF=30
res@tmXBLabelJust=" TopRight

The first one rotates the labels, while the second one shifts the label to the left so that its
end coincides with the ticks locations.

4.2
4.2.1

Contours
First contour plot
256

264

280

50

272

288

296

296
288

264
0

50

264

50

280

272

100

264

264

150

200

250

300

350

Python:
To draw our first contour, we have a one dimensional array for x coordinates, a one dimensional array for y coordinates and a two dimensional array of temperature. To draw a simple
contour plot:
1
2
3

figure ()
c s=c o n t o u r ( lo n , l a t , t2 , c o l o r s= k ) # Contour p l o t s ( not f i l l e d )
c l a b e l ( cs , fmt= %d ) # Add l a b e l s t o t h e l i n e s a s i n t e g e r

NCL:
In NCL, to draw a contour plot, you first have to define the ressources that will contain the
coordinates of the contour plot:
1
2
3
4
5

r e s=True
res@sfXArray = l o n ; X a r r a y
res@sfYArray = l a t ; Y a r r a y
r e s @ c n I n f o L a b e l O n=F a l s e ; Hide t h e i n f o r m a t i o n s on t h e c o n t o u r
p l o t=gsn_csm_contour ( wks , t2 , r e s ) ; Contour command

The cnInfoLabelOn resource allows to hide the information of the contour plot (contour from
256 to 300 by step of 4). that is automatically added at the bottom of the plot.

33

260

50

270

280

30
0
30
0

290

300

300

290
50

280
270

4.2.2

50

100

260

150

260

200

250

300

350

Levels handling

Python:
It might be usefull to define the levels that must be drawn. In Python, you can do that with
the option levels of the contour plots commands
1
2

l e v e l s=np . a r a n g e ( 2 5 0 , 3 0 5 , 5 )
c s=c o n t o u r ( lo n , l a t , t2 , l e v e l s=l e v e l s , c o l o r s= k )

Moreover, in the previous section, we notice that the contours are masked under the labels.
To decactivate this option, you have to set the option inline in the clabel function:
1

c l a b e l ( cs , l e v e l s [ : : 2 ] , i n l i n e=F a l s e , fmt= %d )

We notice that the second argument to the clabel function has been added. It corresponds
to the array of levels at which the labels must be drawn.
NCL:
In NCL, the selection of contour levels to be drawn is done by setting:
1
2
3

l e v e l s=i s p a n ( 2 5 0 , 3 0 0 , 5 )
r e s @ c n L e v e l S e l e c t i o n M o d e=" E x p l i c i t L e v e l s "
r e s @ c n L e v e l s=l e v e l s

To add the labels to specific levels only, it is slightly more complicated than in Python.
The first step is to define an array of strings, that we call flags. The second one is to set the
cnLabelDrawOrder ressource:
1
2
3
4
5

n l e v e l s=d i m s i z e s ( l e v e l s )
f l a g s=new ( n l e v e l s , s t r i n g ) ; I n i t i a l i s a t i o n o f f l a g s a s a s t r i n g a r r a y
f l a g s ( : ) =" LineOnly " ; I n i t i a l i z e t h e a r r a y with t h i s s t r i n g .
f l a g s ( : : 2 ) =" LineAndLabel " ; Change t h e a r r a y with a s t r i d e o f 2
r e s @ c n L e v e l F l a g s=f l a g s ; S e t t h e r e s o u r c e

34

This cnLevelFlags resource has the same length than the levels vectors and indicates how to
draw each specific contours. In this case, we want a line everywhere, and an additional label for
one line out of two. Finally, to erase the white space under the label, you just have to force the
label to be drawn first, by setting
1

res@cnLabelDrawOrder=" PreDraw "

4.2.3

Filled contour plot


300

50

280

270

Label colorbar

290

260

50

250
0

50

100

150

200

250

300

350

Python:
Usually, it is nicer to add some colors to the figures. Here we will learn how to draw filled
contour plots. In Python, you must use contourf instead of contour:
1

c s=c o n t o u r f ( lon , l a t , t2 , l e v e l s=l e v e l s , cmap=cm . get_cmap ( RdYlBu_r ) , e x t e n d= both )

The difference with the previous contour function is the cmap option, which is the choice of
the colormap, and the extend option set to both. Python automatically mask the values that
are greater than the maximum or lower than the minimum of the levels option. This option
allows to disable this. This sole line does not draw black lines. They must be added with a
contour command:
1

c s 2=c o n t o u r ( lon , l a t , t2 , l e v e l s=c s . l e v e l s , c o l o r s= k )

It should be noted that the levels option here is set with the levels used in the contourf
funtction, so that the black lines correspond to the interface of two colors.
Finally, to add the colorbar, it is simply the colorbar option:
1

cb=c o l o r b a r ( cs , o r i e n t a t i o n= v e r t i c a l , drawedges=True )

The drawedges option defines wether line should be drawn between the colors in the colorbar.
Finally, to add the title to the colobar:

35

cb . s e t _ l a b e l ( L a b e l c o l o r b a r )

NCL:
In NCL, you first have to define a colormap, which is done by using:
1

gsn _def ine_c olor map ( wks , " RdYlBu_r " )

It is the same command as described previously that is used for filled contour plots. except
that additional ressources need to be added. For filled contours:
1
2

r e s @ c n F i l l O n=True
r e s @ g s n S p r e a d C o l o r s=True

The gsnSpreadColors forces NCL to use the entire colormap for the figure. If set to False,
if the number of levels to draw is lower than the number of colors in the colormap, NCL will
select the first colors of the colormap so that the numbers of colors equals the number of levels.
In NCL, the colorbar is automatically drawn. However, to have a nice rendering, it must be
improved a little, by setting some resources.
1
2

r e s @ l b O r i e n t a t i o n=" V e r t i c a l "
res@lbBoxLinesOn=F a l s e

Those resources define the orientation of the colormap and wether lines between the boxes
must be drawn. To add a title to the colorbar:
1

r e s @ l b T i t l e S t r i n g=" L a b e l c o l o r b a r "

In this case, the title will be drawn at the top of the colorbar, horizontally. We must change
the position, direction and angle of the title so that is is drawn as in the previous figure. This
is done by:
1
2
3

r e s @ l b T i t l e P o s i t i o n=" Right "


r e s @ l b T i t l e D i r e c t i o n=" A c r o s s "
r e s @ l b T i t l e A n g l e F =90

4.2.4

Gray filled values

Python:
Here we will draw a sligthly more complicated contour. First of all, we notice that where
data are missing, the color is gray. As contourf method draws transparently missing values, we
must set the axes background color:
1
2

ax=gca ( )
ax . s e t _ a x i s _ b g c o l o r ( g r a y )

36

20
15

1000

10
2000

5
0

3000

5
4000

10
15

5000

20
10

10

20

30

40

50

60

Now, we want to have dashed lines for the negative contour lines. This is done by changing
the rc default parameters:
1
2

im por t m a t p l o t l i b
m a t p l o t l i b . rcParams [ c o n t o u r . n e g a t i v e _ l i n e s t y l e ] = dashed

Now, we want to overlay the filled contours, thin contour lines and a thick one for the zero
contour. This is done by using:
1
2
3
4

c s=c o n t o u r f ( l a t , z , moc , l e v e l s=l e v e l s , cmap=cm . get_cmap ( RdBu_r ) , e x t e n d= both )


# C o n t o u r f command
c s 1=c o n t o u r ( l a t , z , moc , l e v e l s=l e v e l s , c o l o r s= k , l i n e w i d t h s =0.5) # Thin c o n t o u r s
c s 2=c o n t o u r ( l a t , z , moc , l e v e l s = [ 0 , 0 ] , c o l o r s= k , l i n e w i d t h s =2) # Thick z e r o c o n t o u r l i n e

Now, we might want to change the stride at which the labels are added to the colorbar. This
is done by the following:
1
2
3
4

cb . s e t _ t i c k s ( l e v e l s ) # Draw one t i c k a t each l e v e l . Handle i r r e g u l a r t i c k s


s t r i d e =5
s e t p ( cb . ax . g e t _ y t i c k l a b e l s ( ) , v i s i b l e=F a l s e ) # Hide a l l t h e l a b e l s
s e t p ( cb . ax . g e t _ y t i c k l a b e l s ( ) [ : : s t r i d e ] , v i s i b l e=True ) # Draw each 5 l e v e l s

However, we can notice that little tickmarks appear in the colorbar. They are due to the
fact that a colorbar is drawn on an axes instance, which has tickmarks. While in the previous
plot, it was not a huge problem, when doing this, it makes the colorbar unreadable. To draw
those ticklines next to the labels:
1
2
3

s e t p ( cb . ax . g e t _ y t i c k l i n e s ( ) , v i s i b l e=F a l s e )
s e t p ( cb . ax . g e t _ y t i c k l i n e s ( ) [ : : 2 s t r i d e ] , v i s i b l e=True )
s e t p ( cb . ax . g e t _ y t i c k l i n e s ( ) [ 1 : : 2 s t r i d e ] , v i s i b l e=True )

Moreover, Python allows to add lines to the colorbar at a given levels. Imagine you want to
highlight that the thick contour is the zero line, you can add:
1

cb . a d d _ l i n e s ( c s 2 )

37

with cs2 being the contour instance for the zero line.
NCL:
As always with NCL, you do not have to change the function but only the resources. To
define the gray color used for the continents, you must use:
1
2

g =0.7
newindex=NhlNewColor ( wks , g , g , g )

This command add the color, the rgb of which are put in argument, to the workspace
colormap. However, when drawing the contouring, the last contour will be drawn in gray
because of the newcolor added (via NhlNewColor). To avoir the contouring to use this color,
you must set
1

res@gsnSpreadColorEnd=newindex 1

To change the color in which are drawn the filled values, you must set
1

r e s @ c n M i s s i n g V a l F i l l C o l o r=newindex

Now to change the dash pattern of the negative contours and the zero line thickness:
1
2
3

res@gsnContourNegLineDashPattern=2
r e s @ g s n C o n t o u r Z e r o L i n e T h i c k n e s s F=3
r e s @ l b O r i e n t a t i o n=" V e r t i c a l "

Finally, to change the stride of the colorbar labels:


1

r e s @ l b L a b e l S t r i d e =5

However, it should be noted that contrary to Python, NCL does not automatically interpolate
the data onto a regular grid. In this case, we have many levels in the first few meters, which
will cause a stretchin of the plot at the surface. To have an identical plit, we must force NCL
to interpolate the data. This is done by adding the following resources:
1
2

r e s @ g s n X A x i s I r r e g u l a r 2 L i n e a r=True
r e s @ g s n Y A x i s I r r e g u l a r 2 L i n e a r=True

4.2.5

Homemade colormaps

Python:
It is often usefull to define our own colormap. Imagine we have a colormap that we want
to draw from svg colors (such as LightSkyBlue for example). In python, one has to use the
function ListedColormap:
1
2
3

from m a t p l o t l i b . c o l o r s i mpo rt L i s t e d C o l o r m a p
v e c t =[ g o l d , l i g h t s a l m o n , P u r p l e , o r a n g e , f i r e b r i c k , l i g h t s k y b l u e ]
cmap=L i s t e d C o l o r m a p ( v e c t )

38

20

1000
10
2000
0

3000
4000

10

5000
20
10

10

20

30

40

50

60

This however has a drawback, as one must choose the number of levels identical to the number
of colors. I suggest the use of another function, LinearSegmentedColormap(cmapname,dict,N=256).
This function permits to generate a colormap made by linear interpolation on 256 value. The
values used in the interpolation are contained in the dictionnary dict, which is as follows:
1

c d i c t = { red :

2
3

[(0.0 ,
(0.5 ,
(1.0 ,

0.0 , 0.0) ,
1.0 , 1.0) ,
1.0 , 1.0) ] ,

4
5
6
7
8

green : [ ( 0 . 0 ,
0.0 ,
(0.25 , 0.0 ,
(0.75 , 1.0 ,
(1.0 ,
1.0 ,

0.0)
0.0)
1.0)
1.0)

,
,
,
],

9
10
11
12

blue :

[(0.0 ,
(0.5 ,
(1.0 ,

0.0 , 0.0) ,
0.0 , 0.0) ,
1.0 , 1.0) ]}

The tuple contains the mapping value, the percentage of a color at the benning and at the
end (usually, the two last values are identical). In this example, described in the matplotlib
website, the colormap contains red that increases from 0 to 1 over the bottom half, the green of
which does the same over the middle half, and blue over the top half.
NCL:
In NCL, it is done exactly in the same way:
1
2

cmap=(/ " w h i t e " , " b l a c k " , " g o l d " , " LightSalmon " , " p u r p l e " , " o r a n g e " , " f i r e b r i c k " , "
l i g h t s k y b l u e " /)
gsn _def ine_c olor map ( wks , cmap )

Compared to Python, we must start the colormap with white (background color) and black
(foreground color).
Note: I have chosen here to describe the method with named svg colors, but it works exactly in the same way with N 3 arrays. Moreover, the cpt-city website (http: // soliton.
vm. bytemark. co. uk/ pub/ cpt-city/ ) contains a huge amount of colormap. Python and
NCL functions that permit to use them for filled contours can be downloaded in https: // dl.
dropboxusercontent. com/ u/ 99128427/ Site/ barriernicolas/ Python_ NCL. html (you will
39

also find examples on how to use them). The Python function also permits to deal with numpy
arrays or list of named colors

4.3

Vectors

4.3.1

First quiver plot


70
60
50
40
30
20
10

80

70

60

50

40

30

20

10

Python:
In Python, a quiver plot is done by using the quiver command:
1

q u i v e r ( l on , l a t , u , v )

The first two options are the x and y coordinates (it can be either 1D or 2D), and the two
last are the zonal and meridional components of the field.
NCL:
In NCL, you first have to define the x and y coordinates by setting the ressources:
1
2
3

r e s=True
res@vfXArray = l o n
res@vfYArray = l a t

Note that it is not the same ressources than for contour plots.
Finally, the plotting is done by:
1

p l o t=gsn_csm_vector ( wks , u , v , r e s )

4.3.2

Quiver length handling

Python:

40

70

10 m/s

60
50
40
30
20
1080

70

60

50

40

30

20

10

To change the size of the arrows in Python, you must add the scale option to the quiver
function:
1

qu=q u i v e r ( lo n , l a t , u , v , s c a l e =100)

The scale gives you the size of the array as a function of the size of the domain. In our case,
it means that the length of the array will be 1/100 the size of the domain.
Similarly to the colorbar, the legend of the quiverplot must be added to the figure. This is
done by using the quiverkey function:
1

qk = q u i v e r k e y ( qu , 75 , 7 2 , 1 0 , 10 m/ s , c o o r d i n a t e s= data )

This takes as arguments the quiverkey instance (qu), the position of the reference vector
(here, in data coordinates, ie. longitudes and latitudes), the value of the reference vector and
the corresponding string.
NCL:
In NCL, you set the length of the arrows by setting:
1
2

res@vcRefMagnitudeF
res@vcRefLengthF

= 10
= 0.07

; make v e c t o r s l a r g e r
; r e f vec l e n g t h

The first one controls the magnitude of the reference vector, the second one its length. In
NCL, the reference vector is plotted automatically. However, to control it, you must set:
1
2
3
4
5
6
7
8

res@vcRefAnnoOn = True ; F o r c e t h e a n n o t a t i o n
r e s @ v c R e f A n n o S t r i n g 1 = " 10 m/ s "
; Ann ot ati on s t r i n g
res@vcRefAnnoString2On = F a l s e ; Hide t h e r e f e r e n c e v e c t o r
a u t o m a t i c a l l y added
res@vcRefAnnoOrthogonalPosF
= 1.2 ; Y p o s i t i o n o f t h e r e f e r e n c e v e c t o r
res@vcRefAnnoParallelPosF
= 0.3 ; X p o s i t i o n of the r e f e r e n c e vector
res@vcRefAnnoPerimOn=F a l s e ; Hide t h e bar around t h e r e f e r e n c e
vector

Note that it is not the same ressources than for contour plots.
41

4.3.3

Distance between the quivers


70
60
50
40
30
20
10

80

70

60

50

40

30

20

10

Python:
Oftenly, you must skip some arrows to have a nice rendering. One way to do it in Python is
do draw only a few arrows:
1
2
3

s t l a t =3
s t l o n =3
qu=q u i v e r ( l o n [ : : s t l o n ] , l a t [ : : s t l a t ] , u [ : : s t l o n , : : s t l a t ] , v [ : : s t l o n , : : s t l a t ] , s c a l e =100)

This will draw one arrow out of 3.


NCL:
In NCL, to do the same thing is very easy. You just have to set:
1

res@vcMinDistanceF = 0 . 0 2 5

This resource controls the minimum distance to let between two consecutive arrows.

4.3.4

NCL curly vectors

One limitation with quiver plots in Python or Matlab is that they do not handle curly vectors.
One strong advantage with NCL is that it does. You just have to set the resource:
1

res@vcGlyphStyle = " CurlyVector "

In figure 4.3.1, we compare the previous figure when curly vectors are activated or not.

4.4

Panels

4.4.1

First panel plot

Python:

42

(a) Normal vectors)

(b) Curly vectors

Figure 4.3.1: Examples of quiver plots with NCL

First subplot

Subplot 1

2
1
Index

Index

1
0
1
2

Subplot
Years 3

3
19401950196019701980199020002010
3

1
Index

Index

0
1

3
19401950196019701980199020002010
3

Subplot 2

0
1

Subplot
Years 4

0
1

3
19401950196019701980199020002010

3
19401950196019701980199020002010

Years

Years

43

figure ()

2
3
4
5
6
7

ax=s u b p l o t ( 2 , 2 , 1 ) # F i r s t p a n e l
plot ( years , indexes [ 0 , : ] )
x l a b e l ( Years )
y l a b e l ( Index )
t i t l e ( Subplot 1 )

8
9
10
11
12
13

ax=s u b p l o t ( 2 , 2 , 2 ) # Second p a n e l
plot ( years , indexes [ 0 , : ] )
x l a b e l ( Years )
y l a b e l ( Index )
t i t l e ( Subplot 2 )

14
15
16
17
18
19

ax=s u b p l o t ( 2 , 2 , 3 ) # Third p a n e l
plot ( years , indexes [ 0 , : ] )
x l a b e l ( Years )
y l a b e l ( Index )
t i t l e ( Subplot 3 )

20
21
22
23
24
25

ax=s u b p l o t ( 2 , 2 , 4 ) # Four p a n e l
plot ( years , indexes [ 0 , : ] )
x l a b e l ( Years )
y l a b e l ( Index )
t i t l e ( Subplot 4 )

26
27

s u p t i t l e ( F i r s t subplot ) # Global t i t l e

To draw panel plot in Python, it is simple. You have to use the subplot function to define
your new axis. It takes as an input the number of lines, the number of column of your panel,
and the number of the panel you want to draw. It should be noted that the use of the tight
option when saving the figure erases the suptitle.
NCL:
1

wks

= gsn_open_wks ( " p d f " , " f i g / "+g e t _ s c r i p t _ p r e f i x _ n a m e ( )+" _ncl " )

2
3

p a n e l=new ( 4 , g r a p h i c ) ;

I n i t i a l i s a t i o n panel

4
5
6
7
8
9
10

; D e f i n e t h e r e s s o u r c e s o f each i n d i v i d u a l p l o t s
res
= True
res@gsnDraw=F a l s e
res@gsnFrame=F a l s e
res@tiXAxisString
= " Years "
res@tiYAxisString
= " Index "

11
12
13

res@tiMainString
= " S u b p l o t 1 " ; Change t h e t i t l e o f t h e f i g u r e
p a n e l ( 0 ) = gsn_csm_xy ( wks , y e a r s , i n d e x e s ( 0 , : ) , r e s ) ; Add t h e f i g u r e t o t h e p a n e l

14
15
16

res@tiMainString
= " Subplot 2 "
p a n e l ( 1 ) = gsn_csm_xy ( wks , y e a r s , i n d e x e s ( 0 , : ) , r e s )

17
18
19

res@tiMainString
= " Subplot 3 "
p a n e l ( 2 ) = gsn_csm_xy ( wks , y e a r s , i n d e x e s ( 0 , : ) , r e s )

20
21
22

res@tiMainString
= " Subplot 4 "
p a n e l ( 3 ) = gsn_csm_xy ( wks , y e a r s , i n d e x e s ( 0 , : ) , r e s )

23
24
25
26

r e s P=True ; R e s o u r c e f o r t h e s e t o f p a n e l s
r e s P @ t x S t r i n g=" F i r s t s u b p l o t " ; G l o b a l t i t l e
gsn_panel ( wks , p a n e l , ( / 2 , 2 / ) , r e s P ) ; Draw t h e p a n e l

NCL

44

In NCL, you have to define a new graphic instance, which will store each individual figure.
This is done in line 3. Note the resources gsnFrame and gsnDraw set to False. If they were
not, each individual figure will be drawn on a single pdf file. When you have attributed to each
case of panel the individual plots, you define the resources of the panel plot (resP). The title is
by txString resource and the panel plot is drawn with the gsn_panel panel function. It takes
as an input the workspace, the graphic instance, the panel shapes (in this case, two lines, two
columns) and the panel resources.

4.4.2

Space control
Subplot 1

First subplot

1950

1970

1990

Subplot 2

Index

Index

2010

1950

Years

2010

Subplot 4

2
1
Index

1
Index

1990

Years

Subplot 3

1970

0
1

0
1

1950

1970

1990

2010

Years

1950

1970

1990

2010

Years

Python:
As you can see in the previous figure, it is sometimes necessary to control the spacing between
the subplots. In Python, it is the subplots_adjust command which allows this.
1
2

figure ()
s u b p l o t s _ a d j u s t ( wspace = 0 . 2 , h s p a c e = 0 . 3 5 , top =1 0.07 , bottom = 0 . 0 7 , l e f t = 0 . 0 7 , r i g h t =1 0.07)

wspace is the white space along the X dimension (in percent), hspace is the white space
along the Y dimension while the four other options are the start and end coordinates along the
X and Y dimensions.
NCL:
1
2
3
4
5
6
7
8
9

r e s P=True
r e s P @ t x S t r i n g=" F i r s t s u b p l o t "
resP@gsnPanelXWhiteSpacePercent=5 ; Add 5% o f w h i t e s p a c i n g i n X d i r e c t i o n
resP@gsnPanelYWhiteSpacePercent=5 ; Add 5% o f w h i t e s p a c i n g i n Y d i r e c t i o n
r e s P @ g s n P a n e l L e f t =0.1 ; L e f t m o s t l i m i t
resP@gsnPanelRight =0.9 ; Rightmost l i m i t
resP@gsnPanelBottom =0.1 ; Lowermost l i m i t
resP@gsnPanelTop =0.9 ; Uppermost l i m i t
gsn_panel ( wks , p a n e l , ( / 2 , 2 / ) , r e s P )

45

In NCL, you must set the gsnPanel resources described above, which have exactly the same
purpose than the one described for Python.
To debug the paneling, you can set:
1

resP@gsnPanelDebug = True

This will print out the coordinates of each panel in the terminal.

4.4.3

Hand positionning
Subplot 1

Index

3
1940

1950

1960

1970

1980

1990

2000

2010

Years

Python:
Sometimes, you must place the panels yourself for a better rendering. This can be the case if
you try to subplot a time-series and a map. In Python, you must define an axes instance (when
you use plot, it implicitely creates one by using the command gca()).
1
2
3

figure ()
ax=a x e s ( [ 0 . 6 5 , 0 . 6 8 , 0 . 2 , 0 . 2 ] )
plot (x , indexes [ 0 , : ] )

It takes as an input the X and Y locations, the width and the height of the figure. When
you use any of the matplotlib command, it is drawn on the last axes instance. You can also do
this on a specific axes by doing:
1
2
3

figure ()
ax=a x e s ( [ 0 . 6 5 , 0 . 6 8 , 0 . 2 , 0 . 2 ] )
ax . p l o t ( x , i n d e x e s [ 0 , : ] )

NCL:
In NCL, the positionning of the panels is done by setting the resources
1
2
3
4

res@vpXF =0.6 ; X p o s i t i o n o f t h e l e f t p a r t o f t h e i n s i d e f i g u r e
res@vpYF =0.78 ; Y p o s i t i o n o f t h e top p a r t o f t h e i n s i d e f i g u r e
res@vpWidthF =0.15 ; Width o f t h e i n s i d e f i g u r e
res@vpHeightF =0.15 ; H e i g h t o f t h e i n s i d e f i g u r e

46

It should be notice that the vpYF resource is the location of the top of the panel, while in
Python it is the bottom of the figure.

4.4.4

Shared colormap

50

50

50

50

0 50 100 150 200 250 300 350


252.5

260.0

267.5

275.0

0 50 100 150 200 250 300 350


282.5

Common colorbar

290.0

297.5

305.0

Python:
If you want to compare two 2D fields, it might be useful to know how to define one common
colorbar.
1
2

subplot (1 ,2 ,1) # First subplot


c s 1=c o n t o u r f ( lon , l a t , t2 , 2 0 ) # F i r s t c o n t o u r f

3
4
5

s u b p l o t ( 1 , 2 , 2 ) # Second s u b p l o t
c s 2=c o n t o u r f ( lon , l a t , t2 , l e v e l s=c s 1 . l e v e l s ) # Second c o n t o u r f , same l e v e l s

6
7
8
9

cax=a x e s ( [ o f f x , 0 . 0 8 , 1 2 o f f x , 0 . 0 3 ] ) # D e f i n e a x e s f o r t h e c o l o r b a r
cb=c o l o r b a r ( cs2 , cax , o r i e n t a t i o n= h o r i z o n t a l ) # Draw h o r i z o n t a l c o l o r b a r
cb . s e t _ l a b e l ( Common c o l o r b a r ) # L a b e l c o l o r b a r

As we try to compare two fields, it is important that both contours share the same levels.
To retrive the levels of the first contours, you just have to use cs1.levels command. Then, you
must define the position in which the common colorbar will be drawn. This is done by using
the axes instance described in the previous subsection. Then, when using colorbar function, you
must specify the axes that will be used for the colorbar drawing.
NCL:
In NCL, you first have to deactivate the drawing of individual colormaps.
1

res@lbLabelBarOn = F a l s e ; Hide i n d i v i d u a l c o l o r b a r s

Then you have to set to true the Panel resource:


47

1
2

r e s P=True ; Panel r e s o u r c e s
resP@gsnPanelLabelBar = True ; F o r c e p a n e l c o l o r b a r q

4.4.5

Two colormaps

50

50

50

50
0 50 100 150 200 250 300 350
260.0

275.0

290.0

305.0

0 50 100 150 200 250 300 350


260.0

275.0

290.0

305.0

Python:
If you want to subplot two figures with different colorbar (for example to compare a mean,
and an anomaly), it is easy in Python. You draw your subplots independently, you draw the
colorbar and you are all set. However, the colorbar labels might not be visible. You thus must
hide som of the labels:
1
2
3
4
5

subplot (1 ,2 ,1)
c s 1=c o n t o u r f ( lon , l a t , t2 , 2 0 , cmap=cm . get_cmap ( RdBu_r ) ) # F i r s t c o n t o u r f
cb=c o l o r b a r ( cs1 , o r i e n t a t i o n= h o r i z o n t a l ) # Drawing o f t h e f i r s t c o l o r b a r
f o r t i n cb . ax . g e t _ x t i c k l a b e l s ( ) [ : : 2 ] : # H i d i n g o f one c o l o r b a r l a b e l out o f 2
s e t p ( t , v i s i b l e=F a l s e )

6
7
8

c s 2=c o n t o u r f ( lon , l a t , t2 , 2 0 , cmap=cm . get_cmap ( RdYlBu_r ) ) # Second c o n t o u r f


cb=c o l o r b a r ( cs2 , o r i e n t a t i o n= h o r i z o n t a l ) # Drawing o f t h e s e c o n d c o l o r b a r

NCL:
In NCL, it is far more complicated to do such a thing. Fist of all, we must merge the two
colormaps.
1

gsn_merge_colormaps ( wks , " BlueDarkRed18 " , " cmp_flux " )

This will give one big colorbar. Then you have to draw the first plot by defining the resources
gsnSpreadColorStart and gsnSpreadColorEnd to the first and last elements of the first colorbar:
1
2
3
4

r e s @ g s n S p r e a d C o l o r s=True
r e s @ g s n S p r e a d C o l o r S t a r t=2
res@gsnSpreadColorEnd =19
p a n e l ( 0 ) = gsn_csm_contour ( wks , t2 , r e s )

Then, you do exactly the same thing but after changing the values of the previous resources:
48

1
2
3

r e s @ g s n S p r e a d C o l o r S t a r t =20
res@gsnSpreadColorEnd =32
p a n e l ( 1 ) = gsn_csm_contour ( wks , t2 , r e s )

To help with the colors indexes to put, a very helpflul function is


1

gsn_draw_colormap ( wks )

which will draw the colorbar defined in the wks, with the numbers corresponding to each
color.

4.5
4.5.1

Maps
First map

50

50

50

100

150

200

250

300

350

Python:
In Earth Science, it is necessary to be aware of how to draw data on a map. In Python, you
first must import the Basemap function
1

from m p l _ t o o l k i t s . basemap i mp ort Basemap

Now the next step is to define the map object, which is done by the Basemap command.
1

m=Basemap ( l l c r n r l a t =90, l l c r n r l o n =0 , u r c r n r l a t =90 , u r c r n r l o n =360 , s u p p r e s s _ t i c k s=F a l s e )

Here we set the lower left and upper right coordinates of the map. In this case, longitudes
are from 0 to 360. The next step is to define the map coordinates (instead of longitude and
latitude coordinates) that will be used in the contouring:
1
2

l o n I , l a t I=np . m e s h g r i d ( l on , l a t )
x , y=m( l o n I , l a t I )

It should be noted that for the drawing, we must have 2D coordinates. This is done with
the numpy meshgrid function. Now, we can do contour, contourf, pcolor or quiver plots on the
map as follow:

49

m. c o n t o u r f ( x , y , t 2 )

Now, we must add the coastlines, which is done as follow.


1

m. d r a w c o a s t l i n e s ( )

NCL:
In NCL, it is very similar than to do a contourf plot. You first have to set-up the resources:
1
2
3
4
5

res@sfXArray=l o n
res@sfYArray=l a t
res@cnFillOn
= True
r e s @ g s n S p r e a d C o l o r s=True
re s@g snAd dCy cli c=F a l s e

The gsnAddCyclic is set to False because in this case, you have data that spans the entire
globe and thus need no additional cyclic point. So far, NCL will automatically draw the map
with the Atlantic in the center of the plot. However, we have data in which the Pacific is in the
center. You thus must add the ressource:
1

res@mpCenterLonF = 180

The last step is to draw the contour map. This is done with the gsn_csm_contour_map
command:
1

p l o t=gsn_csm_contour_map ( wks , t2 , r e s )

NCL automatically draws continental outlines. To hide them, you must set the resource:
1

mpOutlineOn=F a l s e

4.5.2

Grid handling
90
60
30
0
30
60
90
0

30

60

90

120 150 180 210 240 270 300 330 360

Imagine that data are masked on non-ocean grid points, and that we want to add coordinate
grids. It should be noted that the classical grid method described in the first section, as they
are working on axes objects, are not applicable here.
50

Python:
In Python, you first have to define the meridians and the parallels in which you want to add
the map grid.
1
2

mer=np . a r a n g e ( 0 , 3 6 0 + 3 0 , 3 0 )
par=np . a r a n g e ( 90 ,90+30 ,30)

Now, to effectively draw the grid, you must use the following commands
1
2

m. d r a w p a r a l l e l s ( par , d a s h e s = [ 1 0 , 5 ] )
m. d r a w m e r i d i a n s ( mer , d a s h e s = [ 1 0 , 5 ] )

The dashes options specifies the length of the lines (10) and the lines of the blanks (5) for
the grid. However, in this case, the xticks and yticks do not coincide with the grid lines. We
thus have to set
1
2

ax . s e t _ x t i c k s ( mer )
ax . s e t _ y t i c k s ( par )

Finally, to fill the continents:


1

m. f i l l c o n t i n e n t s ( )

NCL:
Here, we assume that the gray color was defined as in the previous section (newindex). The
grid handling is done with the following resources
1
2
3
4
5
6

res@mpGridAndLimbOn
= True ; Grid on
res@mpGridLineDashPattern
= 2 ; dashed g r i d
res@mpGridLatSpacingF = 30 ; M e r i d i o n a l g r i d s p a c i n g
res@mpGridLonSpacingF = 30 ; Zonal g r i d s p a c i n g
r e s @ g s n M a j o r L a t S p a c i n g =30 ; Major m e r i d i o n a l g r i d s p a c i n g
res@gsnMajorLonSpacing =30 ; M e r i d i o n a l g r i d s p a c i n g

Finally, to change the color of the land:


1

res@mpLandFillColor

4.5.3

= newindex

Shifting longitudes

In the previous maps, longitudes span 0 to 360, which implies that the map will be centered in
the Pacific. Here, we will learn how to shift the longitudes so that they span -180 to 180. We
will also learn how to limit the spatial domain.
Python:
In Python, the shifting of the grid is done by using the shiftgrid command; which must be
imported beforehand.
51

70
60
50
40
30
20
10

1
2

80

70

60

50

40

30

20

10

from m p l _ t o o l k i t s . basemap i mp ort s h i f t g r i d


t2 , l o n = s h i f t g r i d ( 1 8 0 . , t2 , l on , s t a r t=F a l s e )

The first argument is the starting longitude if start option is set to True, and the ending
longitude otherwise. It takes as an input the field to shift and the corresponding longitudes. We
have already shown previously how to limit the spatial domain of the map:
1

m=Basemap ( l l c r n r l a t =10 , l l c r n r l o n =80, u r c r n r l a t =70 , u r c r n r l o n =0 , s u p p r e s s _ t i c k s=F a l s e )

NCL:
In NCL, the switching of the longitudes is performed with the lonFlip command, the argument of which is the field assuming that it has longitudes coordinates attached to it.
1

t 2=l o n F l i p ( t 2 )

Now, the limitation of the spatial domain of the grid is done by setting the ressources:
1
2
3
4
5

res@mpLimitMode=" LatLon "


res@mpMinLatF
res@mpMaxLatF
res@mpMinLonF
res@mpMaxLonF

=
=
=
=

10
70
80
0

The first one defines how we limit the spatial domain. Here, we set Longitudes and Latitudes
limits, which is the easiest, but there are many other ways.

4.5.4

Plot Overlays

Python:
In Python, the overlay is implicitely done. The second plot is drawn on top of the first one.
For example, if we want to overlay a quiver plot on top of a contourf plot:

52

8
70

60

50

40

30

3
2

20
10

1
2
3

1
80

70

60

50

40

30

20

10

c s=m. c o n t o u r f ( x , y , ws )
qu=m. q u i v e r ( x [ : : s t l o n , : : s t l a t ] , y [ : : s t l o n , : : s t l a t ] , u [ : : s t l o n , : : s t l a t ] , v [ : : s t l o n , : : s t l a t ] ,
s c a l e =100)
colorbar ( cs )

NCL:
In NCL, overlays on a map are slightly more complicated. First, you have to set-up the
resources for the contourf plot on a map (see section ??).
1
2
3
4
5
6
7
8
9
10
11
12
13
14

resC=True
resC@mpLimitMode=" LatLon "
resC@mpMinLatF
resC@mpMaxLatF
resC@mpMinLonF
resC@mpMaxLonF
resC@gsnFrame=F a l s e
resC@gsnDraw=F a l s e
resC@sfXArray = l o n
resC@sfYArray = l a t
resC@gsnAddCyclic=F a l s e
resC@cnInfoLabelOn=F a l s e
resC@cnFillOn=True
r e s C @ g s n S p r e a d C o l o r s=True

=
=
=
=

10
70
80
0

The seconde step is to define the resources of the vector plot. Here, we do not add
resources relative to maps.
1
2
3
4
5
6
7
8
9
10
11
12

resV=True
resV@gsnFrame=F a l s e
resV@gsnDraw=F a l s e
resV@vfXArray = l o n
resV@vfYArray = l a t
resV@vcRefAnnoOn=F a l s e
resV@vcMinDistanceF
resV@vcRefMagnitudeF
resV@vcRefLengthF
resV@vcRefAnnoOn=F a l s e
resV@vcLineArrowThicknessF =
resV@vcLineArrowColor=0

= 0.022
= 10
= 0.07

; t h i n out v e c t o r s
; make v e c t o r s l a r g e r
; r e f vec l e n g t h

53

Note that in each case, the gsnFrame and gsnDraw resources are set to False. Then, you
must draw the contourf and the vector plot:
1
2

p l o t c=gsn_csm_contour_map ( wks , wspeed , r e s )


p l o t v=gsn_csm_vector ( wks , u , v , resV )

You would have notice that in the first case, we draw on a map contrary to the second case.
The last step is to overlay both figures:
1

overlay ( plotc , plotv )

This will project the plotv onto the map of the plotc vector. The next step is to draw the
contourf (and as the plotv is now attached to it, it will also be drawn) and to open a frame:
1
2

draw ( p l o t c )
frame ( wks )

4.5.5

Orthographic projection

Python:
In Python, to change the projection of the map, you must set the projection option in the
Basemap function:
1

m=Basemap ( r e s o l u t i o n= l , p r o j e c t i o n= o r t h o , lon_0=40, l a t _ 0 =0)

Moreover, you will notice that we have added two more options, which are the longitude and
the latitude at the center of the map. Now, we must fill the continents (or draw the coastlines):
1

m. f i l l c o n t i n e n t s ( c o l o r= k )

So far, the Earth is not closed, meaning that the continents seem to drift in the paper. To
close the Earth (ie. to draw the circle that will limit the Earth), you must use the drawmapboundary function:
54

m. drawmapboundary ( )

NCL:
In NCL, the choice of the projection and of the longitudes/latitudes of the center of the map
are done with the ressources:
1
2
3
4

res@mpLimitMode=" LatLon "


res@mpProjection
= " Orthographic "
res@mpCenterLonF = 40.
res@mpCenterLatF = 0 .

Now, if we want to close the Earth, we must set the following resources:
1
2
3

res@mpGridAndLimbOn
res@mpGridMaskMode
res@mpPerimOn=F a l s e

= True
= " MaskFillArea "

The first one allows to draw the circle that will close the Earth, but it will also add the Earth
Grid. The second resource allows to hide the grid and to let only the circle. Automatically, NCL
draws a box around the map, which can be hidden by the last resource. Finally, the drawing of
the map only (without contours or quivers) is done by:
1

p l o t=gsn_csm_map ( wks , r e s )

4.6
4.6.1

Text
Plot coordinates
3
2
1
0
1

Text, plot coordinates

2
3
1940

1950

1960

1970

1980

1990

2000

2010

Python:
In Python, to add text in map coordinates is pretty straigthforward. You simply need to
use the text command. If we want to add text on figure ??, you must add:
55

t e x t ( 1 9 6 0 , 2 , Text , p l o t c o o r d i n a t e s , f o n t s i z e =15 , c o l o r = r )

NCL:
In NCL, you must use the command gsn_text .
1
2
3
4

txres
= True
; t e x t mods d e s i r e d
txres@txFontHeightF = 0 . 0 3
; font smaller . default big
t x r e s @ t x F o n t C o l o r =" r e d "
g s n _ t e x t ( wks , p l o t , " Text , p l o t c o o r d i n a t e s " , 1 9 6 0 , 2 , t x r e s )

txres are the resources of the text (ie. fontsize, font color). The function takes as an input
the workspace and the plot in which the text will be added, the text its X and Y coordinates
and finally the text resources.

4.6.2

Figure coordinates
3
2
1

Text, figure coordinates

0
1
2
3
1940

1950

1960

1970

1980

1990

2000

2010

Python:
It can be usefull to add text in figure coordinates. In Python, it is done by using figtext
instead of text .
1

f i g t e x t ( 0 . 5 , 0 . 5 , Text , f i g u r e c o o r d i n a t e s , f o n t s i z e =15 , c o l o r = r )

NCL:
In NCL, you also need to use another function:
1

gsn_text_ndc ( wks , " Text , f i g u r e c o o r d i n a t e s " , 0 . 5 , 0 . 5 , t x r e s )

This command ressembles the gsn_text command, but takes as an input the coordinates of
the figure.

56

4.6.3

Text on a map

50
Text on a map

0
50
0

50

100

150

200

250

300

350

Python:
Imagine that you want to add text on the map of figure ??. Similarly with the previous example, you must use the text command. However, you first must convert the longitude/latitude
coordinates into map coordinates as follows:
1
2
3

m=Basemap ( l l c r n r l a t =90, l l c r n r l o n =0 , u r c r n r l a t =90 , u r c r n r l o n =360)


xt , y t=m( 1 8 0 , 0 )
t e x t ( xt , yt , " Text on a map " )

NCL:
In NCL, you must use another function to add text on a map, gsn_add_text.
1

t e x t=gsn_add_text ( wks , p l o t , " Text on a map " , 1 8 0 , 0 , t x r e s )

It works identically to the gsn_text command.

4.6.4

Equations
3
2
1
0
1
2
3
1940

1950

1960

1970

1980

ei
n
n =1 2

57

1990

2000

2010

Python:
You might need to add equations to a figure. In Python, it is quiete easy as it follows the
EX syntax.

LAT
1

x l a b e l ( r $ \sum_{n=1}^{\ i n f t y } \ f r a c { e^{ i \ p i }}{2^ n}$ , f o n t s i z e =20)

You notice that before writing the string, we have add a r, which force Python to use raw
strings. Its omission will raise an exception. The mathmode is opened and closed by $ signs, as
in LATEX.
Note: It should be noted that Python allows to use TEX rendering. This is done as follows:
1
2

im por t m a t p l o t l i b
m a t p l o t l i b . rcParams [ t e x t . u s e t e x ] = True

The use of TEX rendering slightly change the syntax of the equation:
1

x l a b e l ( r \ TeX\

$ \ d i s p l a y s t y l e \sum_{n=1}^{\ i n f t y } \ f r a c { e^{ i \ p i }}{2^ n}$ , f o n t s i z e =20)

Indeed, the mathmode is now opened by a $ followed by \displaystyle.


NCL:
One major limitation of NCL compared to Python is the handling of equations. Indeed,
you must place everything by hand, which can become quiete restristing. This is done by using
numerous function codes. Those are the symbols located between ::
1
2
3

res@tiXAxisString
= " : F34 : e
: H65: : V30: : Z50 : : F21 : n=1
: Z100 : : H70: : V50 : : H10 : : F18 : x : H20: : F21 : e : S : i : H10: : F8 : p :N:
: V5: : X300 : : H190: : F21 :_ : H120: : V30: : Z90 : : H10: : F21 : 2 : S : n "

This line permits to draw as best as possible the string axis. .They allow string manipulaP
tions. For example, :F34:e draw the
symbol. :H-65: offsets the following string to the left,
:V-30: offsets the following string to the top, :Z50: diminishes the size of the following string
by 50%, :F21: changes the font, :F18:x is the symbol, :S: implies that the following strings
are superscripts, :N: forces to return to normal levels, :F8:p is the symbol and finally :X300:
forces the following string widths to increase by 300%.
Obviously, the syntax in NCL is far more complicated than the syntax in Python and for a
worst rendering. I would advise not to add complicated equations to a NCL plot.

4.7

Polylines

4.7.1

Polylines on a map

Python:

58

Polylines are often usefull on a map, to draw sections for examples. In python, the plot
command permits to do it simply. The first step is to define longitude and latitude arrays that
contains the points locations of the line:
1
2
3
4
5
6

marx = [ 2 1 . 0 6 5 , 3 4 . 6 8 5 , 3 5 . 4 5 9 , 2 9 . 8 8 7 , 2 9 . ]
mary = [ 6 4 . 8 6 , 5 6 . 1 8 9 , 5 3 . 0 3 6 , 5 2 . 0 1 1 , 4 3 . ]
qdex =[ 29 , 9]
qdey = [ 4 3 , 5 2 ]
qdwx=[ 29 , 49 , 53]
qdwy = [ 4 3 , 4 2 , 4 7 ]

If m has been initialized as a basemap object,


1

m=Basemap ( l l c r n r l o n =60, l l c r n r l a t =30 , u r c r n r l o n =0 , u r c r n r l a t =80)

Then, each longitude and latitude needs to be converted into map coordinates, as done for
contouring on a map, prior the use of the plit function:
1
2
3
4
5
6

xp , yp=m( marx , mary )


m. p l o t ( xp , yp , c o l o r= r )
xp , yp=m( qdex , qdey )
m. p l o t ( xp , yp , c o l o r= g )
xp , yp=m( qdwx , qdwy )
m. p l o t ( xp , yp , c o l o r= b )

NCL:
In NCL, the philosophy is slightly different. We attach polylines object to an existing plot.
We first draw, lets say, a contour plot:
1
2
3
4

r e s=True
res@gsnFrame=F a l s e
res@gsnDraw=F a l s e
p l o t=gsn_csm_contour_map ( wks , t2 , r e s )

59

with res the resources of the contour plot. Note that gsnFrame and gsnDraw need to be set
to False in order to prevent multiplot plots (one without and one with the polylines).
Similarly with Python, we define the coordinates of the lines:
1
2
3
4
5
6

marx =(/ 21.065 , 34.685 , 35.459 , 29.887 , 29./)


mary = ( / 6 4 . 8 6 , 5 6 . 1 8 9 , 5 3 . 0 3 6 , 5 2 . 0 1 1 , 4 3 . / )
qdex =(/ 29 , 9/)
qdey = ( / 4 3 , 5 2 / )
qdwx=(/ 29 , 49 , 53/)
qdwy = ( / 4 3 , 4 2 , 4 7 / )

Then, we define the resources of the polylines and use them in the gsn_add_polyline function.
1
2

l r e s=True
lres@gsLineThicknessF = 4.0

; line thickness

3
4
5

lres@gsLineColor
= " Red "
; color of l i n e s
dum1 = g s n _ a d d _ p o l y l i n e ( wks , p l o t , marx , mary , l r e s )

6
7
8

lres@gsLineColor
= " Blue "
; color of l i n e s
dum2 = g s n _ a d d _ p o l y l i n e ( wks , p l o t , qdex , qdey , l r e s )

9
10
11

lres@gsLineColor
= " Green "
; color of l i n e s
dum3 = g s n _ a d d _ p o l y l i n e ( wks , p l o t , qdwx , qdwy , l r e s )

12
13
14

draw ( p l o t )
frame ( wks )

One limitation with NCL is the need to have different names for the attached polylines
(dum1, dum2, etc).

4.7.2

Filled polygon on a map

Python:
To show area of importance, it might be needed to draw filled polygons. In Python, this is
done thanks to matplotlib patches and artist. The first step is to import the Polygon patches:
60

from m a t p l o t l i b . p a t c h e s i mpo rt Polygon

Then, similarly with what has been done previously, we define the polygon coordinates as a
2 N array (xy), with the first dimension being the x coordinates, and the second dimension
being the y coordinates.
1
2
3
4

px =[ 21.065 , 34.685 , 35.459 , 29.887 , 29. , 29 , 9]


py = [ 6 4 . 8 6 , 5 6 . 1 8 9 , 5 3 . 0 3 6 , 5 2 . 0 1 1 , 4 3 . , 4 3 , 5 2 ]
xp , yp=m( px , py )
xy=np . t r a n s p o s e ( np . a r r a y ( [ xp , yp ] ) )

Then, we create the polygon artist:


1
2

p o l=Polygon ( xy , c l o s e d=True , f i l l =F a l s e , hatch= / , e d g e c o l o r= k , l i n e w i d t h = 0 . 0 , z o r d e r =20)


ax . a d d _ a r t i s t ( p o l )

The closed option indicates that we want closed polygones, edgecolor indicates the hatching
color, the hatch option defines the hatching pattern, the fill option specifies wether the polygons
is filled or not, the linewidth option specifies the polygon boundaries width (here, we do not
have boundaries) and zorder specifies the order of the drawing (the polygon will be the 20th
object drawn.
Finally, the artist needs to be added to the axes object. If we assume that ax=gca():
1

ax . a d d _ a r t i s t ( p o l )

NCL:
In NCL, adding polygons is much more simple and very alike adding polylines. This is done
using the gsn_add_polygon function. We first define the polygon vectors:
1
2

x =(/ 21.065 , 34.685 , 35.459 , 29.887 , 29. , 29 , 9/)


y=(/64.86 ,56.189 ,53.036 ,52.011 ,43. ,43 ,52/)

We then set the resources of the polygon plot.


1
2
3

p o l r e s=True
p o l r e s @ g s F i l l C o l o r =" Black "
p o l r e s @ g s F i l l I n d e x =2 ; change t h e h a t c h i n g p a t t e r n s

The gsFillColor and gsFillIndex set the color and fill pattern of the polygon plot, respectively.
We finally use the function to draw the polygon:
1

dum4=gsn_add_polygon ( wks , p l o t , x , y , p o l r e s )

61

S-ar putea să vă placă și