Beispiel #1
0
    def get_eattr(self, edges, name=None):
        g = self.parent()._graph

        if nonstring_container(edges[0]):
            # many edges
            eids = [g.get_eid(*e) for e in edges]

            if name is None:
                eprop = {}

                if nonstring_container(name[0]):
                    for k in self.keys():
                        dtype = _np_dtype(super().__getitem__(k))
                        eprop[k] = _to_np_array(
                            [g.es[eid][k] for eid in eids], dtype=dtype)

            dtype = _np_dtype(super().__getitem__(name))
            return _to_np_array([g.es[eid][name] for eid in eids], dtype=dtype)
        elif not nonstring_container(edges):
            raise ValueError("Invalid `edges` entry: {}.".format(edges))

        # single edge
        eid = g.get_eid(*edges)

        if name is None:
            eprop = {}

            for k in self.keys():
                eprop[k] = g.es[eid][k]

            return eprop

        return g.es[eid][name]
Beispiel #2
0
    def __getitem__(self, name):
        '''
        Return the attributes of an edge or a list of edges.
        '''
        eprop = {}
        graph = self.parent()

        if isinstance(name, slice):
            for k in self.keys():
                dtype = _np_dtype(super().__getitem__(k))
                eprop[k] = _to_np_array(self.prop[k], dtype)[name]

            return eprop
        elif nonstring_container(name):
            if nonstring_container(name[0]):
                eids = [graph.edge_id(e) for e in name]

                for k in self.keys():
                    dtype = _np_dtype(super().__getitem__(k))
                    eprop[k] = _to_np_array(self.prop[k], dtype=dtype)[eids]
            else:
                eid = graph.edge_id(name)

                for k in self.keys():
                    eprop[k] = self.prop[k][eid]

            return eprop

        dtype = _np_dtype(super().__getitem__(name))

        return _to_np_array(self.prop[name], dtype=dtype)
Beispiel #3
0
 def __getitem__(self, name):
     edges = None
     if isinstance(name, slice):
         edges = self.parent().edges_array[name]
     elif nonstring_container(name):
         if nonstring_container(name[0]):
             edges = name
         else:
             if len(name) != 2:
                 raise InvalidArgument(
                     "key for edge attribute must be one of the following: "
                     "slice, list of edges, edges or attribute name.")
             return self.parent()[name[0]][name[1]]
     if isinstance(name, str):
         dtype = _np_dtype(super(_NxEProperty, self).__getitem__(name))
         eprop = np.empty(self.parent().edge_nb(), dtype=dtype)
         g = self.parent()
         for d, eid in zip(g.edges(data=name), g.edges(data="eid")):
             eprop[eid[2]] = d[2]
         return eprop
     else:
         eprop = {k: [] for k in self.keys()}
         for edge in edges:
             data = self.parent().get_edge_data(edge[0], edge[1])
             for k, v in data.items():
                 if k != "eid":
                     eprop[k].append(v)
         for k, v in eprop.items():
             dtype = _np_dtype(super(_NxEProperty, self).__getitem__(k))
             eprop = {k: np.array(v, dtype)}
         return eprop
Beispiel #4
0
    def edge_id(self, edge):
        '''
        Return the ID a given edge or a list of edges in the graph.
        Raises an error if the edge is not in the graph or if one of the
        vertices in the edge is nonexistent.

        Parameters
        ----------
        edge : 2-tuple or array of edges
            Edge descriptor (source, target).

        Returns
        -------
        index : int or array of ints
            Index of the given `edge`.
        '''
        g = self._graph

        if nonstring_container(edge) and len(edge):
            if is_integer(edge[0]):
                return g.edge_index[g.edge(*edge)]
            elif nonstring_container(edge[0]):
                Edge = g.edge
                return [g.edge_index[Edge(*e)] for e in edge]

        raise AttributeError("`edge` must be either a 2-tuple of ints or "
                             "an array of 2-tuples of ints.")
