Analyzing Receptive Fields in Neuropixels Visual Coding Data

Tutorial overview

One of the most important features of visually responsive neurons is the location and extent of their receptive field. Is it highly localized or spatially distributed? Is it centered on the stimulus display, or is it on an edge? How much does it overlap with the receptive fields of neurons in other regions? Obtaining answers to these questions is a crucial step for interpreting a results related to neurons' visual coding properties.

This Jupyter notebook will cover the following topics:

This tutorial assumes you've already created a data cache, or are working with the files on AWS. If you haven't reached that step yet, we recommend going through the data access tutorial first.

Functions related to additional aspects of data analysis will be covered in other tutorials. For a full list of available tutorials, see the SDK documentation.

Let's start by creating an EcephysProjectCache object, and pointing it to a new or existing manifest file:

If you're not sure what a manifest file is or where to put it, please check out this tutorial before going further.

Let's load the sessions table and grab the data for one experiment in the list:

Receptive field mapping stimulus

The session object contains all of the spike data for one recording session, as well as information about the stimulus, mouse behavior, and probes.

Because receptive field analysis is so central to interpreting results related to visual coding, every experiment in the Neuropixels Visual Coding dataset includes a standardized receptive field mapping stimulus. This stimulus is always shown at the beginning of the session, and uses the same parameters for every mouse.

We can look at the stimulus_presentations DataFrame in order to examine the parameters of the receptive field mapping stimulus in more detail. The receptive field mapping stimulus consists of drifting Gabor patches with a circular mask, so we're going to filter the DataFrame based on stimulus_name == 'gabors':

There are 3645 trials for the receptive field mapping stimulus. What combination of stimulus parameters is used across these trials? Let's see which parameters actually vary for this stimulus:

We can ignore the parameters related to stimulus timing (start_time, stop_time, and duration), as well as stimulus_condition_id, which is used to find presentations with the same parameters. So we're left with orientation, x_position, and y_position.

We have 3 orientations and a 9 x 9 grid of spatial locations. Note that these locations are relative to the center of the screen, not the mouse's center of gaze. How many repeats are there for each condition?

This should match the number we get when dividing the length of the DataFrame by the total number of conditions:

What about the drifting grating parameters that don't vary, such as size (in degrees), spatial frequency (in cycles/degree), temporal frequency (in Hz), and contrast?

This stimulus is designed to drive neurons reliably across a wide variety of visual areas. Because of the large size (20 degree diameter), it lacks spatial precision. It also cannot be used to map on/off subfields on neurons. However, this is a reasonable compromise to allow us to map receptive fields with high reliability across all visual areas we're recording from.

Now that we have a better understanding of the stimulus, let's look at receptive fields for some neurons.

Plotting receptive fields

In order to visualize receptive fields, we're going to use a function in the ReceptiveFieldMapping class, one of the stimulus-specific analysis classes in the AllenSDK. Let's import it and create a rf_mapping object based on the session we loaded earlier:

The rf_mapping object contains a variety of methods related to receptive field mapping. Its stim_table property holds the same DataFrame we created earlier.

Before we calculate any receptive fields, let's find some units in primary visual cortex (VISp) that are likely to show clear receptive fields:

Now, calculating the receptive field is as simple as calling get_receptive_field() with a unit ID as the input argument.

This method creates a 2D histogram of spike counts at all 81 possible stimulus locations, and outputs it as a 9 x 9 matrix. It's summing over all orientations, so each pixel contains the spike count across 45 trials.

To plot it, just display it as an image. The matrix is already in the correct orientation so that it matches the layout of the screen (e.g., the upper right pixel contains the spike count when the Gabor patch was in the upper right of the screen).

This particular unit has a receptive field that's more or less in the center of the screen.

Let's plot the receptive fields for all the units in V1: