Climate, oceans and data¶

Author: Dr. Chelle Gentemann.

This notebook accompanies a lecture for Berkeley's Data 100 that covers the fundamental physical mechanisms behind global warming and analyzes CO2 and ocean temperature data.

The original resides in this github repository, this is a copy kept as part of the class materials.

Copyright (c) 2021 Chelle Gentemann, MIT Licensed.

In [1]:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

# Small style adjustments for more readable plots
plt.style.use("seaborn-whitegrid")
plt.rcParams["figure.figsize"] = (8, 6)
plt.rcParams["font.size"] = 14

Calculate E$_{in}$ = E$_{out}$¶

In [2]:
# Solve for T (slide 15)
Ω = 1372  # W/m2 incoming solar
σ = 5.67e-8  # stephan boltzman constant W/m2/K4
A = 0.3
T = ((Ω * (1 - A)) / (4 * σ)) ** 0.25
print("Temperature =", "%.2f" % T, "K")
Temperature = 255.10 K

calculate greenhouse effect¶

  • bonus points for greek letters
  • to get a sigma type '\sigma' then hit tab
In [3]:
# standard values
Ω = 1372  # W/m2 incoming solar
σ = 5.67e-8  # stephan boltzman constant W/m2/K4
T = 288  # temperature K
E = (T ** 4) * σ - (Ω * (1 - A)) / 4
print("greenhouse effect:", "%.2f" % E, "W m-2")
greenhouse effect: 149.98 W m-2

Experiment¶

  • Solve for the temperature, so that you can see how changes in albedo and greenhouse effect impact T
In [4]:
# Solve for T, including the greenhouse effect
Tnew = (((Ω * (1 - A)) / 4 + E) / σ) ** 0.25
print("temperature =", Tnew, "K")
temperature = 288.0 K

calculate what a change in the greenhouse effect does to temperature¶

  • what if you increase E by 10%
In [5]:
Enew = E * 1.1
Tnew = (((Ω * (1 - 0.3)) / 4 + Enew) / σ) ** 0.25
print("temperature =", "%.2f" % Tnew)
print(
    "10% increase in E leads to ",
    "%.2f" % (Tnew - T),
    " degree K increase in temperature",
)
print(
    "10% increase in E leads to ",
    "%.2f" % (100 * ((Tnew - T) / T)),
    "% increase in temperature",
)
temperature = 290.73
10% increase in E leads to  2.73  degree K increase in temperature
10% increase in E leads to  0.95 % increase in temperature
In [9]:
# read in data and print some

from pathlib import Path

DATA_DIR = Path.home() / "shared/climate-data"

monthly_2deg_path = DATA_DIR / "era5_monthly_2deg_aws_v20210920.nc"

file = DATA_DIR / "monthly_in_situ_co2_mlo_cleaned.csv"
data = pd.read_csv(file)
data.head()
Out[9]:
year month date_index fraction_date c02 data_adjusted_season data_fit data_adjusted_seasonally_fit data_filled data_adjusted_seasonally_filed
0 1958 1 21200 1958.0411 -99.99 -99.99 -99.99 -99.99 -99.99 -99.99
1 1958 2 21231 1958.1260 -99.99 -99.99 -99.99 -99.99 -99.99 -99.99
2 1958 3 21259 1958.2027 315.70 314.43 316.19 314.90 315.70 314.43
3 1958 4 21290 1958.2877 317.45 315.16 317.30 314.98 317.45 315.16
4 1958 5 21320 1958.3699 317.51 314.71 317.86 315.06 317.51 314.71
In [10]:
# plot the CO2, note the -99 values you see above showing up in the plot
plt.plot(data["fraction_date"], data["c02"]);
In [11]:
# get rid of missing values that are set to -99.99
file = DATA_DIR / "monthly_in_situ_co2_mlo_cleaned.csv"
data = pd.read_csv(file, na_values=-99.99)
data.head()
Out[11]:
year month date_index fraction_date c02 data_adjusted_season data_fit data_adjusted_seasonally_fit data_filled data_adjusted_seasonally_filed
0 1958 1 21200 1958.0411 NaN NaN NaN NaN NaN NaN
1 1958 2 21231 1958.1260 NaN NaN NaN NaN NaN NaN
2 1958 3 21259 1958.2027 315.70 314.43 316.19 314.90 315.70 314.43
3 1958 4 21290 1958.2877 317.45 315.16 317.30 314.98 317.45 315.16
4 1958 5 21320 1958.3699 317.51 314.71 317.86 315.06 317.51 314.71
In [12]:
# plot the data again
plt.plot(data["fraction_date"], data["c02"]);
In [13]:
# use the CO2 in the equation given in class to calculate the greenhouse effect
# then calculate the increase in temperature in deg C rather than K
E = 133.26 + 0.044 * data["c02"]
# calculate new temperature
data["Tnew"] = (((Ω * (1 - 0.3)) / 4 + E) / σ) ** 0.25
plt.plot(data["fraction_date"], (data["Tnew"] - 273.15) * 9 / 5 + 32)
plt.xlabel("Year"), plt.ylabel("Temperature (C)");
In [14]:
# explore the different data provided in the dataset, what are they?
# can you guess from the names and explain how they were calulated?
# can you re-calculate them? can you re-make the figure in the talk?
plt.plot(data["fraction_date"], data["data_filled"], "r.")
plt.plot(data["fraction_date"], data["data_adjusted_seasonally_fit"])
plt.ylabel("CO2 fraction in dry air (ppm)"), plt.xlabel("Year");
In [15]:
# calculate the annual cycle using groupby
annual = data.groupby(data.month).mean()
annual.head()
Out[15]:
year date_index fraction_date c02 data_adjusted_season data_fit data_adjusted_seasonally_fit data_filled data_adjusted_seasonally_filed Tnew
month
1 1989.5 32705.25 1989.541075 356.468571 356.421111 356.461270 356.400952 356.468571 356.421111 287.808514
2 1989.5 32736.25 1989.625925 357.840645 357.139355 357.248889 356.537778 357.240317 356.539841 287.819681
3 1989.5 32764.50 1989.703250 357.965238 356.544603 357.443906 356.010000 357.383750 355.964375 287.820691
4 1989.5 32795.50 1989.788175 359.331270 356.773175 358.718906 356.144844 358.745469 356.190000 287.831802
5 1989.5 32825.50 1989.870325 359.363125 356.253281 359.383750 356.277031 359.363125 356.253281 287.832057
In [16]:
# calculate the anomaly
anomaly = annual - annual.mean()
In [17]:
fig, ax = plt.subplots()

