Skip to content

Colab   Kaggle   Binder

Neural Trajectories Comparative Geometry and Dynamics

Here, we will show how to use the proximity and cosine_similarity functions to analyze the representational geometry and dynamics between two population vector trajectories.


Setup

%reload_ext autoreload
%autoreload 2
import ipywidgets as widgets
import matplotlib
import matplotlib.gridspec
import matplotlib.pyplot as plt
import nelpy as nel
import numpy as np
import sklearn
from IPython.display import HTML
from matplotlib.animation import FuncAnimation

import neuro_py as npy

Section 1: Proximity and cosine similarity of dynamics of simulated data

def plot_3d_trajs(ax, x, y, z1, z2, color1="tab:blue", color2="tab:green"):
    ax.scatter(x, y, z1, color=color1, s=100)
    ax.plot(x, y, z1, color=color1, alpha=0.25)
    ax.scatter(x, y, z2, color=color2, s=100)
    ax.plot(x, y, z2, color=color2, alpha=0.25)

    return ax


def vis_nss_metrics(
    x, y, z1, z2, metric="proximity", color1="tab:blue", color2="tab:red", ax=None
):
    if ax is None:
        fig = plt.figure(figsize=(6, 10))
        ax = fig.add_subplot(111, projection="3d")
    plot_3d_trajs(ax, x, y, z1, z2, color1=color1, color2=color2)
    n_points = len(x)
    i = n_points // 2
    if metric == "proximity":
        for j in range(n_points):
            ax.plot(
                [x[i], x[j]],
                [y[i], y[j]],
                [z1[i], z2[j]],
                color="gray",
                linestyle="dotted",
            )
        ax.quiver(
            x[i],
            y[i],
            z1[i],
            x[i] - x[i],
            y[i] - y[i],
            z2[i] - z1[i],
            color="black",
            arrow_length_ratio=0.25,
            pivot="tail",
            linewidth=2,
        )
        ax.quiver(
            x[i],
            y[i],
            z2[i],
            x[i] - x[i],
            y[i] - y[i],
            z1[i] - z2[i],
            color="black",
            arrow_length_ratio=0.25,
            pivot="tail",
            linewidth=2,
        )
        # insert a small plot on top right of current plot
        ax_inset = ax.inset_axes([0.825, 0.825, 0.165, 0.165])
        ax_inset.plot(x[i], z1[i], "o", color=color1)
        ax_inset.plot(x[i], z2[i], "o", color=color2)
        # join 2 points with quiver
        ax_inset.quiver(
            x[i],
            z1[i],
            np.zeros_like(x[i]),
            z2[i] - z1[i],
            scale_units="xy",
            scale=1,
            color="black",
            pivot="tail",
            width=0.05,
        )
        # opposite quiver
        ax_inset.quiver(
            x[i],
            z2[i],
            np.zeros_like(x[i]),
            z1[i] - z2[i],
            scale_units="xy",
            scale=1,
            color="black",
            pivot="tail",
            width=0.05,
        )
        ax_inset.tick_params(
            axis="both", bottom=False, left=False, labelbottom=False, labelleft=False
        )
        # thick frame
        ax_inset.spines["top"].set_linewidth(2)
        ax_inset.spines["right"].set_linewidth(2)
        ax_inset.spines["left"].set_linewidth(2)
        ax_inset.spines["bottom"].set_linewidth(2)

        ratio = 0.15
        # add 20% padding from current limits
        x0, x1 = ax_inset.get_xlim()
        y0, y1 = ax_inset.get_ylim()
        ax_inset.set_xlim(x0 - ratio * abs(x1 - x0), x1 + ratio * abs(x1 - x0))
        ax_inset.set_ylim(y0 - ratio * abs(y1 - y0), y1 + ratio * abs(y1 - y0))
    elif metric == "cosine":
        ax.quiver(
            x[i],
            y[i],
            z1[i],
            x[i + 1] - x[i],
            y[i + 1] - y[i],
            z1[i + 1] - z1[i],
            color="black",
            arrow_length_ratio=0.2,
            pivot="tail",
            linewidth=2,
            edgecolor="black",
            facecolor="black",
            alpha=1,
        )
        # reverse the arrow
        ax.quiver(
            x[i],
            y[i],
            z2[i],
            x[i + 1] - x[i],
            y[i + 1] - y[i],
            z2[i + 1] - z2[i],
            color="black",
            arrow_length_ratio=0.2,
            pivot="tail",
            linewidth=2,
            edgecolor="black",
            facecolor="black",
            alpha=1,
        )
        ax_inset = ax.inset_axes([0.825, 0.825, 0.165, 0.165])
        ax_inset.plot(x[i + 1], z1[i + 1], "o", color=color1)
        ax_inset.plot(x[i + 1], z2[i + 1], "o", color=color2)
        # visualize the angle between the 2 vectors with quiver using vertex as midpoint between the 2 vectors
        angle = np.arccos(
            np.dot(
                [x[i + 1] - x[i], z1[i + 1] - z1[i]],
                [x[i + 1] - x[i], z2[i + 1] - z2[i]],
            )
            / (
                np.linalg.norm([x[i + 1] - x[i], z1[i + 1] - z1[i]])
                * np.linalg.norm([x[i + 1] - x[i], z2[i + 1] - z2[i]])
            )
        )
        # visualize the angle between the 2 vectors with quiver using vertex as origin
        midpt = (x[i], (z2[i] + z1[i]) / 2)
        ax_inset.quiver(
            *midpt,
            x[i + 1] - midpt[0],
            z2[i + 1] - midpt[1],
            angles="xy",
            scale_units="xy",
            scale=1,
            color="black",
            width=0.05,
        )
        ax_inset.quiver(
            *midpt,
            x[i + 1] - midpt[0],
            z1[i + 1] - midpt[1],
            angles="xy",
            scale_units="xy",
            scale=1,
            color="black",
            width=0.05,
        )

        leftvec = (x[i + 1], z2[i + 1]) if angle > 0 else (x[i + 1], z1[i + 1])
        rightvec = (x[i + 1], z1[i + 1]) if angle > 0 else (x[i + 1], z2[i + 1])
        npy.plotting.AngleAnnotation(
            midpt,
            leftvec,
            rightvec,
            ax=ax_inset,
            size=32.5,
            linewidth=2,
            text="$\\theta$",
            linestyle="-",
            color="darkslategray",
            textposition="outside",
            text_kw=dict(fontsize=11, color="darkslategray"),
        )

        ax_inset.tick_params(
            axis="both", bottom=False, left=False, labelbottom=False, labelleft=False
        )
        # thick frame
        ax_inset.spines["top"].set_linewidth(2)
        ax_inset.spines["right"].set_linewidth(2)
        ax_inset.spines["left"].set_linewidth(2)
        ax_inset.spines["bottom"].set_linewidth(2)

        ratio = 0.15
        # add 20% padding from current limits
        x0, x1 = ax_inset.get_xlim()
        y0, y1 = ax_inset.get_ylim()
        ax_inset.set_xlim(x0 - ratio * abs(x1 - x0), x1 + ratio * abs(x1 - x0))
        ax_inset.set_ylim(y0 - ratio * abs(y1 - y0), y1 + ratio * abs(y1 - y0))
    ax.set_xlabel("Unit 1")
    ax.set_ylabel("Unit 2")
    ax.set_zlabel("Unit 3")
    ax.tick_params(axis="both", pad=0, width=0)
    npy.plotting.clean_plot3d(ax)

    return ax

