-
Notifications
You must be signed in to change notification settings - Fork 24
place fields #126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
MRScheid
wants to merge
49
commits into
master
Choose a base branch
from
place_field
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
place fields #126
Changes from 48 commits
Commits
Show all changes
49 commits
Select commit
Hold shift + click to select a range
60f1c75
Initial code draft
9e9c7c3
place fields almost working
bendichter 4ff6a58
Merge branch 'master' into place_field
bendichter b752882
interactive widget working
bendichter 8d5f754
interactive widget working
bendichter 50e284c
NaN out unexplored territory
bendichter 03f617b
1D place code widget
09e0669
1D place code widget working
c346a60
nelpy package integrated into 1D rate map widget
2e92ed4
1D rate map speed threshold implementation
7b48dc0
1D rate map normalization and collapsed view feature addition
ece7795
- Added Numpy docstring for plot_tuning_curves1D fxn
07a7ae7
Removed nelpy dependency
7f8a790
Moved analysis code to analysis/placefields.py
6fd92c1
Merge branch 'master' into place_field
bendichter 55611dd
Dynamically route rate maps to correspond to dimensionality of the data
d0ff81b
Merge branch 'place_field' of https://github.com/NeurodataWithoutBord…
4c414fa
Merge branch 'master' into place_field
bendichter 8b3bbad
Merge branch 'master' into place_field
bendichter 0ff0037
Add optional TimeSeries of velocity as input
81c40b2
Update nwbwidgets/placefield.py
MRScheid 2601b86
Update nwbwidgets/placefield.py
MRScheid 7290f00
Update nwbwidgets/placefield.py
MRScheid 33f3c70
Update nwbwidgets/placefield.py
MRScheid 0f77f2d
Update nwbwidgets/placefield.py
MRScheid 45ae3ec
Update nwbwidgets/placefield.py
MRScheid c7b0208
Update nwbwidgets/placefield.py
MRScheid fdb0d5b
Corrected velocity as optional input
69bc054
Cleaned up code, fixed single unit input bug
866236a
Merge branch 'master' into place_field
bendichter 6fbd006
Removed group and sort controller. Added multi-select.
9dab486
* lru_cache
bendichter 52d1706
correct index and cache
bendichter 84e87aa
style and caching some analyses
bendichter 6bb219e
Place field modification for towers task.
85dc581
Merge remote-tracking branch 'origin/place_field' into place_field
43080e8
Place field modification for towers task.
c365f2b
Fixed the "TypeError: unhashable type: 'numpy.ndarray" issue that aro…
194f457
Remove group and sort controller import
2624add
Re-factor code
d6905bc
Allow for different pixel width in x and y dimension
04cca71
Changes to accomodate towers task place field
6c68ddf
Added bin number control
3b7863d
Merge branch 'master' into place_field
MRScheid 6e3c1b1
Simple formatting
d259182
Merge branch 'place_field' of https://github.com/NeurodataWithoutBord…
c9fa416
Update imports
c4cc8f6
Merge branch 'master' into place_field
MRScheid 87a2433
Removed old ignore files
MRScheid File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,300 @@ | ||
| from functools import lru_cache | ||
|
|
||
| import numpy as np | ||
| from scipy.ndimage.filters import gaussian_filter | ||
|
|
||
|
|
||
| def find_nearest(arr, tt): | ||
| """Used for picking out elements of a TimeSeries based on spike times | ||
|
|
||
| Parameters | ||
| ---------- | ||
| arr: array-like | ||
| tt: array-like | ||
|
|
||
| Returns | ||
| ------- | ||
| indices: array-like | ||
|
|
||
| """ | ||
| arr = arr[arr > tt[0]] | ||
| arr = arr[arr < tt[-1]] | ||
| return np.searchsorted(tt, arr) | ||
|
|
||
|
|
||
| def smooth(y, box_pts): | ||
| """Moving average | ||
|
|
||
| Parameters | ||
| ---------- | ||
| y: array-like | ||
| box_pts: int | ||
|
|
||
| Returns | ||
| ------- | ||
| output: np.array(dtype=float) | ||
|
|
||
| """ | ||
| box = np.ones(box_pts) / box_pts | ||
| return np.convolve(y, box, mode='same') | ||
|
|
||
|
|
||
| def compute_speed(pos, pos_tt, smooth_param=40): | ||
| """Compute boolean of whether the speed of the animal was above a threshold | ||
| for each time point | ||
|
|
||
| Parameters | ||
| ---------- | ||
| pos: np.ndarray(dtype=float) | ||
| in meters | ||
| pos_tt: np.ndarray(dtype=float) | ||
| in seconds | ||
| smooth_param: float, optional | ||
|
|
||
| Returns | ||
| ------- | ||
| running: np.ndarray(dtype=bool) | ||
|
|
||
| """ | ||
| if len(pos.shape) > 1: | ||
| speed = np.hstack((0, np.sqrt(np.sum(np.diff(pos.T) ** 2, axis=0)) / np.diff(pos_tt))) | ||
| else: | ||
| speed = np.hstack((0, np.sqrt(np.diff(pos.T) ** 2) / np.diff(pos_tt))) | ||
| return smooth(speed, smooth_param) | ||
|
|
||
|
|
||
| def compute_2d_occupancy(pos, pos_tt, edges_x, edges_y, pixel_width, speed_thresh=0.03, velocity=None): | ||
| """Computes occupancy per bin in seconds | ||
|
|
||
| Parameters | ||
| ---------- | ||
| pos: np.ndarray(dtype=float) | ||
| in meters | ||
| pos_tt: np.ndarray(dtype=float) | ||
| in seconds | ||
| edges_x: array-like | ||
| edges of histogram in meters | ||
| edges_y: array-like | ||
| edges of histogram in meters | ||
| pixel_width: array-like | ||
| speed_thresh: float, optional | ||
| in meters. Default = 3.0 cm/s | ||
| velocity: np.ndarray(dtype=float) | ||
| pre-computed velocity | ||
|
|
||
| Returns | ||
| ------- | ||
| occupancy: np.ndarray(dtype=float) | ||
| in seconds | ||
| running: np.ndarray(dtype=bool) | ||
|
|
||
| """ | ||
|
|
||
| sampling_period = (np.max(pos_tt) - np.min(pos_tt)) / len(pos_tt) | ||
| np.seterr(invalid='ignore') | ||
| if velocity is None: | ||
| if pixel_width[1] is not int(1): | ||
| is_running = compute_speed(pos, pos_tt) > speed_thresh | ||
| else: | ||
| is_running = compute_speed(pos[:, 0], pos_tt) > speed_thresh | ||
| else: | ||
| is_running = np.linalg.norm(velocity) > speed_thresh | ||
|
|
||
| run_pos = pos[is_running, :] | ||
| occupancy = np.histogram2d(run_pos[:, 1], | ||
| run_pos[:, 0], | ||
| [edges_y, edges_x])[0] * sampling_period # in seconds | ||
|
|
||
| return occupancy, is_running | ||
|
|
||
|
|
||
| def compute_2d_n_spikes(pos, pos_tt, spikes, edges_x, edges_y, pixel_width, speed_thresh=0.03, velocity=None): | ||
| """Returns speed-gated position during spikes | ||
|
|
||
| Parameters | ||
| ---------- | ||
| pos: np.ndarray(dtype=float) | ||
| (time x 2) in meters | ||
| pos_tt: np.ndarray(dtype=float) | ||
| (time,) in seconds | ||
| spikes: np.ndarray(dtype=float) | ||
| in seconds | ||
| edges_x: np.ndarray(dtype=float) | ||
| edges of histogram in meters | ||
| edges_y: np.ndarray(dtype=float) | ||
| edges of histogram in meters | ||
| pixel_width: array | ||
| speed_thresh: float | ||
| in meters. Default = 3.0 cm/s | ||
| velocity: np.ndarray(dtype=float) | ||
| pre-computed velocity | ||
|
|
||
| Returns | ||
| ------- | ||
| """ | ||
| np.seterr(invalid='ignore') | ||
| if velocity is None: | ||
| if pixel_width[1] is not int(1): | ||
| is_running = compute_speed(pos, pos_tt) > speed_thresh | ||
| else: | ||
| is_running = compute_speed(pos[:, 0], pos_tt) > speed_thresh | ||
| else: | ||
| is_running = np.linalg.norm(velocity) > speed_thresh | ||
|
|
||
| spike_pos_inds = find_nearest(spikes, pos_tt) | ||
| spike_pos_inds = spike_pos_inds[is_running[spike_pos_inds]] | ||
| pos_on_spikes = pos[spike_pos_inds, :] | ||
|
|
||
| n_spikes = np.histogram2d(pos_on_spikes[:, 1], | ||
| pos_on_spikes[:, 0], | ||
| [edges_y, edges_x])[0] | ||
|
|
||
| return n_spikes | ||
|
|
||
|
|
||
| def compute_2d_firing_rate(pos, pos_tt, spikes, | ||
| pixel_width, | ||
| speed_thresh=0.03, | ||
| gaussian_sd_x=0.0184, | ||
| gaussian_sd_y=0.0184, | ||
| x_start=None, x_stop=None, | ||
| y_start=None, y_stop=None, | ||
| velocity=None): | ||
| """Returns speed-gated occupancy and speed-gated and | ||
| Gaussian-filtered firing rate | ||
|
|
||
| Parameters | ||
| ---------- | ||
| pos: np.ndarray(dtype=float) | ||
| (time x 2), in meters | ||
| pos_tt: np.ndarray(dtype=float) | ||
| (time,) in seconds | ||
| spikes: np.ndarray(dtype=float) | ||
| in seconds | ||
| pixel_width: array-like | ||
| speed_thresh: float, optional | ||
| in meters. Default = 3.0 cm/s | ||
| gaussian_sd_x: float, optional | ||
| width of gaussian kernel in x-dim, in meters. Default = 1.84 cm | ||
| gaussian_sd_y: float, optional | ||
| width of gaussian kernel in y-dim, in meters. Default = 1.84 cm | ||
| x_start: float, optional | ||
| x_stop: float, optional | ||
| y_start: float, optional | ||
| y_stop: float, optional | ||
| velocity: np.ndarray(dtype=float) | ||
| pre-computed velocity | ||
|
|
||
| Returns | ||
| ------- | ||
|
|
||
| occupancy: np.ndarray | ||
| in seconds | ||
| filtered_firing_rate: np.ndarray(shape=(cell, x, y), dtype=float) | ||
| in Hz | ||
|
|
||
| """ | ||
|
|
||
| x_start = np.nanmin(pos[:, 0]) if x_start is None else x_start | ||
| x_stop = np.nanmax(pos[:, 0]) if x_stop is None else x_stop | ||
|
|
||
| y_start = np.nanmin(pos[:, 1]) if y_start is None else y_start | ||
| y_stop = np.nanmax(pos[:, 1]) if y_stop is None else y_stop | ||
|
|
||
| edges_x = np.arange(x_start, x_stop, pixel_width[0]) | ||
| edges_y = np.arange(y_start, y_stop, pixel_width[1]) | ||
|
|
||
| occupancy, running = compute_2d_occupancy(pos, pos_tt, edges_x, edges_y, pixel_width, speed_thresh, velocity) | ||
|
|
||
| n_spikes = compute_2d_n_spikes(pos, pos_tt, spikes, edges_x, edges_y, pixel_width, speed_thresh, velocity) | ||
|
|
||
| np.seterr(divide='ignore') | ||
| firing_rate = n_spikes / occupancy # in Hz | ||
| firing_rate[np.isnan(firing_rate)] = 0 # get rid of NaNs so convolution works | ||
| sigmas = [gaussian_sd_y / pixel_width[1], gaussian_sd_x / pixel_width[0]] | ||
| filtered_firing_rate = gaussian_filter(firing_rate, sigmas) | ||
|
|
||
| # filter occupancy to create a mask so non-explored regions are nan'ed | ||
| sigmas_occ = [gaussian_sd_y / pixel_width[1] / 8, gaussian_sd_x / pixel_width[0] / 8] | ||
| filtered_occupancy = gaussian_filter(occupancy, sigmas_occ) | ||
| filtered_firing_rate[filtered_occupancy.astype('bool') < .00001] = np.nan | ||
|
|
||
| return occupancy, filtered_firing_rate, [edges_x, edges_y] | ||
|
|
||
|
|
||
| def compute_1d_occupancy(pos, pos_tt, spatial_bins, sampling_rate, speed_thresh=0.03, velocity=None): | ||
|
|
||
| np.seterr(invalid='ignore') | ||
| if velocity is None: | ||
| is_running = compute_speed(pos, pos_tt) > speed_thresh | ||
| else: | ||
| is_running = np.linalg.norm(velocity) > speed_thresh | ||
|
|
||
| run_pos = pos[is_running, :] | ||
| finite_lin_pos = run_pos[np.isfinite(run_pos)] | ||
|
|
||
| occupancy = np.histogram( | ||
| finite_lin_pos, bins=spatial_bins)[0][:-2] / sampling_rate | ||
|
|
||
| return occupancy | ||
|
|
||
|
|
||
| def compute_linear_firing_rate(pos, pos_tt, spikes, gaussian_sd=0.0557, | ||
| spatial_bin_len=0.0168, speed_thresh=0.03, velocity=None): | ||
| """The occupancy and number of spikes, speed-gated, binned, and smoothed | ||
| over position | ||
|
|
||
| Parameters | ||
| ---------- | ||
| pos: np.ndarray | ||
| linearized position | ||
| pos_tt: np.ndarray | ||
| sample times in seconds | ||
| spikes: np.ndarray | ||
| for a single cell in seconds | ||
| gaussian_sd: float (optional) | ||
| in meters. Default = 5.57 cm | ||
| spatial_bin_len: float (optional) | ||
| in meters. Default = 1.68 cm | ||
| speed_thresh: float (optional) | ||
| in m/s. Default = 0.03 | ||
| velocity: np.ndarray(dtype=float) | ||
| pre-computed velocity | ||
|
|
||
| Returns | ||
| ------- | ||
| xx: np.ndarray | ||
| center of position bins in meters | ||
| occupancy: np.ndarray | ||
| time in each spatial bin in seconds, during appropriate trials and | ||
| while running | ||
| filtered_n_spikes: np.ndarray | ||
| number of spikes in each spatial bin, during appropriate trials, while | ||
| running, and processed with a Gaussian filter | ||
|
|
||
| """ | ||
| spatial_bins = np.arange(np.nanmin(pos), np.nanmax(pos) + spatial_bin_len, spatial_bin_len) | ||
|
|
||
| sampling_rate = len(pos_tt) / (np.nanmax(pos_tt) - np.nanmin(pos_tt)) | ||
|
|
||
| occupancy = compute_1d_occupancy(pos, pos_tt, spatial_bins, sampling_rate, speed_thresh, velocity) | ||
|
|
||
| np.seterr(invalid='ignore') | ||
| is_running = compute_speed(pos, pos_tt) > speed_thresh | ||
|
|
||
| # find pos_tt bin associated with each spike | ||
| spike_pos_inds = find_nearest(spikes, pos_tt) | ||
| spike_pos_inds = spike_pos_inds[is_running[spike_pos_inds]] | ||
| pos_on_spikes = pos[spike_pos_inds] | ||
| finite_pos_on_spikes = pos_on_spikes[np.isfinite(pos_on_spikes)] | ||
|
|
||
| n_spikes = np.histogram(finite_pos_on_spikes, bins=spatial_bins)[0][:-2] | ||
|
|
||
| np.seterr(divide='ignore') | ||
| firing_rate = np.nan_to_num(n_spikes / occupancy) | ||
|
|
||
| filtered_firing_rate = gaussian_filter( | ||
| firing_rate, gaussian_sd / spatial_bin_len) | ||
| xx = spatial_bins[:-3] + (spatial_bins[1] - spatial_bins[0]) / 2 | ||
|
|
||
| return xx, occupancy, filtered_firing_rate |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MRScheid what are these files? Why are you gitignoring them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bendichter I removed all these from the git ignore file--they were modules that I was developing with but weren't quite ready to be committed, I thought I'd get back around to them but I never did. They're irrelevant now.