Beispiel #5
0
    def new_node(self,
                 n=1,
                 ntype=1,
                 attributes=None,
                 value_types=None,
                 positions=None,
                 groups=None):
        '''
        Adding a node to the graph, with optional properties.
        
        Parameters
        ----------
        n : int, optional (default: 1)
            Number of nodes to add.
        ntype : int, optional (default: 1)
            Type of neuron (1 for excitatory, -1 for inhibitory)
            
        Returns
        -------
        The node or an iterator over the nodes created.
        '''
        first_node_idx = self.vcount()
        super(_IGraph, self).add_vertices(n)
        nodes = list(range(first_node_idx, first_node_idx + n))

        if attributes is not None:
            for k, v in attributes.items():
                if k not in self._nattr:
                    self._nattr.new_attribute(k, value_types[k], val=v)
                else:
                    v = v if nonstring_container(v) else [v]
                    self._nattr.set_attribute(k, v, nodes=nodes)
        self.vs[nodes[0]:nodes[-1] + 1]['type'] = ntype

        if self.is_spatial():
            old_pos = self._pos
            self._pos = np.full((self.node_nb(), 2), np.NaN)
            num_existing = len(old_pos) if old_pos is not None else 0
            if num_existing != 0:
                self._pos[:num_existing, :] = old_pos
        if positions is not None:
            assert self.is_spatial(), \
                "`positions` argument requires a SpatialGraph/SpatialNetwork."
            self._pos[nodes] = positions

        if groups is not None:
            assert self.is_network(), \
                "`positions` argument requires a Network/SpatialNetwork."
            if nonstring_container(groups):
                assert len(groups) == n, "One group per neuron required."
                for g, node in zip(groups, nodes):
                    self.population.add_to_group(g, node)
            else:
                self.population.add_to_group(groups, nodes)

        if n == 1:
            return nodes[0]
        return nodes
Beispiel #6
0
    def new_node(self, n=1, ntype=1, attributes=None, value_types=None,
                 positions=None, groups=None):
        '''
        Adding a node to the graph, with optional properties.

        Parameters
        ----------
        n : int, optional (default: 1)
            Number of nodes to add.
        ntype : int, optional (default: 1)
            Type of neuron (1 for excitatory, -1 for inhibitory)
        attributes : dict, optional (default: None)
            Dictionary containing the attributes of the nodes.
        value_types : dict, optional (default: None)
            Dict of the `attributes` types, necessary only if the `attributes`
            do not exist yet.

        Returns
        -------
        The node or a list of the nodes created.
        '''
        nodes = super(_GtGraph, self).add_vertex(n)
        nodes = [nodes] if n == 1 else list(nodes)

        if attributes is not None:
            for k, v in attributes.items():
                if k not in self._nattr:
                    self._nattr.new_attribute(k, value_types[k], val=v)
                else:
                    v = v if nonstring_container(v) else [v]
                    self._nattr.set_attribute(k, v, nodes=nodes)

        if self.is_spatial():
            old_pos      = self._pos
            self._pos    = np.full((self.node_nb(), 2), np.NaN)
            num_existing = len(old_pos) if old_pos is not None else 0
            if num_existing != 0:
                self._pos[:num_existing, :] = old_pos
        if positions is not None:
            assert self.is_spatial(), \
                "`positions` argument requires a SpatialGraph/SpatialNetwork."
            self._pos[nodes] = positions

        if groups is not None:
            assert self.is_network(), \
                "`positions` argument requires a Network/SpatialNetwork."
            if nonstring_container(groups):
                assert len(groups) == n, "One group per neuron required."
                for g, node in zip(groups, nodes):
                    self.population.add_to_group(g, node)
            else:
                self.population.add_to_group(groups, nodes)

        if n == 1:
            return nodes[0]
        return nodes
Beispiel #7
0
    def new_node(self, n=1, ntype=1, attributes=None, value_types=None,
                 positions=None, groups=None):
        '''
        Adding a node to the graph, with optional properties.
        
        Parameters
        ----------
        n : int, optional (default: 1)
            Number of nodes to add.
        ntype : int, optional (default: 1)
            Type of neuron (1 for excitatory, -1 for inhibitory)
            
        Returns
        -------
        The node or a list of the nodes created.
        '''
        new_nodes = list(range(len(self), len(self)+n))
        for v in new_nodes:
            super(_NxGraph, self).add_node(v)

        if attributes is not None:
            for k, v in attributes.items():
                if k not in self._nattr:
                    self._nattr.new_attribute(k, value_types[k], val=v)
                else:
                    v = v if nonstring_container(v) else [v]
                    self._nattr.set_attribute(k, v, nodes=new_nodes)
        else:
            filler = [None for _ in new_nodes]
            for k in self._nattr:
                self._nattr.set_attribute(k, filler, nodes=new_nodes)

        if self.is_spatial():
            old_pos      = self._pos
            self._pos    = np.full((self.node_nb(), 2), np.NaN)
            num_existing = len(old_pos) if old_pos is not None else 0
            if num_existing != 0:
                self._pos[:num_existing, :] = old_pos
        if positions is not None and len(positions):
            assert self.is_spatial(), \
                "`positions` argument requires a SpatialGraph/SpatialNetwork."
            self._pos[new_nodes, :] = positions

        if groups is not None:
            assert self.is_network(), \
                "`positions` argument requires a Network/SpatialNetwork."
            if nonstring_container(groups):
                assert len(groups) == n, "One group per neuron required."
                for g, node in zip(groups, new_nodes):
                    self.population.add_to_group(g, node)
            else:
                self.population.add_to_group(groups, new_nodes)

        if len(new_nodes) == 1:
            return new_nodes[0]
        return new_nodes