ax.plot("fraction_date", "data_filled", "r.", data=data)
ax.plot("fraction_date", "data_adjusted_seasonally_fit", data=data)
ax.set_xlabel("Year")
ax.set_ylabel("CO2 fraction in dry air (ppm)")
ax.set_title("Monthly Mean CO2")
ax.grid(False)

axin1 = ax.inset_axes([0.1, 0.5, 0.35, 0.35])
axin1.plot(anomaly.c02, "b")
axin1.plot(anomaly.c02, "r.")
axin1.set_title("Seasonal Anomaly");
In [18]:
# reading the C02 data from the base file rather than the cleaned up one.
file = DATA_DIR / "monthly_in_situ_co2_mlo.csv"
column_names = [
    "year",
    "month",
    "date_index",
    "fraction_date",
    "c02",
    "data_adjusted_season",
    "data_fit",
    "data_adjusted_seasonally_fit",
    "data_filled",
    "data_adjusted_seasonally_filed",
]
data = pd.read_csv(file, header=0, skiprows=56, names=column_names)
data.head()
Out[18]:
year month date_index fraction_date c02 data_adjusted_season data_fit data_adjusted_seasonally_fit data_filled data_adjusted_seasonally_filed
0 1958 1 21200 1958.0411 -99.99 -99.99 -99.99 -99.99 -99.99 -99.99
1 1958 2 21231 1958.1260 -99.99 -99.99 -99.99 -99.99 -99.99 -99.99
2 1958 3 21259 1958.2027 315.70 314.43 316.19 314.90 315.70 314.43
3 1958 4 21290 1958.2877 317.45 315.16 317.30 314.98 317.45 315.16
4 1958 5 21320 1958.3699 317.51 314.71 317.86 315.06 317.51 314.71

Using xarray to explore era5 data¶

In [20]:
import xarray as xr

ds = xr.open_dataset(DATA_DIR / "era5_monthly_2deg_aws_v20210920.nc")
ds
Out[20]:
<xarray.Dataset>
Dimensions:                                                                                   (
                                                                                               time: 504,
                                                                                               latitude: 90,
                                                                                               longitude: 180)
Coordinates:
  * time                                                                                      (time) datetime64[ns] ...
  * latitude                                                                                  (latitude) float32 ...
  * longitude                                                                                 (longitude) float32 ...
Data variables: (12/15)
    air_pressure_at_mean_sea_level                                                            (time, latitude, longitude) float32 ...
    air_temperature_at_2_metres                                                               (time, latitude, longitude) float32 ...
    air_temperature_at_2_metres_1hour_Maximum                                                 (time, latitude, longitude) float32 ...
    air_temperature_at_2_metres_1hour_Minimum                                                 (time, latitude, longitude) float32 ...
    dew_point_temperature_at_2_metres                                                         (time, latitude, longitude) float32 ...
    eastward_wind_at_100_metres                                                               (time, latitude, longitude) float32 ...
    ...                                                                                        ...
    northward_wind_at_100_metres                                                              (time, latitude, longitude) float32 ...
    northward_wind_at_10_metres                                                               (time, latitude, longitude) float32 ...
    precipitation_amount_1hour_Accumulation                                                   (time, latitude, longitude) float32 ...
    sea_surface_temperature                                                                   (time, latitude, longitude) float32 ...
    snow_density                                                                              (time, latitude, longitude) float32 ...
    surface_air_pressure                                                                      (time, latitude, longitude) float32 ...
Attributes:
    institution:  ECMWF
    source:       Reanalysis
    title:        ERA5 forecasts
