Project: s41467-024-50381-2 | Function: hierarchical_clustering (python)

system: You are an expert Python programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow Python best practices and maintain consistent code style.
Return **only** the complete Python function code.

user: Complete this Python function:

**DESCRIPTION:** Implements agglomerative hierarchical clustering analysis to identify marine subregions with coherent phytoplankton seasonal patterns using different linkage methods (complete, single, average, ward) and euclidean distance

**KEY TERMS:** {
  "dist_mat": "euclidean distance matrix between pixels",
  "method": "linkage method (complete/single/average/ward)",
  "Z": "linkage matrix for dendrogram construction",
  "dendrogram": "hierarchical clustering visualization",
  "distmatrix_eucledian": "euclidean distance matrix for clustering"
}

**CONTEXT CODE:** lat = fh['lat'][100:]
lon = fh['lon'][30:250]
chl_averagecycle = fh['chl_averagecycle'][100:, 30:250, :]
time_date = fh['time_date']
time_date_years = np.empty_like(time_date)
time_date_months = np.empty_like(time_date)
for i in range(0, len(time_date)):
    time_date_years[i] = time_date[i].year
    time_date_months[i] = time_date[i].month
### Take away pixels with very low frequency
### Load data 1998-2020
fh = np.load('chloc4so_19972021_10km.npz', allow_pickle=True)
chl = fh['chl'][100:, 30:250, :]
for i in range(0, len(lat)):
    for j in range(0, len(lon)):
        if np.count_nonzero(np.isnan(chl[i, j, :])) > 8500:
            chl[i, j, :] = np.nan
#chl_1D = np.nanmean(chl, 2).ravel()
#%%
map_indexes_number = np.arange(1,26401)
map_indexes = np.array((np.reshape(map_indexes_number,(120,220))),dtype=float)
map_indexes_1D = map_indexes.ravel()
chl_averagecycle_1D = np.reshape(chl_averagecycle, (26400 , 12))
# Exclude pixels that do not have data September to March
chl_averagecycle_1D_sepdec = chl_averagecycle_1D[:, 8:]
chl_averagecycle_1D_janmar = chl_averagecycle_1D[:, :3]
chl_averagecycle_1D_sepmar = np.hstack((chl_averagecycle_1D_sepdec, chl_averagecycle_1D_janmar))
#a = chl_averagecycle_1D_sepmar[~np.isnan(chl_averagecycle_1D_sepmar)]
nonnan_indices = []
for i in range(0, len(chl_averagecycle_1D_sepmar)):
    temp_cycle = chl_averagecycle_1D_sepmar[i, :]
    if ~np.isnan(np.sum(temp_cycle)): #and ~np.isnan(chl_1D[i]):
        nonnan_indices = np.append(nonnan_indices, int(i))

nonnan_indices = nonnan_indices.astype(int)
map_indexes_1D_nonan = map_indexes_1D[nonnan_indices]
chl_averagecycle_1D_sepmar_nonnan = chl_averagecycle_1D_sepmar[nonnan_indices]
# Euclidean k-means
#a = pd.DataFrame(data=chl_averagecycle_1D_sepmar_nonnan, columns = ['S', 'O', 'N', 'D', 'J', 'F', 'M'])
#combined_values = a['J'].map(str) + df1['Month'].map(str) + '-' + df1['Year'].map(str) + ': ' + 'Unemployment: ' + df2['Unemployment Rate'].map(str) + '; ' + 'Interest: ' + df2['Interest Rate'].map(str)
#print (combined_values)
def euclidean_distance(v1, v2):
    return np.sqrt(np.sum((v1 - v2)**2)) 

from sklearn.metrics.pairwise import euclidean_distances

distmatrix_eucledian = euclidean_distances(chl_averagecycle_1D_sepmar_nonnan).round(2)

from scipy.cluster.hierarchy import single, complete, average, ward, dendrogram

def hierarchical_clustering(dist_mat, method='complete'):
    # MASKED: Implements agglomerative hierarchical clustering analysis to identify marine subregions with coherent phytoplankton seasonal patterns using different linkage methods (complete, single, average, ward) and euclidean distance
    raise NotImplementedError("Function has been masked for testing purposes")

linkage_matrix = hierarchical_clustering(distmatrix_eucledian)

from sklearn.cluster import AgglomerativeClustering
cluster = AgglomerativeClustering(n_clusters=10, affinity='euclidean', linkage='ward')  
cluster.fit_predict(chl_averagecycle_1D_sepmar_nonnan)
y_pred = cluster.labels_

import scipy.cluster.hierarchy as shc
plt.figure(figsize=(10, 7))  
plt.title("Phenoregions Hierarchical Clustering Dendogram")  
dend = shc.dendrogram(shc.linkage(chl_averagecycle_1D_sepmar_nonnan, method='ward'), truncate_mode = 'lastp',
                                  color_threshold=10, show_contracted=True)