Beispiel #8
0
    def get_degrees(self, mode="total", nodes=None, weights=None):
        '''
        Returns the degree of the nodes.

        .. warning ::
            When using MPI, returns only the degree related to local edges.
        '''
        g = self._graph

        num_nodes = None
        weights = 'weight' if weights is True else weights

        if nodes is None:
            num_nodes = self.node_nb()
            nodes = slice(num_nodes)
        elif nonstring_container(nodes):
            nodes = list(nodes)
            num_nodes = len(nodes)
        else:
            nodes = [nodes]
            num_nodes = 1

        # weighted
        if nonstring_container(weights) or weights in self._eattr:
            degrees = np.zeros(num_nodes)
            adj_mat = self.adjacency_matrix(types=False, weights=weights)

            if mode in ("in", "total") or not self.is_directed():
                degrees += adj_mat.sum(axis=0).A1[nodes]
            if mode in ("out", "total") and self.is_directed():
                degrees += adj_mat.sum(axis=1).A1[nodes]

            return degrees
        elif weights not in {None, False}:
            raise ValueError("Invalid `weights` {}".format(weights))

        # unweighted
        degrees = np.zeros(num_nodes, dtype=int)

        if not g._directed or mode in ("in", "total"):
            if isinstance(nodes, slice):
                degrees += g._in_deg[nodes]
            else:
                degrees += [g._in_deg[i] for i in nodes]

        if g._directed and mode in ("out", "total"):
            if isinstance(nodes, slice):
                degrees += g._out_deg[nodes]
            else:
                degrees += [g._out_deg[i] for i in nodes]

        if num_nodes == 1:
            return degrees[0]

        return degrees
Beispiel #9
0
def _get_data(source):
    '''
    Returns the (times, senders) array.

    Parameters
    ----------
    source : list or str
        Indices of spike detectors or path to the .gdf files.

    Returns
    -------
    data : 2D array of shape (N, 2)
    '''
    data = [[], []]

    is_string = isinstance(source, str)

    if is_string:
        source = [source]
    elif nonstring_container(source) and isinstance(source[0], str):
        is_string = True

    if is_string:
        for path in source:
            tmp = np.loadtxt(path)
            data[0].extend(tmp[:, 0])
            data[1].extend(tmp[:, 1])
    else:
        source_shape = np.shape(np.squeeze(source))

        if len(source_shape) == 2:
            # source is directly the data
            if source_shape[0] == 2 and source_shape[1] != 2:
                return np.array(source).T
            else:
                return np.array(source)
        else:
            # source contains gids
            source = _get_nest_gids(source)
            events = None

            if nonstring_container(source[0]):
                events = [nest.GetStatus(gid, "events")[0] for gid in source]
            else:
                events = nest.GetStatus(source, "events")
            for ev in events:
                data[0].extend(ev["senders"])
                data[1].extend(ev["times"])

    idx_sort = np.argsort(data[1])

    return np.array(data)[:, idx_sort].T
Beispiel #10
0
def _format_arg(arg, num_expected, arg_name):
    if nonstring_container(arg):
        assert len(arg) == num_expected, "One entry per attribute " +\
            "required for `" + arg_name + "`."
    elif arg is not None:
        arg = [arg for _ in range(num_expected)]
    return arg
Beispiel #11
0
def binning(x, bins='bayes', log=False):
    """
    Binning function providing automatic binning using Bayesian blocks in
    addition to standard linear and logarithmic uniform bins.

    .. versionadded:: 0.7

    Parameters
    ----------
    x : array-like
        Array of data to be histogrammed
    bins : int, list or 'auto', optional (default: 'bayes')
        If `bins` is 'bayes', in use bayesian blocks for dynamic bin widths; if
        it is an int, the interval will be separated into 
    log : bool, optional (default: False)
        Whether the bins should be evenly spaced on a logarithmic scale.
    """
    x = np.asarray(x)
    new_bins = None

    if bins == 'bayes':
        return bayesian_blocks(x)
    elif nonstring_container(bins):
        return bins
    elif is_integer(bins):
        if log:
            return np.logspace(np.log10(np.maximum(x.min(), 1e-10)),
                               np.log10(x.max()), bins)
        else:
            return np.linspace(x.min(), x.max(), bins)
    else:
        raise ValueError("unrecognized bin code: '" + str(bins) + "'.")