xarray.Dataset
    • time: 504
    • latitude: 90
    • longitude: 180
    • time
      (time)
      datetime64[ns]
      1979-01-16T11:30:00 ... 2020-12-...
      array(['1979-01-16T11:30:00.000000000', '1979-02-14T23:30:00.000000000',
             '1979-03-16T11:30:00.000000000', ..., '2020-10-16T11:30:00.000000000',
             '2020-11-15T23:30:00.000000000', '2020-12-16T11:30:00.000000000'],
            dtype='datetime64[ns]')
    • latitude
      (latitude)
      float32
      -88.88 -86.88 ... 87.12 89.12
      long_name :
      latitude
      standard_name :
      latitude
      units :
      degrees_north
      array([-88.875, -86.875, -84.875, -82.875, -80.875, -78.875, -76.875, -74.875,
             -72.875, -70.875, -68.875, -66.875, -64.875, -62.875, -60.875, -58.875,
             -56.875, -54.875, -52.875, -50.875, -48.875, -46.875, -44.875, -42.875,
             -40.875, -38.875, -36.875, -34.875, -32.875, -30.875, -28.875, -26.875,
             -24.875, -22.875, -20.875, -18.875, -16.875, -14.875, -12.875, -10.875,
              -8.875,  -6.875,  -4.875,  -2.875,  -0.875,   1.125,   3.125,   5.125,
               7.125,   9.125,  11.125,  13.125,  15.125,  17.125,  19.125,  21.125,
              23.125,  25.125,  27.125,  29.125,  31.125,  33.125,  35.125,  37.125,
              39.125,  41.125,  43.125,  45.125,  47.125,  49.125,  51.125,  53.125,
              55.125,  57.125,  59.125,  61.125,  63.125,  65.125,  67.125,  69.125,
              71.125,  73.125,  75.125,  77.125,  79.125,  81.125,  83.125,  85.125,
              87.125,  89.125], dtype=float32)
    • longitude
      (longitude)
      float32
      0.875 2.875 4.875 ... 356.9 358.9
      long_name :
      longitude
      standard_name :
      longitude
      units :
      degrees_east
      array([  0.875,   2.875,   4.875,   6.875,   8.875,  10.875,  12.875,  14.875,
              16.875,  18.875,  20.875,  22.875,  24.875,  26.875,  28.875,  30.875,
              32.875,  34.875,  36.875,  38.875,  40.875,  42.875,  44.875,  46.875,
              48.875,  50.875,  52.875,  54.875,  56.875,  58.875,  60.875,  62.875,
              64.875,  66.875,  68.875,  70.875,  72.875,  74.875,  76.875,  78.875,
              80.875,  82.875,  84.875,  86.875,  88.875,  90.875,  92.875,  94.875,
              96.875,  98.875, 100.875, 102.875, 104.875, 106.875, 108.875, 110.875,
             112.875, 114.875, 116.875, 118.875, 120.875, 122.875, 124.875, 126.875,
             128.875, 130.875, 132.875, 134.875, 136.875, 138.875, 140.875, 142.875,
             144.875, 146.875, 148.875, 150.875, 152.875, 154.875, 156.875, 158.875,
             160.875, 162.875, 164.875, 166.875, 168.875, 170.875, 172.875, 174.875,
             176.875, 178.875, 180.875, 182.875, 184.875, 186.875, 188.875, 190.875,
             192.875, 194.875, 196.875, 198.875, 200.875, 202.875, 204.875, 206.875,
             208.875, 210.875, 212.875, 214.875, 216.875, 218.875, 220.875, 222.875,
             224.875, 226.875, 228.875, 230.875, 232.875, 234.875, 236.875, 238.875,
             240.875, 242.875, 244.875, 246.875, 248.875, 250.875, 252.875, 254.875,
             256.875, 258.875, 260.875, 262.875, 264.875, 266.875, 268.875, 270.875,
             272.875, 274.875, 276.875, 278.875, 280.875, 282.875, 284.875, 286.875,
             288.875, 290.875, 292.875, 294.875, 296.875, 298.875, 300.875, 302.875,
             304.875, 306.875, 308.875, 310.875, 312.875, 314.875, 316.875, 318.875,
             320.875, 322.875, 324.875, 326.875, 328.875, 330.875, 332.875, 334.875,
             336.875, 338.875, 340.875, 342.875, 344.875, 346.875, 348.875, 350.875,
             352.875, 354.875, 356.875, 358.875], dtype=float32)
    • air_pressure_at_mean_sea_level
      (time, latitude, longitude)
      float32
      ...
      long_name :
      Mean sea level pressure
      nameCDM :
      Mean_sea_level_pressure_surface
      nameECMWF :
      Mean sea level pressure
      product_type :
      analysis
      shortNameECMWF :
      msl
      standard_name :
      air_pressure_at_mean_sea_level
      units :
      Pa
      [8164800 values with dtype=float32]
    • air_temperature_at_2_metres
      (time, latitude, longitude)
      float32
      ...
      long_name :
      2 metre temperature
      nameCDM :
      2_metre_temperature_surface
      nameECMWF :
      2 metre temperature
      product_type :
      analysis
      shortNameECMWF :
      2t
      standard_name :
      air_temperature
      units :
      K
      [8164800 values with dtype=float32]
    • air_temperature_at_2_metres_1hour_Maximum
      (time, latitude, longitude)
      float32
      ...
      long_name :
      Maximum temperature at 2 metres since previous post-processing
      nameCDM :
      Maximum_temperature_at_2_metres_since_previous_post-processing_surface_1_Hour_2
      nameECMWF :
      Maximum temperature at 2 metres since previous post-processing
      product_type :
      forecast
      shortNameECMWF :
      mx2t
      standard_name :
      air_temperature
      units :
      K
      [8164800 values with dtype=float32]
    • air_temperature_at_2_metres_1hour_Minimum
      (time, latitude, longitude)
      float32
      ...
      long_name :
      Minimum temperature at 2 metres since previous post-processing
      nameCDM :
      Minimum_temperature_at_2_metres_since_previous_post-processing_surface_1_Hour_2
      nameECMWF :
      Minimum temperature at 2 metres since previous post-processing
      product_type :
      forecast
      shortNameECMWF :
      mn2t
      standard_name :
      air_temperature
      units :
      K
      [8164800 values with dtype=float32]
    • dew_point_temperature_at_2_metres
      (time, latitude, longitude)
      float32
      ...
      long_name :
      2 metre dewpoint temperature
      nameCDM :
      2_metre_dewpoint_temperature_surface
      nameECMWF :
      2 metre dewpoint temperature
      product_type :
      analysis
      shortNameECMWF :
      2d
      standard_name :
      dew_point_temperature
      units :
      K
      [8164800 values with dtype=float32]
    • eastward_wind_at_100_metres
      (time, latitude, longitude)
      float32
      ...
      long_name :
      100 metre U wind component
      nameCDM :
      100_metre_U_wind_component_surface
      nameECMWF :
      100 metre U wind component
      product_type :
      analysis
      shortNameECMWF :
      100u
      standard_name :
      eastward_wind
      units :
      m s**-1
      [8164800 values with dtype=float32]
    • eastward_wind_at_10_metres
      (time, latitude, longitude)
      float32
      ...
      long_name :
      10 metre U wind component
      nameCDM :
      10_metre_U_wind_component_surface
      nameECMWF :
      10 metre U wind component
      product_type :
      analysis
      shortNameECMWF :
      10u
      standard_name :
      eastward_wind
      units :
      m s**-1
      [8164800 values with dtype=float32]
    • integral_wrt_time_of_surface_direct_downwelling_shortwave_flux_in_air_1hour_Accumulation
      (time, latitude, longitude)
      float32
      ...
      long_name :
      Surface solar radiation downwards
      nameCDM :
      Surface_solar_radiation_downwards_surface_1_Hour_Accumulation
      nameECMWF :
      Surface solar radiation downwards
      product_type :
      forecast
      shortNameECMWF :
      ssrd
      standard_name :
      integral_wrt_time_of_surface_direct_downwelling_shortwave_flux_in_air
      units :
      J m**-2
      [8164800 values with dtype=float32]
    • lwe_thickness_of_surface_snow_amount
      (time, latitude, longitude)
      float32
      ...
      long_name :
      Snow depth
      nameCDM :
      Snow_depth_surface
      nameECMWF :
      Snow depth
      product_type :
      analysis
      shortNameECMWF :
      sd
      standard_name :
      lwe_thickness_of_surface_snow_amount
      units :
      m of water equivalent
      [8164800 values with dtype=float32]
    • northward_wind_at_100_metres
      (time, latitude, longitude)
      float32
      ...
      long_name :
      100 metre V wind component
      nameCDM :
      100_metre_V_wind_component_surface
      nameECMWF :
      100 metre V wind component
      product_type :
      analysis
      shortNameECMWF :
      100v
      standard_name :
      northward_wind
      units :
      m s**-1
      [8164800 values with dtype=float32]
    • northward_wind_at_10_metres
      (time, latitude, longitude)
      float32
      ...
      long_name :
      10 metre V wind component
      nameCDM :
      10_metre_V_wind_component_surface
      nameECMWF :
      10 metre V wind component
      product_type :
      analysis
      shortNameECMWF :
      10v
      standard_name :
      northward_wind
      units :
      m s**-1
      [8164800 values with dtype=float32]
    • precipitation_amount_1hour_Accumulation
      (time, latitude, longitude)
      float32
      ...
      long_name :
      Total precipitation
      nameCDM :
      Total_precipitation_1hour_Accumulation
      nameECMWF :
      Total precipitation
      product_type :
      forecast
      shortNameECMWF :
      tp
      standard_name :
      precipitation_amount
      units :
      m
      [8164800 values with dtype=float32]
    • sea_surface_temperature
      (time, latitude, longitude)
      float32
      ...
      long_name :
      Sea surface temperature
      nameCDM :
      Sea_surface_temperature_surface
      nameECMWF :
      Sea surface temperature
      product_type :
      analysis
      shortNameECMWF :
      sst
      standard_name :
      sea_surface_temperature
      units :
      K
      [8164800 values with dtype=float32]
    • snow_density
      (time, latitude, longitude)
      float32
      ...
      long_name :
      Snow density
      nameCDM :
      Snow_density_surface
      nameECMWF :
      Snow density
      product_type :
      analysis
      shortNameECMWF :
      rsn
      standard_name :
      snow_density
      units :
      kg m**-3
      [8164800 values with dtype=float32]
    • surface_air_pressure
      (time, latitude, longitude)
      float32
      ...
      long_name :
      Surface pressure
      nameCDM :
      Surface_pressure_surface
      nameECMWF :
      Surface pressure
      product_type :
      analysis
      shortNameECMWF :
      sp
      standard_name :
      surface_air_pressure
      units :
      Pa
      [8164800 values with dtype=float32]
  • institution :
    ECMWF
    source :
    Reanalysis
    title :
    ERA5 forecasts
