<jupyter_start><jupyter_text>Implementation of the Maximum Separation methodThis notebook shows the Python implementation of the Maximum Separation method, a variant of the threshold method for phenology metric estimation. <NAME> - <EMAIL> / CREAF - Centre de Recerca Ecològica i Aplicacions Forestals<jupyter_code># clone the repository with the data
! git clone https://github.com/adriadescals/MaximumSeparation_method.git
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# read the data
pathCsv = '/content/MaximumSeparation_method/toy_timeSeries.csv'
df = pd.read_csv(pathCsv) 

DOY = df.DOY.to_numpy()
GCC = df.GCC.to_numpy()
# plot the time series
plt.plot(DOY, GCC,'.k')
plt.xlabel('DOY')
plt.ylabel('GCC')
# Define the window size 
wsize = 30; 

# Define threshold dynamically (percentage of the amplitude)
p = 50  # percentage

bio_min = np.percentile(GCC, 5)
bio_max = np.percentile(GCC, 95)
amplitude = bio_max-bio_min

thresh = amplitude*p/100+bio_min;
print('threshold = ' + str(thresh))

# Convert the original data into a binary time series
bio_bin = GCC>thresh; 

plt.plot(DOY, bio_bin,'.k')
plt.xlabel('DOY')
plt.ylabel('GCC>thresh')
# Estimate the ratio of observations above the threshold before and after each day of the time series
DOYdiff = np.array(DOY[wsize:-wsize],ndmin=2)
D = np.zeros((1,DOYdiff.shape[1]), dtype=float)
for idoy in np.nditer(DOYdiff.T):
  bin1 = bio_bin[np.logical_and(DOY>(idoy-wsize),DOY<idoy)]
  bin2 = bio_bin[np.logical_and(DOY<(idoy+wsize),DOY>idoy)]

  p1 = np.sum(bin1)/bin1.shape;
  p2 = np.sum(bin2)/bin2.shape;

  D[DOYdiff==idoy] = p1-p2

plt.plot(DOYdiff, D,'.k')
plt.xlabel('DOY')
plt.ylabel('diff')
# Find the Start of Season (minimum value of D) and the End of Season (maximum value in D)
SoS = DOYdiff[0,np.argmin(D)]
EoS = DOYdiff[0,np.argmax(D)]

plt.plot(DOY, GCC,'.k')
plt.xlabel('DOY')
plt.ylabel('GCC')
plt.axvline(x=SoS)
plt.axvline(x=EoS)
plt.hlines(y = thresh, xmin = min(DOY), xmax = max(DOY), color ='r',linestyles='dashed')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13720703125, 'fraction_numerical': 0.01220703125, 'mean_word_length': 5.423197492163009, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 11, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '289318', 'license': 'MIT', 'n_tokens_mistral': 838, 'n_tokens_neox': 786, 'n_words': 195, 'path': 'MS_demo.ipynb', 'repo_name': 'adriadescals/MaximumSeparation_method', 'size': '2071'}