Beispiel #12
0
def node_attributes(network, attributes, nodes=None, data=None):
    '''
    Return node `attributes` for a set of `nodes`.
    
    Parameters
    ----------
    network : :class:`~nngt.Graph`
        The graph where the `nodes` belong.
    attributes : str or list
        Attributes which should be returned, among:
        * "betweenness"
        * "clustering"
        * "in-degree", "out-degree", "total-degree"
        * "subgraph_centrality"
    nodes : list, optional (default: all nodes)
        Nodes for which the attributes should be returned.
    data : :class:`numpy.array` of shape (N, 2), optional (default: None)
        Potential data on the spike events; if not None, it must contain the
        sender ids on the first column and the spike times on the second.
    
    Returns
    -------
    values : array-like or dict
        Returns the attributes, either as an array if only one attribute is
        required (`attributes` is a :obj:`str`) or as a :obj:`dict` of arrays.
    '''
    if nonstring_container(attributes):
        values = {}
        for attr in attributes:
            values[attr] = _get_attribute(network, attr, nodes, data)
        return values
    else:
        return _get_attribute(network, attributes, nodes, data)
Beispiel #13
0
def correlation_to_attribute(network, reference_attribute, other_attributes,
                             nodes=None, title=None, show=True):
    '''
    For each node plot the value of `reference_attributes` against each of the
    `other_attributes` to check for correlations.
    
    Parameters
    ----------
    network : :class:`~nngt.Graph`
        The graph where the `nodes` belong.
    reference_attribute : str or array-like
        Attribute which should serve as reference, among:

        * "betweenness"
        * "clustering"
        * "in-degree", "out-degree", "total-degree"
        * "subgraph_centrality"
        * "b2" (requires NEST)
        * "firing_rate" (requires NEST)
        * a custom array of values, in which case one entry per node in `nodes`
          is required.
    other_attributes : str or list
        Attributes that will be compared to the reference.
    nodes : list, optional (default: all nodes)
        Nodes for which the attributes should be returned.
    '''
    import matplotlib.pyplot as plt
    if not nonstring_container(other_attributes):
        other_attributes = [other_attributes]
    fig = plt.figure()
    fig.patch.set_visible(False)
    # get reference data
    ref_data = reference_attribute
    if isinstance(reference_attribute, str):
        ref_data = node_attributes(network, reference_attribute, nodes=nodes)
    else:
        reference_attribute = "user defined attribute"
    # plot the remaining attributes
    assert isinstance(other_attributes, (str, list)), \
        "Only attribute names are allowed for `other_attributes`"
    values = node_attributes(network, other_attributes, nodes=nodes)
    fig, axes = _set_new_plot(fignum=fig.number, names=other_attributes)
    for i, (attr, val) in enumerate(values.items()):
        end_attr = attr[1:]
        end_ref_attr = reference_attribute[1:]
        if nngt._config["use_tex"]:
            end_attr = end_attr.replace("_", "\\_")
            end_ref_attr = end_ref_attr.replace("_", "\\_")
        # reference nodes
        axes[i].plot(val, ref_data, ls="", marker="o")
        axes[i].set_xlabel(attr[0].upper() + end_attr)
        axes[i].set_ylabel(reference_attribute[0].upper() + end_ref_attr)
        axes[i].set_title(
            "{}{} vs {} for each ".format(
                reference_attribute[0].upper(), end_ref_attr, attr[0] + \
                end_attr, network.name) + \
            "node in {}".format(network.name),
            loc='left', x=0., y=1.05)
    # adjust space, set title, and show
    _format_and_show(fig, 0, values, title, show)
Beispiel #14
0
    def get_eattr(self, edges, name=None):
        g = self.parent()

        eid = g.edge_id

        if nonstring_container(edges[0]):
            # many edges
            if name is None:
                eprop = {}

                for k in self.keys():
                    prop = self.prop[k]

                    dtype = super().__getitem__(k)

                    eprop[k] = _to_np_array(
                        [prop[eid(tuple(e))] for e in edges], dtype)

                return eprop

            prop = self.prop[name]

            dtype = super().__getitem__(name)

            return _to_np_array([prop[eid(tuple(e))] for e in edges], dtype)

        # single edge
        if name is None:
            eprop = {}
            for k in self.keys():
                eprop[k] = self.prop[k][eid(tuple(edges))]

            return eprop

        return self.prop[name][eid(tuple(edges))]