In [21]:
ds.dims
Out[21]:
Frozen({'time': 504, 'latitude': 90, 'longitude': 180})
In [22]:
ds.coords
Out[22]:
Coordinates:
  * time       (time) datetime64[ns] 1979-01-16T11:30:00 ... 2020-12-16T11:30:00
  * latitude   (latitude) float32 -88.88 -86.88 -84.88 ... 85.12 87.12 89.12
  * longitude  (longitude) float32 0.875 2.875 4.875 6.875 ... 354.9 356.9 358.9
In [23]:
# two ways to print out the data for temperature at 2m
ds["air_temperature_at_2_metres"]
ds.air_temperature_at_2_metres
Out[23]:
<xarray.DataArray 'air_temperature_at_2_metres' (time: 504, latitude: 90,
                                                 longitude: 180)>
[8164800 values with dtype=float32]
Coordinates:
  * time       (time) datetime64[ns] 1979-01-16T11:30:00 ... 2020-12-16T11:30:00
  * latitude   (latitude) float32 -88.88 -86.88 -84.88 ... 85.12 87.12 89.12
  * longitude  (longitude) float32 0.875 2.875 4.875 6.875 ... 354.9 356.9 358.9
Attributes:
    long_name:       2 metre temperature
    nameCDM:         2_metre_temperature_surface
    nameECMWF:       2 metre temperature
    product_type:    analysis
    shortNameECMWF:  2t
    standard_name:   air_temperature
    units:           K
xarray.DataArray
'air_temperature_at_2_metres'
  • time: 504
  • latitude: 90
  • longitude: 180
  • ...
    [8164800 values with dtype=float32]
    • time
      (time)
      datetime64[ns]
      1979-01-16T11:30:00 ... 2020-12-...
      array(['1979-01-16T11:30:00.000000000', '1979-02-14T23:30:00.000000000',
             '1979-03-16T11:30:00.000000000', ..., '2020-10-16T11:30:00.000000000',
             '2020-11-15T23:30:00.000000000', '2020-12-16T11:30:00.000000000'],
            dtype='datetime64[ns]')
    • latitude
      (latitude)
      float32
      -88.88 -86.88 ... 87.12 89.12
      long_name :
      latitude
      standard_name :
      latitude
      units :
      degrees_north
      array([-88.875, -86.875, -84.875, -82.875, -80.875, -78.875, -76.875, -74.875,
             -72.875, -70.875, -68.875, -66.875, -64.875, -62.875, -60.875, -58.875,
             -56.875, -54.875, -52.875, -50.875, -48.875, -46.875, -44.875, -42.875,
             -40.875, -38.875, -36.875, -34.875, -32.875, -30.875, -28.875, -26.875,
             -24.875, -22.875, -20.875, -18.875, -16.875, -14.875, -12.875, -10.875,
              -8.875,  -6.875,  -4.875,  -2.875,  -0.875,   1.125,   3.125,   5.125,
               7.125,   9.125,  11.125,  13.125,  15.125,  17.125,  19.125,  21.125,
              23.125,  25.125,  27.125,  29.125,  31.125,  33.125,  35.125,  37.125,
              39.125,  41.125,  43.125,  45.125,  47.125,  49.125,  51.125,  53.125,
              55.125,  57.125,  59.125,  61.125,  63.125,  65.125,  67.125,  69.125,
              71.125,  73.125,  75.125,  77.125,  79.125,  81.125,  83.125,  85.125,
              87.125,  89.125], dtype=float32)
    • longitude
      (longitude)
      float32
      0.875 2.875 4.875 ... 356.9 358.9
      long_name :
      longitude
      standard_name :
      longitude
      units :
      degrees_east
      array([  0.875,   2.875,   4.875,   6.875,   8.875,  10.875,  12.875,  14.875,
              16.875,  18.875,  20.875,  22.875,  24.875,  26.875,  28.875,  30.875,
              32.875,  34.875,  36.875,  38.875,  40.875,  42.875,  44.875,  46.875,
              48.875,  50.875,  52.875,  54.875,  56.875,  58.875,  60.875,  62.875,
              64.875,  66.875,  68.875,  70.875,  72.875,  74.875,  76.875,  78.875,
              80.875,  82.875,  84.875,  86.875,  88.875,  90.875,  92.875,  94.875,
              96.875,  98.875, 100.875, 102.875, 104.875, 106.875, 108.875, 110.875,
             112.875, 114.875, 116.875, 118.875, 120.875, 122.875, 124.875, 126.875,
             128.875, 130.875, 132.875, 134.875, 136.875, 138.875, 140.875, 142.875,
             144.875, 146.875, 148.875, 150.875, 152.875, 154.875, 156.875, 158.875,
             160.875, 162.875, 164.875, 166.875, 168.875, 170.875, 172.875, 174.875,
             176.875, 178.875, 180.875, 182.875, 184.875, 186.875, 188.875, 190.875,
             192.875, 194.875, 196.875, 198.875, 200.875, 202.875, 204.875, 206.875,
             208.875, 210.875, 212.875, 214.875, 216.875, 218.875, 220.875, 222.875,
             224.875, 226.875, 228.875, 230.875, 232.875, 234.875, 236.875, 238.875,
             240.875, 242.875, 244.875, 246.875, 248.875, 250.875, 252.875, 254.875,
             256.875, 258.875, 260.875, 262.875, 264.875, 266.875, 268.875, 270.875,
             272.875, 274.875, 276.875, 278.875, 280.875, 282.875, 284.875, 286.875,
             288.875, 290.875, 292.875, 294.875, 296.875, 298.875, 300.875, 302.875,
             304.875, 306.875, 308.875, 310.875, 312.875, 314.875, 316.875, 318.875,
             320.875, 322.875, 324.875, 326.875, 328.875, 330.875, 332.875, 334.875,
             336.875, 338.875, 340.875, 342.875, 344.875, 346.875, 348.875, 350.875,
             352.875, 354.875, 356.875, 358.875], dtype=float32)
  • long_name :
    2 metre temperature
    nameCDM :
    2_metre_temperature_surface
    nameECMWF :
    2 metre temperature
    product_type :
    analysis
    shortNameECMWF :
    2t
    standard_name :
    air_temperature
    units :
    K
In [24]:
# different ways to access the data using index, isel, sel
temp = ds.air_temperature_at_2_metres
print(temp[0, 63, 119].data)
print(temp.isel(time=0, latitude=63, longitude=119).data)
print(temp.sel(time="1979-01", latitude=37.125, longitude=238.875).data)
print(temp.latitude[63].data)
print(temp.longitude[119].data)
280.93103
280.93103
[280.93103]
37.125
238.875

.isel versus .sel¶

  • .isel is endpoint EXclusive
  • .sel is endpoint INclusive