Simulate two population vector trajectories and analyze the representational geometry and dynamics between them.

fig, axes = plt.subplots(2, 2, figsize=(10, 10), subplot_kw={"projection": "3d"})
axes = axes.ravel()

# Create data
N_POINTS = 20
x = np.sin(np.linspace(0, 2 * np.pi, N_POINTS))
y = np.cos(np.linspace(0, 2 * np.pi, N_POINTS))
z1 = np.linspace(0, 1, N_POINTS)
z2 = np.linspace(0, 1, N_POINTS) + np.sin(np.linspace(0.25, 0.75, N_POINTS))
prox_traj1 = np.array([x, y, z1]).T  # shape (N_POINTS, N_NEURONS)
prox_traj2 = np.array([x, y, z2]).T  # shape (N_POINTS, N_NEURONS)

vis_nss_metrics(x, y, z1, z2, metric="proximity", ax=axes[0])
axes[0].set_title("Proximity")

# Create data
N_POINTS = 20
x = -np.sin(np.linspace(0, 2 * np.pi, N_POINTS))
y = np.cos(np.linspace(0, 2 * np.pi, N_POINTS))
z1 = -np.linspace(0, 1, N_POINTS)
z2 = -np.linspace(0, 1, N_POINTS) + np.sin(
    np.linspace(np.pi / 2, 1.5 * np.pi, N_POINTS)
)
cos_traj1 = np.array([x, y, z1]).T  # shape (N_POINTS, N_NEURONS)
cos_traj2 = np.array([x, y, z2]).T  # shape (N_POINTS, N_NEURONS)

