示例#1
0
文件: ig_graph.py 项目: tfardet/NNGT
    def _get_edges(self, source_node=None, target_node=None):
        '''
        Called by Graph.get_edges if source_node and target_node are not both
        integers.
        '''
        g = self._graph

        edges = None

        if source_node is None:
            if target_node is None:
                edges = g.es
            elif is_integer(target_node):
                edges = g.es.select(_target_eq=target_node)
            else:
                edges = g.es.select(_target_in=target_node)
        elif is_integer(source_node):
            if target_node is None:
                edges = g.es.select(_source_eq=source_node)
            else:
                edges = g.es.select(_source_eq=source_node,
                                    _target_in=target_node)
        else:
            if target_node is None:
                edges = g.es.select(_source_in=source_node)
            elif is_integer(target_node):
                edges = g.es.select(_source_in=source_node,
                                    _target_eq=target_node)
            else:
                edges = g.es.select(_source_in=source_node,
                                    _target_in=target_node)

        return [e.tuple for e in edges]
示例#2
0
    def _get_edges(self, source_node=None, target_node=None):
        '''
        Called by Graph.get_edges if source_node and target_node are not both
        integers.
        '''
        g = self._graph

        if source_node is not None:
            source_node = \
                {source_node} if is_integer(source_node) else set(source_node)

            # source only
            if target_node is None:
                if g.is_directed():
                    return [e for e in g._unique if e[0] in source_node]

                return [
                    e for e in g._unique
                    if e[0] in source_node or e[1] in source_node
                ]

            # source and target
            target_node = \
                {target_node} if is_integer(target_node) else set(target_node)

            if g.is_directed():
                return [
                    e for e in g._unique
                    if e[0] in source_node and e[1] in target_node
                ]

            return [
                e for e in g._unique
                if e[0] in source_node and e[1] in target_node
                or e[1] in source_node and e[0] in target_node
            ]

        if target_node is None:
            # return all edges
            return list(g._unique)

        # target only
        target_node = \
            {target_node} if is_integer(target_node) else set(target_node)

        if g.is_directed():
            return [e for e in g._unique if e[1] in target_node]

        return [
            e for e in g._unique if e[0] in target_node or e[1] in target_node
        ]
示例#3
0
    def add_to_group(self, group_name, ids):
        '''
        Add neurons to a specific group.

        Parameters
        ----------
        group_name : str or int
            Name or index of the group.
        ids : list or 1D-array
            Neuron ids.
        '''
        idx = None
        if is_integer(group_name):
            assert 0 <= group_name < len(self), "Group index does not exist."
            idx = group_name
        else:
            idx = list(self.keys()).index(group_name)
        if ids:
            self[group_name].ids += list(ids)
            # update number of neurons
            max_id = np.max(ids)
            _update_max_id_and_size(self, max_id)
            self._neuron_group[np.array(ids)] = idx
            if -1 in list(self._neuron_group):
                self._is_valid = False
            else:
                self._is_valid = True
示例#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.")
示例#5
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) + "'.")
示例#6
0
    def _get_edges(self, source_node=None, target_node=None):
        '''
        Called by Graph.get_edges if source_node and target_node are not both
        integers.
        '''
        nx = nngt._config["library"]

        g = self._graph

        target_node = \
            [target_node] if is_integer(target_node) else target_node

        if source_node is not None:
            source_node = \
                [source_node] if is_integer(source_node) else source_node

            if target_node is None:

                if g.is_directed():
                    return list(g.out_edges(source_node))

                return [
                    e if e[0] <= e[1] else e[::-1]
                    for e in g.edges(source_node)
                ]

            res_iter = nx.edge_boundary(g, source_node, target_node)

            if g.is_directed():
                return list(res_iter)

            return [e if e[0] <= e[1] else e[::-1] for e in res_iter]

        if target_node is None:
            # return all edges
            return list(g.edges)

        if g.is_directed():
            return list(g.in_edges(target_node))

        return [e if e[0] <= e[1] else e[::-1] for e in g.edges(target_node)]
示例#7
0
def degree_distrib(graph, deg_type="total", nodes=None, weights=None,
                   log=False, num_bins='bayes'):
    '''
    Degree distribution of a graph.

    Parameters
    ----------
    graph : :class:`~nngt.Graph` or subclass
        the graph to analyze.
    deg_type : string, optional (default: "total")
        type of degree to consider ("in", "out", or "total").
    nodes : list of ints, optional (default: None)
        Restrict the distribution to a set of nodes (default: all nodes).
    weights : bool or str, optional (default: binary edges)
        Whether edge weights should be considered; if ``None`` or ``False``
        then use binary edges; if ``True``, uses the 'weight' edge attribute,
        otherwise uses any valid edge attribute required.
    log : bool, optional (default: False)
        use log-spaced bins.
    num_bins : int, list or str, optional (default: 'bayes')
        Any of the automatic methodes from :func:`numpy.histogram`, or 'bayes'
        will provide automatic bin optimization. Otherwise, an int for the
        number of bins can be provided, or the direct bins list.

    See also
    --------
    :func:`numpy.histogram`, :func:`~nngt.analysis.binning`

    Returns
    -------
    counts : :class:`numpy.array`
        number of nodes in each bin
    deg : :class:`numpy.array`
        bins
    '''
    degrees = graph.get_degrees(deg_type, nodes, weights)

    if num_bins == 'bayes' or is_integer(num_bins):
        num_bins = binning(degrees, bins=num_bins, log=log)
    elif log:
        deg = degrees[degrees > 0]
        counts, bins = np.histogram(np.log(deg), num_bins)

        return counts, np.exp(bins)

    return np.histogram(degrees, num_bins)
示例#8
0
def degree_distrib(graph,
                   deg_type="total",
                   node_list=None,
                   use_weights=False,
                   log=False,
                   num_bins='bayes'):
    '''
    Degree distribution of a graph.

    .. versionchanged:: 0.7

    Inclusion of automatic binning.

    Parameters
    ----------
    graph : :class:`~nngt.Graph` or subclass
        the graph to analyze.
    deg_type : string, optional (default: "total")
        type of degree to consider ("in", "out", or "total").
    node_list : list or numpy.array of ints, optional (default: None)
        Restrict the distribution to a set of nodes (default: all nodes).
    use_weights : bool, optional (default: False)
        use weighted degrees (do not take the sign into account: all weights
        are positive).
    log : bool, optional (default: False)
        use log-spaced bins.
    num_bins : int, list or str, optional (default: 'bayes')
        Any of the automatic methodes from :func:`numpy.histogram`, or 'bayes'
        will provide automatic bin optimization. Otherwise, an int for the
        number of bins can be provided, or the direct bins list.

    See also
    --------
    :func:`numpy.histogram`, :func:`~nngt.analysis.binning`

    Returns
    -------
    counts : :class:`numpy.array`
        number of nodes in each bin
    deg : :class:`numpy.array`
        bins
    '''
    degrees = graph.get_degrees(deg_type, node_list, use_weights)
    if num_bins == 'bayes' or is_integer(num_bins):
        num_bins = binning(degrees, bins=num_bins, log=log)
    return np.histogram(degrees, num_bins)
示例#9
0
    def __init__(self, nodes=None, ntype=1, model=None, neuron_param=None):
        '''
        Create a group of neurons (empty group is default, but it is not a
        valid object for most use cases).

        .. versionchanged:: 0.8
            Removed `syn_model` and `syn_param`.

        Parameters
        ----------
        nodes : int or array-like, optional (default: None)
            Desired size of the group or, a posteriori, NNGT indices of the
            neurons in an existing graph.
        ntype : int, optional (default: 1)
            Type of the neurons (1 for excitatory, -1 for inhibitory).
        model : str, optional (default: None)
            NEST model for the neuron.
        neuron_param : dict, optional (default: model defaults)
            Dictionary containing the parameters associated to the NEST model.

        Returns
        -------
        A new :class:`~nngt.core.NeuralGroup` instance.
        '''
        assert ntype in (1, -1), "`ntype` can either be 1 or -1."
        neuron_param = {} if neuron_param is None else neuron_param.copy()
        self._has_model = False if model is None else True
        self._neuron_model = model
        if nodes is None:
            self._desired_size = None
            self._ids = []
        elif nonstring_container(nodes):
            self._desired_size = None
            self._ids = list(nodes)
        elif is_integer(nodes):
            self._desired_size = nodes
            self._ids = []
        else:
            raise InvalidArgument('`nodes` must be either array-like or int.')
        self._nest_gids = None
        self.neuron_param = neuron_param if self._has_model else None
        self.neuron_type = ntype
示例#10
0
 def __setitem__(self, key, value):
     self._validity_check(key, value)
     int_key = None
     if is_integer(key):
         new_key = tuple(self.keys())[key]
         int_key = key
         OrderedDict.__setitem__(self, new_key, value)
     else:
         OrderedDict.__setitem__(self, key, value)
         int_key = list(super(NeuralPop, self).keys()).index(key)
     # update pop size/max_id
     group_size = len(value.ids)
     max_id = np.max(value.ids) if group_size != 0 else 0
     _update_max_id_and_size(self, max_id)
     self._neuron_group[value.ids] = int_key
     if -1 in list(self._neuron_group):
         self._is_valid = False
     else:
         if self._desired_size is not None:
             self._is_valid = (self._desired_size == self._size)
         else:
             self._is_valid = True
示例#11
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`.
        '''
        if is_integer(edge[0]):
            return self[edge[0]][edge[1]]["eid"]
        elif nonstring_container(edge[0]):
            return [self[e[0]][e[1]]["eid"] for e in edge]
        else:
            raise AttributeError("`edge` must be either a 2-tuple of ints or "
                                 "an array of 2-tuples of ints.")
示例#12
0
文件: nest_plot.py 项目: tfardet/NNGT
def plot_activity(gid_recorder=None,
                  record=None,
                  network=None,
                  gids=None,
                  axis=None,
                  show=False,
                  limits=None,
                  histogram=False,
                  title=None,
                  fignum=None,
                  label=None,
                  sort=None,
                  average=False,
                  normalize=1.,
                  decimate=None,
                  transparent=True,
                  kernel_center=0.,
                  kernel_std=None,
                  resolution=None,
                  cut_gaussian=5.,
                  **kwargs):
    '''
    Plot the monitored activity.

    .. versionchanged:: 1.2
        Switched `hist` to `histogram` and default value to False.

    .. versionchanged:: 1.0.1
        Added `axis` parameter, restored missing `fignum` parameter.

    Parameters
    ----------
    gid_recorder : tuple or list of tuples, optional (default: None)
        The gids of the recording devices. If None, then all existing
        spike_recs are used.
    record : tuple or list, optional (default: None)
        List of the monitored variables for each device. If `gid_recorder` is
        None, record can also be None and only spikes are considered.
    network : :class:`~nngt.Network` or subclass, optional (default: None)
        Network which activity will be monitored.
    gids : tuple, optional (default: None)
        NEST gids of the neurons which should be monitored.
    axis : matplotlib axis object, optional (default: new one)
        Axis that should be use to plot the activity. This takes precedence
        over `fignum`.
    show : bool, optional (default: False)
        Whether to show the plot right away or to wait for the next plt.show().
    histogram : bool, optional (default: False)
        Whether to display the histogram when plotting spikes rasters.
    limits : tuple, optional (default: None)
        Time limits of the plot (if not specified, times of first and last
        spike for raster plots).
    title : str, optional (default: None)
        Title of the plot.
    fignum : int, or dict, optional (default: None)
        Plot the activity on an existing figure (from ``figure.number``). This
        parameter is ignored if `axis` is provided.
    label : str or list, optional (default: None)
        Add labels to the plot (one per recorder).
    sort : str or list, optional (default: None)
        Sort neurons using a topological property ("in-degree", "out-degree",
        "total-degree" or "betweenness"), an activity-related property
        ("firing_rate" or neuronal property) or a user-defined list of sorted
        neuron ids. Sorting is performed by increasing value of the `sort`
        property from bottom to top inside each group.
    normalize : float or list, optional (default: None)
        Normalize the recorded results by a given float. If a list is provided,
        there should be one entry per voltmeter or multimeter in the recorders.
        If the recording was done through `monitor_groups`, the population can
        be passed to normalize the data by the nuber of nodes in each group.
    decimate : int or list of ints, optional (default: None)
        Represent only a fraction of the spiking neurons; only one neuron in
        `decimate` will be represented (e.g. setting `decimate` to 5 will lead
        to only 20% of the neurons being represented). If a list is provided,
        it must have one entry per NeuralGroup in the population.
    kernel_center : float, optional (default: 0.)
        Temporal shift of the Gaussian kernel, in ms (for the histogram).
    kernel_std : float, optional (default: 0.5% of simulation time)
        Characteristic width of the Gaussian kernel (standard deviation) in ms
        (for the histogram).
    resolution : float or array, optional (default: `0.1*kernel_std`)
        The resolution at which the firing rate values will be computed.
        Choosing a value smaller than `kernel_std` is strongly advised.
        If resolution is an array, it will be considered as the times were the
        firing rate should be computed (for the histogram).
    cut_gaussian : float, optional (default: 5.)
        Range over which the Gaussian will be computed (for the histogram).
        By default, we consider the 5-sigma range. Decreasing this value will
        increase speed at the cost of lower fidelity; increasing it with
        increase the fidelity at the cost of speed.
    **kwargs : dict
        "color" and "alpha" values can be overriden here.

    Warning
    -------
    Sorting with "firing_rate" only works if NEST gids form a continuous
    integer range.

    Returns
    -------
    lines : list of lists of :class:`matplotlib.lines.Line2D`
        Lines containing the data that was plotted, grouped by figure.
    '''
    import matplotlib.pyplot as plt
    recorders = _get_nest_gids([])
    lst_labels, lines, axes, labels = [], {}, {}, {}

    # normalize recorders and recordables
    if gid_recorder is not None:
        assert record is not None, "`record` must also be provided."
        if len(record) != len(gid_recorder):
            raise InvalidArgument('`record` must either be the same for all '
                                  'recorders, or contain one entry per '
                                  'recorder in `gid_recorder`')
        for rec in gid_recorder:
            if nest_version == 3:
                recorders = _get_nest_gids(gid_recorder)
            else:
                if isinstance(gid_recorder[0], tuple):
                    recorders.append(rec)
                else:
                    recorders.append((rec, ))
    else:
        prop = {'model': spike_rec}
        if nest_version == 3:
            recorders = nest.GetNodes(properties=prop)
        else:
            recorders = [(gid, )
                         for gid in nest.GetNodes((0, ), properties=prop)[0]]

        record = tuple("spikes" for _ in range(len(recorders)))

    # get gids and groups
    gids = network.nest_gids if (gids is None and network is not None) \
           else gids

    if gids is None:
        gids = []

        for rec in recorders:
            gids.extend(nest.GetStatus(rec)[0]["events"]["senders"])

        gids = np.unique(gids)

    num_group = 1 if network is None else len(network.population)
    num_lines = max(num_group, len(recorders))

    # sorting
    sorted_neurons = np.array([])

    if len(gids):
        sorted_neurons = np.arange(np.max(gids) +
                                   1).astype(int) - np.min(gids) + 1

    attr = None

    if sort is not None:
        assert network is not None, "`network` is required for sorting."
        if nonstring_container(sort):
            attr = sort
            sorted_neurons = _sort_neurons(attr, gids, network)
            sort = "user defined sort"
        else:
            data = None
            if sort.lower() in ("firing_rate", "b2"):  # get senders
                data = [[], []]
                for rec in recorders:
                    info = nest.GetStatus(rec)[0]
                    if str(info["model"]) == spike_rec:
                        data[0].extend(info["events"]["senders"])
                        data[1].extend(info["events"]["times"])
                data = np.array(data).T
            sorted_neurons, attr = _sort_neurons(sort,
                                                 gids,
                                                 network,
                                                 data=data,
                                                 return_attr=True)
    elif network is not None and network.is_spatial():
        sorted_neurons, attr = _sort_neurons("space",
                                             gids,
                                             network,
                                             data=None,
                                             return_attr=True)

    # spikes plotting
    colors = palette_discrete(np.linspace(0, 1, num_lines))
    num_raster, num_detec, num_meter = 0, 0, 0
    fignums = fignum if isinstance(fignum, dict) else {}
    decim = []
    if decimate is None:
        decim = [None for _ in range(num_lines)]
    elif is_integer(decimate):
        decim = [decimate for _ in range(num_lines)]
    elif nonstring_container(decimate):
        assert len(decimate) == num_lines, "`decimate` should have one " +\
                                           "entry per plot."
        decim = decimate
    else:
        raise AttributeError(
            "`decimate` must be either an int or a list of `int`.")

    # set labels
    if label is None:
        lst_labels = [None for _ in range(len(recorders))]
    else:
        if isinstance(label, str):
            lst_labels = [label]
        else:
            lst_labels = label
        if len(label) != len(recorders):
            _log_message(
                logger, "WARNING",
                'Incorrect length for `label`: expecting {} but got '
                '{}.\nIgnoring.'.format(len(recorders), len(label)))
            lst_labels = [None for _ in range(len(recorders))]

    datasets = []
    max_time = 0.

    for rec in recorders:
        info = nest.GetStatus(rec)[0]

        if len(info["events"]["times"]):
            max_time = max(max_time, np.max(info["events"]["times"]))

        datasets.append(info)

    if kernel_std is None:
        kernel_std = max_time * 0.005

    if resolution is None:
        resolution = 0.5 * kernel_std

    # plot
    for info, var, lbl in zip(datasets, record, lst_labels):
        fnum = fignums.get(info["model"], fignum)
        if info["model"] not in labels:
            labels[info["model"]] = []
            lines[info["model"]] = []

        if str(info["model"]) == spike_rec:
            if spike_rec in axes:
                axis = axes[spike_rec]
            c = colors[num_raster]
            times, senders = info["events"]["times"], info["events"]["senders"]
            sorted_ids = sorted_neurons[senders]
            l = raster_plot(times,
                            sorted_ids,
                            color=c,
                            show=False,
                            limits=limits,
                            sort=sort,
                            fignum=fnum,
                            axis=axis,
                            decimate=decim[num_raster],
                            sort_attribute=attr,
                            network=network,
                            histogram=histogram,
                            transparent=transparent,
                            hist_ax=axes.get('histogram', None),
                            kernel_center=kernel_center,
                            kernel_std=kernel_std,
                            resolution=resolution,
                            cut_gaussian=cut_gaussian)
            num_raster += 1
            if l:
                fig_raster = l[0].figure.number
                fignums[spike_rec] = fig_raster
                axes[spike_rec] = l[0].axes
                labels[spike_rec].append(lbl)
                lines[spike_rec].extend(l)
                if histogram:
                    axes['histogram'] = l[1].axes
        elif "detector" in str(info["model"]):
            c = colors[num_detec]
            times, senders = info["events"]["times"], info["events"]["senders"]
            sorted_ids = sorted_neurons[senders]
            l = raster_plot(times,
                            sorted_ids,
                            fignum=fnum,
                            color=c,
                            axis=axis,
                            show=False,
                            histogram=histogram,
                            limits=limits,
                            kernel_center=kernel_center,
                            kernel_std=kernel_std,
                            resolution=resolution,
                            cut_gaussian=cut_gaussian)
            if l:
                fig_detect = l[0].figure.number
                num_detec += 1
                fignums[info["model"]] = fig_detect
                labels[info["model"]].append(lbl)
                lines[info["model"]].extend(l)
                if histogram:
                    axes['histogram'] = l[1].axes
        else:
            da_time = info["events"]["times"]
            # prepare axis setup
            fig = None
            if axis is None:
                fig = plt.figure(fnum)
                fignums[info["model"]] = fig.number
            else:
                fig = axis.get_figure()
            lines_tmp, labels_tmp = [], []
            if nonstring_container(var):
                m_colors = palette_discrete(np.linspace(0, 1, len(var)))
                axes = fig.axes
                if axis is not None:
                    # multiple y axes on a single subplot, adapted from
                    # https://matplotlib.org/examples/pylab_examples/
                    # multiple_yaxis_with_spines.html
                    axes = [axis]
                    axis.name = var[0]
                    if len(var) > 1:
                        axes.append(axis.twinx())
                        axes[-1].name = var[1]
                    if len(var) > 2:
                        fig.subplots_adjust(right=0.75)
                        for i, name in zip(range(len(var) - 2), var[2:]):
                            new_ax = axis.twinx()
                            new_ax.spines["right"].set_position(
                                ("axes", 1.2 * (i + 1)))
                            axes.append(new_ax)
                            _make_patch_spines_invisible(new_ax)
                            new_ax.spines["right"].set_visible(True)
                            axes[-1].name = name
                if not axes:
                    axes = _set_new_plot(fig.number, names=var)[1]
                labels_tmp = [lbl for _ in range(len(var))]
                for subvar, c in zip(var, m_colors):
                    c = kwargs.get('color', c)
                    alpha = kwargs.get('alpha', 1)
                    for ax in axes:
                        if ax.name == subvar:
                            da_subvar = info["events"][subvar]
                            if isinstance(normalize, nngt.NeuralPop):
                                da_subvar /= normalize[num_meter].size
                            elif nonstring_container(normalize):
                                da_subvar /= normalize[num_meter]
                            elif normalize is not None:
                                da_subvar /= normalize
                            lines_tmp.extend(
                                ax.plot(da_time,
                                        da_subvar,
                                        color=c,
                                        alpha=alpha))
                            ax.set_ylabel(subvar)
                            ax.set_xlabel("time")
                            if limits is not None:
                                ax.set_xlim(limits[0], limits[1])
            else:
                num_axes, ax = len(fig.axes), axis
                if axis is None:
                    ax = fig.add_subplot(num_axes + 1, 1, num_axes + 1)
                da_var = info["events"][var]
                c = kwargs.get('color', None)
                alpha = kwargs.get('alpha', 1)
                lines_tmp.extend(
                    ax.plot(da_time, da_var / normalize, color=c, alpha=alpha))
                labels_tmp.append(lbl)
                ax.set_ylabel(var)
                ax.set_xlabel("time")
            labels[info["model"]].extend(labels_tmp)
            lines[info["model"]].extend(lines_tmp)
            num_meter += 1

    if spike_rec in axes:
        ax = axes[spike_rec]

        if limits is not None:
            ax.set_xlim(limits[0], limits[1])
        else:
            t_min, t_max, idx_min, idx_max = np.inf, -np.inf, np.inf, -np.inf

            for l in ax.lines:
                t_max = max(np.max(l.get_xdata()), t_max)
                t_min = min(np.min(l.get_xdata()), t_max)
                idx_min = min(np.min(l.get_ydata()), idx_min)
                idx_max = max(np.max(l.get_ydata()), idx_max)

            dt = t_max - t_min
            didx = idx_max - idx_min
            pc = 0.02

            if not np.any(np.isinf((t_max, t_min))):
                ax.set_xlim([t_min - pc * dt, t_max + pc * dt])

            if not np.any(np.isinf((idx_min, idx_max))):
                ax.set_ylim([idx_min - pc * didx, idx_max + pc * didx])

    for recorder in fignums:
        fig = plt.figure(fignums[recorder])
        if title is not None:
            fig.suptitle(title)
        if label is not None:
            fig.legend(lines[recorder], labels[recorder])

    if show:
        plt.show()

    return lines
示例#13
0
    def types(graph, inhib_nodes=None, inhib_frac=None):
        '''
        @todo

        Define the type of a set of neurons.
        If no arguments are given, all edges will be set as excitatory.

        Parameters
        ----------
        graph : :class:`~nngt.Graph` or subclass
            Graph on which edge types will be created.
        inhib_nodes : int, float or list, optional (default: `None`)
            If `inhib_nodes` is an int, number of inhibitory nodes in the graph
            (all connections from inhibitory nodes are inhibitory); if it is a
            float, ratio of inhibitory nodes in the graph; if it is a list, ids
            of the inhibitory nodes.
        inhib_frac : float, optional (default: `None`)
            Fraction of the selected edges that will be set as refractory (if
            `inhib_nodes` is not `None`, it is the fraction of the nodes' edges
            that will become inhibitory, otherwise it is the fraction of all
            the edges in the graph).

        Returns
        -------
        t_list : :class:`~numpy.ndarray`
            List of the edges' types.
        '''
        t_list = np.repeat(1., graph.edge_nb())
        edges = graph.edges_array
        num_inhib = 0
        idx_inhib = []
        if inhib_nodes is None and inhib_frac is None:
            graph.new_edge_attribute("type", "double", val=1.)
            return t_list
        else:
            n = graph.node_nb()
            if inhib_nodes is None:
                # set inhib_frac*num_edges random inhibitory connections
                num_edges = graph.edge_nb()
                num_inhib = int(num_edges * inhib_frac)
                num_current = 0
                while num_current < num_inhib:
                    new = randint(0, num_edges, num_inhib - num_current)
                    idx_inhib = np.unique(np.concatenate((idx_inhib, new)))
                    num_current = len(idx_inhib)
                t_list[idx_inhib.astype(int)] *= -1.
            else:
                # get the dict of inhibitory nodes
                num_inhib_nodes = 0
                idx_nodes = {}
                if nonstring_container(inhib_nodes):
                    idx_nodes = {i: -1 for i in inhib_nodes}
                    num_inhib_nodes = len(idx_nodes)
                if isinstance(inhib_nodes, np.float):
                    if inhib_nodes > 1:
                        raise InvalidArgument(
                            "Inhibitory ratio (float value for `inhib_nodes`) "
                            "must be smaller than 1.")
                        num_inhib_nodes = int(inhib_nodes * n)
                if is_integer(inhib_nodes):
                    num_inhib_nodes = int(inhib_nodes)
                while len(idx_nodes) != num_inhib_nodes:
                    indices = randint(0, n, num_inhib_nodes - len(idx_nodes))
                    di_tmp = {i: -1 for i in indices}
                    idx_nodes.update(di_tmp)
                for v in edges[:, 0]:
                    if v in idx_nodes:
                        idx_inhib.append(v)
                idx_inhib = np.unique(idx_inhib)
                # set the inhibitory edge indices
                for v in idx_inhib:
                    idx_edges = np.argwhere(edges[:, 0] == v)
                    n = len(idx_edges)
                    if inhib_frac is not None:
                        idx_inh = []
                        num_inh = n * inhib_frac
                        i = 0
                        while i != num_inh:
                            ids = randint(0, n, num_inh - i)
                            idx_inh = np.unique(np.concatenate((idx_inh, ids)))
                            i = len(idx_inh)
                        t_list[idx_inh] *= -1.
                    else:
                        t_list[idx_edges] *= -1.
            graph.set_edge_attribute("type",
                                     value_type="double",
                                     values=t_list)
            return t_list
示例#14
0
def plot_activity(gid_recorder=None,
                  record=None,
                  network=None,
                  gids=None,
                  show=False,
                  limits=None,
                  hist=True,
                  title=None,
                  label=None,
                  sort=None,
                  average=False,
                  normalize=1.,
                  decimate=None,
                  transparent=True):
    '''
    Plot the monitored activity.
    
    Parameters
    ----------
    gid_recorder : tuple or list of tuples, optional (default: None)
        The gids of the recording devices. If None, then all existing
        "spike_detector"s are used.
    record : tuple or list, optional (default: None)
        List of the monitored variables for each device. If `gid_recorder` is
        None, record can also be None and only spikes are considered.
    network : :class:`~nngt.Network` or subclass, optional (default: None)
        Network which activity will be monitored.
    gids : tuple, optional (default: None)
        NEST gids of the neurons which should be monitored.
    show : bool, optional (default: False)
        Whether to show the plot right away or to wait for the next plt.show().
    hist : bool, optional (default: True)
        Whether to display the histogram when plotting spikes rasters.
    limits : tuple, optional (default: None)
        Time limits of the plot (if not specified, times of first and last
        spike for raster plots).
    title : str, optional (default: None)
        Title of the plot.
    fignum : int, optional (default: None)
        Plot the activity on an existing figure (from ``figure.number``).
    label : str or list, optional (default: None)
        Add labels to the plot (one per recorder).
    sort : str or list, optional (default: None)
        Sort neurons using a topological property ("in-degree", "out-degree",
        "total-degree" or "betweenness"), an activity-related property
        ("firing_rate" or neuronal property) or a user-defined list of sorted
        neuron ids. Sorting is performed by increasing value of the `sort`
        property from bottom to top inside each group.
    normalize : float or list, optional (default: None)
        Normalize the recorded results by a given float. If a list is provided,
        there should be one entry per voltmeter or multimeter in the recorders.
        If the recording was done through `monitor_groups`, the population can
        be passed to normalize the data by the nuber of nodes in each group.
    decimate : int or list of ints, optional (default: None)
        Represent only a fraction of the spiking neurons; only one neuron in
        `decimate` will be represented (e.g. setting `decimate` to 5 will lead
        to only 20% of the neurons being represented). If a list is provided,
        it must have one entry per NeuralGroup in the population.

    Warning
    -------
    Sorting with "firing_rate" only works if NEST gids form a continuous
    integer range.

    Returns
    -------
    lines : list of lists of :class:`matplotlib.lines.Line2D`
        Lines containing the data that was plotted, grouped by figure.
    '''
    lst_rec, lst_labels, lines, labels = [], [], {}, {}
    num_fig = np.max(plt.get_fignums()) if plt.get_fignums() else 0
    # normalize recorders and recordables
    if gid_recorder is not None:
        if len(record) != len(gid_recorder):
            raise InvalidArgument('`record` must either be the same for all '
                                  'recorders, or contain one entry per '
                                  'recorder in `gid_recorder`')
        for rec in gid_recorder:
            if isinstance(gid_recorder[0], tuple):
                lst_rec.append(rec[0])
            else:
                lst_rec.append(rec)
    else:
        lst_rec = nest.GetNodes((0, ), properties={'model':
                                                   'spike_detector'})[0]
        record = tuple("spikes" for _ in range(len(lst_rec)))
    # get gids and groups
    gids = network.nest_gid if (gids is None and network is not None) else gids
    if gids is None:
        gids = []
        for rec in lst_rec:
            gids.extend(nest.GetStatus([rec])[0]["events"]["senders"])
        gids = np.unique(gids)
    num_group = len(network.population) if network is not None else 1
    # sorting
    sorted_neurons = np.array([])
    if len(gids):
        sorted_neurons = np.arange(np.max(gids) +
                                   1).astype(int) - np.min(gids) + 1
    attr = None
    if sort is not None:
        assert network is not None, "`network` is required for sorting."
        if nonstring_container(sort):
            attr = sort
            sorted_neurons = _sort_neurons(attr, gids, network)
            sort = "user defined sort"
        else:
            data = None
            if sort.lower() in ("firing_rate", "b2"):  # get senders
                data = [[], []]
                for rec in lst_rec:
                    info = nest.GetStatus([rec])[0]
                    if str(info["model"]) == "spike_detector":
                        data[0].extend(info["events"]["senders"])
                        data[1].extend(info["events"]["times"])
                data = np.array(data).T
            sorted_neurons, attr = _sort_neurons(sort,
                                                 gids,
                                                 network,
                                                 data=data,
                                                 return_attr=True)
    # spikes plotting
    colors = palette(np.linspace(0, 1, num_group))
    num_raster, num_detec, num_meter = 0, 0, 0
    fignums = {}
    decim = []
    if decimate is None:
        decim = [None for _ in range(num_group)]
    elif is_integer(decimate):
        decim = [decimate for _ in range(num_group)]
    elif nonstring_container(decimate):
        assert len(decimate) == num_group, "`decimate` should have one " +\
                                           "entry per group in the population."
        decim = decimate
    else:
        raise AttributeError(
            "`decimate` must be either an int or a list of `int`.")

    # set labels
    if label is None:
        lst_labels = [None for _ in range(len(lst_rec))]
    else:
        if isinstance(label, str):
            lst_labels = [label]
        else:
            lst_labels = label
        if len(label) != len(lst_rec):
            _log_message(
                logger, "WARNING",
                'Incorrect length for `label`: expecting {} but got '
                '{}.\nIgnoring.'.format(len(lst_rec), len(label)))
            lst_labels = [None for _ in range(len(lst_rec))]

    # plot
    for rec, var, lbl in zip(lst_rec, record, lst_labels):
        info = nest.GetStatus([rec])[0]
        fnum = fignums[info["model"]] if info["model"] in fignums else None
        if info["model"] not in labels:
            labels[info["model"]] = []
            lines[info["model"]] = []
        if str(info["model"]) == "spike_detector":
            c = colors[num_raster]
            times, senders = info["events"]["times"], info["events"]["senders"]
            sorted_ids = sorted_neurons[senders]
            l = raster_plot(times,
                            sorted_ids,
                            color=c,
                            show=False,
                            limits=limits,
                            sort=sort,
                            fignum=fnum,
                            decimate=decim[num_raster],
                            sort_attribute=attr,
                            network=network,
                            transparent=transparent)
            num_raster += 1
            if l:
                fig_raster = l[0].figure.number
                fignums['spike_detector'] = fig_raster
                labels["spike_detector"].append(lbl)
                lines["spike_detector"].extend(l)
        elif "detector" in str(info["model"]):
            c = colors[num_detec]
            times, senders = info["events"]["times"], info["events"]["senders"]
            sorted_ids = sorted_neurons[senders]
            l = raster_plot(times,
                            sorted_ids,
                            fignum=fnum,
                            color=c,
                            show=False,
                            hist=hist,
                            limits=limits)
            if l:
                fig_detect = l[0].figure.number
                num_detec += 1
                fignums[info["model"]] = fig_detect
                labels[info["model"]].append(lbl)
                lines[info["model"]].extend(l)
        else:
            da_time = info["events"]["times"]
            fig = plt.figure(fnum)
            fignums[info["model"]] = fig.number
            lines_tmp, labels_tmp = [], []
            if nonstring_container(var):
                axes = fig.axes
                if not axes:
                    axes = _set_new_plot(fig.number, names=var)[1]
                labels_tmp = [lbl for _ in range(len(var))]
                for subvar in var:
                    for ax in axes:
                        if ax.name == subvar:
                            da_subvar = info["events"][subvar]
                            if isinstance(normalize, nngt.NeuralPop):
                                da_subvar /= normalize[num_meter].size
                            elif nonstring_container(normalize):
                                da_subvar /= normalize[num_meter]
                            elif normalize is not None:
                                da_subvar /= normalize
                            lines_tmp.extend(ax.plot(da_time, da_subvar))
                            ax.set_ylabel(subvar)
                            ax.set_xlabel("time")
                            if limits is not None:
                                ax.set_xlim(limits[0], limits[1])
            else:
                ax = fig.add_subplot(111)
                da_var = info["events"][var]
                lines_tmp.extend(ax.plot(da_time, da_var / normalize))
                labels_tmp.append(lbl)
                ax.set_ylabel(var)
                ax.set_xlabel("time")
            labels[info["model"]].extend(labels_tmp)
            lines[info["model"]].extend(lines_tmp)
            num_meter += 1
    for recorder in fignums:
        fig = plt.figure(fignums[recorder])
        if title is not None:
            fig.suptitle(title)
        if label is not None:
            fig.legend(lines[recorder], labels[recorder])
    if show:
        plt.show()
    return lines
示例#15
0
    def _get_edges(self, source_node=None, target_node=None):
        '''
        Called by Graph.get_edges if source_node and target_node are not both
        integers.
        '''
        g = self._graph

        edges = set()

        if source_node is not None:
            if target_node is None:
                if is_integer(source_node):
                    if g.is_directed():
                        return [
                            tuple(e) for e in g.iter_out_edges(source_node)
                        ]

                    return [
                        tuple(e) if e[0] < e[1] else tuple(e[::-1])
                        for e in g.iter_all_edges(source_node)
                    ]

                for s in source_node:
                    if g.is_directed():
                        edges.update((tuple(e) for e in g.iter_out_edges(s)))
                    else:
                        for e in g.iter_all_edges(s):
                            edges.add(
                                tuple(e) if e[0] <= e[1] else tuple(e[::-1]))
            else:
                target_node = {target_node} if is_integer(target_node) \
                              else set(target_node)

                if is_integer(source_node):
                    if g.is_directed():
                        return [
                            tuple(e) for e in g.get_out_edges(source_node)
                            if e[1] in target_node
                        ]

                    return [
                        tuple(e) for e in g.get_all_edges(source_node)
                        if e[0] in target_node or e[1] in target_node
                    ]

                for s in source_node:
                    if g.is_directed():
                        edges.update((tuple(e) for e in g.iter_out_edges(s)
                                      if e[1] in target_node))
                    else:
                        for e in g.iter_all_edges(s):
                            e = tuple(e) if e[0] <= e[1] else tuple(e[::-1])

                            if e[0] in target_node or e[1] in target_node:
                                edges.add(e)

            return list(edges)

        if target_node is None:
            # return all edges
            return list(g.get_edges())

        if is_integer(target_node):
            if g.is_directed():
                return [tuple(e) for e in g.iter_in_edges(target_node)]

            return [
                tuple(e) if e[0] <= e[1] else tuple(e[::-1])
                for e in g.iter_all_edges(target_node)
            ]

        for t in target_node:
            if g.is_directed():
                edges.update((tuple(e) for e in g.iter_in_edges(t)))
            else:
                for e in g.iter_all_edges(t):
                    edges.add(tuple(e) if e[0] <= e[1] else tuple(e[::-1]))

        return list(edges)