Beispiel #15
0
def node_attributes(network, attributes, nodes=None):
    '''
    Return node `attributes` for a set of `nodes`.
    
    Parameters
    ----------
    network : :class:`~nngt.Graph`
        The graph where the `nodes` belong.
    attributes : str or list
        Attributes which should be returned, among:
        * "betweenness"
        * "clustering"
        * "in-degree", "out-degree", "total-degree"
        * "subgraph_centrality"
    nodes : list, optional (default: all nodes)
        Nodes for which the attributes should be returned.
    
    Returns
    -------
    values : array-like or dict
        Returns the attributes, either as an array if only one attribute is
        required (`attributes` is a :obj:`str`) or as a :obj:`dict` of arrays.
    '''
    if nonstring_container(attributes):
        values = {}
        for attr in attributes:
            values[attr] = _get_attribute(network, attr, nodes)
        return values
    else:
        return _get_attribute(network, attributes, nodes)
Beispiel #16
0
    def delete_nodes(self, nodes):
        '''
        Remove nodes (and associated edges) from the graph.
        '''
        g = self._graph

        if nonstring_container(nodes):
            for n in nodes:
                g.remove_node(n)
        else:
            g.remove_node(nodes)

        # relabel nodes from zero
        nx = nngt._config["library"]

        nx.relabel_nodes(g, {n: i for i, n in enumerate(g.nodes)}, copy=False)

        # update attributes
        for key in self._nattr:
            self._nattr._num_values_set[key] = self.node_nb()

        for key in self._eattr:
            self._eattr._num_values_set[key] = self.edge_nb()

        # check spatial and structure properties
        _post_del_update(self, nodes)
Beispiel #17
0
def monitor_nodes(gids, nest_recorder=None, params=None, network=None):
    '''
    Monitoring the activity of nodes in the network.

    Parameters
    ----------
    gids : tuple of ints or list of tuples
        GIDs of the neurons in the NEST subnetwork; either one list per
        recorder if they should monitor different neurons or a unique list
        which will be monitored by all devices.
    nest_recorder : strings or list, optional (default: spike recorder)
        Device(s) to monitor the network.
    params : dict or list of, optional (default: `{}`)
        Dictionarie(s) containing the parameters for each recorder (see
        `NEST documentation <http://www.nest-simulator.org/quickref/#nodes>`_
        for details).
    network : :class:`~nngt.Network` or subclass, optional (default: None)
        Network which population will be used to differentiate groups.

    Returns
    -------
    recorders : list or NodeCollection containing the recorders' gids
    recordables : list of the recordables' names.
    '''
    if nest_recorder is None:
        nest_recorder = [spike_rec]
    elif not nonstring_container(nest_recorder):
        nest_recorder = [nest_recorder]

    if params is None:
        params = [{}]
    elif isinstance(params, dict):
        params = [params]

    return _monitor(gids, nest_recorder, params)
Beispiel #18
0
 def new_edges(self, edge_list, attributes=None):
     '''
     Add a list of edges to the graph.
     
     Parameters
     ----------
     edge_list : list of 2-tuples or np.array of shape (edge_nb, 2)
         List of the edges that should be added as tuples (source, target)
     attributes : dict, optional (default: ``None``)
         Dictionary of the form ``{ "name": [], "values": [],
         "type": [] }``, containing the attributes of the new edges.
     
     warning ::
         For now attributes works only when adding edges for the first time
         (i.e. adding edges to an empty graph).
         
     @todo: add example, check the edges for self-loops and multiple edges
     
     Returns
     -------
     Returns new edges only.
     '''
     if attributes is None:
         attributes = {}
     initial_ecount = self.ecount()
     if not self._directed:
         edge_list = np.concatenate((edge_list, edge_list[:, ::-1]))
         for key, val in attributes.items():
             attributes[key] = np.concatenate((val, val))
     first_eid = self.ecount()
     super(_IGraph, self).add_edges(edge_list)
     _set_edge_attr(self, edge_list, attributes)
     num_edges = self.ecount()
     # attributes
     if self._weighted and "weight" not in attributes:
         attributes["weight"] = np.repeat(1., num_edges)
     if attributes:
         elist0 = None  #@todo: make elist supported and remove this
         # take care of classic attributes
         if "weight" in attributes:
             self.set_weights(weight=attributes["weight"], elist=elist0)
         if "delay" in attributes:
             self.set_delays(delay=attributes["delay"], elist=elist0)
         if "distance" in attributes:
             raise NotImplementedError("distance not implemented yet")
             #~ self.set_distances(elist=edge_list,
             #~ dlist=attributes["distance"])
         # take care of potential additional attributes
         if "names" in attributes:
             num_attr = len(attributes["names"])
             for i in range(num_attr):
                 v = attributes["values"]
                 if not nonstring_container(v):
                     v = np.repeat(v, self.ecount())
                 self._eattr.new_ea(attributes["names"][i],
                                    attributes["types"][i],
                                    values=v)
     return edge_list
