Loading a single experiment
To load an experiment, we use the Experiment
class. This class aggregates all modalities and their respective interpolators
in a single object. Its main job is to unify the access to all modalities.
Experiment.interpolate accepts an arbitrary array of time
points and returns the corresponding values for each modality by looking them
up in the raw stored data (e.g., using nearest-neighbour or linear
interpolation for sequences). When you need a regular sampling grid or
fixed-length intervals (chunks) for training, a dataset object such as
ChunkDataset should be used on top of
Experiment. There you can define the time
discretization (via sampling_rate and chunk_size), construct the
appropriate time points, and delegate the data retrieval to the
underlying Experiment.
Loading an experiment
A single experiment can be loaded using the following approach:
# Import the Experiment class from Experanto
from experanto.experiment import Experiment
# Set the experiment folder as the root directory
root_folder = '../data/allen_data/experiment_951980471_train'
# Initialize the Experiment object
e = Experiment(root_folder)
Checking available modalities
All compatible modalities for the loaded experiment can be checked using:
print("Available experiment devices:", e.devices.keys())
Available experiment devices: ['eye_tracker', 'screen', 'treadmill', 'responses']
Interpolating data
Once the modalities are identified, we can interpolate their data using
interpolate().
interpolate() accepts any 1-D array of
time points and returns a NumPy array containing only the valid time
points — those that fall within the recorded range of the requested modality.
The returned array therefore has length n_valid, which is less than or
equal to len(times), and its shape is modality-dependent:
Sequence modalities (
responses,eye_tracker,treadmill):(n_valid, n_signals)Screen modality (
screen):(n_valid, H, W)for grayscale stimuli, or(n_valid, H, W, C)when colour channels are present.
Pass return_valid=True to also receive valid, an integer index
array into the original times array, such that times[valid] gives
the time points that correspond row-for-row to the returned data array.
When you call interpolate() without
a device argument, every modality receives the same time array. Because
each modality may have a different valid range, the n_valid count can
differ between modalities. If you need different time densities per modality,
call interpolate() separately with a
different times array for each device. This is exactly what
ChunkDataset does internally.
The following example interpolates a 20-second window at 2 time points per
second. Any requested time that falls outside a valid screen trial is
excluded, so video.shape[0] may be less than len(times):
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from IPython.display import HTML
# Define the time window for interpolation
times = np.arange(4300., 4320., 0.5)
# Retrieve the frames as a NumPy float32 array with shape (n_valid, H, W)
# ``valid`` is an integer index array into ``times``; times[valid] gives
# the time point for each row of ``video`` (screen is blank outside trials).
video, valid = e.interpolate(times, device="screen", return_valid=True)
# ``video`` already contains only the n_valid frames; no further indexing needed.
video_np = video.astype(np.uint8)
n_frames, height, width = video_np.shape
# Create a figure and axis for animation
fig, ax = plt.subplots()
img = ax.imshow(video_np[0], cmap='gray', vmin=0, vmax=255)
def update(frame):
img.set_array(video_np[frame])
ax.set_title(f'Time step: {frame}')
return [img]
ani = animation.FuncAnimation(fig, update, frames=n_frames, interval=50, blit=True)
plt.close(fig)
HTML(ani.to_jshtml())
This should show a speed up version of the video from the sample experiment.