Startup¶
Edit this to point at the path to where you installed the neuropixel-utils
distribution or repo.
% Load the Neuropixel Utils library
homeDir = string(java.lang.System.getProperty('user.home'));
npixUtilsDistRoot = fullfile(homeDir, 'local', 'repos', 'npxutils-apj-wip-01');
addpath(fullfile(npixUtilsDistRoot, 'Mcode'));
fprintf('Loaded Neuropixel Utils %s\n', npxutils.globals.version)
Loaded Neuropixel Utils 0.5.0-SNAPSHOT
Set the default channel map file you want to use with your data. Some standard channel maps are included in the map_files
directory in the neuropixel-utils
distribution.
setenv('NEUROPIXEL_MAP_FILE', fullfile(npxutils.globals.distroot, 'map_files', 'neuropixPhase3A_kilosortChanMap.mat'))
Optional: Configure Neuropixel Utils to generate paths beneath your data root directory, based on its naming conventions.
This is entirely optional; you can arrange your data however you’d like.
myExampleDataDir = fullfile(homeDir, 'work', 'npxutils', 'example-data');
setenv('NEUROPIXEL_DATAROOT', myExampleDataDir)
Load Raw Imec dataset¶
Here we construct the path to the original, raw dataset as it was recorded by SpikeGLX. You don’t need to use this folder nesting structure.
subject = 'Vinnie';
dateStr = '2018-08-17';
rawBinFile = 'Vinnie_20180817_All.imec.ap.bin';
imecFile = npxutils.generatePath(subject, 'raw_datasets', dateStr, rawBinFile)
imecFile = '/home/janke/work/npxutils/example-data/Vinnie/raw_datasets/2018-08-17/Vinnie_20180817_All.imec.ap.bin'
We then use this path to construct an ImecDataset object which will facilitate access to the raw data and load the metadata from disk. You can pass the path of the Imec dataset in several ways:
- Path to raw
.imec.ap.bin
file orimec.lf.bin
file. - Path to the containing directory, if there is only one set of
.bin
files within.
To construct the ImecDataset object, pass the identifying path directly to the constructor.
imec = npxutils.ImecDataset(imecFile)
imec =
ImecDataset with properties:
bytesPerSample: 2
pathRoot: '/home/janke/work/npxutils/example-data/Vinnie/raw_datasets/2018-08-17'
fileStem: 'Vinnie_20180817_All'
fileImecNumber: NaN
creationTime: 7.3729e+05
nChannels: 385
fileTypeAP: 'ap'
fileTypeLF: 'lf'
nSamplesAP: 36177457
nSamplesLF: 0
fsAP: 30000
fsLF: NaN
fsSync: NaN
highPassFilterHz: 300
apGain: 500
apRange: [-0.6000 0.6000]
lfGain: 250
lfRange: []
adcBits: 10
snsShankMap: "(1,2,480)(0:0:0:1)(0:1:0:1)(0:0:1:1)(0:1:1:1)(0:0:2:1)(0:1:2:1)(0:0:3:1)(0:1:3:1)(0:0:4:1)(0:1:4:1)(0:0:5:1)(0:1:5:1)(0:0:6:1)(0:1:6:1)(0:0:7:1)(0:1:7:1)(0:0:8:1)(0:1:8:1)(0:0:9:1)(0:1:9:1)(0:0:10:1)(0:1:10:1)(0:0:11:1)(0:1:11:1)(0:0:12:1)(0:1:12:1)(0:0:13:1)(0:1:13:1)(0:0:14:1)(0:1:14:1)(0:0:15:1)(0:1:15:1)(0:0:16:1)(0:1:16:1)(0:0:17:1)(0:1:17:1)(0:0:18:0)(0:1:18:1)(0:0:19:1)(0:1:19:1)(0:0:20:1)(0:1:20:1)(0:0:21:1)(0:1:21:1)(0:0:22:1)(0:1:22:1)(0:0:23:1)(0:1:23:1)(0:0:24:1)(0:1:24:1)(0:0:25:1)(0:1:25:1)(0:0:26:1)(0:1:26:1)(0:0:27:1)(0:1:27:1)(0:0:28:1)(0:1:28:1)(0:0:29:1)(0:1:29:1)(0:0:30:1)(0:1:30:1)(0:0:31:1)(0:1:31:1)(0:0:32:1)(0:1:32:1)(0:0:33:1)(0:1:33:1)(0:0:34:1)(0:1:34:1)(0:0:35:1)(0:1:35:1)(0:0:36:1)(0:1:36:1)(0:0:37:1)(0:1:37:0)(0:0:38:1)(0:1:38:1)(0:0:39:1)(0:1:39:1)(0:0:40:1)(0:1:40:1)(0:0:41:1)(0:1:41:1)(0:0:42:1)(0:1:42:1)(0:0:43:1)(0:1:43:1)(0:0:44:1)(0:1:44:1)(0:0:45:1)(0:1:45:1)(0:0:46:1)(0:1:46:1)(0:0:47:1)(0:1:47:1)(0:0:48:1)(0:1:48:1)(0:0:49:1)(0:1:49:1)(0:0:50:1)(0:1:50:1)(0:0:51:1)(0:1:51:1)(0:0:52:1)(0:1:52:1)(0:0:53:1)(0:1:53:1)(0:0:54:1)(0:1:54:1)(0:0:55:1)(0:1:55:1)(0:0:56:0)(0:1:56:1)(0:0:57:1)(0:1:57:1)(0:0:58:1)(0:1:58:1)(0:0:59:1)(0:1:59:1)(0:0:60:1)(0:1:60:1)(0:0:61:1)(0:1:61:1)(0:0:62:1)(0:1:62:1)(0:0:63:1)(0:1:63:1)(0:0:64:1)(0:1:64:1)(0:0:65:1)(0:1:65:1)(0:0:66:1)(0:1:66:1)(0:0:67:1)(0:1:67:1)(0:0:68:1)(0:1:68:1)(0:0:69:1)(0:1:69:1)(0:0:70:1)(0:1:70:1)(0:0:71:1)(0:1:71:1)(0:0:72:1)(0:1:72:1)(0:0:73:1)(0:1:73:1)(0:0:74:1)(0:1:74:1)(0:0:75:1)(0:1:75:0)(0:0:76:1)(0:1:76:1)(0:0:77:1)(0:1:77:1)(0:0:78:1)(0:1:78:1)(0:0:79:1)(0:1:79:1)(0:0:80:1)(0:1:80:1)(0:0:81:1)(0:1:81:1)(0:0:82:1)(0:1:82:1)(0:0:83:1)(0:1:83:1)(0:0:84:1)(0:1:84:1)(0:0:85:1)(0:1:85:1)(0:0:86:1)(0:1:86:1)(0:0:87:1)(0:1:87:1)(0:0:88:1)(0:1:88:1)(0:0:89:1)(0:1:89:1)(0:0:90:1)(0:1:90:1)(0:0:91:1)(0:1:91:1)(0:0:92:1)(0:1:92:1)(0:0:93:1)(0:1:93:1)(0:0:94:0)(0:1:94:1)(0:0:95:1)(0:1:95:1)(0:0:96:1)(0:1:96:1)(0:0:97:1)(0:1:97:1)(0:0:98:1)(0:1:98:1)(0:0:99:1)(0:1:99:1)(0:0:100:1)(0:1:100:1)(0:0:101:1)(0:1:101:1)(0:0:102:1)(0:1:102:1)(0:0:103:1)(0:1:103:1)(0:0:104:1)(0:1:104:1)(0:0:105:1)(0:1:105:1)(0:0:106:1)(0:1:106:1)(0:0:107:1)(0:1:107:1)(0:0:108:1)(0:1:108:1)(0:0:109:1)(0:1:109:1)(0:0:110:1)(0:1:110:1)(0:0:111:1)(0:1:111:1)(0:0:112:1)(0:1:112:1)(0:0:113:1)(0:1:113:0)(0:0:114:1)(0:1:114:1)(0:0:115:1)(0:1:115:1)(0:0:116:1)(0:1:116:1)(0:0:117:1)(0:1:117:1)(0:0:118:1)(0:1:118:1)(0:0:119:1)(0:1:119:1)(0:0:120:1)(0:1:120:1)(0:0:121:1)(0:1:121:1)(0:0:122:1)(0:1:122:1)(0:0:123:1)(0:1:123:1)(0:0:124:1)(0:1:124:1)(0:0:125:1)(0:1:125:1)(0:0:126:1)(0:1:126:1)(0:0:127:1)(0:1:127:1)(0:0:128:1)(0:1:128:1)(0:0:129:1)(0:1:129:1)(0:0:130:1)(0:1:130:1)(0:0:131:1)(0:1:131:1)(0:0:132:0)(0:1:132:1)(0:0:133:1)(0:1:133:1)(0:0:134:1)(0:1:134:1)(0:0:135:1)(0:1:135:1)(0:0:136:1)(0:1:136:1)(0:0:137:1)(0:1:137:1)(0:0:138:1)(0:1:138:1)(0:0:139:1)(0:1:139:1)(0:0:140:1)(0:1:140:1)(0:0:141:1)(0:1:141:1)(0:0:142:1)(0:1:142:1)(0:0:143:1)(0:1:143:1)(0:0:144:1)(0:1:144:1)(0:0:145:1)(0:1:145:1)(0:0:146:1)(0:1:146:1)(0:0:147:1)(0:1:147:1)(0:0:148:1)(0:1:148:1)(0:0:149:1)(0:1:149:1)(0:0:150:1)(0:1:150:1)(0:0:151:1)(0:1:151:0)(0:0:152:1)(0:1:152:1)(0:0:153:1)(0:1:153:1)(0:0:154:1)(0:1:154:1)(0:0:155:1)(0:1:155:1)(0:0:156:1)(0:1:156:1)(0:0:157:1)(0:1:157:1)(0:0:158:1)(0:1:158:1)(0:0:159:1)(0:1:159:1)(0:0:160:1)(0:1:160:1)(0:0:161:1)(0:1:161:1)(0:0:162:1)(0:1:162:1)(0:0:163:1)(0:1:163:1)(0:0:164:1)(0:1:164:1)(0:0:165:1)(0:1:165:1)(0:0:166:1)(0:1:166:1)(0:0:167:1)(0:1:167:1)(0:0:168:1)(0:1:168:1)(0:0:169:1)(0:1:169:1)(0:0:170:0)(0:1:170:1)(0:0:171:1)(0:1:171:1)(0:0:172:1)(0:1:172:1)(0:0:173:1)(0:1:173:1)(0:0:174:1)(0:1:174:1)(0:0:175:1)(0:1:175:1)(0:0:176:1)(0:1:176:1)(0:0:177:1)(0:1:177:1)(0:0:178:1)(0:1:178:1)(0:0:179:1)(0:1:179:1)(0:0:180:1)(0:1:180:1)(0:0:181:1)(0:1:181:1)(0:0:182:1)(0:1:182:1)(0:0:183:1)(0:1:183:1)(0:0:184:1)(0:1:184:1)(0:0:185:1)(0:1:185:1)(0:0:186:1)(0:1:186:1)(0:0:187:1)(0:1:187:1)(0:0:188:1)(0:1:188:1)(0:0:189:1)(0:1:189:0)(0:0:190:1)(0:1:190:1)(0:0:191:1)(0:1:191:1)"
channelMap: [1x1 npxutils.ChannelMap]
badChannels: [0x1 uint32]
syncBitNames: [16x1 string]
concatenationInfoAP: [1x1 npxutils.ConcatenationInfo]
concatenationInfoLF: []
sourceDatasets: []
syncRaw: []
hasAP: 1
hasLF: 0
hasSourceDatasets: 0
hasSourceAP: 0
hasSourceLF: 0
hasSourceSync: 0
channelMapFile: "/home/janke/local/repos/npxutils-apj-wip-01/map_files/neuropixPhase3A_kilosortChanMap.mat"
mappedChannels: [384x1 uint32]
mappedChannelInds: [384x1 double]
nChannelsMapped: 384
connectedChannels: [374x1 uint32]
connectedChannelInds: [374x1 double]
nChannelsConnected: 374
goodChannels: [374x1 uint32]
goodChannelInds: [374x1 double]
nGoodChannels: 374
channelIds: [385x1 uint32]
channelNames: [385x1 string]
channelNamesPadded: [385x1 string]
nSyncBits: 16
syncBitsNamed: [11x1 double]
fileAP: 'Vinnie_20180817_All.imec.ap.bin'
pathAP: '/home/janke/work/npxutils/example-data/Vinnie/raw_datasets/2018-08-17/Vinnie_20180817_All.imec.ap.bin'
fileAPMeta: 'Vinnie_20180817_All.imec.ap.meta'
pathAPMeta: '/home/janke/work/npxutils/example-data/Vinnie/raw_datasets/2018-08-17/Vinnie_20180817_All.imec.ap.meta'
fileLF: 'Vinnie_20180817_All.imec.lf.bin'
pathLF: '/home/janke/work/npxutils/example-data/Vinnie/raw_datasets/2018-08-17/Vinnie_20180817_All.imec.lf.bin'
fileLFMeta: 'Vinnie_20180817_All.imec.lf.meta'
pathLFMeta: '/home/janke/work/npxutils/example-data/Vinnie/raw_datasets/2018-08-17/Vinnie_20180817_All.imec.lf.meta'
fileSync: 'Vinnie_20180817_All.imec.ap.bin'
pathSync: '/home/janke/work/npxutils/example-data/Vinnie/raw_datasets/2018-08-17/Vinnie_20180817_All.imec.ap.bin'
fileSyncCached: 'Vinnie_20180817_All.sync.mat'
pathSyncCached: '/home/janke/work/npxutils/example-data/Vinnie/raw_datasets/2018-08-17/Vinnie_20180817_All.sync.mat'
creationTimeStr: '17-Aug-2018 13:50:34'
apScaleToUv: 2.3438
lfScaleToUv: NaN
syncChannelId: 385
syncChannelIndex: 385
syncInAPFile: 1
syncInLFFile: 0
Specifying the channel map manually¶
By default, the channel map will be loaded from whatever the environment variable NEUROPIXEL_MAP_FILE is set to, which we set above. If you want to manaully specify a channel map, pass it in to the ImecDataset constructor using the channelMap
option:
imec = npxutils.ImecDataset(imecFile, ‘channelMap’, ‘/path/to/channelMap.mat’);
Explore the loaded metadata¶
Here we see that this option 3A probe has 384 total channels (saved in the .imec.ap.bin
file), and that 374 of these channels are connected, namely those listed in connectedChannels
.
imec.channelMap
ans =
ChannelMap with properties:
file: "/home/janke/local/repos/npxutils-apj-wip-01/map_files/neuropixPhase3A_kilosortChanMap.mat"
name: "neuropixPhase3A_kilosortChanMap"
channelIdsMapped: [384x1 uint32]
connected: [384x1 logical]
shankInd: [384x1 double]
nSpatialDims: 2
xcoords: [384x1 double]
ycoords: [384x1 double]
zcoords: [384x1 double]
syncChannelIndex: 385
syncChannelId: 385
coords: [384x2 double]
syncInAPFile: 1
syncInLFFile: 1
channelIds: [385x1 uint32]
nChannels: 385
nChannelsMapped: 384
connectedChannels: [374x1 uint32]
referenceChannels: [10x1 uint32]
invertChannelsY: 1
yspacing: 20
xspacing: 16
zspacing: [0x1 double]
xlim: [-9 79]
ylim: [0 3860]
We can determine the duration of the recording using the number of samples and the frequency in the Imec data:
durationMinutes = imec.nSamplesAP / imec.fsAP / 60;
fprintf('Duration of recording %s is %.1f minutes.\n', imec.fileStem, durationMinutes)
Duration of recording Vinnie_20180817_All is 20.1 minutes.
Accessing the raw AP data¶
You can access the raw AP data in several ways. (See the full list of methods with methods(imec)
or doc npxutils.ImecDataset
). The most straightforward is to memory-map the full binary data:
This bit is broken because it references code that doesn’t exist in this library. Probably left over from an older version of the library and never updated? Or maybe it has an external dependency?
% This is broken because NeuropixelExpt doesn't exist?
% NeuropixelExpt.DataLoad.setImecSyncBitNames(imec);
% What does "p" refer to here?
% if ~isempty(p.Results.badChannels)
% imec.markBadChannels(p.Results.badChannels);
% end
This stuff works:
rmsBadChannels = imec.markBadChannelsByRMS('rmsRange', [3 100]);
fprintf('Marked %d channels bad based on RMS\n', numel(rmsBadChannels));
Marked 0 channels bad based on RMS
% Save the bad channels and sync bit names back to the meta file
imec.writeModifiedAPMeta();
% CAR the file and flush the unused sync bits to the cleaned_datasets folder
cleanedBinFile = 'Vinnie_20180817_All_cleaned.imec.ap.bin'
cleanedBinFile = 'Vinnie_20180817_All_cleaned.imec.ap.bin'
cleanedPath = npxutils.generatePath(subject, 'cleaned_datasets', dateStr, cleanedBinFile);
fprintf('Writing CAR version at %s\n', cleanedPath);
Writing CAR version at /home/janke/work/npxutils/example-data/Vinnie/cleaned_datasets/2018-08-17/Vinnie_20180817_All_cleaned.imec.ap.bin
extraMeta = struct;
extraMeta.run_clearUnusedSyncBits = true;
extraMeta.run_detectAndMarkStimArtifactWindows = true;
fnList = {
% This is broken because NeuropixelExpt doesn't exist?
% @NeuropixelExpt.DataClean.clearUnusedSyncBits
@npxutils.dataprocess.commonAverageReference
}';
cleanedDataDir = fullfile(myExampleDataDir, 'Vinnie', 'cleaned_datasets');
npxutils.io.rmrf(cleanedDataDir);
imec = imec.saveTransformedDataset(cleanedPath, ...
'goodChannelsOnly', false, 'writeSyncSeparate', false, ...
'transformAP', fnList, 'extraMeta', extraMeta);
Writing AP meta file Vinnie_20180817_All_cleaned.imec.ap.meta
Writing AP bin file /home/janke/work/npxutils/example-data/Vinnie/cleaned_datasets/2018-08-17/Vinnie_20180817_All_cleaned.imec.ap.bin
Writing contents of Vinnie_20180817_All
Copying ap file 1 / 1: Vinnie_20180817_All : 100% [_______________]
Warning: AP bin file size is not an integral number of samples, file data may not be fully copied, truncating nSamplesAP
Error using npxutils.ConcatenationInfo (line 56)
Mismatch between time shifts and total number of samples
Error in npxutils.ImecDataset/readInfo (line 313)
this.concatenationInfoAP = npxutils.ConcatenationInfo(this, 'ap', metaAP);
Error in npxutils.ImecDataset (line 193)
this.readInfo();
Error in npxutils.ImecDataset.writeConcatenatedFileMatchGains (line 2763)
imecOut = npxutils.ImecDataset(outFile, 'channelMap', imecList{1}.channelMapFile, 'sourceDatasets', cat(1, imecList{:}));
Error in npxutils.ImecDataset/saveTransformedDataset (line 1943)
imecOut = npxutils.ImecDataset.writeConcatenatedFileMatchGains({this}, outPath, p.Results);
% Symlink into ks directory for Kilosort's use
ksPath = npxutils.generatePath(subject, 'ks', dateStr, cleanedBinFile);
fprintf('Symlinking to %s\n', ksPath);
% And run Kilosort on the symlinked data set
imec = imec.symLinkAPIntoDirectory(ksPath);
fprintf('Running Kilosort2\n');
npxutils.runKilosort2(imec);
% Here's a little summary output
info.rawPath = imecFile;
info.cleanedPath = cleanedPath;
info.ksPath = ksPath;
info