Regional precipitation analysis with Python

We want to analyze average annual precipitation data on a regional scale for the North of Peru. The dataset has 20 stations from the Peruvian desert coast, Andes and rainforest with differences in elevation and precipitation rates.

The main objective is to analyze precipitation patterns and trends by plotting them in different ways using Python.

For this task we use IPython Notebook, which you can install on your own computer or run it on the cloud from wakari.io. You can download the station data for this exercise here.

Importing the file

First, we import the files on the IPython Notebook that runs on your favorite browser. Variables are written in Spanish to differenciate them from the rest of the python commands.

In[]:%pylab inline
%cd C:\Users\Saul\Dropbox\Curso_19_Python_en_Hidrologia_v2\1_Doc\AuxData
import numpy as np
import matplotlib.pyplot as plt
datos = np.genfromtxt('DatosEstaciones.csv', delimiter=",")
datos

Out[]:
array([[ nan,nan,nan,nan,nan],
[-76.25, -10.68,4334.,nan,1052.04],
[-75.75,-9.9 ,1860.,nan, 378.],
[-76.78,-9.55,3430.,nan, 702.],
[-77.36, -10.06,3950.,nan, 755.04],
[-75.53, -10.03, 680.,nan,2424.96],
[-75.9 , -11.48,3632.,nan, 735.96],
[-77.43,-9.73,3561.,nan, 744.96],
[-76.21, -11.63,4193.,nan, 741.],
[-75.93, -11.55,3750.,nan, 567.],
[-75.13, -10.61,1050.,nan,3096.96],
[-75.3 , -11.13, 800.,nan,2007.96],
[-77.83, -10.68,46.,nan, 9.96],
[-76.38, -11.83,2379.,nan, 237.96],
[-75.95,-9.13, 669.,nan,3203.04],
[-77.51,-9.5 ,3050.,nan, 579.],
[-74.9 , -10.3 , 301.,nan,3309.],
[-77.6 ,-9.35,2760.,nan, 737.04],
[-78.05, -10.28, 100.,nan, 6.],
[-74.93,-9.86, 250.,nan,1701.96],
[-75.46, -11.78,3322.,nan, 714.]])

The first row are column names that could not be imported with a numpy array. Column names are: Longitude, Latitude, Elevation, Name, Annual Precipitation.

There is no need to fix the array to delete the unwated not-a-number “nan” since we will do array slicing on our script.

 

Plotting values separately

We will do a couple of plots to see the spatial distribution of station precipitation and station elevation.

 

Precipitation distribution

The first plot shows stations as circles scaled with their average annual precipitation. Color is uniform for all stations. The script also saves the resulting plot as a .png file.

In[]:plt.scatter(datos[:,0],datos[:,1], marker="o", s=datos[:,4])
plt.savefig('puntosconmagnitud.png')
Out[]:

Precipitation increases towards East of Peru where the big circles are located. In the Andes, stations have relative similar circles, while in the Peruvian coast, precipitation is minimal (two small dots on the right side).

 

Elevation distribution

We do a similar plot, but this time with station elevation plotted as hexagons with a colour and size scaled to the elevation.

We can see the biggest and red hexagons corresponding to stations high in the Andes. On both sides of the Andes (desert coast and rainforest) elevations are lower.

 

3D plotting to show precipitation and elevation

We have analyzed elevation and precipitation separately. We need some graphic tools or plots to have them on the same graphic. In this part, we will surf among some plot options to analyze both precipitation and elevetation on a same graphic.

 

Elevation and precipitation as dots

The next plot shows elevation as red dots and precipitation as blue dots. On the box bottom we can see a station location as grey dots.