Beispiel #19
0
    def get_degrees(self, mode="total", nodes=None, weights=None):
        g = self._graph
        w = _get_ig_weights(self, weights)
    
        mode = 'all' if mode == 'total' else mode

        if nonstring_container(weights) or weights not in {False, None}:
            return np.array(g.strength(nodes, mode=mode, weights=w))

        return np.array(g.degree(nodes, mode=mode), dtype=int)
Beispiel #20
0
    def delete_edges(self, edges):
        ''' Remove a list of edges '''
        if len(edges):
            if nonstring_container(edges[0]):
                self._graph.remove_edges_from(edges)
            else:
                self._graph.remove_edge(*edges)

            for key in self._eattr:
                self._eattr._num_values_set[key] = self.edge_nb()
Beispiel #21
0
 def new_edges(self, edge_list, attributes=None):
     '''
     Add a list of edges to the graph.
     
     Parameters
     ----------
     edge_list : list of 2-tuples or np.array of shape (edge_nb, 2)
         List of the edges that should be added as tuples (source, target)
     attributes : dict, optional (default: ``None``)
         Dictionary of the form ``{ "name": [], "values": [],
         "type": [] }``, containing the attributes of the new edges.
     
     warning ::
         For now attributes works only when adding edges for the first time
         (i.e. adding edges to an empty graph).
         
     @todo: add example, check the edges for self-loops and multiple edges
     '''
     if attributes is None:
         attributes = {}
     initial_ecount = self.ecount()
     if not self._directed:
         edge_list = np.concatenate((edge_list, edge_list[:,::-1]))
         for key, val in attributes.items():
             attributes[key] = np.concatenate((val, val))
     edge_generator = (edge for edge in edge_list)
     edge_list = np.array(edge_list)
     first_eid = self.ecount()
     super(_IGraph, self).add_edges(edge_list)
     last_eid = self.ecount()
     edge_list = self.edges_array
     # attributes
     if self._weighted and "weight" not in attributes:
         attributes["weight"] = np.repeat(1., edge_list.shape[0])
     if attributes:
         elist0 = None #@todo: make elist supported and remove this
         # take care of classic attributes
         if "weight" in attributes:
             self.set_weights(weight=attributes["weight"], elist=elist0)
         if "delay" in attributes:
             self.set_delays(delay=attributes["delay"], elist=elist0)
         if "distance" in attributes:
             raise NotImplementedError("distance not implemented yet")
             #~ self.set_distances(elist=edge_list,
                                #~ dlist=attributes["distance"])
         # take care of potential additional attributes
         if "names" in attributes:
             num_attr = len(attributes["names"])
             for i in range(num_attr):
                 v = attributes["values"]
                 if not nonstring_container(v):
                     v = np.repeat(v, self.ecount())
                 self._eattr.new_ea(attributes["names"][i],
                                    attributes["types"][i], values=v)
     return edge_list
Beispiel #22
0
 def __getitem__(self, name):
     '''
     Return the attributes of an edge or a list of edges.
     '''
     if isinstance(name, slice):
         eprop = {}
         for k in self.keys():
             eprop[k] = self.parent().edge_properties[k].a[name]
         return eprop
     elif nonstring_container(name):
         eprop = {}
         if nonstring_container(name[0]):
             eids = [self.parent().edge_index[e] for e in name]
             for k in self.keys():
                 eprop[k] = self.parent().edge_properties[k].a[eids]
         else:
             for k in self.keys():
                 eprop[k] = self.parent().edge_properties[k][name]
         return eprop
     return np.array(self.parent().edge_properties[name].a)
Beispiel #23
0
def _get_nest_gids(gids):
    ''' Convert nodes to NodeCollection if NEST is version 3+ '''
    if nest_version == 3:
        if isinstance(gids, NodeCollection):
            return gids

        return NodeCollection(sorted(gids))

    if nonstring_container(gids):
        return list(gids)

    return [gids]
Beispiel #24
0
    def delete_edges(self, edges):
        ''' Remove a list of edges '''
        if len(edges):
            if nonstring_container(edges[0]):
                if isinstance(edges[0], tuple):
                    self._graph.delete_edges(edges)
                else:
                    self._graph.delete_edges([tuple(e) for e in edges])
            else:
                self._graph.delete_edges([edges])

            for key in self._eattr:
                self._eattr._num_values_set[key] = self.edge_nb()
Beispiel #25
0
 def __getitem__(self, name):
     if isinstance(name, slice):
         eprop = {}
         for k in self.keys():
             dtype = _np_dtype(super(_IgEProperty, self).__getitem__(k))
             eprop[k] = np.array(self.parent().es[k], dtype=dtype)[name]
         return eprop
     elif nonstring_container(name):
         eprop = {}
         if nonstring_container(name[0]):
             eids = [self.parent().get_eid(*e) for e in name]
             for k in self.keys():
                 dtype = _np_dtype(
                     super(_IgENProperty, self).__getitem__(k))
                 eprop[k] = np.array(self.parent().es[k], dtype=dtype)[eids]
         else:
             eid = self.parent().get_eid(*name)
             for k in self.keys():
                 eprop[k] = self.parent().es[k][eid]
         return eprop
     dtype = _np_dtype(super(_IgEProperty, self).__getitem__(name))
     return np.array(self.parent().es[name], dtype=dtype)
Beispiel #26
0
 def new_edges(self, edge_list, attributes=None):
     '''
     Add a list of edges to the graph.
     
     .. warning ::
         This function currently does not check for duplicate edges!
     
     Parameters
     ----------
     edge_list : list of 2-tuples or np.array of shape (edge_nb, 2)
         List of the edges that should be added as tuples (source, target)
     attributes : :class:`dict`, optional (default: ``{}``)
         Dictionary containing optional edge properties. If the graph is
         weighted, defaults to ``{"weight": ones}``, where ``ones`` is an
         array the same length as the `edge_list` containing a unit weight
         for each connection (synaptic strength in NEST).
         
     @todo: add example, check the edges for self-loops and multiple edges
     '''
     #check attributes
     if attributes is None:
         attributes = {}
     initial_edges = self.edge_nb()
     if not isinstance(edge_list, np.ndarray):
         edge_list = np.array(edge_list)
     if not self._directed:
         recip_edges = edge_list[:,::-1]
         # slow but works
         unique = ~(recip_edges[..., np.newaxis]
                    == edge_list[..., np.newaxis].T).all(1).any(1)
         edge_list = np.concatenate((edge_list, recip_edges[unique]))
         for key, val in attributes.items():
             attributes[key] = np.concatenate((val, val[unique]))
     # create the edges
     ws        = None
     num_added = len(edge_list)
     if "weight" in attributes:
         if nonstring_container(attributes["weight"]):
             ws = attributes["weight"]
         else:
             ws = (attributes["weight"] for _ in range(num_added))
     else:
         ws = (1 for _ in range(num_added))
     for i, (e, w) in enumerate(zip(edge_list, ws)):
         self._edges[tuple(e)]     = initial_edges + i
         self._out_deg[e[0]]  += 1
         self._in_deg[e[1]]   += 1
         self._adj_mat[e[0], e[1]] = w
     # call parent function to set the attributes
     self.attr_new_edges(edge_list, attributes=attributes)
     return edge_list
Beispiel #27
0
 def __getitem__(self, name):
     '''
     Return the attributes of an edge or a list of edges.
     '''
     eprop = {}
     if isinstance(name, slice):
         for k in self.keys():
             dtype = _np_dtype(super(_EProperty, self).__getitem__(k))
             eprop[k] = np.array(self.prop[k][name], dtype=dtype)
         return eprop
     elif nonstring_container(name):
         if nonstring_container(name[0]):
             eids = [self.parent().edge_id(e) for e in name]
             for k in self.keys():
                 dtype = _np_dtype(super(_EProperty, self).__getitem__(k))
                 eprop[k] = np.array(self.prop[k][eids], dtype=dtype)
         else:
             for k in self.keys():
                 dtype = _np_dtype(super(_EProperty, self).__getitem__(k))
                 eprop[k] = np.array(self.prop[k][name], dtype=dtype)
         return eprop
     dtype = _np_dtype(super(_EProperty, self).__getitem__(name))
     return np.array(self.prop[name], dtype=dtype)