vis_nss_metrics(x, y, z1, z2, metric="cosine", ax=axes[1])
axes[1].set_title("Cosine similarity of dynamics")

# convert axes to 2D
axes[2].axis("off")
axes[3].axis("off")

# insert axis 2d replacing the 3d plot
ax2d = fig.add_subplot(axes[2].get_position(), frame_on=True)
ax2d.plot(npy.ensemble.proximity(prox_traj1, prox_traj2), ".-")

ax2d.set_xlabel("Time")
ax2d.set_ylabel("Proximity")
ax2d.set_title("Proximity between trajectories")

# insert axis 2d replacing the 3d plot
ax2d = fig.add_subplot(axes[3].get_position(), frame_on=True)
ax2d.plot(
    npy.ensemble.cosine_similarity(np.diff(cos_traj1.T).T, np.diff(cos_traj2.T).T), ".-"
)

ax2d.set_xlabel("Time")
ax2d.set_ylabel("Cosine similarity")
ax2d.set_title("Cosine similarity of temporal differences")

plt.tight_layout()
plt.show()
/tmp/ipykernel_316323/3793467759.py:54: UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect.

png

Section 2: Proximity and cosine similarity of dynamics of real data

Section 2.1: Load data

basepath = r"/run/user/1000/gvfs/smb-share:server=132.236.112.212,share=ayadata1/Data/GrosmarkAD/Achilles/Achilles_10252013"

epoch_df = npy.io.load_epoch(basepath)
# get session bounds to provide support
session_bounds = nel.EpochArray(
    [epoch_df.startTime.iloc[0], epoch_df.stopTime.iloc[-1]]
)
# compress repeated sleep sessions
epoch_df = npy.session.compress_repeated_epochs(epoch_df)
beh_epochs = nel.EpochArray(epoch_df[["startTime", "stopTime"]].values.astype(float))

st, cell_metrics = npy.io.load_spikes(
    basepath, putativeCellType="Pyr", brainRegion="CA"
)

position_df = npy.io.load_animal_behavior(basepath)

position_df_no_nan = position_df.query("x.isnull() == False")
# put position into a nelpy position array for ease of use
pos = nel.AnalogSignalArray(
    data=position_df_no_nan["x"].values.T,
    timestamps=position_df_no_nan.timestamps.values,
)

# get outbound and inbound epochs
outbound_epochs, inbound_epochs = npy.behavior.get_linear_track_lap_epochs(
    pos.abscissa_vals, pos.data[0], newLapThreshold=20
)
inbound_epochs = npy.behavior.find_good_lap_epochs(
    pos, inbound_epochs, thres=0.5, binsize=3, min_laps=10
)
outbound_epochs = npy.behavior.find_good_lap_epochs(
    pos, outbound_epochs, thres=0.5, binsize=3, min_laps=10
)

outbound_epochs, inbound_epochs
WARNING:root:fs was not specified, so we try to estimate it from the data...
WARNING:root:fs was estimated to be 39.06263603480421 Hz
WARNING:root:creating support from abscissa_vals and sampling rate, fs!
WARNING:root:'fs' has been deprecated; use 'step' instead





(<EpochArray at 0x7a610db358b0: 42 epochs> of length 17:07:964 minutes,
 <EpochArray at 0x7a610db351c0: 42 epochs> of length 15:28:585 minutes)

Section 2.2: Compute population vectors trajectories in space

SPATIAL_BIN_SIZE = 3
BEHAVIOR_TIME_BIN_SIZE = 0.05
REPLAY_TIME_BIN_SIZE = 0.02
SPEED_THRESHOLD = 3
TUNING_CURVE_SIGMA = 2
PLACE_CELL_MIN_SPKS = 100
PLACE_CELL_MIN_RATE = 1
PLACE_CELL_PEAK_MIN_RATIO = 1.5

N_SHUFFLES = 100