In[]:from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
fig.set_size_inches(10,10)
ax = fig.gca(projection='3d')
este = datos[:,0]
norte = datos[:,1]
elev = datos[:,2]
precip = datos[:,4]
ax.scatter(este, norte, elev, marker='o', c='r',s=(datos[:,4]/20))
ax.scatter(este, norte, precip, marker='o', c='b',s=(datos[:,4]/20))
ax.scatter(este, norte, 0, marker='o', c='#4b4b4b',s=(datos[:,4]/20))
ax.set_zlim3d(0, 5000)
plt.show()

Out[]:

Representation of elevation and precipitation is possible on this 3D plot. In a “user oriented” approach we need a more “friendly” and “talkative” plot.

We will do a similar plot, but this time we will use columns instead of dots. We will have two columns next to each other, one red for elevation and another blue for precipitation.

In[]:from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
fig.set_size_inches(10,10)
ax = fig.gca(projection='3d')
este = datos[:,0]
norte = datos[:,1]
datum = np.zeros(este.size)
elev = datos[:,2]
precip = datos[:,4]
ax.bar3d(datos[:,0]-0.1,datos[:,1]-0.1,datum, .1, .1, datos[:,2], color='r', alpha=0.5)
ax.bar3d(datos[:,0],datos[:,1],datum, .1, .1, datos[:,4], color='b',alpha=0.5)
ax.set_xlabel('Este')
ax.set_ylabel('Norte')
ax.set_zlabel('Elevacion / Precipitacion')
ax.set_zlim3d(0, 5000)
plt.show()

Out[]:

Interpolation and 3D grid plotting

Instead of using discrete values, we will interpolate precipitation to have a distributed precipitation. Scipy has the interpolate.griddata module that is suitable for this exercise. At the end of the script, we show the interpolated grid.

In[]: from scipy import interpolate
%pylab inline
#generamos parametros para la grilla
delta=0.25
este_r = np.arange(-78.5,-74.5,delta)
norte_r = np.arange(-12.0,-9.0,delta)
este_g,norte_r = np.meshgrid(este_r,norte_r)
#generamos la grilla regular
X,Y =np.meshgrid(np.linspace(-78.5,-74.5,100), np.linspace(-12,-8,100))
#realizamos la interpolación
grid_datos = interpolate.griddata((datos[1:,0],datos[1:,1]),
datos[1:,4],(X,Y)
,method='cubic')
clf()
contourf(X,Y,grid_datos,8,cmap='Blues')
colorbar()
scatter(datos[:,0],datos[:,1])
xlim(np.min(datos[1:,0]),np.max(datos[1:,0]))
ylim(np.min(datos[1:,1]),np.max(datos[1:,1]))

Out[]:

We can show the interpolated precipitation as contours with labels.

In[]:clabel(contour(X,Y,grid_datos,8,cmap='Blues'),fmt='%r')
scatter(datos[:,0],datos[:,1])
xlim(np.min(datos[1:,0]),np.max(datos[1:,0]))
ylim(np.min(datos[1:,1]),np.max(datos[1:,1]))

Out[]:

Finally, we can 3D plot the interpolated grid and have a fancy projection on each axis.

In[]:from mpl_toolkits.mplot3d import Axes3D
%pylab inline
fig = figure()
ax = Axes3D(fig)
cset = ax.contourf(X, Y, grid_datos, zdir='z',
 offset=-500, cmap=cm.coolwarm)
cset = ax.contourf(X, Y, grid_datos, zdir='x',
 offset=-78.5, cmap=cm.coolwarm)
ax.plot_surface(X,Y,grid_datos,rstride=8,
cstride=8,alpha=0.3,
linewidth=0.1, antialiased=True)
Out[]:

Saul Montoya

Saul Montoya es Ingeniero Civil graduado de la Pontificia Universidad Católica del Perú en Lima con estudios de postgrado en Manejo e Ingeniería de Recursos Hídricos (Programa WAREM) de la Universidad de Stuttgart con mención en Ingeniería de Aguas Subterráneas y Hidroinformática.

Smiley face

Subscribe to our free e-newsletter for tutorials, articles, webminars, courses and more.