Some tips with xarray and pandas#
We have massively different levels here
Try to make some aims for technical skills you can learn!
If you are beginning with python → learn the basics
If you are good at basic python → learn new packages and tricks
If you know all the packages → improve your skills with producing your own software, organising your code etc.
If you don’t know git and github → get better at this!
Learn from each other!
How many have used jupyter lab?
How many have used pandas?
How many have used xarray?
What are pandas and xarray?#
Pandas → like a spreadsheet 2D data with columns and rows
xarray → like pandas, but in N dimensions
Use the functionality these packages gives you! Will help you avoid mistakes. Try to get as good as possible :)
Pandas#
(Source: https://www.geeksforgeeks.org/python-pandas-dataframe/)
Xarray#
(Source: https://docs.xarray.dev/)
1. Read in CMIP6 data: We will skip this next part, but you can check it later to read data:#
Import python packages#
import xarray as xr
xr.set_options(display_style='html')
import intake
import cftime
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import numpy as np
import pandas as pd
import datetime
import seaborn as sns
#cat_url = "https://storage.googleapis.com/cmip6/pangeo-cmip6.json"
#cat_url = "/mnt/craas1-ns9989k-geo4992/data/cmip6.json"
cat_url = '/mnt/craas1-ns9989k-geo4992/data/catalogs/cmip6.json'
col = intake.open_esm_datastore(cat_url)
col
cmip6 catalog with 155 dataset(s) from 536945 asset(s):
unique | |
---|---|
variable_id | 583 |
table_id | 24 |
source_id | 75 |
experiment_id | 94 |
member_id | 190 |
grid_label | 11 |
time_range | 9100 |
activity_id | 18 |
institution_id | 35 |
version | 577 |
path | 536945 |
dcpp_init_year | 0 |
derived_variable_id | 0 |
Search corresponding data#
Please check here for info about CMIP and variables :)
Particularly useful is maybe the variable search which you find here: https://clipc-services.ceda.ac.uk/dreq/mipVars.html
cat = col.search(source_id = ['CESM2'],
experiment_id=['historical'],
table_id=['Amon','fx','AERmon'],
variable_id=['tas','hurs', 'areacella','mmrso4' ],
member_id=['r1i1p1f1'],
)
cat.df
variable_id | table_id | source_id | experiment_id | member_id | grid_label | time_range | activity_id | institution_id | version | path | dcpp_init_year | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | mmrso4 | AERmon | CESM2 | historical | r1i1p1f1 | gn | 185001-201412 | CMIP | NCAR | v20190308 | /mnt/craas1-ns9989k-ns9560k/ESGF/CMIP6/CMIP/NC... | NaN |
1 | hurs | Amon | CESM2 | historical | r1i1p1f1 | gn | 185001-201412 | CMIP | NCAR | v20190308 | /mnt/craas1-ns9989k-ns9560k/ESGF/CMIP6/CMIP/NC... | NaN |
2 | tas | Amon | CESM2 | historical | r1i1p1f1 | gn | 185001-201412 | CMIP | NCAR | v20190308 | /mnt/craas1-ns9989k-ns9560k/ESGF/CMIP6/CMIP/NC... | NaN |
3 | areacella | fx | CESM2 | historical | r1i1p1f1 | gn | NaN | CMIP | NCAR | v20190308 | /mnt/craas1-ns9989k-ns9560k/ESGF/CMIP6/CMIP/NC... | NaN |
cat.esmcat.aggregation_control.groupby_attrs = ['activity_id','experiment_id', 'source_id','table_id','grid_label']
cat.esmcat.aggregation_control.groupby_attrs
['activity_id', 'experiment_id', 'source_id', 'table_id', 'grid_label']
Create dictionary from the list of datasets we found#
This step may take several minutes so be patient!
dset_dict = cat.to_dataset_dict(zarr_kwargs={'use_cftime':True})
--> The keys in the returned dictionary of datasets are constructed as follows:
'activity_id.experiment_id.source_id.table_id.grid_label'
/opt/conda/envs/pangeo-notebook/lib/python3.11/site-packages/xarray/conventions.py:286: SerializationWarning: variable 'areacella' has multiple fill values {1e+20, 1e+20} defined, decoding all values to NaN.
var = coder.decode(var, name=name)
/opt/conda/envs/pangeo-notebook/lib/python3.11/site-packages/xarray/conventions.py:286: SerializationWarning: variable 'hurs' has multiple fill values {1e+20, 1e+20} defined, decoding all values to NaN.
var = coder.decode(var, name=name)
/opt/conda/envs/pangeo-notebook/lib/python3.11/site-packages/xarray/conventions.py:286: SerializationWarning: variable 'mmrso4' has multiple fill values {1e+20, 1e+20} defined, decoding all values to NaN.
var = coder.decode(var, name=name)
/opt/conda/envs/pangeo-notebook/lib/python3.11/site-packages/xarray/conventions.py:286: SerializationWarning: variable 'tas' has multiple fill values {1e+20, 1e+20} defined, decoding all values to NaN.
var = coder.decode(var, name=name)
list(dset_dict.keys())
['CMIP.historical.CESM2.fx.gn',
'CMIP.historical.CESM2.AERmon.gn',
'CMIP.historical.CESM2.Amon.gn']
ds_list =[]
for k in dset_dict.keys():
ds = dset_dict[k]
for v in ['lon_bnds', 'lat_bnds', 'time_bnds']:
if v in ds:
ds= ds.drop(v)
ds_list.append(ds)
ds = xr.merge(ds_list,compat='override')
/tmp/ipykernel_14081/179335234.py:6: DeprecationWarning: dropping variables using `drop` is deprecated; use drop_vars.
ds= ds.drop(v)
1.1 Reading in the data from file:#
Open dataset#
Use
xarray
python package to analyze netCDF datasetopen_dataset
allows to get all the metadata without loading data into memory.with
xarray
, we only load into memory what is needed.
path='filename.nc'
ds = xr.open_dataset(path)
Opening multiple files:#
list_of_files = [
'file1.nc',
'file2.nc'
]
xr.open_mfdataset(list_of_files, concat_dim='time',combine='by_coords')
2. Check how your dataset looks#
NetCDF + xarray = <3NetCDF (Network Common Data Form) is a machine-independent data format (and software) that support the creation, access, and sharing of array-oriented scientific data. It was originally developed by UCAR (University Corporation for Atmospheric Research), and it’s widely used in the atmospheric and oceanographic sciences, as well as in other fields such as Earth sciences, geophysics, and climatology.
What is really great is that it keeps a lot of metadata (see below)
Xarray is a Python library designed to work with multi-dimensional arrays and datasets, particularly those used in earth sciences, climate science, and atmospheric science. It builds upon and extends the functionality of NumPy, Pandas, and NetCDF, providing a high-level interface for working with labeled, multi-dimensional data.
Different types of information/data:#
Coordinates
Data variables
Global attributes
Variable attributes
Other?
ds
<xarray.Dataset> Size: 15GB Dimensions: (member_id: 1, lat: 192, lon: 288, time: 1980, lev: 32, nbnd: 2) Coordinates: * lat (lat) float64 2kB -90.0 -89.06 -88.12 -87.17 ... 88.12 89.06 90.0 * lon (lon) float64 2kB 0.0 1.25 2.5 3.75 ... 355.0 356.2 357.5 358.8 * member_id (member_id) object 8B 'r1i1p1f1' * lev (lev) float64 256B -3.643 -7.595 -14.36 ... -957.5 -976.3 -992.6 * time (time) object 16kB 1850-01-15 12:00:00 ... 2014-12-15 12:00:00 Dimensions without coordinates: nbnd Data variables: areacella (member_id, lat, lon) float32 221kB dask.array<chunksize=(1, 192, 288), meta=np.ndarray> mmrso4 (member_id, time, lev, lat, lon) float32 14GB dask.array<chunksize=(1, 1, 16, 96, 144), meta=np.ndarray> ps (time, lat, lon) float32 438MB dask.array<chunksize=(1, 192, 288), meta=np.ndarray> p0 float32 4B ... a (lev) float64 256B dask.array<chunksize=(32,), meta=np.ndarray> b (lev) float64 256B dask.array<chunksize=(32,), meta=np.ndarray> b_bnds (lev, nbnd) float64 512B dask.array<chunksize=(32, 2), meta=np.ndarray> lev_bnds (lev, nbnd) float64 512B dask.array<chunksize=(32, 2), meta=np.ndarray> a_bnds (lev, nbnd) float64 512B dask.array<chunksize=(32, 2), meta=np.ndarray> hurs (member_id, time, lat, lon) float32 438MB dask.array<chunksize=(1, 1, 192, 288), meta=np.ndarray> tas (member_id, time, lat, lon) float32 438MB dask.array<chunksize=(1, 1, 192, 288), meta=np.ndarray> Attributes: (12/57) Conventions: CF-1.7 CMIP-6.2 activity_id: CMIP case_id: 15 cesm_casename: b.e21.BHIST.f09_g17.CMIP6-historical.001 contact: cesm_cmip6@ucar.edu creation_date: 2019-01-16T21:43:39Z ... ... intake_esm_attrs:activity_id: CMIP intake_esm_attrs:institution_id: NCAR intake_esm_attrs:version: v20190308 intake_esm_attrs:path: /mnt/craas1-ns9989k-ns9560k/ESGF/CMIP6/... intake_esm_attrs:_data_format_: netcdf intake_esm_dataset_key: CMIP.historical.CESM2.fx.gn
3. Sometimes we want to do some nice tweaks before we start:#
Selecting data and super quick plotting:#
xarray loads data only when it needs to (it’s lazy, someone else can explain), and you might want to early on define the subset of data you want to look at so that you don’t end up loading a lot of extra data.
See here for nice overview#
In order to reduce unecessary calculations and loading of data, think about which part of the data you want, and slice early on.
Slice in time: the sel method#
dss = ds.sel(time = slice('1990-01-01','2010-01-01'))
dss
<xarray.Dataset> Size: 2GB Dimensions: (member_id: 1, lat: 192, lon: 288, time: 240, lev: 32, nbnd: 2) Coordinates: * lat (lat) float64 2kB -90.0 -89.06 -88.12 -87.17 ... 88.12 89.06 90.0 * lon (lon) float64 2kB 0.0 1.25 2.5 3.75 ... 355.0 356.2 357.5 358.8 * member_id (member_id) object 8B 'r1i1p1f1' * lev (lev) float64 256B -3.643 -7.595 -14.36 ... -957.5 -976.3 -992.6 * time (time) object 2kB 1990-01-15 12:00:00 ... 2009-12-15 12:00:00 Dimensions without coordinates: nbnd Data variables: areacella (member_id, lat, lon) float32 221kB dask.array<chunksize=(1, 192, 288), meta=np.ndarray> mmrso4 (member_id, time, lev, lat, lon) float32 2GB dask.array<chunksize=(1, 1, 16, 96, 144), meta=np.ndarray> ps (time, lat, lon) float32 53MB dask.array<chunksize=(1, 192, 288), meta=np.ndarray> p0 float32 4B ... a (lev) float64 256B dask.array<chunksize=(32,), meta=np.ndarray> b (lev) float64 256B dask.array<chunksize=(32,), meta=np.ndarray> b_bnds (lev, nbnd) float64 512B dask.array<chunksize=(32, 2), meta=np.ndarray> lev_bnds (lev, nbnd) float64 512B dask.array<chunksize=(32, 2), meta=np.ndarray> a_bnds (lev, nbnd) float64 512B dask.array<chunksize=(32, 2), meta=np.ndarray> hurs (member_id, time, lat, lon) float32 53MB dask.array<chunksize=(1, 1, 192, 288), meta=np.ndarray> tas (member_id, time, lat, lon) float32 53MB dask.array<chunksize=(1, 1, 192, 288), meta=np.ndarray> Attributes: (12/57) Conventions: CF-1.7 CMIP-6.2 activity_id: CMIP case_id: 15 cesm_casename: b.e21.BHIST.f09_g17.CMIP6-historical.001 contact: cesm_cmip6@ucar.edu creation_date: 2019-01-16T21:43:39Z ... ... intake_esm_attrs:activity_id: CMIP intake_esm_attrs:institution_id: NCAR intake_esm_attrs:version: v20190308 intake_esm_attrs:path: /mnt/craas1-ns9989k-ns9560k/ESGF/CMIP6/... intake_esm_attrs:_data_format_: netcdf intake_esm_dataset_key: CMIP.historical.CESM2.fx.gn
You might even select only the arctic e.g.:
dss_arctic = dss.sel(lat = slice(60,None))
dss_arctic
<xarray.Dataset> Size: 310MB Dimensions: (member_id: 1, lat: 32, lon: 288, time: 240, lev: 32, nbnd: 2) Coordinates: * lat (lat) float64 256B 60.79 61.73 62.67 63.61 ... 88.12 89.06 90.0 * lon (lon) float64 2kB 0.0 1.25 2.5 3.75 ... 355.0 356.2 357.5 358.8 * member_id (member_id) object 8B 'r1i1p1f1' * lev (lev) float64 256B -3.643 -7.595 -14.36 ... -957.5 -976.3 -992.6 * time (time) object 2kB 1990-01-15 12:00:00 ... 2009-12-15 12:00:00 Dimensions without coordinates: nbnd Data variables: areacella (member_id, lat, lon) float32 37kB dask.array<chunksize=(1, 32, 288), meta=np.ndarray> mmrso4 (member_id, time, lev, lat, lon) float32 283MB dask.array<chunksize=(1, 1, 16, 32, 144), meta=np.ndarray> ps (time, lat, lon) float32 9MB dask.array<chunksize=(1, 32, 288), meta=np.ndarray> p0 float32 4B ... a (lev) float64 256B dask.array<chunksize=(32,), meta=np.ndarray> b (lev) float64 256B dask.array<chunksize=(32,), meta=np.ndarray> b_bnds (lev, nbnd) float64 512B dask.array<chunksize=(32, 2), meta=np.ndarray> lev_bnds (lev, nbnd) float64 512B dask.array<chunksize=(32, 2), meta=np.ndarray> a_bnds (lev, nbnd) float64 512B dask.array<chunksize=(32, 2), meta=np.ndarray> hurs (member_id, time, lat, lon) float32 9MB dask.array<chunksize=(1, 1, 32, 288), meta=np.ndarray> tas (member_id, time, lat, lon) float32 9MB dask.array<chunksize=(1, 1, 32, 288), meta=np.ndarray> Attributes: (12/57) Conventions: CF-1.7 CMIP-6.2 activity_id: CMIP case_id: 15 cesm_casename: b.e21.BHIST.f09_g17.CMIP6-historical.001 contact: cesm_cmip6@ucar.edu creation_date: 2019-01-16T21:43:39Z ... ... intake_esm_attrs:activity_id: CMIP intake_esm_attrs:institution_id: NCAR intake_esm_attrs:version: v20190308 intake_esm_attrs:path: /mnt/craas1-ns9989k-ns9560k/ESGF/CMIP6/... intake_esm_attrs:_data_format_: netcdf intake_esm_dataset_key: CMIP.historical.CESM2.fx.gn
isel, sel: index selecting#
Select the surface (which in this case is the last index :)
dss
<xarray.Dataset> Size: 2GB Dimensions: (member_id: 1, lat: 192, lon: 288, time: 240, lev: 32, nbnd: 2) Coordinates: * lat (lat) float64 2kB -90.0 -89.06 -88.12 -87.17 ... 88.12 89.06 90.0 * lon (lon) float64 2kB 0.0 1.25 2.5 3.75 ... 355.0 356.2 357.5 358.8 * member_id (member_id) object 8B 'r1i1p1f1' * lev (lev) float64 256B -3.643 -7.595 -14.36 ... -957.5 -976.3 -992.6 * time (time) object 2kB 1990-01-15 12:00:00 ... 2009-12-15 12:00:00 Dimensions without coordinates: nbnd Data variables: areacella (member_id, lat, lon) float32 221kB dask.array<chunksize=(1, 192, 288), meta=np.ndarray> mmrso4 (member_id, time, lev, lat, lon) float32 2GB dask.array<chunksize=(1, 1, 16, 96, 144), meta=np.ndarray> ps (time, lat, lon) float32 53MB dask.array<chunksize=(1, 192, 288), meta=np.ndarray> p0 float32 4B ... a (lev) float64 256B dask.array<chunksize=(32,), meta=np.ndarray> b (lev) float64 256B dask.array<chunksize=(32,), meta=np.ndarray> b_bnds (lev, nbnd) float64 512B dask.array<chunksize=(32, 2), meta=np.ndarray> lev_bnds (lev, nbnd) float64 512B dask.array<chunksize=(32, 2), meta=np.ndarray> a_bnds (lev, nbnd) float64 512B dask.array<chunksize=(32, 2), meta=np.ndarray> hurs (member_id, time, lat, lon) float32 53MB dask.array<chunksize=(1, 1, 192, 288), meta=np.ndarray> tas (member_id, time, lat, lon) float32 53MB dask.array<chunksize=(1, 1, 192, 288), meta=np.ndarray> Attributes: (12/57) Conventions: CF-1.7 CMIP-6.2 activity_id: CMIP case_id: 15 cesm_casename: b.e21.BHIST.f09_g17.CMIP6-historical.001 contact: cesm_cmip6@ucar.edu creation_date: 2019-01-16T21:43:39Z ... ... intake_esm_attrs:activity_id: CMIP intake_esm_attrs:institution_id: NCAR intake_esm_attrs:version: v20190308 intake_esm_attrs:path: /mnt/craas1-ns9989k-ns9560k/ESGF/CMIP6/... intake_esm_attrs:_data_format_: netcdf intake_esm_dataset_key: CMIP.historical.CESM2.fx.gn
dss_s = dss.isel(lev=-1)
dss_s
<xarray.Dataset> Size: 213MB Dimensions: (member_id: 1, lat: 192, lon: 288, time: 240, nbnd: 2) Coordinates: * lat (lat) float64 2kB -90.0 -89.06 -88.12 -87.17 ... 88.12 89.06 90.0 * lon (lon) float64 2kB 0.0 1.25 2.5 3.75 ... 355.0 356.2 357.5 358.8 * member_id (member_id) object 8B 'r1i1p1f1' lev float64 8B -992.6 * time (time) object 2kB 1990-01-15 12:00:00 ... 2009-12-15 12:00:00 Dimensions without coordinates: nbnd Data variables: areacella (member_id, lat, lon) float32 221kB dask.array<chunksize=(1, 192, 288), meta=np.ndarray> mmrso4 (member_id, time, lat, lon) float32 53MB dask.array<chunksize=(1, 1, 96, 144), meta=np.ndarray> ps (time, lat, lon) float32 53MB dask.array<chunksize=(1, 192, 288), meta=np.ndarray> p0 float32 4B ... a float64 8B dask.array<chunksize=(), meta=np.ndarray> b float64 8B dask.array<chunksize=(), meta=np.ndarray> b_bnds (nbnd) float64 16B dask.array<chunksize=(2,), meta=np.ndarray> lev_bnds (nbnd) float64 16B dask.array<chunksize=(2,), meta=np.ndarray> a_bnds (nbnd) float64 16B dask.array<chunksize=(2,), meta=np.ndarray> hurs (member_id, time, lat, lon) float32 53MB dask.array<chunksize=(1, 1, 192, 288), meta=np.ndarray> tas (member_id, time, lat, lon) float32 53MB dask.array<chunksize=(1, 1, 192, 288), meta=np.ndarray> Attributes: (12/57) Conventions: CF-1.7 CMIP-6.2 activity_id: CMIP case_id: 15 cesm_casename: b.e21.BHIST.f09_g17.CMIP6-historical.001 contact: cesm_cmip6@ucar.edu creation_date: 2019-01-16T21:43:39Z ... ... intake_esm_attrs:activity_id: CMIP intake_esm_attrs:institution_id: NCAR intake_esm_attrs:version: v20190308 intake_esm_attrs:path: /mnt/craas1-ns9989k-ns9560k/ESGF/CMIP6/... intake_esm_attrs:_data_format_: netcdf intake_esm_dataset_key: CMIP.historical.CESM2.fx.gn
3.2 Calculates variables and assign attributes!#
Nice for plotting and to keep track of what is in your dataset (especially ‘units’ and ‘standard_name’/’long_name’ will be looked for by xarray.
dss['T_C'] = dss['tas']-273.15
dss['T_C'] = dss['T_C'].assign_attrs({'units': '$^\circ$C'})
dss['T_C']
<xarray.DataArray 'T_C' (member_id: 1, time: 240, lat: 192, lon: 288)> Size: 53MB dask.array<sub, shape=(1, 240, 192, 288), dtype=float32, chunksize=(1, 1, 192, 288), chunktype=numpy.ndarray> Coordinates: * lat (lat) float64 2kB -90.0 -89.06 -88.12 -87.17 ... 88.12 89.06 90.0 * lon (lon) float64 2kB 0.0 1.25 2.5 3.75 ... 355.0 356.2 357.5 358.8 * member_id (member_id) object 8B 'r1i1p1f1' * time (time) object 2kB 1990-01-15 12:00:00 ... 2009-12-15 12:00:00 Attributes: units: $^\circ$C
dss['time']
<xarray.DataArray 'time' (time: 240)> Size: 2kB array([cftime.DatetimeNoLeap(1990, 1, 15, 12, 0, 0, 0, has_year_zero=True), cftime.DatetimeNoLeap(1990, 2, 14, 0, 0, 0, 0, has_year_zero=True), cftime.DatetimeNoLeap(1990, 3, 15, 12, 0, 0, 0, has_year_zero=True), ..., cftime.DatetimeNoLeap(2009, 10, 15, 12, 0, 0, 0, has_year_zero=True), cftime.DatetimeNoLeap(2009, 11, 15, 0, 0, 0, 0, has_year_zero=True), cftime.DatetimeNoLeap(2009, 12, 15, 12, 0, 0, 0, has_year_zero=True)], dtype=object) Coordinates: * time (time) object 2kB 1990-01-15 12:00:00 ... 2009-12-15 12:00:00 Attributes: axis: T bounds: time_bnds standard_name: time title: time type: double
This calendar is in cftime and noLeap. Sometimes this causes issues when plotting timeseries, so just for fun we will convert to a standard datetime64 index calendar because it’s anyway monthly.
dss['time'] = dss['time'].to_dataframe().index.to_datetimeindex()
/tmp/ipykernel_14081/4195133999.py:1: RuntimeWarning: Converting a CFTimeIndex with dates from a non-standard calendar, 'noleap', to a pandas.DatetimeIndex, which uses dates from the standard calendar. This may lead to subtle errors in operations that depend on the length of time between dates.
dss['time'] = dss['time'].to_dataframe().index.to_datetimeindex()
dss['time']
<xarray.DataArray 'time' (time: 240)> Size: 2kB array(['1990-01-15T12:00:00.000000000', '1990-02-14T00:00:00.000000000', '1990-03-15T12:00:00.000000000', ..., '2009-10-15T12:00:00.000000000', '2009-11-15T00:00:00.000000000', '2009-12-15T12:00:00.000000000'], dtype='datetime64[ns]') Coordinates: * time (time) datetime64[ns] 2kB 1990-01-15T12:00:00 ... 2009-12-15T12:...
3.3 Convert longitude:#
this data comes in 0–360 degrees, but often -180 to 180 is more convenient. So we can convert:
NOTE: Maybe you want to put this in a module? Or a package..
dss
<xarray.Dataset> Size: 2GB Dimensions: (member_id: 1, lat: 192, lon: 288, time: 240, lev: 32, nbnd: 2) Coordinates: * lat (lat) float64 2kB -90.0 -89.06 -88.12 -87.17 ... 88.12 89.06 90.0 * lon (lon) float64 2kB 0.0 1.25 2.5 3.75 ... 355.0 356.2 357.5 358.8 * member_id (member_id) object 8B 'r1i1p1f1' * lev (lev) float64 256B -3.643 -7.595 -14.36 ... -957.5 -976.3 -992.6 * time (time) datetime64[ns] 2kB 1990-01-15T12:00:00 ... 2009-12-15T1... Dimensions without coordinates: nbnd Data variables: areacella (member_id, lat, lon) float32 221kB dask.array<chunksize=(1, 192, 288), meta=np.ndarray> mmrso4 (member_id, time, lev, lat, lon) float32 2GB dask.array<chunksize=(1, 1, 16, 96, 144), meta=np.ndarray> ps (time, lat, lon) float32 53MB dask.array<chunksize=(1, 192, 288), meta=np.ndarray> p0 float32 4B ... a (lev) float64 256B dask.array<chunksize=(32,), meta=np.ndarray> b (lev) float64 256B dask.array<chunksize=(32,), meta=np.ndarray> b_bnds (lev, nbnd) float64 512B dask.array<chunksize=(32, 2), meta=np.ndarray> lev_bnds (lev, nbnd) float64 512B dask.array<chunksize=(32, 2), meta=np.ndarray> a_bnds (lev, nbnd) float64 512B dask.array<chunksize=(32, 2), meta=np.ndarray> hurs (member_id, time, lat, lon) float32 53MB dask.array<chunksize=(1, 1, 192, 288), meta=np.ndarray> tas (member_id, time, lat, lon) float32 53MB dask.array<chunksize=(1, 1, 192, 288), meta=np.ndarray> T_C (member_id, time, lat, lon) float32 53MB dask.array<chunksize=(1, 1, 192, 288), meta=np.ndarray> Attributes: (12/57) Conventions: CF-1.7 CMIP-6.2 activity_id: CMIP case_id: 15 cesm_casename: b.e21.BHIST.f09_g17.CMIP6-historical.001 contact: cesm_cmip6@ucar.edu creation_date: 2019-01-16T21:43:39Z ... ... intake_esm_attrs:activity_id: CMIP intake_esm_attrs:institution_id: NCAR intake_esm_attrs:version: v20190308 intake_esm_attrs:path: /mnt/craas1-ns9989k-ns9560k/ESGF/CMIP6/... intake_esm_attrs:_data_format_: netcdf intake_esm_dataset_key: CMIP.historical.CESM2.fx.gn
def convert_lon_to_180(ds):
ds['lon'] =(ds['lon']+ 180) % 360 - 180
ds = ds.sortby('lon')
return ds
def convert_lon_to_360(ds):
ds['lon'] =ds['lon']% 360
ds = ds.sortby('lon')
return lon % 360
(migth want to move this to a module!)
dss = convert_lon_to_180(dss)
dss['lon'].attrs['units'] = '$^\circ$ East'
Notice how the labels use both the attribute “standard_name” and “units” from the dataset.
4. The easiest interpolation: select with ‘nearest’ neighboor#
Example: let’s select zeppelin station: 78.906661, 11.889203
lat_zep = 78.906661
lon_zep = 11.889203
dss['T_C'].sel(lon=lon_zep, lat=lat_zep, method='nearest').plot()
[<matplotlib.lines.Line2D at 0x7f344060d090>]
Super quick averaging etc#
da_so4 = dss['mmrso4']
da_so4
<xarray.DataArray 'mmrso4' (member_id: 1, time: 240, lev: 32, lat: 192, lon: 288)> Size: 2GB dask.array<getitem, shape=(1, 240, 32, 192, 288), dtype=float32, chunksize=(1, 1, 16, 96, 144), chunktype=numpy.ndarray> Coordinates: * lat (lat) float64 2kB -90.0 -89.06 -88.12 -87.17 ... 88.12 89.06 90.0 * lon (lon) float64 2kB -180.0 -178.8 -177.5 ... 176.2 177.5 178.8 * member_id (member_id) object 8B 'r1i1p1f1' * lev (lev) float64 256B -3.643 -7.595 -14.36 ... -957.5 -976.3 -992.6 * time (time) datetime64[ns] 2kB 1990-01-15T12:00:00 ... 2009-12-15T1... Attributes: (12/19) cell_measures: area: areacella cell_methods: area: time: mean comment: Dry mass of sulfate (SO4) in aerosol particles as a fract... description: Dry mass of sulfate (SO4) in aerosol particles as a fract... frequency: mon id: mmrso4 ... ... time_label: time-mean time_title: Temporal mean title: Aerosol Sulfate Mass Mixing Ratio type: real units: kg kg-1 variable_id: mmrso4
Mean:
da_so4.mean(['time','lon'], keep_attrs=True).plot()#ylim=[1000,100], yscale='log')
<matplotlib.collections.QuadMesh at 0x7f34404d8750>
da_so4['lev'] = np.abs(da_so4['lev'].values)
da_so4.mean(['time','lon'], keep_attrs=True).plot(
ylim=[1000,100],
yscale='log'
)
<matplotlib.collections.QuadMesh at 0x7f34400b9490>
Standard deviation
dss['T_C'].std(['time']).plot()
<matplotlib.collections.QuadMesh at 0x7f34142cfa10>
Temperature change much stronger over land than ocean and higher at high latitudes…
5. Mask data and groupby: pick out seasons#
month = ds['time.month']
month
<xarray.DataArray 'month' (time: 1980)> Size: 16kB array([ 1, 2, 3, ..., 10, 11, 12]) Coordinates: * time (time) object 16kB 1850-01-15 12:00:00 ... 2014-12-15 12:00:00
dss_JA = dss.where(month.isin([7,8])).mean('time')
dss_JA
<xarray.Dataset> Size: 8MB Dimensions: (member_id: 1, lat: 192, lon: 288, lev: 32, nbnd: 2) Coordinates: * lat (lat) float64 2kB -90.0 -89.06 -88.12 -87.17 ... 88.12 89.06 90.0 * lon (lon) float64 2kB -180.0 -178.8 -177.5 ... 176.2 177.5 178.8 * member_id (member_id) object 8B 'r1i1p1f1' * lev (lev) float64 256B -3.643 -7.595 -14.36 ... -957.5 -976.3 -992.6 Dimensions without coordinates: nbnd Data variables: areacella (member_id, lat, lon) float32 221kB dask.array<chunksize=(1, 192, 288), meta=np.ndarray> mmrso4 (member_id, lev, lat, lon) float32 7MB dask.array<chunksize=(1, 16, 96, 144), meta=np.ndarray> ps (lat, lon) float32 221kB dask.array<chunksize=(192, 288), meta=np.ndarray> p0 float32 4B nan a (lev) float64 256B dask.array<chunksize=(32,), meta=np.ndarray> b (lev) float64 256B dask.array<chunksize=(32,), meta=np.ndarray> b_bnds (lev, nbnd) float64 512B dask.array<chunksize=(32, 2), meta=np.ndarray> lev_bnds (lev, nbnd) float64 512B dask.array<chunksize=(32, 2), meta=np.ndarray> a_bnds (lev, nbnd) float64 512B dask.array<chunksize=(32, 2), meta=np.ndarray> hurs (member_id, lat, lon) float32 221kB dask.array<chunksize=(1, 192, 288), meta=np.ndarray> tas (member_id, lat, lon) float32 221kB dask.array<chunksize=(1, 192, 288), meta=np.ndarray> T_C (member_id, lat, lon) float32 221kB dask.array<chunksize=(1, 192, 288), meta=np.ndarray>
dss_season = dss.groupby('time.season').mean(keep_attrs=True)
dss_season
<xarray.Dataset> Size: 33MB Dimensions: (season: 4, member_id: 1, lev: 32, lat: 192, lon: 288, nbnd: 2) Coordinates: * lat (lat) float64 2kB -90.0 -89.06 -88.12 -87.17 ... 88.12 89.06 90.0 * lon (lon) float64 2kB -180.0 -178.8 -177.5 ... 176.2 177.5 178.8 * member_id (member_id) object 8B 'r1i1p1f1' * lev (lev) float64 256B -3.643 -7.595 -14.36 ... -957.5 -976.3 -992.6 * season (season) object 32B 'DJF' 'JJA' 'MAM' 'SON' Dimensions without coordinates: nbnd Data variables: mmrso4 (season, member_id, lev, lat, lon) float32 28MB dask.array<chunksize=(1, 1, 16, 96, 144), meta=np.ndarray> ps (season, lat, lon) float32 885kB dask.array<chunksize=(1, 192, 288), meta=np.ndarray> hurs (season, member_id, lat, lon) float32 885kB dask.array<chunksize=(1, 1, 192, 288), meta=np.ndarray> tas (season, member_id, lat, lon) float32 885kB dask.array<chunksize=(1, 1, 192, 288), meta=np.ndarray> T_C (season, member_id, lat, lon) float32 885kB dask.array<chunksize=(1, 1, 192, 288), meta=np.ndarray> areacella (season, member_id, lat, lon) float32 885kB dask.array<chunksize=(4, 1, 192, 288), meta=np.ndarray> p0 (season) float32 16B 1e+05 1e+05 1e+05 1e+05 a (season, lev) float64 1kB dask.array<chunksize=(4, 32), meta=np.ndarray> b (season, lev) float64 1kB dask.array<chunksize=(4, 32), meta=np.ndarray> b_bnds (season, lev, nbnd) float64 2kB dask.array<chunksize=(4, 32, 2), meta=np.ndarray> lev_bnds (season, lev, nbnd) float64 2kB dask.array<chunksize=(4, 32, 2), meta=np.ndarray> a_bnds (season, lev, nbnd) float64 2kB dask.array<chunksize=(4, 32, 2), meta=np.ndarray> Attributes: (12/57) Conventions: CF-1.7 CMIP-6.2 activity_id: CMIP case_id: 15 cesm_casename: b.e21.BHIST.f09_g17.CMIP6-historical.001 contact: cesm_cmip6@ucar.edu creation_date: 2019-01-16T21:43:39Z ... ... intake_esm_attrs:activity_id: CMIP intake_esm_attrs:institution_id: NCAR intake_esm_attrs:version: v20190308 intake_esm_attrs:path: /mnt/craas1-ns9989k-ns9560k/ESGF/CMIP6/... intake_esm_attrs:_data_format_: netcdf intake_esm_dataset_key: CMIP.historical.CESM2.fx.gn
da_TC = dss_season['T_C']
%%time
da_TC.plot(col='season')
CPU times: user 21min 5s, sys: 3min 15s, total: 24min 20s
Wall time: 3min 13s
<xarray.plot.facetgrid.FacetGrid at 0x7f344060fa50>
Tip: Might want to load or compute.#
from dask.diagnostics import ProgressBar
%%time
with ProgressBar():
da_TC.load()
[########################################] | 100% Completed | 51.84 s
CPU times: user 10min 8s, sys: 3min 37s, total: 13min 46s
Wall time: 51.9 s
6. Controle the plot visuals:#
%%time
da_TC.plot(
col = 'season',
cmap = 'coolwarm',
xlim = [-100,100],
cbar_kwargs = {'label':'Temperature [$^\circ$C]'}
)
CPU times: user 644 ms, sys: 55.8 ms, total: 700 ms
Wall time: 702 ms
<xarray.plot.facetgrid.FacetGrid at 0x7f341c7678d0>
da_TC = da_TC.assign_attrs({'long_name': 'Temperature near surface'})
da_TC.mean('season', keep_attrs=True).plot()
<matplotlib.collections.QuadMesh at 0x7f33b044f9d0>
7. Plotting with cartopy#
See more here:
import cartopy as cy
import cartopy.crs as ccrs
da_plt = dss['mmrso4'].isel(lev=-1).mean('time', keep_attrs=True).squeeze()#('member_id')
da_plt
<xarray.DataArray 'mmrso4' (lat: 192, lon: 288)> Size: 221kB dask.array<getitem, shape=(192, 288), dtype=float32, chunksize=(96, 144), chunktype=numpy.ndarray> Coordinates: * lat (lat) float64 2kB -90.0 -89.06 -88.12 -87.17 ... 88.12 89.06 90.0 * lon (lon) float64 2kB -180.0 -178.8 -177.5 ... 176.2 177.5 178.8 member_id <U8 32B 'r1i1p1f1' lev float64 8B -992.6 Attributes: (12/19) cell_measures: area: areacella cell_methods: area: time: mean comment: Dry mass of sulfate (SO4) in aerosol particles as a fract... description: Dry mass of sulfate (SO4) in aerosol particles as a fract... frequency: mon id: mmrso4 ... ... time_label: time-mean time_title: Temporal mean title: Aerosol Sulfate Mass Mixing Ratio type: real units: kg kg-1 variable_id: mmrso4
from matplotlib.colors import LogNorm
with ProgressBar():
da_plt.load()
[########################################] | 100% Completed | 3.53 sms
da_plt
<xarray.DataArray 'mmrso4' (lat: 192, lon: 288)> Size: 221kB array([[7.0655864e-12, 7.0656254e-12, 7.0656757e-12, ..., 7.0654580e-12, 7.0654359e-12, 7.0655357e-12], [7.4523243e-12, 7.4701799e-12, 7.4873961e-12, ..., 7.3945355e-12, 7.4097612e-12, 7.4321209e-12], [8.0703352e-12, 8.0987569e-12, 8.1331625e-12, ..., 7.9838211e-12, 8.0185901e-12, 8.0491083e-12], ..., [3.2195205e-11, 3.2224824e-11, 3.2185157e-11, ..., 3.2204971e-11, 3.2198522e-11, 3.2200648e-11], [3.1399085e-11, 3.1360515e-11, 3.1390588e-11, ..., 3.1466201e-11, 3.1436742e-11, 3.1405465e-11], [3.0563073e-11, 3.0563111e-11, 3.0562844e-11, ..., 3.0563923e-11, 3.0565092e-11, 3.0564863e-11]], dtype=float32) Coordinates: * lat (lat) float64 2kB -90.0 -89.06 -88.12 -87.17 ... 88.12 89.06 90.0 * lon (lon) float64 2kB -180.0 -178.8 -177.5 ... 176.2 177.5 178.8 member_id <U8 32B 'r1i1p1f1' lev float64 8B -992.6 Attributes: (12/19) cell_measures: area: areacella cell_methods: area: time: mean comment: Dry mass of sulfate (SO4) in aerosol particles as a fract... description: Dry mass of sulfate (SO4) in aerosol particles as a fract... frequency: mon id: mmrso4 ... ... time_label: time-mean time_title: Temporal mean title: Aerosol Sulfate Mass Mixing Ratio type: real units: kg kg-1 variable_id: mmrso4
My headline#
my comments
comment number two#
8. Global average: weighted means!#
Why is this wrong?
9. Convert to pandas & do some random fun stuff:#
Maybe we e.g. want to compare with a station, or just use some of the considerable functionalities available from pandas. It’s easy to convert back and forth between xarray and pandas:
A lot of these functions also exist in xarray!10 Other stuff#
Pick out station:#
Pick out the vairables we need.
Resample:#
Obs: might want to convert to pandas#
At this point we basically have a time series and the dataset is not to big, so might want to convert to pandas:
240 rows × 9 columns
lets do something unnecesarily complicated :D#
Convert to pandas dataframe#
Because more functionality
qcut, cut#
qcut splits the data into quantile ranges
Cut cuts into categories
df_ri
13271040 rows × 11 columns
Convert back to xarray if we need:#
ds_new
mask by category#
Improve and reduce risk of typo:#