Source code for pyunicorn.climate.eventseries_climatenetwork

# This file is part of pyunicorn.
# Copyright (C) 2008--2024 Jonathan F. Donges and pyunicorn authors
# URL: <https://www.pik-potsdam.de/members/donges/software-2/software>
# License: BSD (3-clause)
#
# Please acknowledge and cite the use of this software and its authors
# when results are used in publications or published elsewhere.
#
# You can use the following reference:
# J.F. Donges, J. Heitzig, B. Beronov, M. Wiedermann, J. Runge, Q.-Y. Feng,
# L. Tupikina, V. Stolbova, R.V. Donner, N. Marwan, H.A. Dijkstra,
# and J. Kurths, "Unified functional network and nonlinear time series analysis
# for complex systems science: The pyunicorn package"

"""
Provides class for the analysis of dynamical systems and time series based
on event synchronization and event coincidence analysis
"""

# array object and fast numerics
import numpy as np

from ..eventseries import EventSeries
from .climate_network import ClimateNetwork
from .climate_data import ClimateData
from ..core import Data

#
#  Class definitions
#


[docs] class EventSeriesClimateNetwork(EventSeries, ClimateNetwork): """ Class EventSeriesClimateNetwork for generating and quantitatively analyzing event synchronisation and event coincidence analysis networks References: [Boers2014]_. """ # # Internal methods
[docs] def __init__(self, data, method='ES', p_value=None, **kwargs): r""" Initialize an instance of EventSeriesClimateNetwork. For other applications of event series networks please use the EventSeries class together with the Network class. :type data: :class:`..climate.ClimateData` :arg data: The climate data used for network construction. :type method: ``str {'ES', 'ECA', 'ES_pval', 'ECA_pval'}`` :arg method: determines if ES, ECA, or the p-values of one of the methods should be used for network reconstruction. :type p_value: ``float in [0,1]`` :arg p_value: determines the p-value threshold for network reconstruction. ES/ECA scores of event time series pairs with p-value higher than threshold are set to zero leading to missing link in climate network. Default: None. No p-value thresholding. :arg \**kwargs: optional keyword arguments to specify parent classes' behavior, see below for all options. :Keyword Arguments: * *taumax* (``float``) -- maximum time difference between two events to be considered synchronous. Caution: For ES, the default is np.inf because of the intrinsic dynamic coincidence interval in ES. For ECA, taumax is a parameter of the method that needs to be defined. * *lag* (``float``) -- extra time lag between the event series. * *symmetrization* ( ``str {'directed', 'symmetric', 'antisym', 'mean', 'max', 'min'}`` for ES, str {'directed', 'mean', 'max', 'min'}`` for ECA ) -- determines if and if true, which symmetrization should be used for the ES/ECA score matrix. * *window_type* ( ``str {'retarded', 'advanced', 'symmetric'}`` ) -- Only for ECA. Determines if precursor coincidence rate ('advanced'), trigger coincidence rate ('retarded') or a general coincidence rate with the symmetric interval [-taumax, taumax] are computed ('symmetric'). Default: 'symmetric'. * *threshold_method* ( ``str 'quantile' or 'value' or 1D numpy array of 'quantile' or 'value'`` ) -- specifies the method for generating a binary event matrix from an array of continuous time series. Default: None. * *threshold_values* (``1D Numpy array or float``) -- quantile or real number determining threshold for each variable. Default: None. * *threshold_types* ( ``str 'above' or 'below' or 1D list of strings of 'above' or 'below'`` ) -- determines for each variable if event is below or above threshold. * *non_local* (``bool``) -- determines whether links between spatially close nodes should be suppressed. * *node_weight_type* (``str``) -- The type of geographical node weight to be used. * *arg silence_level* (``int``) -- The inverse level of verbosity of the object. """ # extract ES and CN related optional keyword arguments from **kwargs ES_kwargs = { "taumax": kwargs.get("taumax", np.inf), "lag": kwargs.get("lag", 0.0), "threshold_method": kwargs.get("threshold_method", None), "threshold_values": kwargs.get("threshold_values", None), "threshold_types": kwargs.get("threshold_types", None) } ES_analysis_kwargs = { "symmetrization": kwargs.get("symmetrization", 'directed'), "window_type": kwargs.get("window_type", 'symmetric') } ES_significance_kwargs = { "surrogate": kwargs.get("surrogate", 'shuffle'), "n_surr": kwargs.get("n_surr", 1000), "symmetrization": kwargs.get("symmetrization", 'directed'), "window_type": kwargs.get("window_type", 'symmetric') } CN_kwargs = { "non_local": kwargs.get("non_local", False), "node_weight_type": kwargs.get("node_weight_type", "surface"), "silence_level": kwargs.get("silence_level", 0) } method_types = ['ES', 'ECA', 'ES_pval', 'ECA_pval'] if method not in method_types: raise IOError(f"Method input must be: " f"{method_types[0]}, {method_types[1]}," f"{method_types[2]}, or {method_types[3]}!") self.__method = method self.__p_value = p_value self.__symmetry = kwargs.get("symmetrization", 'directed') self.directed = self.__symmetry == "directed" # Construct an EventSeries object with the chosen parameters EventSeries.__init__(self, data.observable(), **ES_kwargs) # Compute matrix for link weights of ClimateNetwork from event # synchronization or event coincidence analysis with chosen symmetry # option measure_matrix = [] # If standard ES/ECA measure is chosen, calculate pairwise ES/ECA # scores if self.__method in ['ES', 'ECA']: measure_matrix = \ self.event_series_analysis(method=self.__method, **ES_analysis_kwargs) # Check if a p-value is chosen, then: # Set all coupling strengths in the measure matrix with # higher p-value to zero, leading to a missing edge in the climate # network if self.__p_value is not None: if self.__p_value > 1.0 or self.__p_value < 0.0: raise IOError("'p_value' must lie in the unit interval!") significance_matrix = \ self.event_analysis_significance( method=self.__method, **ES_significance_kwargs) for i in range(self.__N): for j in range(self.__N): if significance_matrix[i][j] < 1.0 - p_value: measure_matrix[i][j] = 0.0 elif self.__method in ['ES_pval', 'ECA_pval']: measure_matrix = \ self.event_analysis_significance( method=self.__method, **ES_significance_kwargs) ClimateNetwork.__init__(self, grid=data.grid, similarity_measure=measure_matrix, threshold=0, directed=self.directed, **CN_kwargs)
[docs] def __str__(self): """ Return a string representation of EventSeriesClimateNetwork. **Example:** >>> data = EventSeriesClimateNetwork.SmallTestData() >>> print(EventSeriesClimateNetwork(data, taumax=16.0, >>> threshold_method='quantile', threshold_value=0.8, >>> threshold_types='above')) Extracting network adjacency matrix by thresholding... Setting area weights according to type surface ... Setting area weights according to type surface ... EventSeriesClimateNetwork: EventSeries: 6 variables, 10 timesteps, __taumax: 16.0, lag: 0.0 ClimateNetwork: GeoNetwork: Network: directed, 6 nodes, 0 links, link density 0.000. Geographical boundaries: time lat lon min 0.0 0.00 2.50 max 9.0 25.00 15.00 Threshold: 0 Local connections filtered out: False Type of event series measure to construct the network: directedES """ text = ("EventSeriesClimateNetwork:\n%s\n%s\n" "Type of event series measure to construct the network: " "%s%s") return text % (EventSeries.__str__(self), ClimateNetwork.__str__(self), self.__symmetry, self.__method)
[docs] @staticmethod def SmallTestData(): """ Return test data set of 6 time series with 10 sampling points each. **Example:** >>> r(Data.SmallTestData().observable()) array([[ 0. , 1. , 0. , -1. , -0. , 1. ], [ 0.309 , 0.9511, -0.309 , -0.9511, 0.309 , 0.9511], [ 0.5878, 0.809 , -0.5878, -0.809 , 0.5878, 0.809 ], [ 0.809 , 0.5878, -0.809 , -0.5878, 0.809 , 0.5878], [ 0.9511, 0.309 , -0.9511, -0.309 , 0.9511, 0.309 ], [ 1. , 0. , -1. , -0. , 1. , 0. ], [ 0.9511, -0.309 , -0.9511, 0.309 , 0.9511, -0.309 ], [ 0.809 , -0.5878, -0.809 , 0.5878, 0.809 , -0.5878], [ 0.5878, -0.809 , -0.5878, 0.809 , 0.5878, -0.809 ], [ 0.309 , -0.9511, -0.309 , 0.9511, 0.309 , -0.9511]]) :rtype: ClimateData instance :return: a ClimateData instance for testing purposes. """ data = Data.SmallTestData() return ClimateData(observable=data.observable(), grid=data.grid, time_cycle=5, silence_level=2)