<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Groundwater signatures
R.A. Collenteur, University of Graz, 2022
In this notebook we introduce the groundwater signatures module available in Pastas. The signatures methods can be accessed through the signatures module in the pastas.stats sub-package. This module is partly based on the work from Heudorfer et al. (2019) and others (see References).
Groundwater signatures characterize different aspects of a groundwater time series, and can be subdivided in different categories
Step1:  1. Load two time series with different characteristics
To illustrate the use of groundwater signatures we load two time series of hydraulic heads with visually different characteristics.
Step2:  2. Compute signatures
To compute all available signatures at once, we can use the stats method from the signatures module. This is shown below. Alternatively, each signature can be computed with a separate method (e.g., ps.stats.signatures.baseflow_index).
Step3:  3. Plot the results
Depending on the signature, different ranges of parameters can be expected. We therefore split the signatures in two range for visualization purposes.
<ASSISTANT_TASK:>
Python Code:
import numpy as np
import pandas as pd
import pastas as ps
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
ps.show_versions(numba=True)
Explanation: Groundwater signatures
R.A. Collenteur, University of Graz, 2022
In this notebook we introduce the groundwater signatures module available in Pastas. The signatures methods can be accessed through the signatures module in the pastas.stats sub-package. This module is partly based on the work from Heudorfer et al. (2019) and others (see References).
Groundwater signatures characterize different aspects of a groundwater time series, and can be subdivided in different categories: shape, distribution, and structure. Groundwater signatures are also referred to as 'indices' or 'quantitative' metrics. In Pastas, 'signatures' is adopted to avoid any confusion with time indices and goodness-of-fit metrics. 
The signatures can be used to objectively characterize different groundwater systems, for example distinquishing between fast and slow groundwater systems. The use of signatures is common in other parts of hydrology (e.g., rainfall-runoff modeling) and can be applied in all phases of modeling (see, for example McMillan, 2020 for an overview). 
<div class="alert alert-warning">
<b>Note:</b>
The `signatures` module is still work in progress and needs further verification. Please report any issues and bugs on the Pastas GitHub repository!
</div>
End of explanation
head1 = pd.read_csv("data_notebook_20/head_threshold.csv", index_col=0, parse_dates=True).squeeze()
head2 = pd.read_csv("data_wagna/head_wagna.csv", index_col=0, parse_dates=True, skiprows=2).squeeze()
head2 = head2.resample("D").mean().loc["2012":]
fig, [ax1, ax2] = plt.subplots(2,1, figsize=(10,4), sharex = True);
head1.plot(ax=ax1)
head2.plot(ax=ax2)
Explanation: 1. Load two time series with different characteristics
To illustrate the use of groundwater signatures we load two time series of hydraulic heads with visually different characteristics.
End of explanation
sigs1 = ps.stats.signatures.summary(head1)
sigs2 = ps.stats.signatures.summary(head2)
# Create a dataframe for easy comparison and plotting
df = pd.concat([sigs1, sigs2], axis=1)
df
Explanation: 2. Compute signatures
To compute all available signatures at once, we can use the stats method from the signatures module. This is shown below. Alternatively, each signature can be computed with a separate method (e.g., ps.stats.signatures.baseflow_index).
End of explanation
fig = plt.figure(constrained_layout=True, figsize=(10, 4))
gs = GridSpec(1, 5, figure=fig)
ax1 = fig.add_subplot(gs[0, :4])
ax2 = fig.add_subplot(gs[0, 4])
low_values = df.where(df < 2).dropna()
low_values.plot(ax=ax1)
ax1.set_xticks(np.arange(len(low_values)),low_values.index, rotation=90);
ax1.grid()
high_values = df.where(df > 2).dropna()
high_values.plot(ax=ax2)
ax2.set_xticks(np.arange(len(high_values)),high_values.index, rotation=90);
ax2.grid()
ax1.set_title("Low value signatures")
ax2.set_title("High value signatures");
Explanation: 3. Plot the results
Depending on the signature, different ranges of parameters can be expected. We therefore split the signatures in two range for visualization purposes.
End of explanation
<END_TASK>