Source code for analyseur.cbgtc.visual.rate

# ~/analyseur/cbgtc/visual/rate.py
#
# Documentation by Lungsi 30 Oct 2025
#
# This contains function for SpikingStats
#

"""
=============
Rate Plotting
=============

+------------------------------------------------------+
| Functions                                            |
+======================================================+
| :func:`plot_mean_rate_isi`                           |
+------------------------------------------------------+
| :func:`plot_mean_rate_isi_in_ax`                     |
+------------------------------------------------------+
| :func:`plot_pool_avg_inst_rates`                     |
+------------------------------------------------------+
| :func:`plot_pool_avg_inst_rates_in_ax`               |
+------------------------------------------------------+
| :func:`plot_true_avg_inst_rate`                      |
+------------------------------------------------------+
| :func:`plot_true_avg_inst_rate_in_ax`                |
+------------------------------------------------------+
| :func:`plot_mean_rate_spikecounts_in_ax`             |
+------------------------------------------------------+
| :func:`plot_mean_rate_all_neurons_across_time_in_ax` |
+------------------------------------------------------+

--------------
Plot Mean Rate
--------------

1. Pre-requisites
=================

1.1. Import Modules
-------------------
::

    from analyseur.cbgtc.loader import LoadSpikeTimes
    from analyseur.cbgtc.visual.rate import plot_mean_rate_isi

1.2. Load file and get spike times
----------------------------------
::

    loadST = LoadSpikeTimes("spikes_GPi.csv")
    spiketimes_superset = loadST.get_spiketimes_superset()

2. Cases
========

2.1. Visualize Mean Rate with default setting
---------------------------------------------
::

    [fig, ax] = plot_mean_rate_isi(spiketimes_superset)

2.2. Visualize Mean Rate in portrait mode
-----------------------------------------
::

    [fig, ax] = plot_mean_rate_isi(spiketimes_superset, mode="portrait")

2.3. Visualize Mean Rate in portrait mode with nucleus name in title
--------------------------------------------------------------------
::

    [fig, ax] = plot_mean_rate_isi(spiketimes_superset, mode="portrait", nucleus="GPi")

2.4. Create the plot for customization
--------------------------------------
This is for power users who for instance want to insert the Mean Rate plot in their
collage of subplots.
::

    import matplotlib.pyplot as plt
    from analyseur.cbgtc.visual.rate import plot_mean_rate_isi_in_ax

    fig, (ax1, ax2) = plt.subplots(1, 2)
    fig.suptitle('Horizontally stacked subplots')

    ax1 = plot_mean_rate_isi_in_ax(ax1, spiketimes_superset)
    ax2 = plot_mean_rate_isi_in_ax(ax2, spiketimes_superset)

    plt.show()

NOTE: This example shows :func:`plot_mean_rate_isi_in_ax` in default setting but this function works like
:func:`plot_mean_rate_isi` therefore all the cases 2.1, 2.2 and 2.3 are applicable for :func:`plot_mean_rate_isi_in_ax`.

-------------------------------
Plot Average Instantaneous Rate
-------------------------------

Similar as documented above for plotting Mean Rate but using the function
:func:`plot_avg_inst_rate` and :func:`plot_avg_inst_rate_in_ax` with the
additional OPTIONAL argument for `binsz` (otherwise it picks a default value).
This is imported as
::

    from analyseur.cbgtc.visual.rate import plot_avg_inst_rate, plot_avg_inst_rate_in_ax

.. raw:: html

    <hr style="border: 2px solid red; margin: 20px 0;">

"""

import numbers
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import gaussian_kde, alpha

import re

from analyseur.cbgtc.curate import get_desired_spiketimes_subset
from analyseur.cbgtc.stats.rate import Rate
from analyseur.cbgtc.stats.isi import InterSpikeInterval
from analyseur.cbgtc.parameters import SignalAnalysisParams, SimulationParams

