Skip to content

Commit f1ab1c5

Browse files
Merge pull request #20 from climate-resource/add-cubic
Add basic cubic interpolator
2 parents 22b146a + 221ab07 commit f1ab1c5

10 files changed

Lines changed: 1084 additions & 10 deletions

File tree

changelog/20.docs.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
+ convert `scratch.py` into how-to-guide and add it into the navigation
2+
+ add docstring to functions in `add_cubic.py` module

docs/NAVIGATION.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ See https://oprypin.github.io/mkdocs-literate-nav/
88
- [Installation](installation.md)
99
- [How-to guides](how-to-guides/index.md)
1010
- [Do a basic calculation](how-to-guides/basic-calculation.md)
11+
- [Use a cubic spline for harmonisation](how-to-guides/cubic_spline.py)
1112
- [Tutorials](tutorials/index.md)
1213
- [Getting Started](tutorials/tutorial.py)
1314
- [Further background](further-background/index.md)
20.9 KB
Loading

docs/how-to-guides/cubic_spline.py

Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
# ---
2+
# jupyter:
3+
# jupytext:
4+
# text_representation:
5+
# extension: .py
6+
# format_name: percent
7+
# format_version: '1.3'
8+
# jupytext_version: 1.16.6
9+
# kernelspec:
10+
# display_name: Python 3 (ipykernel)
11+
# language: python
12+
# name: python3
13+
# ---
14+
15+
# %% [markdown]
16+
# # How to use a cubic-spline as harmonisation of two functions?
17+
# In this tutorial, we present use cases for applying a cubic-spline
18+
# to harmonise two functions which we will call in the following
19+
# `diverge_from` and `harmonisee`.
20+
# The `cubic-spline` interpolates between `diverge_from` and `harmonisee`.
21+
22+
23+
# %%
24+
# import relevant libraries
25+
from __future__ import annotations
26+
27+
import matplotlib.pyplot as plt
28+
import numpy as np
29+
import scipy.interpolate
30+
31+
from gradient_aware_harmonisation.add_cubic import (
32+
harmonise_splines_add_cubic,
33+
)
34+
from gradient_aware_harmonisation.spline import SplineScipy
35+
36+
# %% [markdown]
37+
38+
# We start by defining the spline `diverge_from` as a linear
39+
# function with intercept=1.0 and slope=2.5.
40+
41+
# %%
42+
diverge_from_gradient = 2.5
43+
diverge_from_y_intercept = 1.0
44+
45+
diverge_from = SplineScipy(
46+
scipy.interpolate.PPoly(
47+
c=[[diverge_from_gradient], [diverge_from_y_intercept]],
48+
x=[0, 1e8],
49+
)
50+
)
51+
52+
# %% [markdown]
53+
# ## Scenarios
54+
# ### Harmonisation time < convergence time
55+
# In the following, we consider nine scenarios in which the
56+
# `harmonisee` spline differs from the `diverge_from` spline
57+
# due to varying shifts in the intercept (`[0.0, -1.2, 1.2]`)
58+
# and slope (`[1.0, 0.7, 1.4]`).
59+
# In all of these scenarios we consider harmonisation time
60+
# (`=0`) < convergence time (`=3.2`).
61+
62+
# %%
63+
harmonisation_time = 0.0
64+
convergence_time = 3.2
65+
66+
67+
# %%
68+
def plot_spline(spline, x, ax, label, gradient=False): # noqa: D103
69+
ax.plot(
70+
x,
71+
spline(x),
72+
label=label,
73+
)
74+
75+
if gradient:
76+
ax.set_title("Gradient")
77+
else:
78+
ax.set_title("Function")
79+
80+
81+
# %%
82+
i = 0
83+
for y_intercept_shift in [0.0, -1.2, 1.2]:
84+
for gradient_factor in [1.0, 0.7, 1.4]:
85+
harmonisee = SplineScipy(
86+
scipy.interpolate.PPoly(
87+
c=[
88+
[diverge_from_gradient * gradient_factor],
89+
[diverge_from_y_intercept + y_intercept_shift],
90+
],
91+
x=[0, 1e8],
92+
)
93+
)
94+
95+
res = harmonise_splines_add_cubic(
96+
diverge_from=diverge_from,
97+
harmonisee=harmonisee,
98+
harmonisation_time=harmonisation_time,
99+
convergence_time=convergence_time,
100+
)
101+
102+
fig, axes = plt.subplots(ncols=2, figsize=(12, 4))
103+
104+
plot_spline(
105+
diverge_from, np.linspace(-1.0, 3.0, 101), ax=axes[0], label="diverge_from"
106+
)
107+
plot_spline(
108+
harmonisee,
109+
np.linspace(harmonisation_time, 2 * convergence_time, 101),
110+
ax=axes[0],
111+
label="harmonisee",
112+
)
113+
plot_spline(
114+
res,
115+
np.linspace(harmonisation_time, 2 * convergence_time, 101),
116+
ax=axes[0],
117+
label="res",
118+
)
119+
120+
plot_spline(
121+
diverge_from.derivative(),
122+
np.linspace(-1.0, 3.0, 101),
123+
ax=axes[1],
124+
label="diverge_from",
125+
gradient=True,
126+
)
127+
plot_spline(
128+
harmonisee.derivative(),
129+
np.linspace(harmonisation_time, 2 * convergence_time, 101),
130+
ax=axes[1],
131+
label="harmonisee",
132+
gradient=True,
133+
)
134+
plot_spline(
135+
res.derivative(),
136+
np.linspace(harmonisation_time, 2 * convergence_time, 101),
137+
ax=axes[1],
138+
label="cubic-spline",
139+
gradient=True,
140+
)
141+
142+
for ax in axes:
143+
ax.axvline(
144+
harmonisation_time,
145+
label="harmonisation_time",
146+
color="gray",
147+
linestyle=":",
148+
)
149+
ax.axvline(
150+
convergence_time, label="convergence_time", color="gray", linestyle="--"
151+
)
152+
for ax in axes[1::2]:
153+
ax.legend(handlelength=1.1, loc="center right", fontsize="small")
154+
155+
fig.suptitle(
156+
f"Scenario {i+1} (intercept shift: {y_intercept_shift},"
157+
+ f" slope factor: {gradient_factor})"
158+
)
159+
plt.show()
160+
i = i + 1
161+
162+
# %% [markdown]
163+
# ### Harmonisation time > convergence time
164+
# In the following, we consider the same nine scenarios as
165+
# above in which the `harmonisee` spline differs
166+
# from the `diverge_from` spline due to varying shifts in the
167+
# intercept (`[0.0, -1.2, 1.2]`) and slope (`[1.0, 0.7, 1.4]`).
168+
# However, this time we consider
169+
# harmonisation time (`=1.0`) > convergence time (`=-1.0`).
170+
171+
# %%
172+
diverge_from_gradient = 2.5
173+
diverge_from_y_intercept = 1.0
174+
175+
# TODO: from left-edge or something here
176+
diverge_from = SplineScipy(
177+
scipy.interpolate.PPoly(
178+
c=[
179+
[diverge_from_gradient],
180+
[diverge_from_y_intercept - 10.0 * diverge_from_gradient],
181+
],
182+
x=[-10.0, 10.0],
183+
)
184+
)
185+
186+
# %%
187+
harmonisation_time = 1.0
188+
convergence_time = -1.0
189+
190+
# %%
191+
# Backwards along x harmonisation
192+
i = 0
193+
for y_intercept_shift in [0.0, -1.2, 1.2]:
194+
for gradient_factor in [1.0, 0.7, 1.4]:
195+
harmonisee = SplineScipy(
196+
scipy.interpolate.PPoly(
197+
c=[
198+
[diverge_from_gradient * gradient_factor],
199+
[
200+
diverge_from_y_intercept
201+
- 10.0 * diverge_from_gradient
202+
+ y_intercept_shift
203+
],
204+
],
205+
x=[-10.0, 10.0],
206+
)
207+
)
208+
209+
res = harmonise_splines_add_cubic(
210+
diverge_from=diverge_from,
211+
harmonisee=harmonisee,
212+
harmonisation_time=harmonisation_time,
213+
convergence_time=convergence_time,
214+
)
215+
216+
fig, axes = plt.subplots(ncols=2, figsize=(12, 4))
217+
218+
plot_spline(
219+
diverge_from, np.linspace(-1.0, 3.0, 101), ax=axes[0], label="diverge_from"
220+
)
221+
plot_spline(
222+
harmonisee,
223+
np.linspace(harmonisation_time, 2 * convergence_time, 101),
224+
ax=axes[0],
225+
label="harmonisee",
226+
)
227+
plot_spline(
228+
res,
229+
np.linspace(harmonisation_time, 2 * convergence_time, 101),
230+
ax=axes[0],
231+
label="res",
232+
)
233+
234+
plot_spline(
235+
diverge_from.derivative(),
236+
np.linspace(-1.0, 3.0, 101),
237+
ax=axes[1],
238+
label="diverge_from",
239+
gradient=True,
240+
)
241+
plot_spline(
242+
harmonisee.derivative(),
243+
np.linspace(harmonisation_time, 2 * convergence_time, 101),
244+
ax=axes[1],
245+
label="harmonisee",
246+
gradient=True,
247+
)
248+
plot_spline(
249+
res.derivative(),
250+
np.linspace(harmonisation_time, 2 * convergence_time, 101),
251+
ax=axes[1],
252+
label="cubic-spline",
253+
gradient=True,
254+
)
255+
256+
for ax in axes:
257+
ax.axvline(
258+
harmonisation_time,
259+
label="harmonisation_time",
260+
color="gray",
261+
linestyle=":",
262+
)
263+
ax.axvline(
264+
convergence_time, label="convergence_time", color="gray", linestyle="--"
265+
)
266+
for ax in axes[1::2]:
267+
ax.legend(handlelength=1.1, loc="center right", fontsize="small")
268+
269+
fig.suptitle(
270+
f"Scenario {i+1} (intercept shift: {y_intercept_shift},"
271+
+ f" slope factor: {gradient_factor})"
272+
)
273+
plt.show()
274+
i = i + 1

docs/how-to-guides/index.md

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,4 @@ This part of the project documentation
44
focuses on a **problem-oriented** approach.
55
We'll go over how to solve common tasks.
66

7-
## How can I do a basic calculation?
8-
9-
<!---
10-
You will probably want to remove this bit.
11-
12-
It is included to demonstrate how to include sub-sections
13-
and cross-reference them.
14-
-->
7+
+ [How can I use a cubic spline for harmonisation?](cubic_spline)

mkdocs.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,11 @@ plugins:
9292
- http://xarray.pydata.org/en/stable/objects.inv
9393
options:
9494
docstring_style: numpy
95-
relative_crossrefs: yes
95+
relative_crossrefs: true
9696
separate_signature: true
9797
show_root_heading: false
9898
show_signature_annotations: true
99+
show_docstring_examples: true
99100
show_source: true
100101
signature_crossrefs: true
101102
summary:

0 commit comments

Comments
 (0)