def get_tuning_curves(
    pos, st, x_min, x_max, speed_thres, s_binsize, tuning_curve_sigma
):
    spatial_maps = npy.tuning.SpatialMap(
        pos,
        st,
        dim=1,
        x_minmax=(x_min, x_max),
        s_binsize=s_binsize,
        speed_thres=speed_thres,
        tuning_curve_sigma=tuning_curve_sigma,
        minbgrate=0,  # decoding does not like 0 firing rate
        # min_duration=0,
    )

    return spatial_maps.tc


x_max = np.ceil(np.nanmax(pos.data))
x_min = np.floor(np.nanmin(pos.data))

tc_in = get_tuning_curves(
    pos[inbound_epochs],
    st[inbound_epochs],
    x_min,
    x_max,
    SPEED_THRESHOLD,
    SPATIAL_BIN_SIZE,
    TUNING_CURVE_SIGMA,
)
tc_out = get_tuning_curves(
    pos[outbound_epochs],
    st[outbound_epochs],
    x_min,
    x_max,
    SPEED_THRESHOLD,
    SPATIAL_BIN_SIZE,
    TUNING_CURVE_SIGMA,
)
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
pv_trials = []
for ep in inbound_epochs + outbound_epochs:
    spatial_maps = npy.tuning.SpatialMap(
        pos[ep],
        st[ep],
        dim=1,
        x_minmax=(x_min, x_max),
        s_binsize=SPATIAL_BIN_SIZE,
        speed_thres=SPEED_THRESHOLD,
        tuning_curve_sigma=TUNING_CURVE_SIGMA,
        minbgrate=0,  # decoding does not like 0 firing rate
        min_duration=0,
    )
    pv_trials.append(spatial_maps.tc.ratemap.T)
pv_trials = np.asarray(pv_trials)
pv_trials.shape  # (n_trials, n_neurons, n_bins)
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring signal outside of support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring events outside of eventarray support
WARNING:root:ignoring signal outside of support





(84, 65, 241)

Section 2.3: Visualize single neuron tuning properties in relation to the behavioral trajectory

Visualize the spatial tuning curves of the neurons such that the neurons are sorted by their peak firing order in the inbound and outbound tuning curves

def vis_spatial_tc(ntrial):
    inbound_nrnorder = np.asarray(tc_in.get_peak_firing_order_ids()) - 1
    outbound_nrnorder = np.asarray(tc_out.get_peak_firing_order_ids()) - 1
    CMAP = "terrain"

    fig, axes = plt.subplots(2, 3, figsize=(15, 10))
    axes = axes.ravel()
    scaler = sklearn.preprocessing.MinMaxScaler()
    zscored_tc_in = scaler.fit_transform(tc_in.ratemap.T).T
    zscored_tc_out = scaler.fit_transform(tc_out.ratemap.T).T
    zscored_trial = scaler.fit_transform(pv_trials[ntrial])

    ax = axes[0]
    im = ax.imshow(
        zscored_tc_in[inbound_nrnorder], aspect="auto", interpolation="none", cmap=CMAP
    )
    plt.colorbar(im, ax=ax)
    ax.set_title("Tuning Curves Inbound")
    ax.set_xlabel("Spatial Bin")
    ax.set_ylabel("Neurons (sorted by peak firing order in inbound TC)")

    ax = axes[1]
    im = ax.imshow(
        zscored_tc_out[inbound_nrnorder], aspect="auto", interpolation="none", cmap=CMAP
    )
    plt.colorbar(im, ax=ax)
    ax.set_title("Tuning Curves Outbound")
    ax.set_xlabel("Spatial Bin")
    ax.set_ylabel("Neurons (sorted by peak firing order in inbound TC)")

    ax = axes[2]
    im = ax.imshow(
        zscored_trial.T[inbound_nrnorder],
        aspect="auto",
        interpolation="none",
        cmap=CMAP,
    )
    plt.colorbar(im, ax=ax)
    ax.set_title("Spatial Binned Trial")
    ax.set_xlabel("Spatial Bin")
    ax.set_ylabel("Neurons (sorted by peak firing order in inbound TC)")

    ax = axes[3]
    im = ax.imshow(
        zscored_tc_in[outbound_nrnorder], aspect="auto", interpolation="none", cmap=CMAP
    )
    plt.colorbar(im, ax=ax)
    ax.set_title("Tuning Curves Inbound")
    ax.set_xlabel("Spatial Bin")
    ax.set_ylabel("Neurons (sorted by peak firing order in outbound TC)")

    ax = axes[4]
    im = ax.imshow(
        zscored_tc_out[outbound_nrnorder],
        aspect="auto",
        interpolation="none",
        cmap=CMAP,
    )
    plt.colorbar(im, ax=ax)
    ax.set_title("Tuning Curves Outbound")
    ax.set_xlabel("Spatial Bin")
    ax.set_ylabel("Neurons (sorted by peak firing order in outbound TC)")

    ax = axes[5]
    im = ax.imshow(
        zscored_trial.T[outbound_nrnorder],
        aspect="auto",
        interpolation="none",
        cmap=CMAP,
    )
    plt.colorbar(im, ax=ax)
    ax.set_title("Spatial Binned Trial")
    ax.set_xlabel("Spatial Bin")
    ax.set_ylabel("Neurons (sorted by peak firing order in outbound TC)")

    plt.show()


