Linear Regression across time for Lat Lon Map

Author: Abdullah A. Fahad (a.fahad@nasa.gov)

In [ ]:
import xarray as xr
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.pyplot as plt
In [ ]:
!pip install cartopy
import cartopy.crs as ccrs
In [ ]:
!wget https://downloads.psl.noaa.gov/Datasets/noaa.oisst.v2.highres/sst.mon.mean.nc
In [ ]:
# Read the data using xarray
ds = xr.open_dataset('/content/sst.mon.mean.nc').sel(time=slice('1982','2022'))

#ds = xr.decode_cf(ds, use_cftime=True) # Ignore this line. It is only needed if time coordinates are given in floating data and you need to convert it to cftime format
ds
Out[ ]:
<xarray.Dataset>
Dimensions:  (time: 492, lat: 720, lon: 1440)
Coordinates:
  * time     (time) datetime64[ns] 1982-01-01 1982-02-01 ... 2022-12-01
  * lat      (lat) float32 -89.88 -89.62 -89.38 -89.12 ... 89.38 89.62 89.88
  * lon      (lon) float32 0.125 0.375 0.625 0.875 ... 359.1 359.4 359.6 359.9
Data variables:
    sst      (time, lat, lon) float32 ...
Attributes:
    Conventions:    CF-1.5
    title:          NOAA/NCEI 1/4 Degree Daily Optimum Interpolation Sea Surf...
    institution:    NOAA/National Centers for Environmental Information
    source:         NOAA/NCEI https://www.ncei.noaa.gov/data/sea-surface-temp...
    References:     https://www.psl.noaa.gov/data/gridded/data.noaa.oisst.v2....
    dataset_title:  NOAA Daily Optimum Interpolation Sea Surface Temperature
    version:        Version 2.1
    comment:        Reynolds, et al.(2007) Daily High-Resolution-Blended Anal...
In [ ]:
# converting the data to numpy array
lon=ds.lon.data
lat=ds.lat.data
time=ds.time.data
nlon=len(lon); nlat=len(lat); nt=len(time)
sst=ds.sst.data
sst.shape
Out[ ]:
(492, 720, 1440)
In [ ]:
nmonth=12
nyear=nt//nmonth
year=np.arange(1982,2022+1)
In [ ]:
#reshaping data to year, mon, lat, lon
sst=np.reshape(sst,(nyear,nmonth,nlat,nlon))
sst.shape
Out[ ]:
(41, 12, 720, 1440)
In [ ]:
#making annual mean data by taking average ver the month dimension
sst_annual=np.nanmean(sst,1)
sst_annual.shape
<ipython-input-25-7dbb5e229cc7>:2: RuntimeWarning: Mean of empty slice
  sst_annual=np.nanmean(sst,1)
Out[ ]:
(41, 720, 1440)
In [ ]:
#plotting Climatology of Annual mean SST

plt.figure(figsize=(10, 6))
plt.contourf(lon, lat, np.nanmean(sst_annual,0),cmap='YlOrRd')
plt.colorbar(label='SST')
plt.title('Sea Surface Temperature')
plt.xlabel('Longitude')
plt.ylabel('Latitude')
plt.show()
<ipython-input-27-a48716cadc65>:4: RuntimeWarning: Mean of empty slice
  plt.contourf(lon, lat, np.nanmean(sst_annual,0),cmap='YlOrRd')
In [ ]:
## function for linear regression
from scipy import stats
from numpy import *
def l_trend(var,lon,lat,time,sig=False):
    nlon=len(lon)
    nlat=len(lat)
    nt=len(time)
    vart=zeros(nlat*nlon)
    varp=zeros(nlat*nlon)

    if len(var.shape)== 3:
        var=reshape(var,(nt,nlat*nlon))
        print('l_trend: assuming variable as 3D [time,lat,lon]')
        for i in range(nlat*nlon):
            v=var[:,i]
            vart[i], intercept, r_value, varp[i], std_err=stats.linregress(time,v)

        vart=reshape(vart,(nlat,nlon))
        varp=reshape(varp,(nlat,nlon))
        #return (vart,varp)

    else:
        raise ValueError('Variable shape is not 2D or 3D. plese instert variable in this format var[time,lat,lon] or var[time,lon*lat]')

    if sig==False:
        return (vart, varp)
    else:
        for i in range(nlat):
            for j in range (nlon):
                if varp[i,j]>sig:
                  vart[i,j]=nan
        return (vart, varp)
In [ ]:
## calculating SST linear trend and their pvalues

SST_trend, SST_pvalue=l_trend(sst_annual, lon, lat, time=year)
l_trend: assuming variable as 3D [time,lat,lon]
In [ ]:
#plotting SST annual mean 41 years of trend, stippling pvalue where it is significant at 95%

plt.figure(figsize=(10, 6))
plt.contourf(lon,lat,SST_pvalue,[0,0.05],colors='none',hatches='...')
plt.contourf(lon, lat, SST_trend*41,cmap='coolwarm',levels=np.arange(-2,2.1,.25),extend='both',alpha=.85)
plt.colorbar(label='degree C')
plt.title('Sea Surface Temperature Trend per 41 years')
plt.xlabel('Longitude')
plt.ylabel('Latitude')
plt.show()
In [ ]: