This Version 3.0 is authored by Briana Ramirez, edited by Samuel Shen. Liu Yang, Sandra Villamar, and Joaquin Stawsky contributed codes to this version.
Video tutorial for the python code can be found at the following URL: https://www.youtube.com/channel/UC7D9i0kBMzPTHyEhU0h6W9g
This version is based upon the previous version described in the following box.
######################################################################################################################
#This Python Code for Climate Science is written for the book entitled "Climate Mathematics: Theory and Applications"#
#A Cambridge University Press book authored by SSP Shen and RCJ Somerville in July 2019 #
#The Python codes were based on the R codes written by Samuel Shen Distinguished Professor, #
#San Diego State University, USA and were translated from R by Louis Selstad, Stephen Shen, #
#Gregori Clarke, and Dakota Newmann and edited by Samuel Shen. #
######################################################################################################################
#FIRST TIME Python users*****
#These package need to be installed (on the terminal or anaconda interface) before importing them below.
#Follow this tutorial for package installation before
# https://towardsdatascience.com/importerror-no-module-named-xyz-45e4a5339e1b
#Change your file path to the folder where your downloaded data is stored
#MAC HELP: https://support.apple.com/guide/mac-help/go-directly-to-a-specific-folder-on-mac-mchlp1236/mac
#PC HELP: https://www.sony.com/electronics/support/articles/00015251
import os
# os.chdir("/Users/sshen/climmath/data")
os.chdir('/Users/HP/Documents/sshen/climmath/data')
%%javascript
IPython.OutputArea.prototype._should_scroll = function(lines) {
return false;
}
#Style Dictionary to standardize plotting scheme between different python scripts
import matplotlib.pyplot as plt
styledict = {'xtick.labelsize':20,
'xtick.major.size':9,
'xtick.major.width':1,
'ytick.labelsize':20,
'ytick.major.size':9,
'ytick.major.width':1,
'legend.framealpha':0.0,
'legend.fontsize':15,
'axes.labelsize':20,
'axes.titlesize':25,
'axes.linewidth':2,
'figure.figsize':(12,8),
'savefig.format':'jpg'}
plt.rcParams.update(**styledict)
#Function that creates personalized discrete Colormap
import numpy as np
from matplotlib import cm as cm1
from matplotlib.colors import ListedColormap, to_rgba
def newColMap(colors):
"""
This function creates a new color map from a list of colors given
as a parameter. Recommended length of list of colors is at least 6.
"""
first = np.repeat([to_rgba(colors[0])], 2, axis = 0)
last = np.repeat([to_rgba(colors[-1])], 2, axis = 0)
v = cm1.get_cmap('viridis', 16*(len(colors)-2))
newcolors = v(np.linspace(0, 1, 16*(len(colors)-2)))
for (i, col) in enumerate(colors[1:-1]):
newcolors[16*i : 16*(i+1), :] = to_rgba(col)
return ListedColormap(np.append(np.append(first,newcolors, axis=0), last, axis=0))
import numpy as np
import pandas as pd
import warnings
import os
import plotly.express as px
import sympy as sm
import math as m
import netCDF4 as nc
# import cartopy
# import cartopy.crs as ccrs
# import cartopy.feature as cfeature
# from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
import matplotlib
from matplotlib import cm as cm1
from matplotlib import pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
from matplotlib.patches import Polygon
from matplotlib import animation as animation
from matplotlib.animation import ArtistAnimation
from mpl_toolkits.basemap import Basemap, cm, shiftgrid, addcyclic
from datetime import datetime
from scipy import optimize as opt
from scipy.ndimage import gaussian_filter
import time
warnings.filterwarnings("ignore")
Two Different Time Series on the Same Plot
#Set up Variables
time = np.arange(2001,2011)
Tmean = np.array([12.06, 11.78, 11.81, 11.72, 12.02,
12.36, 12.03, 11.27, 11.33, 11.66])
Prec = np.array([737.11, 737.87, 774.95, 844.55, 764.03,
757.43, 741.17, 793.50, 820.42, 796.80])
#Fig 9.1
# set up figure
fig, ax = plt.subplots(1,1,figsize=(12, 8))
# plot data
ax.plot(time, Tmean, 'o-r', label="$T_{mean}$")
# set labels
ax.set_ylabel("$T_{mean}$ [$\degree$C]", size=18)
ax.set_xlabel("Year", size=18)
ax.set_title("Contiguous U.S. Annual Mean Temperature and Total Precipitation", size=18, fontweight="bold")
ax.grid()
plt.yticks(rotation=90, size=18)
plt.xticks(size=18)
# creates twin axis
ax1 = ax.twinx()
# plot of twin axis
ax1.plot(time, Prec, 'o-b', label="Precipitation")
ax1.set_ylabel("Precipitation [mm]")
plt.yticks(rotation=90, size=18)
# create legend
hand1, lab1 = ax.get_legend_handles_labels()
hand2, lab2 = ax1.get_legend_handles_labels()
ax.legend(handles=hand1+hand2, labels=lab1+lab2,
loc='upper left', prop={'size': 20});
ax1.tick_params(direction='out')
ax.tick_params(direction='out')
# show plot
plt.show()
Figure Setups: Margins, Fonts, Mathematical Symbols, and More
#Fig 9.2
x = 0.25*np.arange(-30, 31)
# find constraint on variables
yPositive = np.where(np.sin(x) > 0)[0]
yNegative = np.where(np.sin(x) < 0)[0]
# set up figure
fig, ax = plt.subplots(figsize=(14,8))
plt.rcParams['hatch.color'] = 'blue'
# create bar plot
ax.bar(x[yPositive], np.sin(x[yPositive]), width=.1, color='red')
ax.bar(x[yNegative], np.sin(x[yNegative]), hatch='.', fc='white', color="blue")
# add annotations
ax.text(-5, .7, "$Sine\ Waves$", size=75, color='green')
ax.set_xlabel(r"Angle in Radians: $\theta - \phi_0$", color='red',
labelpad=-75)
ax.set_xticks([2*i for i in range(-3, 4)])
ax.set_xlim(x.min(), x.max())
ax.set_ylabel(r"$y = \sin(\theta - \hat{\phi})$", color='blue')
ax.set_yticks([-1., 0., .5, 1.])
ax.spines['bottom'].set_position(('data',-1.4))
ax.spines['bottom'].set_bounds(-6,6)
# twin axis
ax1 = ax.twinx()
# plot on twin axis
ax1.plot(x, np.sin(x), alpha=0)
# set labels
ax1.set_yticks([-1., -.5, 0., .5, 1.])
ax1.set_yticklabels(['A', 'B', 'C', 'D', 'E'])
ax1.tick_params(width=1, length=9)
fig.text(0.28,.95,"Text outside of the figure on side 3", size=25, fontweight="bold")
# show plot
fig.show()
#Fig 9.3
#Illustrating how to adjust font size, axis labels space, and margins.
# create Random Variable
randVals = np.random.standard_normal(200)
x = np.linspace(0, 10, randVals.size)
# set up Figure
fig, ax = plt.subplots(1, figsize=(12,8))
fig.suptitle("Normal Random Values", fontsize=25, y=.93)
# plot data
ax.scatter(x, randVals, alpha=1, facecolors='none', edgecolors='k')
# add plot labels
ax.set_title("Subtitle: 200 Random Values", y=-.2, fontsize=20)
ax.set_ylabel("Random Values")
plt.yticks(rotation=90)
ax.set_yticks([i for i in range(-2, 3)])
ax.set_xlabel("Time")
# show plot and grid
plt.grid()
fig.show()
# read in data
NOAATemp = np.loadtxt("aravg.ann.land_ocean.90S.90N.v4.0.1.2016.txt",skiprows=0)
# set up variables
x=NOAATemp[:,0]
y=NOAATemp[:,1]
z = [-99] * x.size
def forz(z,y):
for i in range(2,134):
rslt = [(y[i-2],y[i-1],y[i],y[i+1],y[i+2])]
z[i] = np.mean(rslt)
return z
zz = forz(z,y)
def n1func():
n1 = []
for i in range(0,137):
if y[i] >= 0:
n1.append(i)
return n1
def n2func():
n2 = []
for i in range(0,137):
if y[i] < 0:
n2.append(i)
return n2
n1 = n1func()
n2 = n2func()
x1= x[n1]
y1= y[n1]
x2 = x[n2]
y2 = y[n2]
x3 = x[2:134]
y3 = z[2:134]
#Fig 9.4
# fancy plot of the NOAAGlobalTemp time series
plt.bar(x1,y1,color='r', width=0.5)
plt.bar(x2,y2,color='b', width=0.5)
plt.plot(x3,y3,color='k')
plt.xlim(1877,2020)
plt.xlabel('Time')
plt.ylabel('Temperature [$\degree$C]')
plt.title('NOAA Global Average Annual Mean Temperature Anomalies', fontweight="bold", size=20)
plt.grid()
plt.show()
#Fig 9.5
# Contiguous United States (a) annual mean temperature and (b) annual total precipitation
# plot the US temp and prec time series on the same figure
fig, ax = plt.subplots(2,1, figsize=(10,8))
# add additional axis
ax[0].axes.get_xaxis().set_visible(False)
# plot first subplot data
ax[0].plot(time, Tmean, 'ro-', alpha=.6, label="(a)")
ax[0].set_yticks([11.4, np.mean([11.4, 11.8]), 11.8
, np.mean([11.8, 12.2]), 12.2])
ax[0].set_yticklabels([11.4, None, 11.8, None, 12.2])
ax[0].set_ylabel("$T_{mean}$ [$\degree$C]")
ax[0].text(2004,12.0,"US Annual Mean Temperature"
, fontsize = "xx-large", fontweight="bold")
ax[0].text(2001,12.3,"(a)", size=18)
# plot second subplot data
ax[1].plot(time, Prec, 'bo-', alpha=.6, label="(b)")
ax[1].text(2004,810,"US Annual Total Precipitation"
, fontsize = "xx-large", fontweight="bold")
plt.ylabel("Precipitation [mm]")
ax[1].set_yticks([740, 760, 780, 800, 820, 840])
ax[1].set_yticklabels([740, None, 780, None, 820, None])
#set labels
plt.text(2001,840,"(b)", size=18)
# ensures no overlap in plots
fig.tight_layout(pad=-1.5)
# show plot
fig.show()
Basic Principals for a Python Contour Plot
#9.2.1
# set up variables
x, y = np.linspace(-1, 1, 25), np.linspace(-1, 1, 25)
z = np.random.standard_normal(size=(25,25))
# set up figure
fig, ax = plt.subplots(1,figsize=(12,12))
# plot contour plot
mymap = ax.contourf(x,y,z, cmap=cm1.get_cmap('jet'))
# create and set labels
ticklabs = [-1., None, -.5, None, 0., None, .5, None, 1.]
ax.set_yticklabels(ticklabs)
ax.set_xticklabels(ticklabs)
ax.set_ylabel("$y$")
ax.set_xlabel("$x$")
ax.set_title("Filled Contour Plot of Normal Random Values", size = 22)
fig.colorbar(mymap)
# show plot
fig.show()
Plot Contour Color Maps for Random Values on a Map
#Fig 9.6
# plot a 5-by-5 grid of global map of standard normal random values
# set up variables
lat = np.linspace(-90, 90, 37)
lon = np.linspace(0, 359.9, 72)
# create data to be plotted
mapdat = np.reshape(np.random.normal(loc=0.,size=72*37),(37,72))
##
plt.figure(figsize=(14., 7.))
#using the basemap package to put the cylindrical projection map into the image
ReAn = Basemap(projection='cyl',llcrnrlat=-90.,urcrnrlat=90.,\
llcrnrlon=-180.,urcrnrlon=180.,resolution='c')
#shifting the data because
lons, data = ReAn.shiftdata(lon, datain = mapdat, lon_0=0)
#draw coastlines, latitudes, and longitudes on the map
ReAn.drawcoastlines(color='black', linewidth=1)
ReAn.drawparallels(np.arange(-90.,91.,30.), labels = [1,0,0,1])
ReAn.drawmeridians(np.arange(-180.,181.,60.), labels= [1,0,0,1])
ReAn.drawcountries()
# create desired Colormap
colors = ["darkred","firebrick","firebrick","indianred","lightcoral","lightcoral","lightpink"
,"bisque","moccasin","yellow","yellow","greenyellow","yellowgreen","limegreen","limegreen"
,"mediumspringgreen","palegreen","honeydew","lavender","mediumpurple",
"blueviolet","blueviolet","mediumorchid","mediumvioletred","darkmagenta","indigo","black"]
colors.reverse()
myColMap = newColMap(colors)
limit = np.linspace(-3.,3.,81)
ReAn_plt = plt.contourf(np.array(lons),np.array(lat),data,limit,cmap = myColMap)
ceb = plt.colorbar(ReAn_plt, shrink = 0.82)
ceb.set_ticks([i for i in range(-3, 4)])
plt.xlabel('Longitude',labelpad = 30)
plt.ylabel('Latitude',labelpad =30)
plt.title('Standard Normal Random Values')
plt.show()
##