Skip to content

Commit

Permalink
Merge pull request #269 from JuliaDataCubes/lina_examples
Browse files Browse the repository at this point in the history
Lina examples
  • Loading branch information
lazarusA authored Jun 30, 2023
2 parents f4f7f4c + a8fb690 commit 08f1d8f
Show file tree
Hide file tree
Showing 14 changed files with 999 additions and 15 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/Documenter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ jobs:
env:
DISPLAY: ':0'
steps:
- name: Install matplotlib
run: if [ "$RUNNER_OS" = "Linux" ]; then sudo apt-get install -y python3-matplotlib; fi
shell: bash
- uses: actions/checkout@v3
- uses: julia-actions/setup-julia@v1
- uses: julia-actions/cache@v1
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ build
.vscode
.DS_Store
*.zarr
*.nc

docs/docs
docs/site
Expand Down
18 changes: 14 additions & 4 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
[deps]
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
ClusterManagers = "34f1f09b-3a8b-5176-ab39-66d58a4d544e"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
DimensionalData = "0703355e-b756-11e9-17c0-8b28908087d0"
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
DiskArrays = "3c3547ce-8d99-4f5e-a174-61eb10b00ae3"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
DocumenterMarkdown = "997ab1e6-3595-5248-9280-8efb232c3433"
Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
EarthDataLab = "359177bc-a543-11e8-11b7-bb015dba3358"
GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a"
GeoInterface = "cf35fbd7-0cd7-5166-be24-54bfbe79505f"
GeoJSON = "61d90e0f-e114-555e-ac52-39dfb47a3ef9"
GeoMakie = "db073c08-6b98-4ee5-b6a4-5efafb3259c6"
JSServe = "824d6782-a2ef-11e9-3a09-e5662e0c26f9"
Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
MakieTeX = "6d554a22-29e7-47bd-aee5-0c5f06619414"
MultivariateStats = "6f286f6a-111f-5878-ab1e-185364afe411"
NetCDF = "30363a11-5582-574a-97bb-aa9a979735b9"
PlotUtils = "995b91a9-d308-5afd-9ec6-746e21dbc043"
PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"
PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee"
SkipNan = "aed68c70-c8b0-4309-8cd1-d392a74f991a"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
WGLMakie = "276b4fcb-3e11-5398-bf8b-a0c2d153d008"
WeightedOnlineStats = "bbac0a1f-7c9d-5672-960b-c6ca726e5d5d"
YAXArrayBase = "90b8fcef-0c2d-428d-9c56-5f86629e9d14"
YAXArrays = "c21b50f5-aa40-41ea-b809-c0f5e47bfa5c"
Zarr = "0a941bbe-ad1d-11e8-39d9-ab76183a1d99"
4 changes: 2 additions & 2 deletions docs/examples/Gallery/simplemaps.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Zarr, YAXArrays, Dates
using GLMakie, GeoMakie
using CairoMakie.GeometryBasics
using GLMakie.GeometryBasics

store ="gs://cmip6/CMIP6/ScenarioMIP/DKRZ/MPI-ESM1-2-HR/ssp585/r1i1p1f1/3hr/tas/gn/v20190710/"
g = open_dataset(zopen(store, consolidated=true))
Expand All @@ -26,7 +26,7 @@ fig
nlon = lon .- 180 .+ δlon
ndata = circshift(data, (192,1))

GLMakie.activate!()

fig = Figure(resolution = (1200,600))
ax = GeoAxis(fig[1,1])
surface!(ax, nlon, lat, ndata; colormap = :seaborn_icefire_gradient, shading=false)
Expand Down
17 changes: 15 additions & 2 deletions docs/examples/HowdoI/howdoi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# !!! question

# ## extract the axes names from a Cube?
# ## Extract the axes names from a Cube

using YAXArrays
c = YAXArray(rand(10,10,5))
Expand All @@ -12,7 +12,20 @@ caxes(c)

# !!! question

# ## concatenate cubes?
# ## Obtain values from axes and data from the cube

# There are two options to collect values from axes. In this examples the axis ranges from 1 to 10. Later we will see that axes can be `RangeAxis` such as latitude and longitude values, or `CategoricalAxis` which are strings such as variable names.

## this two examples bring the same result
collect(getAxis("Dim_1", c).values)
collect(c.axes[1].values)

## to collect data from a cube works exactly the same as doing it from an array
c[:,:,1]



# ## Concatenate cubes

# It is possible to concatenate several cubes that shared the same dimensions using the [`concatenatecubes`]@ref function.

Expand Down
2 changes: 1 addition & 1 deletion docs/examples/UserGuide/applyfunctions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ function mean_seasonal_cycle(c; ndays = 365)
return msc
end

msc = mean_seasonal_cycle(c)
msc = mean_seasonal_cycle(c);

# ## Plot results: mean seasonal cycle

Expand Down
2 changes: 1 addition & 1 deletion docs/examples/UserGuide/create_from_func.jl
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,4 @@ gen_cube = mapCube(g, (lon, lat, time);
# !!! info "slicing dim"
# Note that now the broadcasted dimension is `lon`.

gen_cube.data[:,:,1]
gen_cube.data[:, :, 1]
1 change: 0 additions & 1 deletion docs/examples/UserGuide/examples_from_esdl.jl

This file was deleted.

228 changes: 228 additions & 0 deletions docs/examples/UserGuide/examples_from_esdl_study_1.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
# # Examples from the ESDL paper
# ## Earth Syst. Dynam., 11, 201–234, 2020 [doi](https://doi.org/10.5194/esd-11-201-2020)

# **NOTE:** This section is based on the case studies from the paper "Earth system data cubes unravel global multivariate dynamics" by Mahecha, Gans et al. (2019). Original scripts are available at https://github.com/esa-esdl/ESDLPaperCode.jl.
# - We have slightly adjusted the scripts. A few differences are that these new scripts are updated to Julia 1.9, and the YAXArrays.jl package is used.
# - The dataset has been updated but it has less available variables. Therefore the results might differ.
# - The calculations are performed with a very coarse spatial (2.5°) and temporal resolution (monthly).
# - These are examples for illustrative purposes of the packages and do not intend any deeper scientific interpretation. For scientific analysis use the higher spatio-temporal resolution datasets.

# ## Case study 1: Seasonal dynamics on the land surface
# ### Based on simple seasonal statistics

# * The code is written based on Julia 1.9

# * Normal text are explanations referring to notation and equations in the paper

# * `# comments in the code are itended explain specific aspects of the coding`

# * **New steps in workflows are introduced with bold headers**

# Load requiered packages

using Pkg

## for plotting later on (need to be loaded first, to avoid conflicts)
using PyCall, PyPlot, PlotUtils

## for operating data cubes
using Zarr, YAXArrays
using EarthDataLab

## for data analysis
using Statistics, Dates, SkipNan


# Next we get a handle to the Earth System Data Cube we want to use, which provides a description of the cube:
cube_handle = esdc(res="tiny")

## if we want the names of the variables:
println(getAxis("Var", cube_handle).values)

# We decide which variables to plot:
vars = ["gross_primary_productivity", "air_temperature_2m", "surface_moisture"]

## time based on data span availability
time_overlap = Date("2001-01-01")..Date("2020-12-31")

# So we "virtually get" the cube data virtually:
cube_subset = subsetcube(cube_handle, variable=vars, time=time_overlap)

# The next function estimates the median seasonal cycle. This changes the dimension of the cube, as the time domain is replaced by day of year (doy); Eq. 9 in the manuscript:
# $$
# f_{\{time\}}^{\{doy\}} : \mathcal{C}(\{lat, lon, time, var\}) \rightarrow \mathcal{C}(\{lat, lon, doy, var\})
# $$

# median seasonal cycle built-in function
cube_msc = getMedSC(cube_subset)

# The resulting cube `cube_msc` has is of the form $\mathcal{C}(\{lat, lon, doy, var\})$. On this cube we want to apply function `nan_med` (see below) to estimate latitudinal averages for all variables. The atomic function (Eq. 10) needs to
# have the form, i.e. expecting a longitude and returning a scalar:
# $$
# f_{\{lon\}}^{\{\}} : \mathcal{C}(\{lat, lon, doy, var\}) \rightarrow \mathcal{C}(\{lat, doy, var\})
# $$

import Statistics.median
cube_msc_lat = mapslices(median skipmissing, cube_msc, dims = "Lon")

# The result of each operation on a data cube is a data cube. Here the resulting cube has the form $\mathcal{C}(\{doy, lat, var\})$ as expected but in different order, which is, irrelevant as axes have no natural order.

# ### Visualization

# At this point we leave the `Earth Data Lab` and and go for visualizations. Using PyPlot we can generate fig. 3 of the paper, the data can be exatracted from the resutls cube via array-access `A[:, :]`.


## Create a plot and make it a polar plot
function zonal_polar_plot(d_msc_lat, sbp, it, vari, lab)

ax = subplot(sbp, polar = "true")
ourcmap = ColorMap(get_cmap("Spectral_r", 72))

## set polar ticks and labels
month_ang = 0:11
month_ang = month_ang .* (360/12)
month_lab = ["Jan"; "Feb"; "Mar"; "Apr"; "May"; "Jun"; "Jul"; "Aug"; "Sep"; "Oct"; "Nov"; "Dec"]

## tuning
ax.set_yticklabels([])
ax.set_thetagrids(angles = month_ang,
labels = month_lab,
#rotation = month_ang
)

## set Jan to the top of the plot
ax.set_theta_zero_location("N")

## switch to clockwise
ax.set_theta_direction(-1)

## color setup
if isequal(vari, "gross_primary_productivity")
N_min = 0
N_max = 8
N_var = 8
elseif isequal(vari, "air_temperature_2m")
N_min = -35
N_max = 35
N_var = 15
elseif isequal(vari, "surface_moisture")
N_min = 0
N_max = 50
N_var = 10
end

## background setup

## define time (all could be done more elegantly in julia I guess... )
time_ang = range(0, stop = 12, step = 0.25)
N_time = length(time_ang)
time_ang = time_ang .* (360/12)
time_rad = time_ang .* (pi / 180)

## create a continous var for the background
N_div = N_time*10
y = range(N_min, stop = N_max, length = N_div)

## grid to fill the polar plot
xgrid = repeat(time_rad', N_div, 1)
ygrid = repeat(y, 1, N_time)

## a grid of NaNs to make an extra colorbar later
nangrid = zeros(size(ygrid)).*NaN
levels = range(-90, stop = 90, step = 10)
ticks = range(-80, stop = 80, step = 20)

axsurf2 = ax.contourf(xgrid, ygrid, ygrid.*NaN, N_max,
cmap = ourcmap,
levels = levels,
ticks = ticks)

## background to the range of values
if isequal(vari, "gross_primary_productivity")
axsurf = ax.contourf(xgrid, ygrid, ygrid, N_max,
cmap = ColorMap("gray_r"),
extend = "max")
elseif isequal(vari, "air_temperature_2m")
axsurf = ax.contourf(xgrid, ygrid, ygrid, N_max,
cmap = ColorMap("gray_r"),
extend = "both")
elseif isequal(vari, "surface_moisture")
axsurf = ax.contourf(xgrid, ygrid, ygrid, N_max,
cmap = ColorMap("gray_r"),
extend = "max")
end

## colorbar setup
if isodd(sbp)
## add forground colorbar
cban = colorbar(axsurf2, fraction = 0.05, shrink = 0.5, pad = 0.18)
cban.ax.set_title(label = "Latitude")
cban.set_ticks([-80, -60, -40, -20, 0, 20, 40, 60, 80])
cban.set_ticklabels(["80°N", "60°N", "40°N", "20°N", "", "20°S", "40°S", "60°S", "80°S"])
cban.ax.invert_yaxis()
else
## add background colorbar
cbsurf = colorbar(axsurf, fraction = 0.05, shrink = 0.5, pad = 0.18)
if vari == "gross_primary_productivity"
cbsurf.ax.set_title(label = "GPP")
cbsurf.set_label(label = "g C / (m2 d)", rotation=270, labelpad=+20)
elseif vari == "air_temperature_2m"
cbsurf.ax.set_title(label = "Tair")
cbsurf.set_label(label = "°C", rotation = 270, labelpad=+20)
elseif vari == "surface_moisture"
cbsurf.ax.set_title(label = "Surf. Moist.")
cbsurf.set_label(label = "[]", rotation = 270, labelpad=+20)
cbsurf.set_ticks([0, 10, 20, 30, 40, 50])
cbsurf.set_ticklabels(["0", "0.1", "0.2", "0.3", "0.4", "0.5"])
end
end

## forground setup

## plot the real data
N_msc = size(d_msc_lat)[1]
time_ang_dat = range(1/N_msc, step = 1/N_msc, length = N_msc)
time_ang_dat = time_ang_dat .* (360)
time_rad_dat = time_ang_dat .* (pi / 180)
time_rad_dat = [time_rad_dat; time_rad_dat[1]]

## add your data
for j = it
jj = convert(Int, j)
try
var_idx = findall(vari .== getAxis("Variable", d_msc_lat).values)[1]
ts = d_msc_lat[:, jj, var_idx]
va = [ts; ts[1]]
## correction for temperature
if isequal(vari, "air_temperature_2m")
va = va.-273.15
elseif isequal(vari, "surface_moisture")
va = va.*100
end
p = ax.plot(time_rad_dat, va,
color = ourcmap(jj),
linewidth = 0.8)
catch
end
end

end

# create a new figure
f1 = figure("polar_lineplot_new", figsize = (10, 15))

# get the latitude values for which we have data
L = collect(getAxis("lat", caxes(cube_msc_lat)).values)

sbps = 321:2:332
labtoshow = ["a)", "b)", "c)", "d)", "e)", "f)"]
vari = getAxis("Variable", caxes(cube_msc_lat)).values

for (sbp, lab, vari) in zip(sbps, labtoshow, vari)
it1 = range(72/2, stop = 1, step = -2)
it2 = range(72/2+1, stop = 72, step = 2)
zonal_polar_plot(cube_msc_lat, sbp, it1, vari, lab)
zonal_polar_plot(cube_msc_lat, sbp+1, it2, vari, lab)
end

f1
Loading

0 comments on commit 08f1d8f

Please sign in to comment.