__siganal = SignalAnalysisParams()
__simparams = SimulationParams()


##########################################################################
#    PLOT Mean Rate Based on Spike Counts
##########################################################################

[docs] def plot_mean_rate_spikecounts_in_ax(ax, spiketimes_set, window=None, binsz=None, nucleus=None, mode=None): """ .. code-block:: text Mean Rate (1/s) ^ | █ █ █ █ █ █ █ █ | ███ ██ ████ ██ ██ ███ ██ | █████████████████████████ | +---------------------------------------------> Neurons 0 50 100 150 200 Each bar represents the mean firing rate of one neuron computed from spike counts within the analysis window. Draws the Mean Rate (1/s) on the given `matplotlib.pyplot.axis <https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.axis.html>`_ :param ax: object `matplotlib.pyplot.axis`` :param spiketimes_set: Dictionary returned using :meth:`~analyseur.cbgtc.loader.LoadSpikeTimes.get_spiketimes_superset` or using :meth:`~analyseur.cbgtc.loader.LoadSpikeTimes.get_spiketimes_subset` OPTIONAL parameters - :param nucleus: string; name of the nucleus - :param mode: "portrait" or None/landscape [default] - :return: object `ax` with Rate Distribution plotting done into it .. raw:: html <hr style="border: 2px solid red; margin: 20px 0;"> """ # ============== DEFAULT Parameters ============== if window is None: window = __siganal.window if binsz is None: binsz = __siganal.binsz_100perbin n_neurons = len(spiketimes_set) match mode: case "portrait": orient = "horizontal" case _: orient = "landscape" get_axis = lambda orient: "x" if orient=="horizontal" else "y" mu_rate_vec, _ = Rate.mean_rate(spiketimes_set=spiketimes_set, window=window, binsz=binsz, neurons="all", across="times") if orient == "horizontal": ax.barh(range(len(mu_rate_vec)), mu_rate_vec, color="steelblue", edgecolor="black") ax.set_ylabel("Neurons") ax.set_xlabel("Mean Rate (1/s)") ax.margins(y=0) else: ax.bar(range(len(mu_rate_vec)), mu_rate_vec, color="steelblue", edgecolor="black") ax.set_ylabel("Mean Rate (1/s)") ax.set_xlabel("Neurons") ax.grid(True, alpha=0.3, axis=get_axis(orient)) nucname = "" if nucleus is None else " in " + nucleus ax.set_title("Mean Rate (Counts) Distribution of " + str(n_neurons) + " neurons" + nucname) return ax
########################################################################## # PLOT Mean Rate Based on ISI ##########################################################################
[docs] def plot_mean_rate_isi_in_ax(ax, spiketimes_set, nucleus=None, mode=None): """ .. code-block:: text Mean Rate (1/s) ^ | █ █ █ █ █ █ █ █ | ███ ██ ████ ██ ██ ███ ██ | █████████████████████████ | +---------------------------------------------> Neurons 0 50 100 150 200 Each bar represents the mean firing rate of one neuron computed from its inter-spike intervals (ISI). Draws the Mean Rate (1/s) on the given `matplotlib.pyplot.axis <https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.axis.html>`_ :param ax: object `matplotlib.pyplot.axis`` :param spiketimes_set: Dictionary returned using :meth:`~analyseur.cbgtc.loader.LoadSpikeTimes.get_spiketimes_superset` or using :meth:`~analyseur.cbgtc.loader.LoadSpikeTimes.get_spiketimes_subset` OPTIONAL parameters - :param nucleus: string; name of the nucleus - :param mode: "portrait" or None/landscape [default] - :return: object `ax` with Rate Distribution plotting done into it .. raw:: html <hr style="border: 2px solid red; margin: 20px 0;"> """ n_neurons = len(spiketimes_set) match mode: case "portrait": orient = "horizontal" case _: orient = "landscape" get_axis = lambda orient: "x" if orient=="horizontal" else "y" [all_isi, _] = InterSpikeInterval.compute(spiketimes_set) mu_arr = InterSpikeInterval.mean_freqs(all_isi) if len(mu_arr)==0: vec_mu = [0] else: vec_mu = mu_arr.values() if orient == "horizontal": ax.barh(range(len(vec_mu)), vec_mu, color="steelblue", edgecolor="black") ax.set_ylabel("Neurons") ax.set_xlabel("Mean Rate (1/s)") ax.margins(y=0) else: ax.bar(range(len(vec_mu)), vec_mu, color="steelblue", edgecolor="black") ax.set_ylabel("Mean Rate (1/s)") ax.set_xlabel("Neurons") ax.grid(True, alpha=0.3, axis=get_axis(orient)) nucname = "" if nucleus is None else " in " + nucleus ax.set_title("Mean Rate (ISI) Distribution of " + str(n_neurons) + " neurons" + nucname) return ax
[docs] def plot_mean_rate_isi(spiketimes_superset, nucleus=None, mode=None): """ Visualize Mean Rate (1/s) of the given neuron population using :py:func:`plot_mean_rate_isi_in_ax`. :param spiketimes_superset: Dictionary returned using :meth:`analyseur.cbgtc.stats.isi.InterSpikeInterval.compute` OPTIONAL parameters - :param nucleus: string; name of the nucleus - :param mode: "portrait" or None/landscape [default] - :return: object `ax` with Rate Distribution plotting done into it .. raw:: html <hr style="border: 2px solid red; margin: 20px 0;"> """ if mode=="portrait": fig, ax = plt.subplots(figsize=(6, 10)) else: fig, ax = plt.subplots(figsize=(10, 6)) ax = plot_mean_rate_isi_in_ax(ax, spiketimes_superset, nucleus=nucleus, mode=mode) plt.show() return fig, ax
########################################################################## # PLOT Average Instantaneous Rate ##########################################################################
[docs] def plot_pool_avg_inst_rates_in_ax(ax, spiketimes_superset, binsz=None, nucleus=None, mode=None): """ .. code-block:: text Average Inst. Rate (Hz) ^ | ███ ████ ███ ████ ███ ███ | █████████████████████████ | ██████████████████████████ | +--------------------------------------------------> Time (s) 0 2 4 6 8 10 Each bar represents the average instantaneous firing rate of the neuron population within a time bin. Draws the Mean Rate (1/s) on the given `matplotlib.pyplot.axis <https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.axis.html>`_ :param ax: object `matplotlib.pyplot.axis`` :param spiketimes_superset: Dictionary returned using :meth:`analyseur.cbgtc.stats.isi.InterSpikeInterval.compute` OPTIONAL parameters - :param binsz: 0.01 [default] - :param nucleus: string; name of the nucleus - :param mode: "portrait" or None/landscape [default] - :return: object `ax` with Rate Distribution plotting done into it .. raw:: html <hr style="border: 2px solid red; margin: 20px 0;"> """ # ============== DEFAULT Parameters ============== if binsz is None: binsz = __siganal.binsz_100perbin n_neurons = len(spiketimes_superset) match mode: case "portrait": orient = "horizontal" case _: orient = "landscape" get_axis = lambda orient: "x" if orient=="horizontal" else "y" [all_isi, all_times] = InterSpikeInterval.compute(spiketimes_superset) all_inst = InterSpikeInterval.inst_rates(all_isi) [avg_rates, bin_centers, bin_counts] = InterSpikeInterval.pool_avg_inst_rates(inst_rates_set=all_inst, tbins_set=all_times, binsz=binsz) if orient == "horizontal": ax.barh(bin_centers, avg_rates, height=binsz*0.8, linewidth=0.5, alpha=0.7, color="steelblue", edgecolor="black") ax.set_ylabel("Time (s)") ax.set_xlabel("Average Inst. Rate (Hz)") else: # Base bar ax.bar(bin_centers, avg_rates, width=binsz*0.8, linewidth=0.5, alpha=0.7, color="steelblue", edgecolor="black") # ax.plot(bin_centers, avg_rates, "o-", linewidth=2, markersize=6) # Plot ax.set_ylabel("Average Inst. Rate (Hz)") ax.set_xlabel("Time (s)") ax.grid(True, alpha=0.3, axis=get_axis(orient)) nucname = "" if nucleus is None else " in " + nucleus ax.set_title("Pooled Average Inst. Rates of " + str(n_neurons) + " neurons" + nucname) return ax
[docs] def plot_pool_avg_inst_rates(spiketimes_superset, binsz=None, nucleus=None, mode=None): """ Visualize Mean Rate (1/s) of the given neuron population using :py:func:`plot_pool_avg_inst_rates_in_ax`. :param spiketimes_superset: Dictionary returned using :class:`~analyseur.cbgtc.loader.LoadSpikeTimes` OPTIONAL parameters - :param binsz: 0.01 [default] - :param nucleus: string; name of the nucleus - :param mode: "portrait" or None/landscape [default] - :return: object `ax` with Rate Distribution plotting done into it .. raw:: html <hr style="border: 2px solid red; margin: 20px 0;"> """ if mode=="portrait": fig, ax = plt.subplots(figsize=(6, 10)) else: fig, ax = plt.subplots(figsize=(10, 6)) ax = plot_pool_avg_inst_rates_in_ax(ax, spiketimes_superset, binsz=binsz, nucleus=nucleus, mode=mode) plt.show() return fig, ax
########################################################################## # PLOT Instantaneous Rate ##########################################################################
[docs] def plot_true_avg_inst_rate_in_ax(ax, spiketimes_set, nucleus=None, mode=None): """ .. code-block:: text Avg. Inst. Rate (Hz) ^ | █ █ █ █ █ █ █ █ | ███ ██ ████ ██ ██ ███ ██ | █████████████████████████ | +---------------------------------------------> Neurons 0 50 100 150 200 Each bar represents the average instantaneous firing rate of an individual neuron computed from its ISI sequence. Draws the Instantaneuous Rate (1/s) on the given `matplotlib.pyplot.axis <https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.axis.html>`_ :param ax: object `matplotlib.pyplot.axis`` :param spiketimes_set: Dictionary returned using :meth:`~analyseur.cbgtc.loader.LoadSpikeTimes.get_spiketimes_superset` or using :meth:`~analyseur.cbgtc.loader.LoadSpikeTimes.get_spiketimes_subset` OPTIONAL parameters :param neurons: `"all"` or `scalar` or `range(a, b)` or list of neuron ids like `[2, 3, 6, 7]` - `"all"` means subset = superset - `N` (a scalar) means subset of first N neurons in the superset - `range(a, b)` or `[2, 3, 6, 7]` means subset of selected neurons :param nucleus: string; name of the nucleus :param mode: "portrait" or None/landscape [default] :return: object `ax` with Rate Distribution plotting done into it .. raw:: html <hr style="border: 2px solid red; margin: 20px 0;"> """ n_neurons = len(spiketimes_set) match mode: case "portrait": orient = "horizontal" case _: orient = "landscape" get_axis = lambda orient: "x" if orient == "horizontal" else "y" [all_isi, _] = InterSpikeInterval.compute(spiketimes_set) all_inst_rates = InterSpikeInterval.inst_rates(isi_set=all_isi) Instarr = InterSpikeInterval.true_avg_inst_rates(inst_rates_set=all_inst_rates) vec_IR = Instarr.values() #print(f"Inst. Rate Array {Instarr}") if orient == "horizontal": ax.barh(range(len(vec_IR)), vec_IR, color="steelblue", edgecolor="black") ax.set_ylabel("Neurons") ax.set_xlabel("Avg. Ins. Rate (1/s)") ax.margins(y=0) else: ax.bar(range(len(vec_IR)), vec_IR, color="steelblue", edgecolor="black") ax.set_ylabel("Avg. Ins. Rate (1/s)") ax.set_xlabel("Neurons") ax.grid(True, alpha=0.3, axis=get_axis(orient)) nucname = "" if nucleus is None else " in " + nucleus ax.set_title("Avg. Inst. Rate Distribution of " + str(n_neurons) + " neurons" + nucname) return ax
[docs] def plot_true_avg_inst_rate(spiketimes_set, nucleus=None, mode=None): """ Visualize Instantaneuous Rate (1/s) of the given neuron population using :py:func:`plot_true_avg_inst_rate_in_ax`. :param spiketimes_set: Dictionary returned using :meth:`~analyseur.cbgtc.loader.LoadSpikeTimes.get_spiketimes_superset` or using :meth:`~analyseur.cbgtc.loader.LoadSpikeTimes.get_spiketimes_subset` OPTIONAL parameters :param neurons: `"all"` or `scalar` or `range(a, b)` or list of neuron ids like `[2, 3, 6, 7]` - `"all"` means subset = superset - `N` (a scalar) means subset of first N neurons in the superset - `range(a, b)` or `[2, 3, 6, 7]` means subset of selected neurons :param nucleus: string; name of the nucleus :param mode: "portrait" or None/landscape [default] :return: object `ax` with Rate Distribution plotting done into it .. raw:: html <hr style="border: 2px solid red; margin: 20px 0;"> """ if mode=="portrait": fig, ax = plt.subplots(figsize=(6, 10)) else: fig, ax = plt.subplots(figsize=(10, 6)) ax = plot_true_avg_inst_rate_in_ax(ax, spiketimes_set, nucleus=nucleus, mode=mode) plt.show() return fig, ax
[docs] def plot_mean_rate_all_neurons_across_time_in_ax(ax, spiketimes_set, window=None, binsz=None, nucleus=None,): """ .. code-block:: text Mean Population Firing Rate Over Time Firing Rate (Hz) ^ | ~~~ ~~~ ~~~ ~~~ | ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ | ~ ~~ ~~ ~~ ~ | +--------------------------------------------------> Time (s) 0 5 10 15 20 Line shows the mean firing rate of the neuron population as it evolves over time. Draws the Mean Firing Rate (1/s) over time on the given `matplotlib.pyplot.axis <https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.axis.html>`_ :param ax: object `matplotlib.pyplot.axis`` :param spiketimes_set: Dictionary returned using :meth:`~analyseur.cbgtc.loader.LoadSpikeTimes.get_spiketimes_superset` or using :meth:`~analyseur.cbgtc.loader.LoadSpikeTimes.get_spiketimes_subset` OPTIONAL parameters :param window: 2-tuple; (0, 10) [default] :param binsz: 0.01 [default] :param nucleus: string; name of the nucleus :return: object `ax` with plotting of the temporal dynamics of the mean firing rate across neurons .. raw:: html <hr style="border: 2px solid red; margin: 20px 0;"> """ # ============== DEFAULT Parameters ============== if window is None: window = __siganal.window if binsz is None: binsz = __siganal.binsz_100perbin n_neurons = len(spiketimes_set) mu_rate_vec, time_bins = Rate.mean_rate(spiketimes_set=spiketimes_set, window=window, binsz=binsz, neurons="all", across="times") # Plot ax.plot(np.arange(len(mu_rate_vec)) / (window[1] - window[0]), mu_rate_vec, "b-", linewidth=1) ax.grid(True, alpha=0.3) ax.set_xlabel("Time (seconds)") ax.set_ylabel("Firing Rate (Hz)") nucname = "" if nucleus is None else " in " + nucleus ax.set_title("Firing Rate Over Time of " + str(n_neurons) + " neurons" + nucname) return ax