In [25]:
temp = ds.air_temperature_at_2_metres
point1 = temp.isel(time=0, latitude=63, longitude=119)
point2 = temp.sel(time="1979-01", latitude=37.125, longitude=238.875)
area1 = temp.isel(time=0, latitude=slice(63, 65), longitude=slice(119, 125))
area2 = temp.sel(
    time="1979-01",
    latitude=slice(temp.latitude[63], temp.latitude[65]),
    longitude=slice(temp.longitude[119], temp.longitude[125]),
)
In [26]:
print("area1 uses isel")
# print(area1.dims)
print(area1.latitude.data)
print(area1.longitude.data)
area1 uses isel
[37.125 39.125]
[238.875 240.875 242.875 244.875 246.875 248.875]
In [27]:
print("area2 uses sel")
# print(area2.dims)
print(area2.latitude.data)
print(area2.longitude.data)
area2 uses sel
[37.125 39.125 41.125]
[238.875 240.875 242.875 244.875 246.875 248.875 250.875]
In [28]:
point = ds.sel(time="1979-01", latitude=37.125, longitude=238.875)
area = ds.sel(
    time="1979-01",
    latitude=slice(temp.latitude[63], temp.latitude[65]),
    longitude=slice(temp.longitude[119], temp.longitude[125]),
)
In [29]:
ds.air_temperature_at_2_metres.sel(time="1979-01").plot();
In [30]:
ds.air_temperature_at_2_metres.sel(latitude=37.125, longitude=238.875).plot();
In [31]:
# ds.air_temperature_at_2_metres.mean("time").plot()
mean_map = ds.mean("time")  # takes the mean across all variables in ds
mean_map.air_temperature_at_2_metres.plot();
In [32]:
# calculate a map of the mean values across all time
ave = ds.mean(("latitude", "longitude"))
ave.air_temperature_at_2_metres.plot();
In [33]:
# calculate a map of the mean values across all time
ave = ds.mean("time")
ave.air_temperature_at_2_metres.plot();
In [34]:
# calculate a map of the mean values across all time
ave = ds.mean(("latitude", "longitude"))
ave.air_temperature_at_2_metres.plot();
In [35]:
ave = ds.mean(keep_attrs=True)
ave
Out[35]:
<xarray.Dataset>
Dimensions:                                                                                   ()
Data variables: (12/15)
    air_pressure_at_mean_sea_level                                                            float32 ...
    air_temperature_at_2_metres                                                               float32 ...
    air_temperature_at_2_metres_1hour_Maximum                                                 float32 ...
    air_temperature_at_2_metres_1hour_Minimum                                                 float32 ...
    dew_point_temperature_at_2_metres                                                         float32 ...
    eastward_wind_at_100_metres                                                               float32 ...
    ...                                                                                        ...
    northward_wind_at_100_metres                                                              float32 ...
    northward_wind_at_10_metres                                                               float32 ...
    precipitation_amount_1hour_Accumulation                                                   float32 ...
    sea_surface_temperature                                                                   float32 ...
    snow_density                                                                              float32 ...
    surface_air_pressure                                                                      float32 ...
Attributes:
    institution:  ECMWF
    source:       Reanalysis
    title:        ERA5 forecasts
