Radial plots for exploratory analysis of climate data with Python and Matplotlib - Tutorial
/On the development of hydrological evaluations, there is a need to assess which weather stations will be used for the numerical modeling stage. The main acceptance criteria would be the amount of climate variables and records available however huge areas could have docens or hundreds of stations delivered in one text file. This tutorial shows the procedure to plot climate variable records from a single text file on a polar plot with aperture angle related to value statistics. The tutorial is done with standar Python packages as Matplotlib, Numpy and Pandas.
Interactive visualization
Tutorial
Code
This is the Python code:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
#open the csv
climateData = pd.read_csv('../Data/2805958.csv',parse_dates=True,index_col=1)
#description of variables
climateData.describe()
C:\Users\saulm\miniconda3\lib\site-packages\IPython\core\interactiveshell.py:3441: DtypeWarning: Columns (15) have mixed types.Specify dtype option on import or set low_memory=False.
exec(code_obj, self.user_global_ns, self.user_ns)
LATITUDE | LONGITUDE | ELEVATION | AWND | PRCP | TMAX | TMIN | TSUN | |
---|---|---|---|---|---|---|---|---|
count | 53094.000000 | 53094.000000 | 53094.000000 | 7198.000000 | 52218.000000 | 24791.000000 | 24757.000000 | 889.0 |
mean | 26.157937 | -81.729122 | 9.599311 | 3.318394 | 4.121282 | 29.018071 | 19.001474 | 0.0 |
std | 0.104336 | 0.041891 | 34.862054 | 1.188413 | 11.728384 | 4.190826 | 5.239559 | 0.0 |
min | 25.949100 | -81.816683 | 1.200000 | 0.600000 | 0.000000 | 5.000000 | -2.200000 | 0.0 |
25% | 26.128961 | -81.763369 | 2.700000 | 2.500000 | 0.000000 | 26.700000 | 15.600000 | 0.0 |
50% | 26.165300 | -81.722053 | 4.300000 | 3.100000 | 0.000000 | 30.000000 | 20.600000 | 0.0 |
75% | 26.235972 | -81.689149 | 12.200000 | 4.000000 | 1.500000 | 32.200000 | 23.300000 | 0.0 |
max | 26.375011 | -81.624320 | 388.900000 | 15.200000 | 245.900000 | 36.700000 | 34.400000 | 0.0 |
Main climate variables
AWND = Average daily wind speed (meters per second or miles per hour as per user preference)
PRCP = Precipitation (mm or inches as per user preference, inches to hundredths on Daily Form pdf file)
TMAX = Maximum temperature (Fahrenheit or Celsius as per user preference, Fahrenheit to tenths on
Daily Form pdf file
TMIN = Minimum temperature (Fahrenheit or Celsius as per user preference, Fahrenheit to tenths on
Daily Form pdf file
TSUN = Daily total sunshine (minutes).
#show stations
weatherStations = pd.unique(climateData.index)
print(weatherStations)
['NAPLES 5.7 SE, FL US' 'NAPLES 1.3 NW, FL US' 'NAPLES 1.3 SE, FL US'
'NAPLES 8.7 SE, FL US' 'NORTH NAPLES 5.1 NE, FL US'
'NAPLES 7.4 NNE, FL US' 'NAPLES 11.8 ENE, FL US'
'BONITA SPRINGS 3.1 NW, FL US' 'NAPLES PARK 3.7 ENE, FL US'
'COLLIER 14.1 NE, FL US' 'NAPLES, FL US'
'NAPLES MUNICIPAL AIRPORT, FL US' 'NAPLES 9.0 NE, FL US'
'MARCO ISLAND 6.6 NNE, FL US' 'GOLDEN GATE 2.2 SW, FL US'
'NAPLES 3.6 N, FL US' 'NORTH NAPLES 7.3 E, FL US'
'NAPLES 12.5 N NUMBER 9 NORTH, FL US'
'NAPLES 11.7 N NUMBER 17 NORTH, FL US' 'EAST NAPLES 0.9 NE, FL US'
'NAPLES 11.0 N CLUBHOUSE, FL US' 'NAPLES 11.9 SSE, FL US'
'NAPLES MANOR 2.3 E, FL US' 'NORTH NAPLES 4.8 NNE, FL US'
'NAPLES 6.7 NE, FL US' 'NAPLES 1.4 NNW, FL US'
'NAPLES 12.0 N NUMBER 2 SOUTH, FL US' 'PALM RIVER 3.9 E, FL US'
'NAPLES 11.5 N NUMBER 17 SOUTH, FL US' 'NAPLES 0.7 SSW, FL US'
'MARCO ISLAND, FL US']
#list of parameters to plot
paramValues = ['AWND','PRCP','TMAX','TMIN','TSUN']
N = len(paramValues)
#analysis of record distribution for one station
stationName = 'MARCO ISLAND, FL US'
stationDf = climateData.loc[stationName]
#get number of windspeed, precipitation, tmax, tmin, tsun
paramArray = stationDf[paramValues].count().values
#get the standard deviation
stdArray = stationDf[paramValues].std().values
#replace nan by 0
stdArray = np.nan_to_num(stdArray)
print(paramArray)
print(stdArray)
[ 0 7118 7106 7106 0]
[ 0. 12.15939423 4.38560156 5.36778437 0. ]
#example of polar plot
theta = np.linspace(0.0, 2 * np.pi, N, endpoint=False)
radii = paramArray
ax = plt.subplot(projection='polar')
ax.bar(theta, radii)
plt.show()
# Improved plot for record amounts
theta = np.linspace(0.0, 2 * np.pi, N, endpoint=False)
radii = paramArray
width = stdArray * np.pi / 180
colors = plt.cm.viridis(radii / 10.)
ax = plt.subplot(projection='polar')
for index, value in enumerate(paramValues):
ax.bar(theta[index], radii[index], width=width[index], label=value)
ax.legend(loc='lower left', bbox_to_anchor=(1.0, 0))
ax.set_title(stationName)
ax.set_ylim(0,climateData.count()[0])
plt.gcf().set_size_inches(15, 8)
plt.show()
#create plot function
def plotRecords(stationName,yMax):
stationDf = climateData.loc[stationName]
#get number of windspeed, precipitation, tmax, tmin, tsun
paramArray = stationDf[paramValues].count().values
#get the standard deviation
stdArray = stationDf[paramValues].std().values
#replace nan by 0
stdArray = np.nan_to_num(stdArray)
theta = np.linspace(0.0, 2 * np.pi, N, endpoint=False)
radii = paramArray
width = stdArray * np.pi / 180
colors = plt.cm.viridis(radii / 10.)
ax = plt.subplot(projection='polar')
for index, value in enumerate(paramValues):
ax.bar(theta[index], radii[index], width=width[index], label=value)
ax.legend(loc='lower left', bbox_to_anchor=(1.0, 0))
ax.set_title(stationName)
ax.set_ylim(0,yMax)
plt.gcf().set_size_inches(15, 8)
plt.show()
plotRecords('MARCO ISLAND, FL US',10000)
import ipywidgets as widgets
from ipywidgets import interact
def interactivePlot(index, yMax):
plotRecords(weatherStations[index], yMax)
interact(interactivePlot, index=(0,weatherStations.shape[0]-1), yMax=(0,5000,200))
interactive(children=(IntSlider(value=15, description='index', max=30), IntSlider(value=2400, description='yMa…
<function __main__.interactivePlot(index, yMax)>
Input data
You can download the input data from this link.