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 numpy as np
import matplotlib
import matplotlib.gridspec
import matplotlib.pyplot as plt
import sklearn
import neuro_py as npy
import nelpy as nel
from IPython.display import HTML
from matplotlib.animation import FuncAnimation
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=.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=.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=.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=.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.
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())
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()
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())