xarray.Dataset
      • air_pressure_at_mean_sea_level
        ()
        float32
        1.01e+05
        long_name :
        Mean sea level pressure
        nameCDM :
        Mean_sea_level_pressure_surface
        nameECMWF :
        Mean sea level pressure
        product_type :
        analysis
        shortNameECMWF :
        msl
        standard_name :
        air_pressure_at_mean_sea_level
        units :
        Pa
        array(100957.39, dtype=float32)
      • air_temperature_at_2_metres
        ()
        float32
        278.5
        long_name :
        2 metre temperature
        nameCDM :
        2_metre_temperature_surface
        nameECMWF :
        2 metre temperature
        product_type :
        analysis
        shortNameECMWF :
        2t
        standard_name :
        air_temperature
        units :
        K
        array(278.5483, dtype=float32)
      • air_temperature_at_2_metres_1hour_Maximum
        ()
        float32
        278.6
        long_name :
        Maximum temperature at 2 metres since previous post-processing
        nameCDM :
        Maximum_temperature_at_2_metres_since_previous_post-processing_surface_1_Hour_2
        nameECMWF :
        Maximum temperature at 2 metres since previous post-processing
        product_type :
        forecast
        shortNameECMWF :
        mx2t
        standard_name :
        air_temperature
        units :
        K
        array(278.64465, dtype=float32)
      • air_temperature_at_2_metres_1hour_Minimum
        ()
        float32
        278.4
        long_name :
        Minimum temperature at 2 metres since previous post-processing
        nameCDM :
        Minimum_temperature_at_2_metres_since_previous_post-processing_surface_1_Hour_2
        nameECMWF :
        Minimum temperature at 2 metres since previous post-processing
        product_type :
        forecast
        shortNameECMWF :
        mn2t
        standard_name :
        air_temperature
        units :
        K
        array(278.3882, dtype=float32)
      • dew_point_temperature_at_2_metres
        ()
        float32
        274.0
        long_name :
        2 metre dewpoint temperature
        nameCDM :
        2_metre_dewpoint_temperature_surface
        nameECMWF :
        2 metre dewpoint temperature
        product_type :
        analysis
        shortNameECMWF :
        2d
        standard_name :
        dew_point_temperature
        units :
        K
        array(274.04156, dtype=float32)
      • eastward_wind_at_100_metres
        ()
        float32
        0.014
        long_name :
        100 metre U wind component
        nameCDM :
        100_metre_U_wind_component_surface
        nameECMWF :
        100 metre U wind component
        product_type :
        analysis
        shortNameECMWF :
        100u
        standard_name :
        eastward_wind
        units :
        m s**-1
        array(0.01399962, dtype=float32)
      • eastward_wind_at_10_metres
        ()
        float32
        -0.05225
        long_name :
        10 metre U wind component
        nameCDM :
        10_metre_U_wind_component_surface
        nameECMWF :
        10 metre U wind component
        product_type :
        analysis
        shortNameECMWF :
        10u
        standard_name :
        eastward_wind
        units :
        m s**-1
        array(-0.05225237, dtype=float32)
      • integral_wrt_time_of_surface_direct_downwelling_shortwave_flux_in_air_1hour_Accumulation
        ()
        float32
        5.908e+05
        long_name :
        Surface solar radiation downwards
        nameCDM :
        Surface_solar_radiation_downwards_surface_1_Hour_Accumulation
        nameECMWF :
        Surface solar radiation downwards
        product_type :
        forecast
        shortNameECMWF :
        ssrd
        standard_name :
        integral_wrt_time_of_surface_direct_downwelling_shortwave_flux_in_air
        units :
        J m**-2
        array(590840.6, dtype=float32)
      • lwe_thickness_of_surface_snow_amount
        ()
        float32
        1.143
        long_name :
        Snow depth
        nameCDM :
        Snow_depth_surface
        nameECMWF :
        Snow depth
        product_type :
        analysis
        shortNameECMWF :
        sd
        standard_name :
        lwe_thickness_of_surface_snow_amount
        units :
        m of water equivalent
        array(1.143496, dtype=float32)
      • northward_wind_at_100_metres
        ()
        float32
        0.1978
        long_name :
        100 metre V wind component
        nameCDM :
        100_metre_V_wind_component_surface
        nameECMWF :
        100 metre V wind component
        product_type :
        analysis
        shortNameECMWF :
        100v
        standard_name :
        northward_wind
        units :
        m s**-1
        array(0.19778013, dtype=float32)
      • northward_wind_at_10_metres
        ()
        float32
        0.1884
        long_name :
        10 metre V wind component
        nameCDM :
        10_metre_V_wind_component_surface
        nameECMWF :
        10 metre V wind component
        product_type :
        analysis
        shortNameECMWF :
        10v
        standard_name :
        northward_wind
        units :
        m s**-1
        array(0.18838629, dtype=float32)
      • precipitation_amount_1hour_Accumulation
        ()
        float32
        9.783e-05
        long_name :
        Total precipitation
        nameCDM :
        Total_precipitation_1hour_Accumulation
        nameECMWF :
        Total precipitation
        product_type :
        forecast
        shortNameECMWF :
        tp
        standard_name :
        precipitation_amount
        units :
        m
        array(9.7828175e-05, dtype=float32)
      • sea_surface_temperature
        ()
        float32
        286.6
        long_name :
        Sea surface temperature
        nameCDM :
        Sea_surface_temperature_surface
        nameECMWF :
        Sea surface temperature
        product_type :
        analysis
        shortNameECMWF :
        sst
        standard_name :
        sea_surface_temperature
        units :
        K
        array(286.5954, dtype=float32)
      • snow_density
        ()
        float32
        128.7
        long_name :
        Snow density
        nameCDM :
        Snow_density_surface
        nameECMWF :
        Snow density
        product_type :
        analysis
        shortNameECMWF :
        rsn
        standard_name :
        snow_density
        units :
        kg m**-3
        array(128.69717, dtype=float32)
      • surface_air_pressure
        ()
        float32
        9.669e+04
        long_name :
        Surface pressure
        nameCDM :
        Surface_pressure_surface
        nameECMWF :
        Surface pressure
        product_type :
        analysis
        shortNameECMWF :
        sp
        standard_name :
        surface_air_pressure
        units :
        Pa
        array(96689.56, dtype=float32)
    • institution :
      ECMWF
      source :
      Reanalysis
      title :
      ERA5 forecasts
    In [36]:
    weights = np.cos(np.deg2rad(ds.latitude))
    weights.name = "weights"
    weights.plot();
    
    In [37]:
    ds_weighted = ds.weighted(weights)
    weighted_mean = ds_weighted.mean()
    weighted_mean
    
    Out[37]:
    <xarray.Dataset>
    Dimensions:                                                                                   ()
    Data variables: (12/15)
        air_pressure_at_mean_sea_level                                                            float64 ...
        air_temperature_at_2_metres                                                               float64 ...
        air_temperature_at_2_metres_1hour_Maximum                                                 float64 ...
        air_temperature_at_2_metres_1hour_Minimum                                                 float64 ...
        dew_point_temperature_at_2_metres                                                         float64 ...
        eastward_wind_at_100_metres                                                               float64 ...
        ...                                                                                        ...
        northward_wind_at_100_metres                                                              float64 ...
        northward_wind_at_10_metres                                                               float64 ...
        precipitation_amount_1hour_Accumulation                                                   float64 ...
        sea_surface_temperature                                                                   float64 ...
        snow_density                                                                              float64 ...
        surface_air_pressure                                                                      float64 ...
    xarray.Dataset
        • air_pressure_at_mean_sea_level
          ()
          float64
          1.011e+05
          array(101139.42848689)
        • air_temperature_at_2_metres
          ()
          float64
          287.4
          array(287.41898692)
        • air_temperature_at_2_metres_1hour_Maximum
          ()
          float64
          287.5
          array(287.48948915)
        • air_temperature_at_2_metres_1hour_Minimum
          ()
          float64
          287.2
          array(287.22215464)
        • dew_point_temperature_at_2_metres
          ()
          float64
          282.4
          array(282.41764692)
        • eastward_wind_at_100_metres
          ()
          float64
          -0.3118
          array(-0.31178976)
        • eastward_wind_at_10_metres
          ()
          float64
          -0.3675
          array(-0.36750093)
        • integral_wrt_time_of_surface_direct_downwelling_shortwave_flux_in_air_1hour_Accumulation
          ()
          float64
          6.769e+05
          array(676858.13418482)
        • lwe_thickness_of_surface_snow_amount
          ()
          float64
          0.3232
          array(0.32322654)
        • northward_wind_at_100_metres
          ()
          float64
          0.1729
          array(0.1728604)
        • northward_wind_at_10_metres
          ()
          float64
          0.1776
          array(0.17764234)
        • precipitation_amount_1hour_Accumulation
          ()
          float64
          0.0001195
          array(0.00011954)
        • sea_surface_temperature
          ()
          float64
          291.2
          array(291.15099328)
        • snow_density
          ()
          float64
          111.1
          array(111.13120752)
        • surface_air_pressure
          ()
          float64
          9.856e+04
          array(98560.59371613)
      In [38]:
      ds_weighted = ds.weighted(weights)
      weighted_mean = ds_weighted.mean(("latitude", "longitude"))
      weighted_mean.air_temperature_at_2_metres.plot();
      
      In [39]:
      # calculate the annual cycle
      annual_cycle = weighted_mean.groupby("time.month").mean()
      annual_cycle.air_temperature_at_2_metres.plot();
      
      In [40]:
      # calculate the annual cycle at a point
      weighted_trend = (
          weighted_mean.groupby("time.month") - annual_cycle + annual_cycle.mean()
      )
      
      In [41]:
      weighted_mean.air_temperature_at_2_metres.plot()
      weighted_trend.air_temperature_at_2_metres.plot();
      
      In [42]:
      bins = np.arange(284, 291, 0.25)
      xr.plot.hist(
          weighted_mean.air_temperature_at_2_metres.sel(time=slice("1980", "2000")),
          bins=bins,
          density=True,
          alpha=0.9,
          color="b",
      )
      xr.plot.hist(
          weighted_mean.air_temperature_at_2_metres.sel(time=slice("2000", "2020")),
          bins=bins,
          density=True,
          alpha=0.85,
          color="r",
      )
      plt.ylabel("Probability Density (/K)");
      
      In [43]:
      pfit = ds.air_temperature_at_2_metres.polyfit("time", 1)
      pfit.polyfit_coefficients[0] *= 3.154000000101e16  # go from nanosecond to year
      pfit.polyfit_coefficients[0].plot(cbar_kwargs={"label": "trend deg/yr"});
      
      In [44]:
      np.timedelta64(1, "Y")
      # /np.timedelta64(1,'s').data
      pfit.polyfit_coefficients[0, 80, 10] * 3.154000000101e16
      
      Out[44]:
      <xarray.DataArray 'polyfit_coefficients' ()>
      array(1.32898438e+15)
      Coordinates:
          latitude   float64 71.12
          longitude  float64 20.88
          degree     int64 1
      xarray.DataArray
      'polyfit_coefficients'
      • 1.329e+15
        array(1.32898438e+15)
        • latitude
          ()
          float64
          71.12
          array(71.125)
        • longitude
          ()
          float64
          20.88
          array(20.875)
        • degree
          ()
          int64
          1
          array(1)
      In [46]:
      import cartopy.crs as ccrs
      
      p = pfit.polyfit_coefficients[0].plot(
          subplot_kws=dict(projection=ccrs.Orthographic(0, 90), facecolor="gray"),
          transform=ccrs.PlateCarree(central_longitude=0),
          cbar_kwargs={"label": "trend deg/yr"},
      )
      
      p.axes.coastlines();
      
      • Subset all variables to just the Arctic
      In [47]:
      arctic_ds_weighted = ds.sel(latitude=slice(70,90)).weighted(weights)
      arctic_weighted_mean = arctic_ds_weighted.mean(("latitude", "longitude"))
      arctic_annual_cycle = arctic_weighted_mean.groupby("time.month").mean()
      arctic_weighted_trend = (
          arctic_weighted_mean.groupby("time.month") - arctic_annual_cycle + arctic_annual_cycle.mean()
      )
      
      In [48]:
      arctic_weighted_mean.air_temperature_at_2_metres.plot()
      arctic_weighted_trend.air_temperature_at_2_metres.plot();
      
      In [49]:
      def linear_trend(x, y):
          pf = np.polyfit(x, y, 1)
          return pf[0]
      
      x = arctic_weighted_mean.time.dt.year
      y = arctic_weighted_mean.air_temperature_at_2_metres
      arctic_trend = linear_trend(x, y)
      x = weighted_mean.time.dt.year
      y = weighted_mean.air_temperature_at_2_metres
      trend = linear_trend(x, y)
      print('linear trend: global=',trend,'arctic', arctic_trend)
      
      linear trend: global= 0.01919810121463834 arctic 0.0760453252027596
      
      In [51]:
      bins = np.arange(245, 280, 1)
      xr.plot.hist(
          arctic_weighted_mean.air_temperature_at_2_metres.sel(time=slice("1980", "2000")),
          bins=bins,
          density=True,
          alpha=0.9,
          color="b",
      )
      xr.plot.hist(
          arctic_weighted_mean.air_temperature_at_2_metres.sel(time=slice("2000", "2020")),
          bins=bins,
          density=True,
          alpha=0.85,
          color="r",
      )
      plt.ylabel("Probability Density (/K)");