plt.axhline(y=10, c='k', linewidth=2)
graphs_dir = 'C:\\Users\\afons\\Documents\\artigos\\antarcticpeninsula-trends-2021\\analysis\\chl\\clustering\\hierarchicalclustering_10km.png'
plt.savefig(graphs_dir,format = 'png', dpi = 500)
plt.close()


#euclidean_distance(chl_averagecycle_1D_sepmar_nonnan[0], chl_averagecycle_1D_sepmar_nonnan[1])
#%%
plt.figure()
for yi in range(5):
    plt.subplot(5, 5, yi + 1)
    for xx in chl_averagecycle_1D_sepmar_nonnan[y_pred == yi]:
        plt.plot(xx.ravel(), "k-", alpha=.2)
    plt.plot(km.cluster_centers_[yi].ravel(), "r-")
    plt.xlim(0, 7)
    #plt.ylim(-4, 4)
    plt.text(0.55, 0.85,'Cluster %d' % (yi + 1),
             transform=plt.gca().transAxes)
    if yi == 1:
        plt.title("Euclidean $k$-means")

#%%
map_indexes_1D_cluster1 = map_indexes_1D_nonan[y_pred == 0] #cluster1
map_indexes_1D_cluster2 = map_indexes_1D_nonan[y_pred == 1] #cluster2
map_indexes_1D_cluster3 = map_indexes_1D_nonan[y_pred == 2] #cluster3
map_indexes_1D_cluster4 = map_indexes_1D_nonan[y_pred == 3] #cluster3
map_indexes_1D_cluster5 = map_indexes_1D_nonan[y_pred == 4] #cluster3
map_indexes_1D_cluster6 = map_indexes_1D_nonan[y_pred == 5] #cluster3
map_indexes_1D_cluster7 = map_indexes_1D_nonan[y_pred == 6] #cluster3
map_indexes_1D_cluster8 = map_indexes_1D_nonan[y_pred == 7] #cluster3
map_indexes_1D_cluster9 = map_indexes_1D_nonan[y_pred == 8] #cluster3
map_indexes_1D_cluster10 = map_indexes_1D_nonan[y_pred == 9] #cluster3
# match
map_clusters = np.empty((120,220))*np.nan
for k in range(0,120):
    for i in range(0,220):
        if map_indexes[k,i] in map_indexes_1D_cluster1:
            map_clusters[k,i] = 1
        elif map_indexes[k,i] in map_indexes_1D_cluster2:
            map_clusters[k,i] = 2  
        elif map_indexes[k,i] in map_indexes_1D_cluster3:
            map_clusters[k,i] = 3        
        elif map_indexes[k,i] in map_indexes_1D_cluster4:
            map_clusters[k,i] = 4
        elif map_indexes[k,i] in map_indexes_1D_cluster5:
            map_clusters[k,i] = 5
        elif map_indexes[k,i] in map_indexes_1D_cluster6:
            map_clusters[k,i] = 6
        elif map_indexes[k,i] in map_indexes_1D_cluster7:
            map_clusters[k,i] = 7
        elif map_indexes[k,i] in map_indexes_1D_cluster8:
            map_clusters[k,i] = 8
        elif map_indexes[k,i] in map_indexes_1D_cluster9:
            map_clusters[k,i] = 9
        elif map_indexes[k,i] in map_indexes_1D_cluster10:
            map_clusters[k,i] = 10

#%%
plt.figure()
map = plt.axes(projection=ccrs.AzimuthalEquidistant(central_longitude=-60, central_latitude=-62))
map.set_extent([-67, -53, -67, -60]) 
f1 = map.pcolormesh(lon, lat, map_clusters[:-1, :-1], transform=ccrs.PlateCarree(), shading='flat')
gl = map.gridlines(draw_labels=True, alpha=0.5, linestyle='dotted', color='black')
cbar = plt.colorbar(f1,
                    fraction=0.04, pad=0.1)
#cbar.ax.set_yticklabels(['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], fontsize=14)
#cbar.set_label('Chl-a Max Month', fontsize=14)
map.coastlines(resolution='10m', color='black', linewidth=1)
map.add_feature(cartopy.feature.NaturalEarthFeature('physical', 'land', '50m',
                                        edgecolor='k',
                                        facecolor=cartopy.feature.COLORS['land']))
#cbar.set_label('Valid Pixels (%)', fontsize=14)
plt.tight_layout()
graphs_dir = 'C:\\Users\\afons\\Documents\\artigos\\antarcticpeninsula-trends-2021\\analysis\\chl\\clustering\\hierarchical_4clusters_10km_usingtimeseries.png'
plt.savefig(graphs_dir,format = 'png', bbox_inches = 'tight', dpi = 300)
plt.close()










Complete the function implementation replacing "raise NotImplementedError".