widgets.interact(vis_spatial_tc, ntrial=(0, pv_trials.shape[0] - 1, 1));
interactive(children=(IntSlider(value=41, description='ntrial', max=83), Output()), _dom_classes=('widget-inte…

Section 2.4: Compute the proximity and cosine similarity of the dynamics of the population vector trajectories

We first visualize the population vector trajectories using Principal Component Analysis (PCA) and then compute the proximity and cosine similarity.

While for simple cases, the proximity and cosine similarity can be interpreted from the PCA plot, the proximity and cosine_similarity functions provide a quantitative measure of the representational geometry and dynamics between the two population vector trajectories in the high-dimensional neural state space.

# Preprocessing and PCA
scaler = sklearn.preprocessing.StandardScaler()
pca = sklearn.decomposition.PCA(n_components=3)

bst = pv_trials.reshape(-1, pv_trials.shape[-1])  # (n_trials * n_neurons, n_bins)
bst = scaler.fit_transform(bst)
clip = 4
bst = np.clip(bst, -clip, clip)
bst = pca.fit_transform(bst)

scaled_tc_in = scaler.transform(tc_in.ratemap.T)
scaled_tc_in = np.clip(scaled_tc_in, -clip, clip)
scaled_tc_out = scaler.transform(tc_out.ratemap.T)
scaled_tc_out = np.clip(scaled_tc_out, -clip, clip)
pca.fit(scaled_tc_in)
pca_tc_in = pca.transform(scaled_tc_in)
pca_tc_out = pca.transform(scaled_tc_out)

proximity = npy.ensemble.proximity(tc_in.ratemap.T, tc_out.ratemap.T)

cossim = npy.ensemble.cosine_similarity(
    np.gradient(tc_in.ratemap.T, axis=0), np.gradient(tc_out.ratemap.T, axis=0)
)

# Create figure and axes
fig = plt.figure(figsize=(6, 10))
ax3d = fig.add_subplot(111, projection="3d")
# ax = fig.add_subplot(111)


# Function to update the plot for each frame
def update(num, x, y, z1, z2):
    ax3d.cla()  # Clear the current axes
    # set limits of axes to be consistent on basis of all data
    ax3d.set_xlim(
        min(pca_tc_in[:, 0].min(), pca_tc_out[:, 0].min()),
        max(pca_tc_in[:, 0].max(), pca_tc_out[:, 0].max()),
    )
    ax3d.set_ylim(
        min(pca_tc_in[:, 1].min(), pca_tc_out[:, 1].min()),
        max(pca_tc_in[:, 1].max(), pca_tc_out[:, 1].max()),
    )
    ax3d.set_zlim(
        min(pca_tc_in[:, 2].min(), pca_tc_out[:, 2].min()),
        max(pca_tc_in[:, 2].max(), pca_tc_out[:, 2].max()),
    )
    ax3d.scatter(x[:num], y[:num], z1[:num], color="tab:blue", s=100, label="Inbound")
    ax3d.plot(x[:num], y[:num], z1[:num], color="tab:blue", alpha=0.25)
    ax3d.scatter(x[:num], y[:num], z2[:num], color="tab:green", s=100, label="Outbound")
    ax3d.plot(x[:num], y[:num], z2[:num], color="tab:green", alpha=0.25)

    # Set labels and title
    ax3d.set_xlabel("PC1")
    ax3d.set_ylabel("PC2")
    ax3d.set_zlabel("PC3")
    ax3d.set_title("Trajectories of tuning curves in PCA space")
    ax3d.legend()


# Create animation
ani = FuncAnimation(
    fig,
    update,
    frames=len(pca_tc_in),  # Number of frames in the animation
    fargs=(pca_tc_in[:, 0], pca_tc_in[:, 1], pca_tc_in[:, 2], pca_tc_out[:, 2]),
    interval=100,  # Interval between frames in milliseconds
)

HTML(ani.to_jshtml())

png

fig, axes = plt.subplots(1, 2, figsize=(10, 5))
axes[0].plot(npy.ensemble.proximity(tc_in.ratemap.T, tc_out.ratemap.T))
axes[0].set_title("Proximity")
axes[0].set_xlabel("Spatial bin")
axes[0].set_ylabel("Proximity")

axes[1].plot(
    npy.ensemble.cosine_similarity(
        np.gradient(tc_in.ratemap.T, axis=0), np.gradient(tc_out.ratemap.T, axis=0)
    )
)
axes[1].set_title("Cosine similarity of dynamics")
axes[1].set_xlabel("Spatial bin")
axes[1].set_ylabel("Cosine similarity")

plt.tight_layout()
plt.show()

png

Finally, we visualize the evolution of the proximity and cosine similarity between the two population vector trajectories over spatial bins.

# Create figure and axes
fig = plt.figure(figsize=(10, 6), constrained_layout=True)
nrows, ncols = 4, 6
gs = matplotlib.gridspec.GridSpec(*(nrows, ncols), figure=fig)
ax3d = fig.add_subplot(gs[0:4, 0:4], projection="3d")
ax_proximity = fig.add_subplot(gs[0:2, 4:6])
ax_cossim = fig.add_subplot(gs[2:4, 4:6])

# Initialize plots
ax_proximity.set_title("Proximity")
ax_proximity.set_xlabel("Spatial bin")
ax_proximity.set_ylabel("Proximity")
ax_cossim.set_title("Cosine Similarity")
ax_cossim.set_xlabel("Spatial bin")
ax_cossim.set_ylabel("Cosine Similarity")


# Function to update the plots for each frame
def update(num, x, y, z1, z2):
    ax3d.cla()  # Clear the current axes
    # set limits of axes to be consistent on basis of all data
    ax3d.set_xlim(
        min(pca_tc_in[:, 0].min(), pca_tc_out[:, 0].min()),
        max(pca_tc_in[:, 0].max(), pca_tc_out[:, 0].max()),
    )
    ax3d.set_ylim(
        min(pca_tc_in[:, 1].min(), pca_tc_out[:, 1].min()),
        max(pca_tc_in[:, 1].max(), pca_tc_out[:, 1].max()),
    )
    ax3d.set_zlim(
        min(pca_tc_in[:, 2].min(), pca_tc_out[:, 2].min()),
        max(pca_tc_in[:, 2].max(), pca_tc_out[:, 2].max()),
    )
    ax3d.scatter(x[:num], y[:num], z1[:num], color="tab:blue", s=100, label="Inbound")
    ax3d.plot(x[:num], y[:num], z1[:num], color="tab:blue", alpha=0.25)
    ax3d.scatter(x[:num], y[:num], z2[:num], color="tab:green", s=100, label="Outbound")
    ax3d.plot(x[:num], y[:num], z2[:num], color="tab:green", alpha=0.25)

    # Update proximity plot
    ax_proximity.cla()
    ax_proximity.set_xlim(-2, len(proximity))
    ax_proximity.set_ylim(proximity.min(), proximity.max())
    ax_proximity.plot(range(num), proximity[:num], color="tab:blue")
    ax_proximity.set_title("Proximity")
    ax_proximity.set_xlabel("Spatial bin")
    ax_proximity.set_ylabel("Proximity")

    # Update cosine similarity plot
    ax_cossim.cla()
    ax_cossim.set_xlim(-2, len(cossim))
    ax_cossim.set_ylim(cossim.min(), cossim.max())
    ax_cossim.plot(range(num), cossim[:num], color="tab:green")
    ax_cossim.set_title("Cosine Similarity")
    ax_cossim.set_xlabel("Spatial bin")
    ax_cossim.set_ylabel("Cosine Similarity")


# Create animation
ani = FuncAnimation(
    fig,
    update,
    frames=len(pca_tc_in),  # Number of frames in the animation
    fargs=(pca_tc_in[:, 0], pca_tc_in[:, 1], pca_tc_in[:, 2], pca_tc_out[:, 2]),
    interval=150,  # Interval between frames in milliseconds
)

HTML(ani.to_jshtml())

png