Beispiel #28
0
def _get_weights(g, weights):
    if weights in g.edge_attributes:
        # existing edge attribute
        return np.array(g._graph.es[weights])
    elif nonstring_container(weights):
        # user-provided array
        return np.array(weights)
    elif weights is True:
        # "normal" weights
        return np.array(g._graph.es["weight"])
    elif not weights:
        # unweighted
        return None

    raise ValueError("Unknown edge attribute '" + str(weights) + "'.")
Beispiel #29
0
    def delete_edges(self, edges):
        ''' Remove a list of edges '''
        if len(edges):
            g = self._graph

            Edge = g.edge

            if nonstring_container(edges[0]):
                # fast loop
                [self._graph.remove_edge(Edge(*e)) for e in edges]
            else:
                self._graph.remove_edge(Edge(*edges))

            self._eattr.edges_deleted()

            self._edges_deleted = True
Beispiel #30
0
def local_clustering_binary_undirected(g, nodes=None):
    r'''
    Returns the undirected local clustering coefficient of some `nodes`.

    .. math::

        C_i = \frac{A^3_{ii}}{d_i(d_i - 1)} = \frac{\Delta_i}{T_i}

    with :math:`A` the adjacency matrix, :math:`d_i` the degree of node
    :math:`i`, :math:`\Delta_i` is the number of triangles, and :math:`T_i` is
    the number of triplets to which :math:`i` belongs.

    If `g` is directed, then it is converted to a simple undirected graph
    (no parallel edges), both directed and reciprocal edges are merged into
    a single edge.

    Parameters
    ----------
    g : :class:`~nngt.Graph`
        Graph to analyze.
    nodes : list, optional (default: all nodes)
        The list of nodes for which the clustering will be returned

    Returns
    -------
    lc : :class:`numpy.ndarray`
        The list of clustering coefficients, on per node.

    References
    ----------
    .. [gt-local-clustering] :gtdoc:`clustering.local_clustering`
    .. [ig-local-clustering] :igdoc:`transitivity_local_undirected`
    .. [nx-local-clustering] :nxdoc:`algorithms.cluster.clustering`
    '''
    # Note, this function is overloaded by the library-specific version
    # if igraph, graph-tool, or networkx is used
    triangles = triangle_count(g, weights=None, nodes=nodes, directed=False)
    triplets  = triplet_count(g, weights=None, nodes=nodes, directed=False)

    if nonstring_container(triangles):
        triplets[triangles == 0] = 1
    elif triangles == 0:
        return 0

    return triangles / triplets
Beispiel #31
0
def correlation_to_attribute(network, reference_attribute, other_attributes,
                             nodes=None, title=None, show=True):
    '''
    For each node plot the value of `reference_attributes` against each of the
    `other_attributes` to check for correlations.
    
    Parameters
    ----------
    network : :class:`~nngt.Graph`
        The graph where the `nodes` belong.
    reference_attribute : str or array-like
        Attribute which should serve as reference, among:
        * "betweenness"
        * "clustering"
        * "in-degree", "out-degree", "total-degree"
        * "subgraph_centrality"
        * "b2" (requires NEST)
        * "firing_rate" (requires NEST)
        * a custom array of values, in which case one entry per node in `nodes`
          is required.
    other_attributes : str or list
    nodes : list, optional (default: all nodes)
        Nodes for which the attributes should be returned.
    '''
    if not nonstring_container(other_attributes):
        other_attributes = [other_attributes]
    fig = plt.figure()
    # get reference data
    ref_data = reference_attribute
    if isinstance(reference_attribute, str):
        ref_data = node_attributes(network, reference_attribute, nodes=nodes)
    # plot the remaining attributes
    values = node_attributes(network, other_attributes, nodes=nodes)
    fig, axes = _set_new_plot(fignum=fig.number, names=other_attributes)
    for i, (attr, val) in enumerate(values.items()):
        # reference nodes
        axes[i].plot(val, ref_data, ls="", marker="o")
        axes[i].set_xlabel(attr[0].upper() + attr[1:])
        axes[i].set_ylabel(
            reference_attribute[0].upper() + reference_attribute[1:])
        axes[i].set_title("{}{} vs {} for each ".format(
            attr[0].upper(), attr[1:], reference_attribute, network.name) +\
            "node in {}".format(network.name), loc='left', x=0., y=1.05)
    # adjust space, set title, and show
    _format_and_show(fig, 0, values, title, show)