Skip to content

Commit cb0d387

Browse files
authored
Addressing the reviews for JOSS submission (#83)
* permute left and right axis to ease reading * write output to csv * correct examples * csv outputs to data folder * read output from new csv file * change timing to min (consistent with @belapsed) * use @belapsed * change csv name in comment * update figures * add extensibility earlier + modify description of performance * specify ewstools version * generalise to OffsetArrays * remove unused packages and add OffsetArrays
1 parent d6b5caf commit cb0d387

File tree

12 files changed

+130
-118
lines changed

12 files changed

+130
-118
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ Manifest.toml
44
*.css
55
*style.jl
66
docs/src/examples/*.md
7-
paper/wip
7+
paper/data/*.csv

ext/TransitionVisualizations.jl

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ function TransitionsInTimeseries.plot_indicator_changes(res::SegmentedWindowResu
5151
fig, n = init_rowwise_visualisation(res, colors, indicator_names,
5252
chametric_names, accent_linewidth)
5353
for k in eachindex(res.t_indicator)
54-
Makie.lines!(contents(fig[1, 1])[1], res.t[k], res.x[k], color = colors[1],
55-
linewidth = accent_linewidth)
5654
lineplot_metrics!(fig, n, res.config, res.t_indicator[k], res.x_indicator[k],
5755
res.t_change[k], res.x_change[k, :], colors, accent_linewidth)
5856
end
@@ -65,17 +63,17 @@ function init_rowwise_visualisation(res, colors, indicator_names,
6563
chametric_names, accent_linewidth)
6664

6765
fig = Makie.Figure(size = (700, 450), fontsize = 12)
68-
rlabels = vcat([""], indicator_names)
69-
llabels = vcat(["Input"], chametric_names)
66+
llabels = vcat(["Input"], indicator_names)
67+
rlabels = vcat([""], chametric_names)
7068
n = length(llabels)
7169

7270
# rowaspect = 5
73-
raxs = [Makie.Axis(fig[i, 1], ylabel = rlabels[i],
74-
xticklabelsvisible = false, yaxisposition = :right, ygridvisible = false,
75-
ylabelcolor = colors[2], yticklabelcolor = colors[2]) for i in 1:n]
7671
laxs = [Makie.Axis(fig[i, 1], ylabel = llabels[i],
7772
xticklabelsvisible = false, ygridvisible = false,
7873
ylabelcolor = colors[1], yticklabelcolor = colors[1]) for i in 1:n]
74+
raxs = [Makie.Axis(fig[i, 1], ylabel = rlabels[i],
75+
xticklabelsvisible = false, yaxisposition = :right, ygridvisible = false,
76+
ylabelcolor = colors[2], yticklabelcolor = colors[2]) for i in 1:n]
7977
Makie.linkxaxes!(laxs..., raxs...)
8078

8179
hidedecorations!(raxs[1])
@@ -90,7 +88,7 @@ function init_rowwise_visualisation(res, colors, indicator_names,
9088
labels = ["original signal", "surro signals"]
9189
width = 0.5
9290
if length(res.t_indicator[1]) > 1
93-
elements = vcat(elements, [MarkerElement(marker = :circle, color = colors[1],
91+
elements = vcat(elements, [MarkerElement(marker = :circle, color = colors[2],
9492
strokecolor = :transparent, markersize = ms) for ms in [10, 5]])
9593
labels = vcat(labels, ["original change metric", "surro change metrics"])
9694
width = 1
@@ -106,14 +104,14 @@ function lineplot_metrics!(fig, n, config, t_ind, x_ind, t_cha, x_cha,
106104
for i in 2:n
107105
j = i-1
108106
if !isnothing(config.indicators)
109-
Makie.lines!(contents(fig[i, 1])[2], t_ind, x_ind[:, j], color = colors[2],
107+
Makie.lines!(contents(fig[i, 1])[1], t_ind, x_ind[:, j], color = colors[1],
110108
linewidth = accent_linewidth)
111109
end
112110
if length(t_cha) > 1
113-
lines!(contents(fig[i, 1])[1], t_cha, x_cha[:, j], color = colors[1],
111+
lines!(contents(fig[i, 1])[2], t_cha, x_cha[:, j], color = colors[2],
114112
linewidth = accent_linewidth)
115113
else
116-
Makie.scatter!(contents(fig[i, 1])[1], t_cha, x_cha[j], color = colors[1],
114+
Makie.scatter!(contents(fig[i, 1])[2], t_cha, x_cha[j], color = colors[2],
117115
markersize = 10)
118116
end
119117
end
@@ -166,26 +164,28 @@ function lines_over_surro!(fig, nsurro, t, t_ind, t_cha, x, signif, config,
166164
for ns in 1:nsurro
167165
s = TimeseriesSurrogates.surrogate(x, signif.surrogate)
168166
Makie.lines!(contents(fig[1, 1])[1], t, s; color = (colors[1], 2/nsurro), linewidth = 1)
169-
for (i, cha) in enumerate(config.change_metrics)
170167

168+
for (i, cha) in enumerate(config.change_metrics)
171169
if isnothing(config.indicators)
172170
p = s
173171
else
174172
p = windowmap(config.indicators[i], s; width = config.width_ind,
175173
stride = config.stride_ind)
176-
Makie.lines!(contents(fig[i+1, 1])[2], t_ind, p; color = (colors[2], 2/nsurro),
174+
Makie.lines!(contents(fig[i+1, 1])[1], t_ind, p; color = (colors[1], 2/nsurro),
177175
linewidth = 1)
178176
end
177+
179178
if length(t_cha) > 1
180179
q = windowmap(cha, p; width = config.width_cha, stride = config.stride_cha)
181-
Makie.lines!(contents(fig[i+1, 1])[1], t_cha, q; color = (colors[1], 2/nsurro),
180+
Makie.lines!(contents(fig[i+1, 1])[2], t_cha, q; color = (colors[2], 2/nsurro),
182181
linewidth = 1)
183182
else
184183
cha = precompute(cha, eachindex(p))
185184
q = windowmap(cha, p; width = length(p), stride = 1)
186-
Makie.scatter!(contents(fig[i+1, 1])[1], t_cha, q[1], color = (colors[1], 2/nsurro),
185+
Makie.scatter!(contents(fig[i+1, 1])[2], t_cha, q[1], color = (colors[2], 2/nsurro),
187186
markersize = 5)
188187
end
188+
189189
if !isnothing(flags) && ns == 1 && length(t_cha) > 1
190190
Makie.vlines!(contents(fig[i+1, 1])[1], t_cha[flags[:, i]];
191191
color = (:black, 0.1))

paper/code/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[deps]
2+
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
23
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
34
DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab"
4-
TransitionsInTimeseries = "5f5b98ec-1183-43e0-887a-12fdc55c52f7"

paper/code/ewstools-tuto-1.py

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,58 +3,74 @@
33
import matplotlib.pyplot as plt
44
import ewstools
55
from ewstools.models import simulate_ricker
6+
from importlib.metadata import version
67

7-
# Set seed for reproducibility
8-
np.random.seed(0)
8+
if version('ewstools') != '2.1.0':
9+
raise ValueError('Please install version 2.1.0 of ewstools')
910

10-
# Initialize time series and spectrum computation
11-
series = simulate_ricker(tmax=1000, F=[0,2.7])
12-
ts = ewstools.TimeSeries(data=series, transition=860)
13-
ts.detrend(method='Lowess', span=0.2)
14-
ts.state[['state','smoothing']].plot()
15-
ts.compute_spectrum(rolling_window=0.5, ham_length=40)
11+
def ewstools_setup():
12+
# Initialize time series and spectrum computation
13+
series = simulate_ricker(tmax=1000, F=[0,2.7])
14+
ts = ewstools.TimeSeries(data=series, transition=860)
15+
ts.detrend(method='Lowess', span=0.2)
16+
ts.state[['state','smoothing']].plot()
17+
ts.compute_spectrum(rolling_window=0.5, ham_length=40)
18+
return ts
1619

17-
# Initialize parameters for timing functions
18-
rw = 0.5
19-
n = 100
20-
t_elapsed = np.zeros(10)
20+
np.random.seed(0) # Set random seed for reproducibility
21+
rw = 0.5 # Rolling window for variance computation
22+
ts = ewstools_setup() # Setup time series
23+
n = 100 # Number of iterations for timing
24+
t_elapsed = np.zeros(n) # Array to store elapsed times
25+
t_minruntime = np.zeros(8) # Array to store minimum runtime
2126

22-
# Time functions (in a not very elegant way)
23-
t0 = time.time()
2427
for i in range(n):
28+
t0 = time.time()
2529
ts.compute_var(rolling_window=rw)
26-
t_elapsed[0] = time.time() - t0
30+
t_elapsed[i] = time.time() - t0
31+
t_minruntime[0] = min(t_elapsed)
2732

28-
t0 = time.time()
2933
for i in range(n):
34+
t0 = time.time()
3035
ts.compute_cv()
31-
t_elapsed[1] = time.time() - t0
36+
t_elapsed[i] = time.time() - t0
37+
t_minruntime[1] = min(t_elapsed)
3238

33-
t0 = time.time()
3439
for i in range(n):
40+
t0 = time.time()
3541
ts.compute_skew(rolling_window=rw)
36-
t_elapsed[2] = time.time() - t0
42+
t_elapsed[i] = time.time() - t0
43+
t_minruntime[2] = min(t_elapsed)
3744

38-
t0 = time.time()
3945
for i in range(n):
46+
t0 = time.time()
4047
ts.compute_kurt()
41-
t_elapsed[3] = time.time() - t0
48+
t_elapsed[i] = time.time() - t0
49+
t_minruntime[3] = min(t_elapsed)
4250

43-
t0 = time.time()
4451
for i in range(n):
52+
t0 = time.time()
4553
ts.compute_auto(rolling_window=rw, lag=1)
46-
t_elapsed[4] = time.time() - t0
54+
t_elapsed[i] = time.time() - t0
55+
t_minruntime[4] = min(t_elapsed)
4756

48-
t0 = time.time()
4957
for i in range(n):
58+
t0 = time.time()
5059
ts.compute_smax()
51-
t_elapsed[5] = time.time() - t0
60+
t_elapsed[i] = time.time() - t0
61+
t_minruntime[5] = min(t_elapsed)
5262

53-
t0 = time.time()
5463
for i in range(n):
64+
t0 = time.time()
5565
ts.compute_ktau()
56-
t_elapsed[6] = time.time() - t0
66+
t_elapsed[i] = time.time() - t0
67+
t_minruntime[6] = min(t_elapsed)
5768

58-
t0 = time.time()
59-
surro = ewstools.core.block_bootstrap(ts.state.residuals, n, bs_type='Stationary', block_size=10)
60-
t_elapsed[7] = time.time() - t0
69+
for i in range(n):
70+
t0 = time.time()
71+
ewstools.core.block_bootstrap(ts.state.residuals, 1, bs_type='Stationary', block_size=10)
72+
t_elapsed[i] = time.time() - t0
73+
t_minruntime[7] = min(t_elapsed)
74+
75+
np.savetxt('../data/ewstools_ricker.csv', ts.state[['residuals']].values)
76+
np.savetxt('../data/ewstools_perfo.csv', t_minruntime, delimiter=',')

paper/code/figure1.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using TransitionsInTimeseries, DelimitedFiles, CairoMakie, Random
22

3-
x = readdlm("ewstools-tuto-1.csv", ',')[:, end]
3+
# Run ewstools-tuto-1.csv first to generate ewstools_ricker.csv
4+
x = readdlm("../data/ewstools_ricker.csv", ',')[:, end]
5+
x = x[isnan.(x) .== 0]
46
t = eachindex(x)
57

68
# Choose the indicators and how to measure their change over time
@@ -12,5 +14,4 @@ results = estimate_changes(config, x, t)
1214
signif = SurrogatesSignificance(n = 1000, tail = [:right, :right], rng = Xoshiro(1995))
1315
flags = significant_transitions(results, signif)
1416
fig = plot_changes_significance(results, signif)
15-
ylims!(contents(fig[2, 1])[2], (0.037, 0.045))
1617
save("../figures/figure1.png", fig)

paper/code/figure2.jl

Lines changed: 23 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,60 @@
1-
using TransitionsInTimeseries, DelimitedFiles, CairoMakie, Random
1+
using CairoMakie
2+
using DelimitedFiles
3+
using Random
4+
using TransitionsInTimeseries
25

36
coefficient_of_variation(x) = std(x) / mean(x)
47

58
function main()
6-
x = readdlm("ewstools-tuto-1.csv", ',')[:, end]
9+
# Run ewstools-tuto-1.csv first to generate ewstools_ricker.csv and ewstools_perfo.csv
10+
x = readdlm("../data/ewstools_ricker.csv", ',')[:, end]
11+
x = x[isnan.(x) .== 0]
712
t = eachindex(x)
813

914
# Choose the indicators and how to measure their change over time
1015
indicators = (var, coefficient_of_variation, skewness, kurtosis,
1116
ar1_whitenoise, LowfreqPowerSpectrum())
1217
stride = [1, 1, 1, 1, 1, 40]
13-
n, m = 100, length(indicators)
18+
m = length(indicators)
1419
t_elapsed = zeros(m+2)
1520

16-
1721
for (i, ind) in enumerate(indicators)
1822
# Build configuration with adequate parameters of the sliding window
1923
config = SegmentedWindowConfig((ind, ind), (nothing, nothing), [t[1]], [t[end]];
2024
width_ind = length(x) ÷ 2, stride_ind = stride[i], whichtime = last,
2125
min_width_cha = 1)
2226

23-
t0 = time()
24-
for i in 1:n
25-
# Compute the metrics over sliding windows and their significance
26-
results = estimate_changes(config, x, t)
27-
end
28-
t_elapsed[i] = (time() - t0) / 2
27+
t_elapsed[i] = @belapsed estimate_changes($config, $x, $t)
2928
end
3029

3130
config = SegmentedWindowConfig((nothing, nothing), (kendalltau, kendalltau), [t[1]], [t[end]];
3231
width_ind = length(x) ÷ 2, stride_ind = 1, whichtime = last, min_width_cha = 1)
33-
t0 = time()
34-
for i in 1:n
35-
results = estimate_changes(config, x, t)
36-
end
37-
t_elapsed[m+1] = (time() - t0) / 2
32+
t_elapsed[m+1] = @belapsed estimate_changes($config, $x, $t)
3833

3934
sgen = surrogenerator(x, BlockShuffle(), Xoshiro(1995))
40-
t0 = time()
41-
for i in 1:n
42-
s = sgen()
43-
end
44-
t_elapsed[m+2] = time() - t0
35+
t_elapsed[m+2] = @belapsed $sgen()
4536

4637
return t_elapsed
4738
end
4839

49-
t_tt = main()
50-
t_et = [0.03840542, 0.05554581, 0.03895116, 0.04029274, 7.96556187,
51-
2.73067856, 0.39529872, 0.02751493]
52-
53-
# [0.04681492, 8.13679838, 0.04035759, 0.09219241]
54-
inds = eachindex(t_et)
40+
t_transitionsintimeries = main()
41+
t_ewstools = readdlm("../data/ewstools_perfo.csv", ',')[:, end]
42+
inds = eachindex(t_ewstools)
5543
w = 0.4
5644

57-
fig, ax = barplot(inds .- 0.5*w, t_et, label = L"ewstools $\,$", width = w,
58-
fillto = 1e-5)
59-
barplot!(ax, inds .+ 0.5*w, t_tt, label = L"TransitionsInTimeseries.jl $\,$",
60-
width = w, fillto = 1e-5)
45+
fig = Figure(resolution = (600, 400))
46+
ax = Axis(fig[1, 1])
47+
ylims!(ax, 1e-7, 0.1)
48+
barplot!(ax, inds .- 0.5*w, t_ewstools, label = L"ewstools $\,$", width = w,
49+
fillto = 1e-8)
50+
barplot!(ax, inds .+ 0.5*w, t_transitionsintimeries, label = L"TransitionsInTimeseries.jl $\,$",
51+
width = w, fillto = 1e-8)
6152
ax.yscale = log10
6253
ax.xticks = (1:8, [L"Variance $\,$", L"Coeff. of variation $\,$", L"Skewness $\,$",
6354
L"Kurtosis $\,$", L"Lag-1 autocorr. $\,$", L"Spectral $\,$",
6455
L"Kendall $\tau$ corr. coeff.", L"Block bootstrap $\,$"])
65-
ax.ylabel = L"Run time (s) of 100 computations on Ricker model data $\,$"
66-
ax.yticks = (10.0 .^ (-5:1), [L"10^{%$e}" for e in -5:1])
56+
ax.ylabel = L"Run time (s) on Ricker model data $\,$"
57+
ax.yticks = (10.0 .^ (-8:1), [L"10^{%$e}" for e in -8:1])
6758
ax.xgridvisible = false
6859
ax.ygridvisible = false
6960
ax.xticklabelrotation = π / 4

paper/figures/figure1.png

-41.7 KB
Loading

paper/figures/figure2.png

-6.11 KB
Loading

0 commit comments

Comments
 (0)