diff --git a/.gitignore b/.gitignore index 65ac1a9..89785ea 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ .DS_Store .idea *__pycache__* -*.edd-info* +*.egg-info* +*.asv diff --git a/RFMapRaw_Keys.mat b/RFMapRaw_Keys.mat deleted file mode 100644 index 536bdf9..0000000 Binary files a/RFMapRaw_Keys.mat and /dev/null differ diff --git a/lib/+ne7/+ip/correctRaster.m b/lib/+ne7/+ip/correctRaster.m index 4ed974d..c450668 100644 --- a/lib/+ne7/+ip/correctRaster.m +++ b/lib/+ne7/+ip/correctRaster.m @@ -1,22 +1,23 @@ function img = correctRaster(img, rasterPhase, fillFraction) -% raster correction for resonant scanners. +% raster correction for resonant scanners. % rasterPhase is the phase different between left-right and right-left scan -% lines. +% lines. % -% img size [x y nSlices nFrames]. 2D, 3D, 4D images also work +% img size [x y nChannel nSlices nFrames]. 2D, 3D, 4D, 5D images also work - -sz = [size(img,1) size(img,2) size(img,3) size(img,4)]; -ix = (-sz(2)/2+0.5:sz(2)/2-0.5)/(sz(2)/2); +assert(ndims(img)<=5) +ix = (-size(img, 2)/2+0.5:size(img, 2)/2-0.5)/(size(img, 2)/2); tx = asin(ix*fillFraction); % convert index to time -for iSlice = 1:size(img,3) - for iFrame = 1:size(img, 4) - im = img(:,:,iSlice,iFrame); - extrapVal = mean(im(:)); - img(1:2:end,:,iSlice,iFrame) = interp1(ix, im(1:2:end,:)', ... - sin(tx'+rasterPhase)/fillFraction,'linear',extrapVal)'; - img(2:2:end,:,iSlice,iFrame) = interp1(ix, im(2:2:end,:)', ... - sin(tx'-rasterPhase)/fillFraction,'linear',extrapVal)'; +for iChannel = 1:size(img, 3) + for iSlice = 1:size(img, 4) + for iFrame = 1:size(img, 5) + im = img(:,:, iChannel, iSlice, iFrame); + extrapVal = mean(im(:)); + img(1:2:end, :, iChannel, iSlice, iFrame) = interp1(ix, im(1:2:end,:)', ... + sin(tx'+rasterPhase)/fillFraction,'linear',extrapVal)'; + img(2:2:end, :, iChannel, iSlice, iFrame) = interp1(ix, im(2:2:end,:)', ... + sin(tx'-rasterPhase)/fillFraction,'linear',extrapVal)'; + end end end end diff --git a/lib/+ne7/+scanimage/Reader5.m b/lib/+ne7/+scanimage/Reader5.m index 7cd4625..13b2108 100644 --- a/lib/+ne7/+scanimage/Reader5.m +++ b/lib/+ne7/+scanimage/Reader5.m @@ -3,7 +3,7 @@ % indexed as reader(col, row, frame, slice, channel). % It works with scanimage 4 and scanimage 5. % - % The reader can then be addressed with subscripts + % The reader can then be addressed with subscripts % reader(y, x, channel, slice, frame) % % Example: @@ -20,7 +20,7 @@ nframes frames_per_file end - + properties(Dependent) nslices channels @@ -32,7 +32,7 @@ dwell_time bidirectional fill_fraction - is_functional + fastz end methods @@ -62,7 +62,7 @@ end end - function f = get.is_functional(self) + function f = get.fastz(self) if self.scanimage_version == 4 f = 1; %f = self.header.fastZEnable; @@ -75,6 +75,8 @@ function n = get.nslices(self) if self.scanimage_version == 4 n = self.header.stackNumSlices; + elseif self.header.hFastZ_enable + n = self.header.hFastZ_numFramesPerVolume; else n = self.header.hStackManager_numSlices; %assert(n == self.header.hFastZ_numFramesPerVolume) @@ -138,7 +140,7 @@ if self.header.hFastZ_enable n = self.header.hFastZ_numVolumes; else - n = hStackManager_framesPerSlice; + n = self.header.hStackManager_framesPerSlice; end end @@ -173,23 +175,17 @@ end function sz = size(self) - if self.is_functional - sz(1) = self.header.hRoiManager_linesPerFrame; % not sure this is lines or pixels (JR) - sz(2) = self.header.hRoiManager_pixelsPerLine; % not sure this is lines or pixels (JR) - sz(3) = self.nchannels; - sz(4) = self.nslices; - sz(5) = self.nframes; - else - sz = size(self.data); - end + sz(1) = self.header.hRoiManager_linesPerFrame; % not sure this is lines or pixels (JR) + sz(2) = self.header.hRoiManager_pixelsPerLine; % not sure this is lines or pixels (JR) + sz(3) = self.nchannels; + sz(4) = self.nslices; + sz(5) = self.nframes; end function data = subsref(self, S) if ~strcmp(S(1).type, '()') data = builtin('subsref', self, S); - elseif ~self.is_functional - data = builtin('subsref', self.data, S); else assert(length(S.subs)==5, 'subscript error') sz = size(self); @@ -236,7 +232,7 @@ k=1; for i=1:length(self.stacks) stackInd = find(ind(sum(self.frames_per_file(1:i-1))+1 : sum(self.frames_per_file(1:i)))); - for j=stackInd + for j=stackInd(:)' setDirectory(self.stacks{i},j); f = read(self.stacks{i}); data(:,:,k) = f(yInd,xInd); @@ -257,24 +253,25 @@ function compute_nframes(self) if self.scanimage_version == 4 n = self.header.acqNumFrames; else - n = (length(self.files)-1) * self.header.hScan2D_logFramesPerFile; - - disp('Reading number of frames in last file...'); - k=1; + n = (length(self.files)-1) * self.header.hScan2D_logFramesPerFile * self.nchannels; + % Reading number of frames in last file + k=1; while ~lastDirectory(self.stacks{end}) - nextDirectory(self.stacks{end}); - k=k+1; - end; - setDirectory(self.stacks{end},1); - - n = floor((n + (k / self.nchannels)) / self.nslices); + nextDirectory(self.stacks{end}); + k=k+1; + end; + setDirectory(self.stacks{end},1); + n = n + k; -% assert(n == round(n),'Total nframes / nslices must be an integer. Maybe scan aborted?') end - self.nframes = n; + self.nframes = n/self.nchannels/self.nslices; + if self.nframes ~= round(self.nframes) + warning 'Total nframes / nslices must be an integer. Maybe scan aborted?' + self.nframes = floor(self.nframes); + end self.frames_per_file(1:length(self.files)-1) = deal(self.header.hScan2D_logFramesPerFile * self.nchannels); - self.frames_per_file(length(self.files)) = n - sum(self.frames_per_file); - + self.frames_per_file(length(self.files)) = self.nframes * self.nchannels * self.nslices - sum(self.frames_per_file); + end function find_files(self, path) @@ -295,12 +292,22 @@ function load_header(self) self.scanimage_version = 5; temp = regexp(hdr, '^scanimage\.SI\.(?[\.\w]*)\s*=\s*(?.*\S)\s*$', 'names'); end + framenums = regexp(hdr, '^(?[\.frameNumbers]*)\s*=\s*(?.*\S)\s*$', 'names'); + framenums = [framenums{~cellfun(@isempty, framenums)}]; hdr = temp; hdr = [hdr{~cellfun(@isempty, hdr)}]; + if isempty(hdr) % in case we have used scanimage 5.2 + hdr = textscan(tiff.getTag('Software'),'%s','Delimiter',char(10)); + hdr = strtrim(hdr{1}); + self.scanimage_version = 5.2; + temp = regexp(hdr, '^SI\.(?[\.\w]*)\s*=\s*(?.*\S)\s*$', 'names'); + hdr = temp; + hdr = [hdr{~cellfun(@isempty, hdr)}]; + end + hdr(end+1) = framenums; assert(~isempty(hdr), 'empty header -- possibly wrong ScanImage version.') self.header = cell2struct(cellfun(@(x) {evaluate(x)}, {hdr.value})', strrep({hdr.attr}, '.', '_')); - - + function str = evaluate(str) % if str is not in the form '', then evaluate it. if str(1)~='<' && str(end)~='>' @@ -310,33 +317,9 @@ function load_header(self) end function init_stacks(self) - if self.is_functional - self.stacks = arrayfun(@(ifile) ... - Tiff(self.files{ifile}), ... - 1:length(self.files), 'uni', false); - - %self.stacks = arrayfun(@(ifile) ... - % TIFFStack(self.files{ifile}, [], [self.nchannels self.nslices]), ... - % 1:length(self.files), 'uni', false); - - %self.stacks = arrayfun(@(ifile) TIFFStack(self.files{ifile}),1:length(self.files), 'uni', false); - else - % if structural data, then load the entire stack into - % memory. The loaded data is initially flat and needs - % reshaping as well as permutation of axis as frames and - % slices are flipped. - data = []; - for idx = 1:length(self.files) - stack = TIFFStack(self.files{idx}, [], self.nchannels); - data = cat(4, data, stack(:,:,:,:)); - end - sz = size(data); - assert(sz(4) == self.nframes * self.nslices, ... - sprintf(['stack size mismatch: expected %d images but only %d '... - 'found -- be sure to load all files together'], self.nframes*self.nslices, sz(4))); - sz = [sz(1:end-1) self.nframes self.nslices]; - self.data = permute(reshape(data, sz), [1,2,3,5,4]); - end + self.stacks = arrayfun(@(ifile) ... + Tiff(self.files{ifile}), ... + 1:length(self.files), 'uni', false); end end diff --git a/lib/+ne7/+ui/BW.mat b/lib/+ne7/+ui/BW.mat new file mode 100644 index 0000000..95322b8 Binary files /dev/null and b/lib/+ne7/+ui/BW.mat differ diff --git a/lib/+ne7/+ui/csvlist.csv b/lib/+ne7/+ui/csvlist.csv new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/lib/+ne7/+ui/csvlist.csv @@ -0,0 +1 @@ +1 diff --git a/lib/+ne7/+ui/drawCells.m b/lib/+ne7/+ui/drawCells.m index ed68c01..ecdb9d1 100644 --- a/lib/+ne7/+ui/drawCells.m +++ b/lib/+ne7/+ui/drawCells.m @@ -43,6 +43,12 @@ case num2cell('1':'9') else removeOutlines end + case 91 + h=findobj(gcf,'type','image'); + set(h,'cdata',get(h,'cdata')*.9) + case 93 + h=findobj(gcf,'type','image'); + set(h,'cdata',get(h,'cdata')*1.1) case 27 yes = questdlg('Do you wish to abort segmenting this image?','Finish segmentation', 'yes','no','no'); if strcmpi('yes', yes) @@ -66,6 +72,8 @@ case num2cell('1':'9') disp 'Shift-click to delete pixels from mask' disp 'Press BACKSPACE to undo' disp 'Press 1-9 to set brush size' + disp '[ to reduce brightness' + disp '] to increase brightness' disp 'Press SPACE to toggle outlines' disp 'Press ESC to discard all edits' disp 'Press ENTER to commit' diff --git a/python/commons/bs.py b/python/commons/bs.py index 3cbce3d..f7bd041 100644 --- a/python/commons/bs.py +++ b/python/commons/bs.py @@ -2,3 +2,4 @@ schema = dj.schema('dimitri_brain_state', locals()) +schema.spawn_missing_classes() \ No newline at end of file diff --git a/python/commons/common.py b/python/commons/common.py index 80e589c..e77cbe6 100644 --- a/python/commons/common.py +++ b/python/commons/common.py @@ -3,3 +3,4 @@ schema = dj.schema('common', locals()) +schema.spawn_missing_classes() \ No newline at end of file diff --git a/python/commons/inj.py b/python/commons/inj.py new file mode 100644 index 0000000..32fb520 --- /dev/null +++ b/python/commons/inj.py @@ -0,0 +1,88 @@ +import datajoint as dj +from commons import virus, mice + +schema = dj.schema('common_injections', locals()) + + +@schema +class Site(dj.Lookup): + definition = """ + # Injection target site + + injection_site : char(8) # ID + --- + """ + + @property + def contents(self): + yield from zip(['V1', 'dLGN', 'AL', 'LM', 'S1','S2','M1', 'PM','_Test']) + + +@schema +class AtlasStereotacticTargets(dj.Lookup): + definition = """ + # Unadjusted stereotactic coordinates from the mouse brain atlas + + ->Site + target_id : char(20) # ID for this set of coordinates + --- + caudal : double # coordinate caudal from bregma in mm + lateral : double # lateral coordinate in mm + ventral : double # coordinate ventral from cortical surface in mm + lambda_bregma_basedist=4.21 : double # base distance between lambda and bregma from the stereotactic atlas in mm + """ + contents = [ + ('dLGN', 'Tang2016', 2.6, 2.15, 2.7, 4.21), + ('dLGN', 'fabee01', 2.3, 2.25, 2.5, 4.21), # dLGN + ('dLGN', 'fabee05', 2.4, 2.25, 2.6, 4.21), # dLGN10302015 + ('dLGN', 'fabee06', 2.5, 2.5, 2.7, 4.21), # dLGN12032015 + ('dLGN', 'fabee02', 2.3, 2.4, 2.7, 4.21), # dLGNDeeper + ('dLGN', 'fabee03', 2.3, 2.3, 2.6, 4.21), # dLGNmod + ('dLGN', 'fabee04', 2.3, 2.4, 2.6, 4.21), # dLGNMoreVentralLateral + ('_Test', 'lambda', 4.21, 0, 0, 4.21), # dLGNMoreVentralLateral + ('_Test', 'bregma', 0, 0, 0, 4.21), # dLGNMoreVentralLateral + ] + + +@schema +class GuidanceMethod(dj.Lookup): + definition = """ + # guidance method for injections + + guidance : char(20) + --- + """ + + @property + def contents(self): + yield from zip(['2P','stereotactic','intrinsic','other']) + +@schema +class VirusInjection(dj.Manual): + definition = """ + # Virus Injection + + -> mice.Mice + -> virus.Virus + -> Site + --- + -> GuidanceMethod + volume=null : double # injection volume in nl + speed=null : double # injection speed [nl/min] + toi=CURRENT_TIMESTAMP : timestamp # time of injection + """ + +@schema +class InjectionLocation(dj.Manual): + definition = """ + # Adjusted stereotactic coordinates for injection + + ->VirusInjection + ->AtlasStereotacticTargets + --- + lambda_bregma : double # distance between lambda and bregma in mm as measured + caudal : double # coordinate caudal from bregma in mm + lateral : double # lateral coordinate in mm + ventral : double # coordinate ventral from cortical surface in mm + adjustment : double # adjustement factor to convert atlas coordinates to this injection + """ diff --git a/python/commons/lab.py b/python/commons/lab.py new file mode 100644 index 0000000..9788c8b --- /dev/null +++ b/python/commons/lab.py @@ -0,0 +1,59 @@ +import sys +import os +import numpy as np + +import datajoint as dj + +schema = dj.schema('common_lab', locals()) + +@schema +class Paths(dj.Lookup): + definition = ... + + def get_local_path(self, path, local_os=None): + + # determine local os + if local_os is None: + local_os = sys.platform + local_os = local_os[:(min(3, len(local_os)))] + if local_os.lower() == 'glo': + local = 0 + home = '~' + + elif local_os.lower() == 'lin': + local = 1 + home = os.environ['HOME'] + + elif local_os.lower() == 'win': + local = 2 + home = os.environ['HOME'] + + elif local_os.lower() == 'dar': + local = 3 + home = '~' + + else: + raise NameError('unknown OS') + + path = path.replace(os.path.sep, '/') + path = path.replace('~', home) + + mapping = np.asarray(self.fetch['global', 'linux', 'windows', 'mac']) + size = mapping.shape + for i in range(size[1]): + for j in range(size[0]): + n = len(mapping[j, i]) + if j != local and path[:n] == mapping[j, i][:n]: + path = os.path.join(mapping[local, i], path[n+1:]) + break + + if os.path.sep == '\\' and local_os.lower() != 'glo': + path = path.replacec('/', '\\') + + else: + path = path.replace('\\', '/') + + return path + + + diff --git a/python/commons/mc.py b/python/commons/mc.py index 76d5647..d919ff7 100644 --- a/python/commons/mc.py +++ b/python/commons/mc.py @@ -2,3 +2,4 @@ schema = dj.schema('common_microcolumns', locals()) +schema.spawn_missing_classes() \ No newline at end of file diff --git a/python/commons/mice.py b/python/commons/mice.py index cc8eec6..9a749f6 100644 --- a/python/commons/mice.py +++ b/python/commons/mice.py @@ -2,3 +2,4 @@ schema = dj.schema('common_mice', locals()) +schema.spawn_missing_classes() \ No newline at end of file diff --git a/python/commons/mp.py b/python/commons/mp.py index d7998f9..db846e3 100644 --- a/python/commons/mp.py +++ b/python/commons/mp.py @@ -2,3 +2,4 @@ schema = dj.schema('common_multipatch', locals()) +schema.spawn_missing_classes() \ No newline at end of file diff --git a/python/commons/opt.py b/python/commons/opt.py index 447fb58..2a8e480 100644 --- a/python/commons/opt.py +++ b/python/commons/opt.py @@ -2,3 +2,4 @@ schema = dj.schema('common_optical', locals()) +schema.spawn_missing_classes() \ No newline at end of file diff --git a/python/commons/psy.py b/python/commons/psy.py index 641fd1a..335a9a1 100644 --- a/python/commons/psy.py +++ b/python/commons/psy.py @@ -2,3 +2,4 @@ schema = dj.schema('common_psy', locals()) +schema.spawn_missing_classes() \ No newline at end of file diff --git a/python/commons/pupil.py b/python/commons/pupil.py index 77d0963..2cde669 100644 --- a/python/commons/pupil.py +++ b/python/commons/pupil.py @@ -3,3 +3,4 @@ schema = dj.schema('dimitri_pupil', locals()) +schema.spawn_missing_classes() \ No newline at end of file diff --git a/python/commons/reso.py b/python/commons/reso.py index ab8acaa..fa427ad 100644 --- a/python/commons/reso.py +++ b/python/commons/reso.py @@ -1,3 +1,4 @@ import datajoint as dj schema = dj.schema('common_resonant', locals()) +schema.spawn_missing_classes() \ No newline at end of file diff --git a/python/commons/tp.py b/python/commons/tp.py index eaef47d..b58bb61 100644 --- a/python/commons/tp.py +++ b/python/commons/tp.py @@ -3,3 +3,4 @@ schema = dj.schema('common_two_photon', locals()) +schema.spawn_missing_classes() \ No newline at end of file diff --git a/python/commons/virus.py b/python/commons/virus.py index 8c6775d..32213ee 100644 --- a/python/commons/virus.py +++ b/python/commons/virus.py @@ -3,8 +3,6 @@ schema = dj.schema('common_virus', locals()) - - @schema class Gene(dj.Manual): definition = """ @@ -17,6 +15,7 @@ class Gene(dj.Manual): risk="no known risk" : varchar(512) # risk for humans """ + @schema class Construct(dj.Manual): definition = """ @@ -24,6 +23,8 @@ class Construct(dj.Manual): construct_id : char(80) """ + + @schema class ConstructGene(dj.Manual): definition = """ @@ -33,6 +34,7 @@ class ConstructGene(dj.Manual): gene_name : char(30) # name of the gene """ + @schema class Type(dj.Lookup): definition = """ @@ -43,7 +45,7 @@ class Type(dj.Lookup): """ - contents = [(t,) for t in ['AAV', 'Rabies', 'Lenti','Herpes']] + contents = [(t,) for t in ['AAV', 'Rabies', 'Lenti', 'Herpes']] @schema @@ -57,7 +59,7 @@ class Source(dj.Lookup): @property def contents(self): - yield from zip(['Penn', 'UNC', 'Homegrown', 'MIT']) + yield from zip(['Penn', 'UNC', 'Homegrown', 'MIT', 'AToliasLab']) @schema diff --git a/python/tests/__init__.py b/python/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/python/tests/test_lab.py b/python/tests/test_lab.py new file mode 100644 index 0000000..7c19475 --- /dev/null +++ b/python/tests/test_lab.py @@ -0,0 +1,28 @@ +from nose.tools import assert_raises, assert_equal, \ + assert_false, assert_true, assert_list_equal, \ + assert_tuple_equal, assert_dict_equal, raises + +import os +import random +from commons import lab +from pipeline import experiment + + +def test_paths(): + rel = experiment.Session() * experiment.Scan.EyeVideo() * experiment.Scan.BehaviorFile().proj( + hdf_file='filename') + + path_info = random.choice(rel.fetch.as_dict()) + + tmp = path_info['hdf_file'].split('.') + if '%d' in tmp[0]: + # new version + path_info['hdf_file'] = tmp[0][:-2] + '0.' + tmp[-1] + else: + path_info['hdf_file'] = tmp[0][:-1] + '0.' + tmp[-1] + + hdf_path = lab.Paths().get_local_path('{behavior_path}/{hdf_file}'.format(**path_info)) + avi_path = lab.Paths().get_local_path('{behavior_path}/{filename}'.format(**path_info)) + + assert_true(os.path.isfile(avi_path) and os.path.isfile(hdf_path)) + diff --git a/schemas/+common/.DS_Store b/schemas/+common/.DS_Store deleted file mode 100644 index 02c3f0c..0000000 Binary files a/schemas/+common/.DS_Store and /dev/null differ diff --git a/schemas/+inj/AtlasStereotacticTargets.m b/schemas/+inj/AtlasStereotacticTargets.m new file mode 100644 index 0000000..5163dcb --- /dev/null +++ b/schemas/+inj/AtlasStereotacticTargets.m @@ -0,0 +1,14 @@ +%{ +inj.AtlasStereotacticTargets (lookup) # Unadjusted stereotactic coordinates from the mouse brain atlas +->inj.Site +target_id : char(20) # ID for this set of coordinates +--- +caudal : double # coordinate caudal from bregma in mm +lateral : double # lateral coordinate in mm +ventral : double # coordinate ventral from cortical surface in mm +lambda_bregma_basedist=4.21 : double # base distance between lambda and bregma from the stereotactic atlas in mm +%} + + +classdef AtlasStereotacticTargets < dj.Relvar +end \ No newline at end of file diff --git a/schemas/+inj/GuidanceMethod.m b/schemas/+inj/GuidanceMethod.m new file mode 100644 index 0000000..f37d419 --- /dev/null +++ b/schemas/+inj/GuidanceMethod.m @@ -0,0 +1,10 @@ +%{ +inj.GuidanceMethod (lookup) # guidance method for injections + +guidance : char(20) +--- +%} + + +classdef GuidanceMethod < dj.Relvar +end \ No newline at end of file diff --git a/schemas/+inj/InjectionLocation.m b/schemas/+inj/InjectionLocation.m new file mode 100644 index 0000000..cc19af5 --- /dev/null +++ b/schemas/+inj/InjectionLocation.m @@ -0,0 +1,16 @@ +%{ +inj.InjectionLocation (manual) # Adjusted stereotactic coordinates for injection + +->inj.VirusInjection +->inj.AtlasStereotacticTargets +--- +lambda_bregma : double # distance between lambda and bregma in mm as measured +caudal : double # coordinate caudal from bregma in mm +lateral : double # lateral coordinate in mm +ventral : double # coordinate ventral from cortical surface in mm +adjustment : double # adjustement factor to convert atlas coordinates to this injection +%} + + +classdef InjectionLocation < dj.Relvar +end \ No newline at end of file diff --git a/schemas/+inj/Site.m b/schemas/+inj/Site.m new file mode 100644 index 0000000..b67b56a --- /dev/null +++ b/schemas/+inj/Site.m @@ -0,0 +1,9 @@ +%{ +inj.Site (lookup) # Injection target site +injection_site : char(8) # ID +--- +%} + + +classdef Site < dj.Relvar +end \ No newline at end of file diff --git a/schemas/+inj/VirusInjection.m b/schemas/+inj/VirusInjection.m new file mode 100644 index 0000000..9bd41db --- /dev/null +++ b/schemas/+inj/VirusInjection.m @@ -0,0 +1,16 @@ +%{ +inj.VirusInjection (manual) # Virus Injection + +-> mice.Mice +-> virus.Virus +-> inj.Site +--- +-> inj.GuidanceMethod +volume=null : double # injection volume in nl +speed=null : double # injection speed [nl/min] +toi=CURRENT_TIMESTAMP : timestamp # time of injection +%} + + +classdef VirusInjection < dj.Relvar +end \ No newline at end of file diff --git a/schemas/+inj/getSchema.m b/schemas/+inj/getSchema.m new file mode 100644 index 0000000..526a0e0 --- /dev/null +++ b/schemas/+inj/getSchema.m @@ -0,0 +1,7 @@ +function obj = getSchema +persistent schemaObject +if isempty(schemaObject) + schemaObject = dj.Schema(dj.conn, 'inj', 'common_injections'); +end +obj = schemaObject; +end diff --git a/schemas/+lab/Paths.m b/schemas/+lab/Paths.m new file mode 100644 index 0000000..8c60a76 --- /dev/null +++ b/schemas/+lab/Paths.m @@ -0,0 +1,13 @@ +%{ +lab.Paths (lookup) # Path translation +global : varchar(255) # global path name +--- +linux : varchar(255) # linux path name +windows : varchar(255) # windows path name +mac : varchar(255) # mac path name +location : varchar(255) # computer path +%} + + +classdef Paths < dj.Relvar +end \ No newline at end of file diff --git a/schemas/+lab/getSchema.m b/schemas/+lab/getSchema.m new file mode 100644 index 0000000..a0b8d8e --- /dev/null +++ b/schemas/+lab/getSchema.m @@ -0,0 +1,7 @@ +function obj = getSchema +persistent schemaObject +if isempty(schemaObject) + schemaObject = dj.Schema(dj.conn, 'lab', 'common_lab'); +end +obj = schemaObject; +end diff --git a/schemas/+mice/+GUIs/NewMice.m b/schemas/+mice/+GUIs/NewMice.m index 4ae2dcd..ee4fd2d 100644 --- a/schemas/+mice/+GUIs/NewMice.m +++ b/schemas/+mice/+GUIs/NewMice.m @@ -1,5 +1,5 @@ f = figure; -set(f, 'position',[0 0 1404 750]) +set(f, 'position',[0 0 1704 750]) uicontrol('style','text','string','Ear Tag #','position',[50 700 90 16],'fontunits','normalized','fontsize',.8); uicontrol('style','text','string','Alternate ID','position',[145 700 90 16],'fontunits','normalized','fontsize',.8); @@ -17,6 +17,12 @@ uicontrol('style','text','string','Genotype 2','position',[1219 630 135 16],'fontunits','normalized','fontsize',.8); uicontrol('style','text','string','Line 3','position',[1048 560 166 16],'fontunits','normalized','fontsize',.8); uicontrol('style','text','string','Genotype 3','position',[1219 560 135 16],'fontunits','normalized','fontsize',.8); +uicontrol('style','text','string','Line 4','position',[1359 700 166 16],'fontunits','normalized','fontsize',.8); +uicontrol('style','text','string','Genotype 4','position',[1530 700 135 16],'fontunits','normalized','fontsize',.8); +uicontrol('style','text','string','Line 5','position',[1359 630 166 16],'fontunits','normalized','fontsize',.8); +uicontrol('style','text','string','Genotype 5','position',[1530 630 135 16],'fontunits','normalized','fontsize',.8); +uicontrol('style','text','string','Line 6','position',[1359 560 166 16],'fontunits','normalized','fontsize',.8); +uicontrol('style','text','string','Genotype 6','position',[1530 560 135 16],'fontunits','normalized','fontsize',.8); uicontrol('style','text','string','Owner','position',[50 630 106 16],'fontunits','normalized','fontsize',.8); uicontrol('style','text','string','Facility','position',[161 630 106 16],'fontunits','normalized','fontsize',.8); uicontrol('style','text','string','Room','position',[272 630 106 16],'fontunits','normalized','fontsize',.8); @@ -66,12 +72,18 @@ h.line1 = uicontrol('style','popupmenu','string',s,'value',v,'position',[1048 660 166 35],'fontunits','normalized','fontsize',.4,'tag','line1Field'); h.line2 = uicontrol('style','popupmenu','string',s,'value',v,'position',[1048 590 166 35],'fontunits','normalized','fontsize',.4,'tag','line2Field'); h.line3 = uicontrol('style','popupmenu','string',s,'value',v,'position',[1048 520 166 35],'fontunits','normalized','fontsize',.4,'tag','line3Field'); +h.line4 = uicontrol('style','popupmenu','string',s,'value',v,'position',[1359 660 166 35],'fontunits','normalized','fontsize',.4,'tag','line4Field'); +h.line5 = uicontrol('style','popupmenu','string',s,'value',v,'position',[1359 590 166 35],'fontunits','normalized','fontsize',.4,'tag','line5Field'); +h.line6 = uicontrol('style','popupmenu','string',s,'value',v,'position',[1359 520 166 35],'fontunits','normalized','fontsize',.4,'tag','line6Field'); s = getEnumValues(mice.Genotypes.table,'genotype'); v = find(strcmp('unknown',s)); h.genotype1 = uicontrol('style','popupmenu','string',s,'value',v,'position',[1219 660 135 35],'fontunits','normalized','fontsize',.4,'tag','genotype1Field'); h.genotype2 = uicontrol('style','popupmenu','string',s,'value',v,'position',[1219 590 135 35],'fontunits','normalized','fontsize',.4,'tag','genotype2Field'); h.genotype3 = uicontrol('style','popupmenu','string',s,'value',v,'position',[1219 520 135 35],'fontunits','normalized','fontsize',.4,'tag','genotype3Field'); +h.genotype4 = uicontrol('style','popupmenu','string',s,'value',v,'position',[1530 660 135 35],'fontunits','normalized','fontsize',.4,'tag','genotype4Field'); +h.genotype5 = uicontrol('style','popupmenu','string',s,'value',v,'position',[1530 590 135 35],'fontunits','normalized','fontsize',.4,'tag','genotype5Field'); +h.genotype6 = uicontrol('style','popupmenu','string',s,'value',v,'position',[1530 520 135 35],'fontunits','normalized','fontsize',.4,'tag','genotype6Field'); last = fetch(mice.Mice); number = size(last,1); @@ -82,14 +94,14 @@ h.autopopulate = uicontrol('style','checkbox','string','Autopopulate','position',[140 550 150 35],'fontunits','normalized','fontsize',.4,'tag','autoBox'); h.clear = uicontrol('style','pushbutton','string','Clear','position',[50 550 90 35],'fontunits','normalized','fontsize',.4,'Callback',@mice.GUIs.clearEntry); -cnames = {'ID','Alt ID','DOB','DOW','Father','Mother1','Mother2','Sex','Color','Ear Punch','Line1','Genotype1','Line2','Genotype2','Line3','Genotype3','Owner','Facility','Room','Rack','Row','Notes'}; -cformat = {'char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char'}; -cwidth = {40,40,'auto','auto',40,50,50,40,40,60,'auto','auto','auto','auto','auto','auto','auto',50,40,40,40,'auto'}; -h.new_mice = uitable('position',[50 60 1304 450],'RowName',' ','ColumnName',cnames,'ColumnFormat',cformat,'columnwidth',cwidth,'tag','miceTable','CellSelectionCallback',@mice.GUIs.selectRow); +cnames = {'ID','Alt ID','DOB','DOW','Father','Mother1','Mother2','Sex','Color','Ear Punch','Line1','Genotype1','Line2','Genotype2','Line3','Genotype3','Line4','Genotype4','Line5','Genotype5','Line6','Genotype6','Owner','Facility','Room','Rack','Row','Notes'}; +cformat = {'char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char'}; +cwidth = {40,40,'auto','auto',40,50,50,40,40,60,'auto','auto','auto','auto','auto','auto','auto','auto','auto','auto','auto','auto','auto',50,40,40,40,'auto'}; +h.new_mice = uitable('position',[50 60 1604 450],'RowName',' ','ColumnName',cnames,'ColumnFormat',cformat,'columnwidth',cwidth,'tag','miceTable','CellSelectionCallback',@mice.GUIs.selectRow); h.add = uicontrol('style','pushbutton','string','+','position',[50 510 25 25],'fontunits','normalized','fontsize',.8,'backgroundcolor','g','Callback',@mice.GUIs.plusCallback); h.delete = uicontrol('style','pushbutton','string','-','position',[75 510 25 25],'fontunits','normalized','fontsize',.8,'backgroundcolor','r','Callback',@mice.GUIs.minusCallback); -h.submit = uicontrol('style','pushbutton','string','Submit New Mice to Database','position',[524 10 256 50],'fontunits','normalized','fontsize',.35,'Callback',@mice.GUIs.submitMice,'tag','submitMiceButton'); +h.submit = uicontrol('style','pushbutton','string','Submit New Mice to Database','position',[674 10 256 50],'fontunits','normalized','fontsize',.35,'Callback',@mice.GUIs.submitMice,'tag','submitMiceButton'); diff --git a/schemas/+mice/+GUIs/UpdateMouseInfo.m b/schemas/+mice/+GUIs/UpdateMouseInfo.m index 30e208a..15be242 100644 --- a/schemas/+mice/+GUIs/UpdateMouseInfo.m +++ b/schemas/+mice/+GUIs/UpdateMouseInfo.m @@ -1,5 +1,5 @@ f = figure; -set(f, 'position',[0 0 1500 500]); +set(f, 'position',[0 0 2000 500]); uicontrol('style','text','string','Enter Mouse IDs:','position',[50 430 110 29],'fontunits','normalized','fontsize',.4,'HorizontalAlignment','Right'); uicontrol('style','text','string','Or Enter Range:','position',[50 400 110 29],'fontunits','normalized','fontsize',.4,'HorizontalAlignment','Right'); @@ -22,13 +22,13 @@ h.range_end = uicontrol('style','edit','position',[220 400 50 30],'fontunits','normalized','fontsize',.4,'tag','rangeEnd'); h.find = uicontrol('style','pushbutton','position',[50 370 110 29],'fontunits','normalized','fontsize',.4,'string','Find Mice','HorizontalAlignment','Center','Callback',@mice.GUIs.findUpdateMice); -cnames = {'ID','DOB','DOW','Sex','Color','Ear Punch','Line 1','Genotype 1','Line 2','Genotype 2','Line 3','Genotype 3','Notes'}; +cnames = {'ID','DOB','DOW','Sex','Color','Ear Punch','Line 1','Genotype 1','Line 2','Genotype 2','Line 3','Genotype 3','Line 4','Genotype 4','Line 5','Genotype 5','Line 6','Genotype 6','Notes'}; genotypes = getEnumValues(mice.Genotypes.table,'genotype'); sexes = getEnumValues(mice.Mice.table,'sex'); colors = getEnumValues(mice.Mice.table,'color'); ears = getEnumValues(mice.Mice.table,'ear_punch'); cformat = {'char','char','char',sexes,colors,ears,'char',genotypes,'char',genotypes,'char',genotypes,'char'}; -cwidth = {50, 75, 75, 100, 100, 100,100,125,100,125,100,125,190}; -h.table = uitable('position',[50 60 1400 310],'RowName',' ','ColumnName',cnames,'tag','miceTable','CellSelectionCallback',@mice.GUIs.selectRow,'ColumnFormat',cformat,'ColumnEditable',[false true true true true true false true false true false true true],'ColumnWidth',cwidth); +cwidth = {50, 75, 75, 100, 100, 100,100,125,100,125,100,125,100,125,100,125,100,125,190}; +h.table = uitable('position',[50 60 1900 310],'RowName',' ','ColumnName',cnames,'tag','miceTable','CellSelectionCallback',@mice.GUIs.selectRow,'ColumnFormat',cformat,'ColumnEditable',[false true true true true true false true false true false true false true false true false true true],'ColumnWidth',cwidth); -h.submitUpdateMice = uicontrol('style','pushbutton','string','Update Mouse Info','position',[650 10 200 50],'fontunits','normalized','fontsize',.35,'Callback',@mice.GUIs.submitUpdateMice); \ No newline at end of file +h.submitUpdateMice = uicontrol('style','pushbutton','string','Update Mouse Info','position',[900 10 200 50],'fontunits','normalized','fontsize',.35,'Callback',@mice.GUIs.submitUpdateMice); \ No newline at end of file diff --git a/schemas/+mice/+GUIs/UsedMice.m b/schemas/+mice/+GUIs/UsedMice.m index 2a3f6ca..d1af956 100644 --- a/schemas/+mice/+GUIs/UsedMice.m +++ b/schemas/+mice/+GUIs/UsedMice.m @@ -1,5 +1,5 @@ f = figure; -set(f, 'position',[0 0 900 600]); +set(f, 'position',[0 0 1300 600]); uicontrol('style','text','string','Enter Mouse IDs:','position',[50 530 110 29],'fontunits','normalized','fontsize',.4,'HorizontalAlignment','Right'); uicontrol('style','text','string','Or Enter Range:','position',[50 500 110 29],'fontunits','normalized','fontsize',.4,'HorizontalAlignment','Right'); @@ -24,11 +24,11 @@ h.range_end = uicontrol('style','edit','position',[220 500 50 30],'fontunits','normalized','fontsize',.4,'tag','rangeEnd'); h.find = uicontrol('style','pushbutton','position',[50 470 110 29],'fontunits','normalized','fontsize',.4,'string','Find Mice','HorizontalAlignment','Center','Callback',@mice.GUIs.findMice); -cnames = {'ID','Line 1','Genotype 1','Line 2','Genotype 2','Line 3','Genotype 3'}; -cwidth = {75,100,125,100,125,100,125}; -h.table = uitable('position',[50 160 800 310],'RowName',' ','ColumnName',cnames,'tag','miceTable','CellSelectionCallback',@mice.GUIs.selectRow,'ColumnWidth',cwidth); +cnames = {'ID','Line 1','Genotype 1','Line 2','Genotype 2','Line 3','Genotype 3','Line 4','Genotype 4','Line 5','Genotype 5','Line 6','Genotype 6'}; +cwidth = {75,100,125,100,125,100,125,100,125,100,125,100,125}; +h.table = uitable('position',[50 160 1200 310],'RowName',' ','ColumnName',cnames,'tag','miceTable','CellSelectionCallback',@mice.GUIs.selectRow,'ColumnWidth',cwidth); h.dod = uicontrol('style','edit','position',[150 118 100 30],'fontunits','normalized','fontsize',.4,'HorizontalAlignment','Center','tag','dod'); h.death_notes = uicontrol('style','edit','position',[375 88 475 60],'fontunits','normalized','fontsize',.25,'HorizontalAlignment','Center','tag','deathNotes'); -h.submitDeath = uicontrol('style','pushbutton','string','Submit DOD','position',[350 10 200 50],'fontunits','normalized','fontsize',.3,'Callback',@mice.GUIs.submitDeath,'tag','submitDeathButton'); \ No newline at end of file +h.submitDeath = uicontrol('style','pushbutton','string','Submit DOD','position',[550 10 200 50],'fontunits','normalized','fontsize',.3,'Callback',@mice.GUIs.submitDeath,'tag','submitDeathButton'); \ No newline at end of file diff --git a/schemas/+mice/+GUIs/ViewMice.m b/schemas/+mice/+GUIs/ViewMice.m index df817a3..ce98b8f 100644 --- a/schemas/+mice/+GUIs/ViewMice.m +++ b/schemas/+mice/+GUIs/ViewMice.m @@ -15,6 +15,12 @@ uicontrol('style','text','string','Genotype 2','position',[934 630 135 16],'fontunits','normalized','fontsize',.8); uicontrol('style','text','string','Line 3','position',[763 560 166 16],'fontunits','normalized','fontsize',.8); uicontrol('style','text','string','Genotype 3','position',[934 560 135 16],'fontunits','normalized','fontsize',.8); +uicontrol('style','text','string','Line 4','position',[1074 700 166 16],'fontunits','normalized','fontsize',.8); +uicontrol('style','text','string','Genotype 4','position',[1245 700 135 16],'fontunits','normalized','fontsize',.8); +uicontrol('style','text','string','Line 5','position',[1074 630 166 16],'fontunits','normalized','fontsize',.8); +uicontrol('style','text','string','Genotype 5','position',[1245 630 135 16],'fontunits','normalized','fontsize',.8); +uicontrol('style','text','string','Line 6','position',[1074 560 166 16],'fontunits','normalized','fontsize',.8); +uicontrol('style','text','string','Genotype 6','position',[1245 560 135 16],'fontunits','normalized','fontsize',.8); uicontrol('style','text','string','Owner','position',[50 630 106 16],'fontunits','normalized','fontsize',.8); uicontrol('style','text','string','Facility','position',[161 630 106 16],'fontunits','normalized','fontsize',.8); uicontrol('style','text','string','Room','position',[272 630 106 16],'fontunits','normalized','fontsize',.8); @@ -61,6 +67,9 @@ h.line1 = uicontrol('style','popupmenu','string',s,'value',v,'position',[763 660 166 35],'fontunits','normalized','fontsize',.4,'tag','line1Field'); h.line2 = uicontrol('style','popupmenu','string',s,'value',v,'position',[763 590 166 35],'fontunits','normalized','fontsize',.4,'tag','line2Field'); h.line3 = uicontrol('style','popupmenu','string',s,'value',v,'position',[763 520 166 35],'fontunits','normalized','fontsize',.4,'tag','line3Field'); +h.line4 = uicontrol('style','popupmenu','string',s,'value',v,'position',[1074 660 166 35],'fontunits','normalized','fontsize',.4,'tag','line4Field'); +h.line5 = uicontrol('style','popupmenu','string',s,'value',v,'position',[1074 590 166 35],'fontunits','normalized','fontsize',.4,'tag','line5Field'); +h.line6 = uicontrol('style','popupmenu','string',s,'value',v,'position',[1074 520 166 35],'fontunits','normalized','fontsize',.4,'tag','line6Field'); s = getEnumValues(mice.Genotypes.table,'genotype'); s = {'' s{:}}; @@ -68,13 +77,16 @@ h.genotype1 = uicontrol('style','popupmenu','string',s,'value',v,'position',[934 660 135 35],'fontunits','normalized','fontsize',.4,'tag','genotype1Field'); h.genotype2 = uicontrol('style','popupmenu','string',s,'value',v,'position',[934 590 135 35],'fontunits','normalized','fontsize',.4,'tag','genotype2Field'); h.genotype3 = uicontrol('style','popupmenu','string',s,'value',v,'position',[934 520 135 35],'fontunits','normalized','fontsize',.4,'tag','genotype3Field'); +h.genotype4 = uicontrol('style','popupmenu','string',s,'value',v,'position',[1245 660 135 35],'fontunits','normalized','fontsize',.4,'tag','genotype4Field'); +h.genotype5 = uicontrol('style','popupmenu','string',s,'value',v,'position',[1245 590 135 35],'fontunits','normalized','fontsize',.4,'tag','genotype5Field'); +h.genotype6 = uicontrol('style','popupmenu','string',s,'value',v,'position',[1245 520 135 35],'fontunits','normalized','fontsize',.4,'tag','genotype6Field'); h.used = uicontrol('style','checkbox','string','Include Used/Euthanized Mice','position',[140 550 250 35],'fontunits','normalized','fontsize',.4,'tag','usedBox'); h.clear = uicontrol('style','pushbutton','string','Clear','position',[50 550 90 35],'fontunits','normalized','fontsize',.4,'Callback',@mice.GUIs.clearEntry); -cnames = {'ID','AltID','DOB','DOW','Parent1','Parent2','Parent3','Sex','Color','EarPunch','Line1','Genotype1','Line2','Genotype2','Line3','Genotype3','Owner','Facility','Room','Rack','Row','Notes'}; -cformat = {'char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char'}; -cwidth = {40,40,'auto','auto',50,50,50,40,40,60,'auto','auto','auto','auto','auto','auto','auto',50,40,40,40,'auto'}; +cnames = {'ID','AltID','DOB','DOW','Parent1','Parent2','Parent3','Sex','Color','EarPunch','Line1','Genotype1','Line2','Genotype2','Line3','Genotype3','Line4','Genotype4','Line5','Genotype5','Line6','Genotype6','Owner','Facility','Room','Rack','Row','Notes'}; +cformat = {'char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char','char'}; +cwidth = {40,40,'auto','auto',50,50,50,40,40,60,'auto','auto','auto','auto','auto','auto','auto','auto','auto','auto','auto','auto','auto',50,40,40,40,'auto'}; h.new_mice = uitable('position',[50 60 1304 450],'RowName',' ','ColumnName',cnames,'ColumnFormat',cformat,'columnwidth',cwidth,'tag','miceTable','CellSelectionCallback',@mice.GUIs.selectRow); h.find = uicontrol('style','pushbutton','position',[50 510 110 29],'fontunits','normalized','fontsize',.4,'string','Find Mice','HorizontalAlignment','Center','Callback',@mice.GUIs.findViewMice); diff --git a/schemas/+mice/+GUIs/clearEntry.m b/schemas/+mice/+GUIs/clearEntry.m index f7e6acb..9281183 100644 --- a/schemas/+mice/+GUIs/clearEntry.m +++ b/schemas/+mice/+GUIs/clearEntry.m @@ -29,9 +29,15 @@ function clearEntry(src,~) set(h.line1,'Value',1); set(h.line2,'Value',1); set(h.line3,'Value',1); + set(h.line4,'Value',1); + set(h.line5,'Value',1); + set(h.line6,'Value',1); set(h.genotype1,'Value',1); set(h.genotype2,'Value',1); set(h.genotype3,'Value',1); + set(h.genotype4,'Value',1); + set(h.genotype5,'Value',1); + set(h.genotype6,'Value',1); set(h.range_start,'String',''); set(h.range_end,'String',''); return @@ -46,8 +52,14 @@ function clearEntry(src,~) set(h.line1,'Value',1); set(h.line2,'Value',1); set(h.line3,'Value',1); +set(h.line4,'Value',1); +set(h.line5,'Value',1); +set(h.line6,'Value',1); set(h.genotype1,'Value',7); set(h.genotype2,'Value',7); set(h.genotype3,'Value',7); +set(h.genotype4,'Value',7); +set(h.genotype5,'Value',7); +set(h.genotype6,'Value',7); end diff --git a/schemas/+mice/+GUIs/findUpdateMice.m b/schemas/+mice/+GUIs/findUpdateMice.m index 2ef7b89..ce66562 100644 --- a/schemas/+mice/+GUIs/findUpdateMice.m +++ b/schemas/+mice/+GUIs/findUpdateMice.m @@ -110,7 +110,7 @@ function findUpdateMice(src,~) mouseTable{i,2*j+5} = genotypes(j).line; mouseTable{i,(2*j+6)} = genotypes(j).genotype; end - mouseTable{i,13} = mouse.mouse_notes; + mouseTable{i,19} = mouse.mouse_notes; end set(h.table,'data',mouseTable); end diff --git a/schemas/+mice/+GUIs/findViewMice.m b/schemas/+mice/+GUIs/findViewMice.m index 185b111..fb7745b 100644 --- a/schemas/+mice/+GUIs/findViewMice.m +++ b/schemas/+mice/+GUIs/findViewMice.m @@ -24,6 +24,9 @@ function findViewMice(src,~) h.line1 = findobj(figHand,'tag','line1Field'); h.line2 = findobj(figHand,'tag','line2Field'); h.line3 = findobj(figHand,'tag','line3Field'); +h.line4 = findobj(figHand,'tag','line4Field'); +h.line5 = findobj(figHand,'tag','line5Field'); +h.line6 = findobj(figHand,'tag','line6Field'); h.used = findobj(figHand,'tag','usedBox'); m.parent1 = get(h.parent1,'string'); @@ -39,6 +42,15 @@ function findViewMice(src,~) v = get(h.line3,'value'); s = get(h.line3,'string'); m.line3 = s{v}; +v = get(h.line4,'value'); +s = get(h.line4,'string'); +m.line4 = s{v}; +v = get(h.line5,'value'); +s = get(h.line5,'string'); +m.line5 = s{v}; +v = get(h.line6,'value'); +s = get(h.line6,'string'); +m.line6 = s{v}; v = get(h.genotype1,'value'); s = get(h.genotype1,'string'); m.genotype1 = s{v}; @@ -48,6 +60,15 @@ function findViewMice(src,~) v = get(h.genotype3,'value'); s = get(h.genotype3,'string'); m.genotype3 = s{v}; +v = get(h.genotype4,'value'); +s = get(h.genotype4,'string'); +m.genotype4 = s{v}; +v = get(h.genotype5,'value'); +s = get(h.genotype5,'string'); +m.genotype5 = s{v}; +v = get(h.genotype6,'value'); +s = get(h.genotype6,'string'); +m.genotype6 = s{v}; m.mouse_notes = get(h.mouse_notes,'string'); m.used = get(h.used,'Value'); @@ -94,33 +115,13 @@ function findViewMice(src,~) b3 = {}; if ~isempty(m.parent1) - a1 = fetch(mice.Parents & ['parent_id="' m.parent1 '"']); - try parent1 = fetch(mice.Mice & ['animal_id=' m.parent1 ''],'*'); - end - if isempty(parent1) - try parent1 = fetch(mice.Mice & ['other_id="' m.parent1 '"'],'*'); - end - end - try a2 = fetch(mice.Parents & ['parent_id="' num2str(parent1.animal_id) '"']); - end - try a3 = fetch(mice.Parents & ['parent_id="' parent1.other_id '"']); - end - a = fetch(mice.Parents & ((mice.Parents & a1) | (mice.Parents & a2) | (mice.Parents & a3))); + a1 = fetch(mice.Mice & ['animal_id=' num2str(m.parent1) ' or other_id=' num2str(m.parent1)]); + a = fetch(mice.Parents & ['parent_id=' num2str(a1.animal_id)]); end if ~isempty(m.parent2) - b1 = fetch(mice.Parents & ['parent_id="' m.parent2 '"']); - try parent2 = fetch(mice.Mice & ['animal_id=' m.parent2 ''],'*'); - end - if isempty(parent2) - try parent2 = fetch(mice.Mice & ['other_id="' m.parent2 '"'],'*'); - end - end - try b2 = fetch(mice.Parents & ['parent_id="' num2str(parent2.animal_id) '"']); - end - try b3 = fetch(mice.Parents & ['parent_id="' parent2.other_id '"']); - end - b = fetch(mice.Parents & ((mice.Parents & b1) | (mice.Parents & b2) | (mice.Parents & b3))); + b1 = fetch(mice.Mice & ['animal_id=' num2str(m.parent2) ' or other_id=' num2str(m.parent2)]); + b = fetch(mice.Parents & ['parent_id=' num2str(b1.animal_id)]); end offspringCount = 0; @@ -386,6 +387,21 @@ function findViewMice(src,~) errorString{errorCount} = 'Please select line 3 or remove genotype 3 restriction.'; end +if ~isempty(m.genotype4) && isempty(m.line4) + errorCount = errorCount + 1; + errorString{errorCount} = 'Please select line 4 or remove genotype 4 restriction.'; +end + +if ~isempty(m.genotype5) && isempty(m.line5) + errorCount = errorCount + 1; + errorString{errorCount} = 'Please select line 5 or remove genotype 5 restriction.'; +end + +if ~isempty(m.genotype6) && isempty(m.line6) + errorCount = errorCount + 1; + errorString{errorCount} = 'Please select line 6 or remove genotype 6 restriction.'; +end + % restrict by specified genotype mouseCount=0; @@ -511,6 +527,129 @@ function findViewMice(src,~) end end +mouseCount=0; +newmouseID = {}; +if ~isempty(m.line4) + if ~isempty(mouseID) + for i = 1:length(mouseID) + a = fetch(mice.Genotypes & ['animal_id=' num2str(mouseID{i})],'*'); + for j = 1:size(a,1) + if strcmp(a(j).line,m.line4) + if ~isempty(m.genotype4) + if strcmp(a(j).genotype,m.genotype4) + mouseCount = mouseCount + 1; + newmouseID{mouseCount} = mouseID{i}; + end + else + mouseCount = mouseCount + 1; + newmouseID{mouseCount} = mouseID{i}; + end + end + end + end + elseif ~isempty(m.genotype4) + a = fetch(mice.Genotypes & ['line="' m.line4 '"'] & ['genotype="' m.genotype4 '"']); + for i = 1:size(a,1) + mouseCount = mouseCount + 1; + newmouseID{mouseCount} = a(i).animal_id; + end + else + a = fetch(mice.Genotypes & ['line="' m.line4 '"']); + for i = 1:size(a,1) + mouseCount = mouseCount + 1; + newmouseID{mouseCount} = a(i).animal_id; + end + end + try mouseID = newmouseID; + if isempty(mouseID) + errorCount = errorCount + 1; + errorString{errorCount} = 'There are no mice matching these search criteria.'; + end + end +end + +mouseCount=0; +newmouseID = {}; +if ~isempty(m.line5) + if ~isempty(mouseID) + for i = 1:length(mouseID) + a = fetch(mice.Genotypes & ['animal_id=' num2str(mouseID{i})],'*'); + for j = 1:size(a,1) + if strcmp(a(j).line,m.line5) + if ~isempty(m.genotype5) + if strcmp(a(j).genotype,m.genotype5) + mouseCount = mouseCount + 1; + newmouseID{mouseCount} = mouseID{i}; + end + else + mouseCount = mouseCount + 1; + newmouseID{mouseCount} = mouseID{i}; + end + end + end + end + elseif ~isempty(m.genotype5) + a = fetch(mice.Genotypes & ['line="' m.line5 '"'] & ['genotype="' m.genotype5 '"']); + for i = 1:size(a,1) + mouseCount = mouseCount + 1; + newmouseID{mouseCount} = a(i).animal_id; + end + else + a = fetch(mice.Genotypes & ['line="' m.line5 '"']); + for i = 1:size(a,1) + mouseCount = mouseCount + 1; + newmouseID{mouseCount} = a(i).animal_id; + end + end + try mouseID = newmouseID; + if isempty(mouseID) + errorCount = errorCount + 1; + errorString{errorCount} = 'There are no mice matching these search criteria.'; + end + end +end + +mouseCount=0; +newmouseID = {}; +if ~isempty(m.line6) + if ~isempty(mouseID) + for i = 1:length(mouseID) + a = fetch(mice.Genotypes & ['animal_id=' num2str(mouseID{i})],'*'); + for j = 1:size(a,1) + if strcmp(a(j).line,m.line6) + if ~isempty(m.genotype6) + if strcmp(a(j).genotype,m.genotype6) + mouseCount = mouseCount + 1; + newmouseID{mouseCount} = mouseID{i}; + end + else + mouseCount = mouseCount + 1; + newmouseID{mouseCount} = mouseID{i}; + end + end + end + end + elseif ~isempty(m.genotype6) + a = fetch(mice.Genotypes & ['line="' m.line6 '"'] & ['genotype="' m.genotype6 '"']); + for i = 1:size(a,1) + mouseCount = mouseCount + 1; + newmouseID{mouseCount} = a(i).animal_id; + end + else + a = fetch(mice.Genotypes & ['line="' m.line6 '"']); + for i = 1:size(a,1) + mouseCount = mouseCount + 1; + newmouseID{mouseCount} = a(i).animal_id; + end + end + try mouseID = newmouseID; + if isempty(mouseID) + errorCount = errorCount + 1; + errorString{errorCount} = 'There are no mice matching these search criteria.'; + end + end +end + % restrict to living mice unless "include used mice" box is checked mouseCount=0; @@ -553,12 +692,12 @@ function findViewMice(src,~) mouseTable{i,8} = mouse.sex; mouseTable{i,9} = mouse.color; mouseTable{i,10} = mouse.ear_punch; - mouseTable{i,17} = mouse.owner; - mouseTable{i,18} = mouse.facility; - mouseTable{i,19} = mouse.room; - mouseTable{i,20} = mouse.rack; - mouseTable{i,21} = mouse.row; - mouseTable{i,22} = mouse.mouse_notes; + mouseTable{i,23} = mouse.owner; + mouseTable{i,24} = mouse.facility; + mouseTable{i,25} = mouse.room; + mouseTable{i,26} = mouse.rack; + mouseTable{i,27} = mouse.row; + mouseTable{i,28} = mouse.mouse_notes; genotypes = fetch(mice.Genotypes & ['animal_id=' num2str(mouseID{i})],'*'); for j = 1:size(genotypes,1) mouseTable{i,(2*j+9)} = genotypes(j).line; diff --git a/schemas/+mice/+GUIs/getUIData.m b/schemas/+mice/+GUIs/getUIData.m index b3292f7..8fb60f4 100644 --- a/schemas/+mice/+GUIs/getUIData.m +++ b/schemas/+mice/+GUIs/getUIData.m @@ -21,9 +21,15 @@ h.line1 = findobj(FigHand,'tag','line1Field'); h.line2 = findobj(FigHand,'tag','line2Field'); h.line3 = findobj(FigHand,'tag','line3Field'); +h.line4 = findobj(FigHand,'tag','line4Field'); +h.line5 = findobj(FigHand,'tag','line5Field'); +h.line6 = findobj(FigHand,'tag','line6Field'); h.genotype1 = findobj(FigHand,'tag','genotype1Field'); h.genotype2 = findobj(FigHand,'tag','genotype2Field'); h.genotype3 = findobj(FigHand,'tag','genotype3Field'); +h.genotype4 = findobj(FigHand,'tag','genotype4Field'); +h.genotype5 = findobj(FigHand,'tag','genotype5Field'); +h.genotype6 = findobj(FigHand,'tag','genotype6Field'); h.new_mice = findobj(FigHand,'tag','miceTable'); h.doa = findobj(FigHand,'tag','doaField'); h.source = findobj(FigHand,'tag','sourceField'); @@ -77,6 +83,15 @@ v = get(h.line3,'value'); s = get(h.line3,'string'); m.line3 = s{v}; + v = get(h.line4,'value'); + s = get(h.line4,'string'); + m.line4 = s{v}; + v = get(h.line5,'value'); + s = get(h.line5,'string'); + m.line5 = s{v}; + v = get(h.line6,'value'); + s = get(h.line6,'string'); + m.line6 = s{v}; v = get(h.genotype1,'value'); s = get(h.genotype1,'string'); m.genotype1 = s{v}; @@ -86,6 +101,15 @@ v = get(h.genotype3,'value'); s = get(h.genotype3,'string'); m.genotype3 = s{v}; + v = get(h.genotype4,'value'); + s = get(h.genotype4,'string'); + m.genotype4 = s{v}; + v = get(h.genotype5,'value'); + s = get(h.genotype5,'string'); + m.genotype5 = s{v}; + v = get(h.genotype6,'value'); + s = get(h.genotype6,'string'); + m.genotype6 = s{v}; m.mouse_notes = get(h.mouse_notes,'string'); end diff --git a/schemas/+mice/+GUIs/plusCallback.m b/schemas/+mice/+GUIs/plusCallback.m index ad6b147..673408e 100644 --- a/schemas/+mice/+GUIs/plusCallback.m +++ b/schemas/+mice/+GUIs/plusCallback.m @@ -157,44 +157,74 @@ function plusCallback(src,~) end end -% If any line is C57Bl/6 or Fvb then it must be the only line and the +% If any line is C57Bl/6, Fvb, or CD1 then it must be the only line and the % genotype must be wild type -if (strcmp(m.line1,'C57Bl/6') || strcmp(m.line1,'Fvb')) && ~strcmp(m.genotype1, 'wild type') +if (strcmp(m.line1,'C57Bl/6') || strcmp(m.line1,'Fvb') || strcmp(m.line1,'CD1') || strcmp(m.line1,'Crl-CD1')) && ~strcmp(m.genotype1, 'wild type') errorCount = errorCount + 1; - errorString{errorCount} = 'Lines C57Bl/6 and Fvb should only be used to designate pure wild type mice.'; + errorString{errorCount} = 'Lines C57Bl/6, Fvb, and CD1 should only be used to designate pure wild type mice.'; end -if (strcmp(m.line1, 'C57Bl/6') || strcmp(m.line1,'Fvb')) && (~isempty(m.line2) || ~isempty(m.line3)) +if (strcmp(m.line1, 'C57Bl/6') || strcmp(m.line1,'Fvb') || strcmp(m.line1,'CD1')|| strcmp(m.line1,'Crl-CD1')) && (~isempty(m.line2) || ~isempty(m.line3)) errorCount = errorCount + 1; - errorString{errorCount} = 'Lines C57Bl/6 and Fvb should only be used to designate pure wild type mice.'; + errorString{errorCount} = 'Lines C57Bl/6, Fvb, and CD1 should only be used to designate pure wild type mice.'; end -if (strcmp(m.line2, 'C57Bl/6') || strcmp(m.line2,'Fvb')) && (~isempty(m.line1) || ~isempty(m.line3)) +if (strcmp(m.line2, 'C57Bl/6') || strcmp(m.line2,'Fvb') || strcmp(m.line2,'CD1')|| strcmp(m.line2,'Crl-CD1')) && (~isempty(m.line1) || ~isempty(m.line3)) errorCount = errorCount + 1; - errorString{errorCount} = 'Lines C57Bl/6 and Fvb should only be used to designate pure wild type mice.'; + errorString{errorCount} = 'Lines C57Bl/6, Fvb, and CD1 should only be used to designate pure wild type mice.'; end -if (strcmp(m.line3, 'C57Bl/6') || strcmp(m.line3,'Fvb')) && (~isempty(m.line1) || ~isempty(m.line2)) +if (strcmp(m.line3, 'C57Bl/6') || strcmp(m.line3,'Fvb') || strcmp(m.line3,'CD1')|| strcmp(m.line3,'Crl-CD1')) && (~isempty(m.line1) || ~isempty(m.line2)) errorCount = errorCount + 1; - errorString{errorCount} = 'Lines C57Bl/6 and Fvb should only be used to designate pure wild type mice.'; + errorString{errorCount} = 'Lines C57Bl/6, Fvb, and CD1 should only be used to designate pure wild type mice.'; +end + +if strcmp(m.line4, 'C57Bl/6') || strcmp(m.line4,'Fvb') || strcmp(m.line4, 'CD1') || strcmp(m.line4,'Crl-CD1') + errorCount = errorCount + 1; + errorString{errorCount} = 'Lines C57Bl/6, Fvb, and CD1 should only be used to designate pure wild type mice.'; +end + +if strcmp(m.line5, 'C57Bl/6') || strcmp(m.line5,'Fvb') || strcmp(m.line5, 'CD1') || strcmp(m.line5,'Crl-CD1') + errorCount = errorCount + 1; + errorString{errorCount} = 'Lines C57Bl/6, Fvb, and CD1 should only be used to designate pure wild type mice.'; +end + +if strcmp(m.line6, 'C57Bl/6') || strcmp(m.line6,'Fvb') || strcmp(m.line6, 'CD1') || strcmp(m.line6,'Crl-CD1') + errorCount = errorCount + 1; + errorString{errorCount} = 'Lines C57Bl/6, Fvb, and CD1 should only be used to designate pure wild type mice.'; end % wild type genotype can only be used for C57Bl/6 or Fvb lines. -if strcmp(m.genotype1,'wild type') && ~strcmp(m.line1,'C57Bl/6') && ~strcmp(m.line1,'Fvb') +if strcmp(m.genotype1,'wild type') && ~strcmp(m.line1,'C57Bl/6') && ~strcmp(m.line1,'Fvb') && ~strcmp(m.line1,'CD1') && ~strcmp(m.line1,'Crl-CD1') + errorCount = errorCount + 1; + errorString{errorCount} = 'The wild type genotype should only be used to describe pure C57Bl/6, Fvb, or CD1 lines.'; +end + +if strcmp(m.genotype2,'wild type') && ~strcmp(m.line2,'C57Bl/6') && ~strcmp(m.line2,'Fvb') && ~strcmp(m.line2,'CD1') && ~strcmp(m.line2,'Crl-CD1') errorCount = errorCount + 1; - errorString{errorCount} = 'The wild type genotype should only be used to describe pure C57Bl/6 or Fvb lines.'; + errorString{errorCount} = 'The wild type genotype should only be used to describe pure C57Bl/6, Fvb, or CD1 lines.'; end -if strcmp(m.genotype2,'wild type') && ~strcmp(m.line2,'C57Bl/6') && ~strcmp(m.line2,'Fvb') +if strcmp(m.genotype3,'wild type') && ~strcmp(m.line3,'C57Bl/6') && ~strcmp(m.line3,'Fvb') && ~strcmp(m.line3,'CD1') && ~strcmp(m.line3,'Crl-CD1') errorCount = errorCount + 1; - errorString{errorCount} = 'The wild type genotype should only be used to describe pure C57Bl/6 or Fvb lines.'; + errorString{errorCount} = 'The wild type genotype should only be used to describe pure C57Bl/6, Fvb, or CD1 lines.'; end -if strcmp(m.genotype3,'wild type') && ~strcmp(m.line3,'C57Bl/6') && ~strcmp(m.line3,'Fvb') +if strcmp(m.genotype4,'wild type') && ~strcmp(m.line4,'C57Bl/6') && ~strcmp(m.line4,'Fvb') && ~strcmp(m.line4,'CD1') && ~strcmp(m.line4,'Crl-CD1') errorCount = errorCount + 1; - errorString{errorCount} = 'The wild type genotype should only be used to describe pure C57Bl/6 or Fvb lines.'; + errorString{errorCount} = 'The wild type genotype should only be used to describe pure C57Bl/6, Fvb, or CD1 lines.'; +end + +if strcmp(m.genotype5,'wild type') && ~strcmp(m.line5,'C57Bl/6') && ~strcmp(m.line5,'Fvb') && ~strcmp(m.line5,'CD1') && ~strcmp(m.line5,'Crl-CD1') + errorCount = errorCount + 1; + errorString{errorCount} = 'The wild type genotype should only be used to describe pure C57Bl/6, Fvb, or CD1 lines.'; +end + +if strcmp(m.genotype6,'wild type') && ~strcmp(m.line6,'C57Bl/6') && ~strcmp(m.line6,'Fvb') && ~strcmp(m.line6,'CD1') && ~strcmp(m.line6,'Crl-CD1') + errorCount = errorCount + 1; + errorString{errorCount} = 'The wild type genotype should only be used to describe pure C57Bl/6, Fvb, or CD1 lines.'; end % at least one parent must share each line, (unless parents are not in the @@ -273,6 +303,18 @@ function plusCallback(src,~) errorCount = errorCount + 1; errorString{errorCount} = ['' m.line3 ' is not a line listed for the parents of this animal.']; end + if ~isempty([a.line]) && ~isempty([b.line]) && ~isempty(m.line4) && ~any(strcmp(m.line4,s)) + errorCount = errorCount + 1; + errorString{errorCount} = ['' m.line4 ' is not a line listed for the parents of this animal.']; + end + if ~isempty([a.line]) && ~isempty([b.line]) && ~isempty(m.line5) && ~any(strcmp(m.line5,s)) + errorCount = errorCount + 1; + errorString{errorCount} = ['' m.line5 ' is not a line listed for the parents of this animal.']; + end + if ~isempty([a.line]) && ~isempty([b.line]) && ~isempty(m.line6) && ~any(strcmp(m.line6,s)) + errorCount = errorCount + 1; + errorString{errorCount} = ['' m.line6 ' is not a line listed for the parents of this animal.']; + end end % all lines from the parents must also be listed for the offspring @@ -291,9 +333,21 @@ function plusCallback(src,~) lineCount = lineCount + 1; m.lines{lineCount} = m.line3; end +if ~isempty(m.line4) + lineCount = lineCount + 1; + m.lines{lineCount} = m.line4; +end +if ~isempty(m.line5) + lineCount = lineCount + 1; + m.lines{lineCount} = m.line5; +end +if ~isempty(m.line6) + lineCount = lineCount + 1; + m.lines{lineCount} = m.line6; +end for i = 1:length(s) - if ~any(strcmp(s{i},m.lines)) && ~isempty(s{i}) && ~(strcmp(s{i},'C57Bl/6')) && ~(strcmp(s{i},'Fvb')) + if ~any(strcmp(s{i},m.lines)) && ~isempty(s{i}) && ~(strcmp(s{i},'C57Bl/6')) && ~(strcmp(s{i},'Fvb')) && ~(strcmp(s{i},'CD1')) errorCount = errorCount + 1; errorString{errorCount} = 'A line from the parents is not listed.'; end @@ -304,63 +358,99 @@ function plusCallback(src,~) if ~isempty(a) a = fetch(mice.Genotypes & a & 'genotype = "homozygous"'); - if ~isempty(m.line1) && ~isempty(a) && strcmp(m.line1,a.line) && strcmp('negative',m.genotype1); + if ~isempty(m.line1) && ~isempty(a) && any(strcmp(m.line1,{a.line})) && strcmp('negative',m.genotype1); errorCount = errorCount + 1; errorString{errorCount} = ['Animal cannot be negative for ' m.line1 ' if a parent is homozygous.']; end - if ~isempty(m.line2) && ~isempty(a) && strcmp(m.line2,a.line) && strcmp('negative',m.genotype2); + if ~isempty(m.line2) && ~isempty(a) && any(strcmp(m.line2,{a.line})) && strcmp('negative',m.genotype2); errorCount = errorCount + 1; errorString{errorCount} = ['Animal cannot be negative for ' m.line2 ' if a parent is homozygous.']; end - if ~isempty(m.line3) && ~isempty(a) && strcmp(m.line3,a.line) && strcmp('negative',m.genotype3); + if ~isempty(m.line3) && ~isempty(a) && any(strcmp(m.line3,{a.line})) && strcmp('negative',m.genotype3); errorCount = errorCount + 1; errorString{errorCount} = ['Animal cannot be negative for ' m.line3 ' if a parent is homozygous.']; end + if ~isempty(m.line4) && ~isempty(a) && any(strcmp(m.line4,{a.line})) && strcmp('negative',m.genotype4); + errorCount = errorCount + 1; + errorString{errorCount} = ['Animal cannot be negative for ' m.line4 ' if a parent is homozygous.']; + end + if ~isempty(m.line5) && ~isempty(a) && any(strcmp(m.line5,{a.line})) && strcmp('negative',m.genotype5); + errorCount = errorCount + 1; + errorString{errorCount} = ['Animal cannot be negative for ' m.line5 ' if a parent is homozygous.']; + end + if ~isempty(m.line6) && ~isempty(a) && any(strcmp(m.line6,{a.line})) && strcmp('negative',m.genotype6); + errorCount = errorCount + 1; + errorString{errorCount} = ['Animal cannot be negative for ' m.line6 ' if a parent is homozygous.']; + end end if ~isempty(b) b = fetch(mice.Genotypes & b & 'genotype = "homozygous"'); - if ~isempty(m.line1) && ~isempty(b) && strcmp(m.line1,b.line) && strcmp('negative',m.genotype1); + if ~isempty(m.line1) && ~isempty(b) && any(strcmp(m.line1,{b.line})) && strcmp('negative',m.genotype1); errorCount = errorCount + 1; errorString{errorCount} = ['Animal cannot be negative for ' m.line1 ' if a parent is homozygous.']; end - if ~isempty(m.line2) && ~isempty(b) && strcmp(m.line2,b.line) && strcmp('negative',m.genotype2); + if ~isempty(m.line2) && ~isempty(b) && any(strcmp(m.line2,{b.line})) && strcmp('negative',m.genotype2); errorCount = errorCount + 1; errorString{errorCount} = ['Animal cannot be negative for ' m.line2 ' if a parent is homozygous.']; end - if ~isempty(m.line3) && ~isempty(b) && strcmp(m.line3,b.line) && strcmp('negative',m.genotype3); + if ~isempty(m.line3) && ~isempty(b) && any(strcmp(m.line3,{b.line})) && strcmp('negative',m.genotype3); errorCount = errorCount + 1; errorString{errorCount} = ['Animal cannot be negative for ' m.line3 ' if a parent is homozygous.']; end + if ~isempty(m.line4) && ~isempty(b) && any(strcmp(m.line4,{b.line})) && strcmp('negative',m.genotype4); + errorCount = errorCount + 1; + errorString{errorCount} = ['Animal cannot be negative for ' m.line4 ' if a parent is homozygous.']; + end + if ~isempty(m.line5) && ~isempty(b) && any(strcmp(m.line5,{b.line})) && strcmp('negative',m.genotype5); + errorCount = errorCount + 1; + errorString{errorCount} = ['Animal cannot be negative for ' m.line5 ' if a parent is homozygous.']; + end + if ~isempty(m.line6) && ~isempty(b) && any(strcmp(m.line6,{b.line})) && strcmp('negative',m.genotype6); + errorCount = errorCount + 1; + errorString{errorCount} = ['Animal cannot be negative for ' m.line6 ' if a parent is homozygous.']; + end end if ~isempty(c) c = fetch(mice.Genotypes & c & 'genotype = "homozygous"'); - if ~isempty(m.line1) && ~isempty(c) && strcmp(m.line1,c.line) && strcmp('negative',m.genotype1); + if ~isempty(m.line1) && ~isempty(c) && any(strcmp(m.line1,{c.line})) && strcmp('negative',m.genotype1); errorCount = errorCount + 1; errorString{errorCount} = ['Animal cannot be negative for ' m.line1 ' if a parent is homozygous.']; end - if ~isempty(m.line2) && ~isempty(c) && strcmp(m.line2,c.line) && strcmp('negative',m.genotype2); + if ~isempty(m.line2) && ~isempty(c) && any(strcmp(m.line2,{c.line})) && strcmp('negative',m.genotype2); errorCount = errorCount + 1; errorString{errorCount} = ['Animal cannot be negative for ' m.line2 ' if a parent is homozygous.']; end - if ~isempty(m.line3) && ~isempty(c) && strcmp(m.line3,c.line) && strcmp('negative',m.genotype3); + if ~isempty(m.line3) && ~isempty(c) && any(strcmp(m.line3,{c.line})) && strcmp('negative',m.genotype3); errorCount = errorCount + 1; errorString{errorCount} = ['Animal cannot be negative for ' m.line3 ' if a parent is homozygous.']; end + if ~isempty(m.line4) && ~isempty(c) && any(strcmp(m.line4,{c.line})) && strcmp('negative',m.genotype4); + errorCount = errorCount + 1; + errorString{errorCount} = ['Animal cannot be negative for ' m.line4 ' if a parent is homozygous.']; + end + if ~isempty(m.line5) && ~isempty(c) && any(strcmp(m.line5,{c.line})) && strcmp('negative',m.genotype5); + errorCount = errorCount + 1; + errorString{errorCount} = ['Animal cannot be negative for ' m.line5 ' if a parent is homozygous.']; + end + if ~isempty(m.line6) && ~isempty(c) && any(strcmp(m.line6,{c.line})) && strcmp('negative',m.genotype6); + errorCount = errorCount + 1; + errorString{errorCount} = ['Animal cannot be negative for ' m.line6 ' if a parent is homozygous.']; + end end % if the mouse is in Taub, the room cannot be VK3. if the mouse is in TMF % the room must be VK3. -if strcmp(m.facility,'Taub') && strcmp(m.room,'VK3') +if strcmp(m.facility,'Taub') && strcmp(m.room,'VK3') && strcmp(m.room,'VH1') errorCount = errorCount + 1; - errorString{errorCount} = 'If the mouse is in Taub it cannot be in room VK3.'; + errorString{errorCount} = 'If the mouse is in Taub it cannot be in room VK3 or VH1.'; end -if strcmp(m.facility,'TMF') && ~strcmp(m.room,'VK3') +if strcmp(m.facility,'TMF') && ~strcmp(m.room,'VK3') && ~strcmp(m.room,'VK3') errorCount = errorCount + 1; - errorString{errorCount} = 'If the mouse is in TMF it must be in room VK3.'; + errorString{errorCount} = 'If the mouse is in TMF it must be in room VK3 or VH1.'; end % add to table if there are no errors @@ -401,14 +491,14 @@ function plusCallback(src,~) if isempty(errorString) && isempty(m.new_mice) mouseCount = mouseCount + 1; - mouseTable(mouseCount,:) = {m.animal_id m.other_id m.dob m.dow m.parent1 m.parent2 m.parent3 m.sex m.color m.ear_punch m.line1 m.genotype1 m.line2 m.genotype2 m.line3 m.genotype3 m.owner m.facility m.room m.rack m.row m.mouse_notes}; + mouseTable(mouseCount,:) = {m.animal_id m.other_id m.dob m.dow m.parent1 m.parent2 m.parent3 m.sex m.color m.ear_punch m.line1 m.genotype1 m.line2 m.genotype2 m.line3 m.genotype3 m.line4 m.genotype4 m.line5 m.genotype5 m.line6 m.genotype6 m.owner m.facility m.room m.rack m.row m.mouse_notes}; set(h.new_mice,'Data',mouseTable); end if isempty(errorString) && ~isempty(m.new_mice) for i = 1: size(m.new_mice,1) if m.animal_id == m.new_mice{i,1} - mouseTable(i,:) = {m.animal_id char(m.other_id) m.dob m.dow m.parent1 m.parent2 m.parent3 m.sex m.color m.ear_punch m.line1 m.genotype1 m.line2 m.genotype2 m.line3 m.genotype3 m.owner m.facility m.room m.rack m.row m.mouse_notes}; + mouseTable(i,:) = {m.animal_id char(m.other_id) m.dob m.dow m.parent1 m.parent2 m.parent3 m.sex m.color m.ear_punch m.line1 m.genotype1 m.line2 m.genotype2 m.line3 m.genotype3 m.line4 m.genotype4 m.line5 m.genotype5 m.line6 m.genotype6 m.owner m.facility m.room m.rack m.row m.mouse_notes}; duplicateCount = duplicateCount + 1; set(h.new_mice,'Data',mouseTable); end @@ -417,7 +507,7 @@ function plusCallback(src,~) if isempty(errorString) && ~isempty(m.new_mice) && duplicateCount == 0 mouseCount = mouseCount + 1; - mouseTable(mouseCount,:) = {m.animal_id m.other_id m.dob m.dow m.parent1 m.parent2 m.parent3 m.sex m.color m.ear_punch m.line1 m.genotype1 m.line2 m.genotype2 m.line3 m.genotype3 m.owner m.facility m.room char(m.rack) m.row m.mouse_notes}; + mouseTable(mouseCount,:) = {m.animal_id m.other_id m.dob m.dow m.parent1 m.parent2 m.parent3 m.sex m.color m.ear_punch m.line1 m.genotype1 m.line2 m.genotype2 m.line3 m.genotype3 m.line4 m.genotype4 m.line5 m.genotype5 m.line6 m.genotype6 m.owner m.facility m.room char(m.rack) m.row m.mouse_notes}; set(h.new_mice,'Data',mouseTable); end diff --git a/schemas/+mice/+GUIs/plusFounderCallback.m b/schemas/+mice/+GUIs/plusFounderCallback.m index c8576b2..c5816a2 100644 --- a/schemas/+mice/+GUIs/plusFounderCallback.m +++ b/schemas/+mice/+GUIs/plusFounderCallback.m @@ -155,29 +155,29 @@ function plusFounderCallback(src,~) % If any line is C57Bl/6 or Fvb then it must be the only line and the % genotype must be wild type -if (strcmp(m.line,'C57Bl/6') || strcmp(m.line,'Fvb')) && ~strcmp(m.genotype, 'wild type') +if (strcmp(m.line,'C57Bl/6') || strcmp(m.line,'Fvb') || strcmp(m.line,'CD1') || strcmp(m.line,'Crl-CD1')) && ~strcmp(m.genotype, 'wild type') errorCount = errorCount + 1; - errorString{errorCount} = 'Lines C57Bl/6 and Fvb should only be used to designate pure wild type mice.'; + errorString{errorCount} = 'Lines C57Bl/6, Fvb, and CD1 should only be used to designate pure wild type mice.'; end % wild type genotype can only be used for C57Bl/6 or Fvb lines. -if strcmp(m.genotype,'wild type') && ~strcmp(m.line,'C57Bl/6') && ~strcmp(m.line,'Fvb') +if strcmp(m.genotype,'wild type') && ~strcmp(m.line,'C57Bl/6') && ~strcmp(m.line,'Fvb') && ~strcmp(m.line,'CD1') && ~strcmp(m.line,'Crl-CD1') errorCount = errorCount + 1; - errorString{errorCount} = 'The wild type genotype should only be used to describe pure C57Bl/6 or Fvb lines.'; + errorString{errorCount} = 'The wild type genotype should only be used to describe pure C57Bl/6, Fvb, or CD1 lines.'; end % if the mouse is in Taub, the room cannot be VK3. if the mouse is in TMF % the room must be VK3. -if strcmp(m.facility,'Taub') && strcmp(m.room,'VK3') +if strcmp(m.facility,'Taub') && strcmp(m.room,'VK3') && strcmp(m.room,'VH1') errorCount = errorCount + 1; - errorString{errorCount} = 'If the mouse is in Taub it cannot be in room VK3.'; + errorString{errorCount} = 'If the mouse is in Taub it cannot be in room VK3 or VH1.'; end -if strcmp(m.facility,'TMF') && ~strcmp(m.room,'VK3') +if strcmp(m.facility,'TMF') && ~strcmp(m.room,'VK3') && ~strcmp(m.room,'VH1') errorCount = errorCount + 1; - errorString{errorCount} = 'If the mouse is in TMF it must be in room VK3.'; + errorString{errorCount} = 'If the mouse is in TMF it must be in room VK3 or VH1.'; end % diff --git a/schemas/+mice/+GUIs/selectRow.m b/schemas/+mice/+GUIs/selectRow.m index 4fd894a..3ffe4d5 100644 --- a/schemas/+mice/+GUIs/selectRow.m +++ b/schemas/+mice/+GUIs/selectRow.m @@ -27,8 +27,8 @@ function selectRow(src,event) if ~isempty(h.isMice) - set(h.rack,'string',m.new_mice{row,20}); - set(h.row,'string',m.new_mice{row,21}); + set(h.rack,'string',m.new_mice{row,26}); + set(h.row,'string',m.new_mice{row,27}); s = get(h.sex,'string'); v = find(strcmp(m.new_mice{row,8},s)); set(h.sex,'value',v); @@ -41,7 +41,7 @@ function selectRow(src,event) set(h.parent1,'string',m.new_mice{row,5}); set(h.parent2,'string',m.new_mice{row,6}); set(h.parent3,'string',m.new_mice{row,7}); - set(h.mouse_notes,'string',m.new_mice{row,22}); + set(h.mouse_notes,'string',m.new_mice{row,28}); s = get(h.line1,'string'); v = find(strcmp(m.new_mice{row,11},s)); set(h.line1,'value',v); @@ -60,16 +60,33 @@ function selectRow(src,event) s = get(h.genotype3,'string'); v = find(strcmp(m.new_mice{row,16},s)); set(h.genotype3,'value',v); - s = get(h.owner,'string'); + s = get(h.line4,'string'); v = find(strcmp(m.new_mice{row,17},s)); + set(h.line4,'value',v); + s = get(h.genotype4,'string'); + v = find(strcmp(m.new_mice{row,18},s)); + set(h.genotype4,'value',v); + s = get(h.line5,'string'); + v = find(strcmp(m.new_mice{row,19},s)); + set(h.line5,'value',v); + s = get(h.genotype5,'string'); + v = find(strcmp(m.new_mice{row,20},s)); + set(h.genotype5,'value',v); + s = get(h.line6,'string'); + v = find(strcmp(m.new_mice{row,21},s)); + set(h.line6,'value',v); + s = get(h.genotype6,'string'); + v = find(strcmp(m.new_mice{row,22},s)); + set(h.genotype6,'value',v); + s = get(h.owner,'string'); + v = find(strcmp(m.new_mice{row,23},s)); set(h.owner,'value',v); s = get(h.facility,'string'); - v = find(strcmp(m.new_mice{row,18},s)); + v = find(strcmp(m.new_mice{row,24},s)); set(h.facility,'value',v); s = get(h.room,'string'); - v = find(strcmp(m.new_mice{row,19},s)); + v = find(strcmp(m.new_mice{row,25},s)); set(h.room,'value',v); - end if ~isempty(h.isFounder) diff --git a/schemas/+mice/+GUIs/submitMice.m b/schemas/+mice/+GUIs/submitMice.m index e186c72..dc04f15 100644 --- a/schemas/+mice/+GUIs/submitMice.m +++ b/schemas/+mice/+GUIs/submitMice.m @@ -22,14 +22,14 @@ function submitMice(src,~) return end -s = struct('animal_id',m.new_mice(:,1),'other_id',m.new_mice(:,2),'dob',m.new_mice(:,3),'dow',m.new_mice(:,4),'parent1',m.new_mice(:,5),'parent2',m.new_mice(:,6),'parent3',m.new_mice(:,7),'sex',m.new_mice(:,8),'color',m.new_mice(:,9),'ear_punch',m.new_mice(:,10),'line1',m.new_mice(:,11),'genotype1',m.new_mice(:,12),'line2',m.new_mice(:,13),'genotype2',m.new_mice(:,14),'line3',m.new_mice(:,15),'genotype3',m.new_mice(:,16),'owner',m.new_mice(:,17),'facility',m.new_mice(:,18),'room',m.new_mice(:,19),'rack',m.new_mice(:,20),'row',m.new_mice(:,21),'mouse_notes',m.new_mice(:,22)); +s = struct('animal_id',m.new_mice(:,1),'other_id',m.new_mice(:,2),'dob',m.new_mice(:,3),'dow',m.new_mice(:,4),'parent1',m.new_mice(:,5),'parent2',m.new_mice(:,6),'parent3',m.new_mice(:,7),'sex',m.new_mice(:,8),'color',m.new_mice(:,9),'ear_punch',m.new_mice(:,10),'line1',m.new_mice(:,11),'genotype1',m.new_mice(:,12),'line2',m.new_mice(:,13),'genotype2',m.new_mice(:,14),'line3',m.new_mice(:,15),'genotype3',m.new_mice(:,16),'line4',m.new_mice(:,17),'genotype4',m.new_mice(:,18),'line5',m.new_mice(:,19),'genotype5',m.new_mice(:,20),'line6',m.new_mice(:,21),'genotype6',m.new_mice(:,22),'owner',m.new_mice(:,23),'facility',m.new_mice(:,24),'room',m.new_mice(:,25),'rack',m.new_mice(:,26),'row',m.new_mice(:,27),'mouse_notes',m.new_mice(:,28)); for i = 1:size(s,1) if ischar(s(i).animal_id) s(i).animal_id = str2num(s(i).animal_id); end end -fields = {'parent1','parent2','parent3','line1','genotype1','line2','genotype2','line3','genotype3'}; +fields = {'parent1','parent2','parent3','line1','genotype1','line2','genotype2','line3','genotype3','line4','genotype4','line5','genotype5','line6','genotype6'}; mouseStruct = rmfield(s,fields); parentStruct = {}; @@ -53,6 +53,24 @@ function submitMice(src,~) genotypeStruct(genotypeCount).line = s(i).line3; genotypeStruct(genotypeCount).genotype = s(i).genotype3; end + if ~isempty(s(i).line4) + genotypeCount = genotypeCount + 1; + genotypeStruct(genotypeCount).animal_id = s(i).animal_id; + genotypeStruct(genotypeCount).line = s(i).line4; + genotypeStruct(genotypeCount).genotype = s(i).genotype4; + end + if ~isempty(s(i).line5) + genotypeCount = genotypeCount + 1; + genotypeStruct(genotypeCount).animal_id = s(i).animal_id; + genotypeStruct(genotypeCount).line = s(i).line5; + genotypeStruct(genotypeCount).genotype = s(i).genotype5; + end + if ~isempty(s(i).line6) + genotypeCount = genotypeCount + 1; + genotypeStruct(genotypeCount).animal_id = s(i).animal_id; + genotypeStruct(genotypeCount).line = s(i).line6; + genotypeStruct(genotypeCount).genotype = s(i).genotype6; + end if ~isempty(s(i).parent1) parentCount = parentCount + 1; parentStruct(parentCount).animal_id = s(i).animal_id; diff --git a/schemas/+mice/+GUIs/submitUpdateMice.m b/schemas/+mice/+GUIs/submitUpdateMice.m index 0bcddba..421e567 100644 --- a/schemas/+mice/+GUIs/submitUpdateMice.m +++ b/schemas/+mice/+GUIs/submitUpdateMice.m @@ -38,26 +38,26 @@ function submitUpdateMice(src,~) % if line 1 is C57Bl/6 or FVB the genotype miust be wild type for i = 1:size(m.table,1) - if (strcmp('C57Bl/6',m.table(i,7)) || strcmp('Fvb',m.table(i,7))) && ~strcmp('wild type',m.table(i,8)) + if (strcmp('C57Bl/6',m.table(i,7)) || strcmp('Fvb',m.table(i,7)) || strcmp('CD1',m.table(i,7))) && ~strcmp('wild type',m.table(i,8)) errorCount = errorCount + 1; - errorString{errorCount} = 'Lines C57Bl/6 and Fvb should only be used to designate pure wild type mice.'; + errorString{errorCount} = 'Lines C57Bl/6, Fvb, and CD1 should only be used to designate pure wild type mice.'; end end % wild type genotype can only be used for C57Bl/6 or Fvb lines for i = 1:size(m.table,1) - if strcmp('wild type',m.table(i,8)) && ~(strcmp('C57Bl/6',m.table(i,7)) || strcmp('Fvb',m.table(i,7))) + if strcmp('wild type',m.table(i,8)) && ~(strcmp('C57Bl/6',m.table(i,7)) || strcmp('Fvb',m.table(i,7)) || strcmp('CD1',m.table(i,7))) errorCount = errorCount + 1; - errorString{errorCount} = 'The wild type genotype should only be used to describe pure C57Bl/6 or Fvb lines.'; + errorString{errorCount} = 'The wild type genotype should only be used to describe pure C57Bl/6, Fvb, or CD1 lines.'; end - if strcmp('wild type',m.table(i,10)) && ~(strcmp('C57Bl/6',m.table(i,9)) || strcmp('Fvb',m.table(i,9))) + if strcmp('wild type',m.table(i,10)) && ~(strcmp('C57Bl/6',m.table(i,9)) || strcmp('Fvb',m.table(i,9)) || strcmp('CD1',m.table(i,9))) errorCount = errorCount + 1; - errorString{errorCount} = 'The wild type genotype should only be used to describe pure C57Bl/6 or Fvb lines.'; + errorString{errorCount} = 'The wild type genotype should only be used to describe pure C57Bl/6, Fvb, or CD1 lines.'; end - if strcmp('wild type',m.table(i,12)) && ~(strcmp('C57Bl/6',m.table(i,11)) || strcmp('Fvb',m.table(i,11))) + if strcmp('wild type',m.table(i,12)) && ~(strcmp('C57Bl/6',m.table(i,11)) || strcmp('Fvb',m.table(i,11)) || strcmp('CD1',m.table(i,11))) errorCount = errorCount + 1; - errorString{errorCount} = 'The wild type genotype should only be used to describe pure C57Bl/6 or Fvb lines.'; + errorString{errorCount} = 'The wild type genotype should only be used to describe pure C57Bl/6, Fvb, or CD1 lines.'; end end @@ -147,7 +147,7 @@ function submitUpdateMice(src,~) update(mice.Mice & ['animal_id=' m.table{i,1}],'sex',m.table{i,4}) update(mice.Mice & ['animal_id=' m.table{i,1}],'color',m.table{i,5}) update(mice.Mice & ['animal_id=' m.table{i,1}],'ear_punch',m.table{i,6}) - update(mice.Mice & ['animal_id=' m.table{i,1}],'mouse_notes',m.table{i,13}) + update(mice.Mice & ['animal_id=' m.table{i,1}],'mouse_notes',m.table{i,19}) if ~isempty(m.table{i,7}) update(mice.Genotypes & ['animal_id=' m.table{i,1}] & ['line="' m.table{i,7} '"'],'genotype',m.table{i,8}) end @@ -157,6 +157,15 @@ function submitUpdateMice(src,~) if ~isempty(m.table{i,11}) update(mice.Genotypes & ['animal_id=' m.table{i,1}] & ['line="' m.table{i,11} '"'],'genotype',m.table{i,12}) end + if ~isempty(m.table{i,13}) + update(mice.Genotypes & ['animal_id=' m.table{i,1}] & ['line="' m.table{i,13} '"'],'genotype',m.table{i,14}) + end + if ~isempty(m.table{i,15}) + update(mice.Genotypes & ['animal_id=' m.table{i,1}] & ['line="' m.table{i,15} '"'],'genotype',m.table{i,16}) + end + if ~isempty(m.table{i,17}) + update(mice.Genotypes & ['animal_id=' m.table{i,1}] & ['line="' m.table{i,17} '"'],'genotype',m.table{i,18}) + end end schema.conn.commitTransaction set(h.table,'Data',{},'RowName',' '); diff --git a/schemas/+mice/.DS_Store b/schemas/+mice/.DS_Store deleted file mode 100644 index bebcda7..0000000 Binary files a/schemas/+mice/.DS_Store and /dev/null differ diff --git a/schemas/+mice/Lines.m b/schemas/+mice/Lines.m index 638f261..e72224b 100644 --- a/schemas/+mice/Lines.m +++ b/schemas/+mice/Lines.m @@ -1,6 +1,6 @@ %{ mice.Lines (manual) # Basic mouse line info$ -line : enum('Nestin-Cre','Nestin-CreER(W)','Nestin-CreER(J)','Wfs1-CreER','ChAT-Cre','Viaat-Cre','SST-Cre','PV-Cre','VIP-Cre','GAD67-GFP','KOPRCS','Ai9','R-EYFP','R-ChR2-EYFP','R-ChR2-tdTomato','R-TVA/G','R-Arch','R-GCaMP3','Confetti','Nuc4','Nuc24','Cyt47','C57Bl/6','Fvb','Etv1-CreER','TH-Cre','Hist GFP','Ntsr1-Cre','CamKII-Cre','DBH Cre','Ai96_GCaMP6s','tetO-GCaMP6s','PronucRosaTw','mESC Twitch','Halo','Emx-1 Cre','Ai93_GCamp6','Ai94_GCamp6','Camk2a-tTA') # Mouse Line Abbreviation +line : enum('Nestin-Cre','Nestin-CreER(W)','Nestin-CreER(J)','Wfs1-CreER','ChAT-Cre','Viaat-Cre','SST-Cre','PV-Cre','VIP-Cre','GAD67-GFP','KOPRCS','Ai9','R-EYFP','R-ChR2-EYFP','R-ChR2-tdTomato','R-TVA/G','R-Arch','R-GCaMP3','Confetti','Nuc4','Nuc24','Cyt47','C57Bl/6','Fvb','Etv1-CreER','TH-Cre','Hist GFP','Ntsr1-Cre','CamKII-Cre','DBH Cre','Ai96_GCaMP6s','tetO-GCaMP6s','PronucRosaTw','mESC Twitch','Halo','Emx-1 Cre','Ai93_GCamp6','Ai94_GCamp6','Camk2a-tTA','ZtTA','CD1','Thy1 (GP5.17)','mCherry (H2B-mCherry)','DREADD','Bact-Cre','FRT-EGFP','Ai148_GCamp6') # Mouse Line Abbreviation --- line_full : varchar(100) # full line name rec_strain : varchar(20) # recipient strain diff --git a/schemas/+mice/Requests.m b/schemas/+mice/Requests.m index b6644a0..8a6fd14 100644 --- a/schemas/+mice/Requests.m +++ b/schemas/+mice/Requests.m @@ -2,15 +2,15 @@ mice.Requests (manual) # requests for transgenic mice$ request_idx : int # request number --- -requestor="none" : enum('Jake','Manolis','Dimitri','Shan','Keith','Cathryn','Fabian','Deumani','Matt','Megan','Paul','Shuang','Other','Available','none') # person who requested the mice +requestor="none" : enum('Jake','Manolis','Dimitri','Shan','Keith','Cathryn','Fabian','Deumani','Matt','Megan','Paul','Shuang','Federico','Jiakun','Other','Available','none') # person who requested the mice dor=null : date # date of request number_mice : int # number of mice requested age=null : enum('any','P18-P21','P21-P28','4-6 Weeks') # age requested -line1=null : enum('','Nestin-Cre','Nestin-CreER(W)','Nestin-CreER(J)','Wfs1-CreER','ChAT-Cre','Viaat-Cre','SST-Cre','PV-Cre','VIP-Cre','GAD67-GFP','KOPRCS','Ai9','R-EYFP','R-ChR2-EYFP','R-ChR2-tdTomato','R-TVA/G','R-Arch','R-GCaMP3','Confetti','Nuc4','Nuc24','Cyt47','C57Bl/6','Fvb','Etv1-CreER','TH-Cre','Hist GFP','Ntsr1-Cre','CamKII-Cre','DBH Cre','Ai96_GCaMP6s','tetO-GCaMP6s','PronucRosaTw','mESC Twitch','Halo','Emx-1 Cre','Ai93_GCamp6','Ai94_GCamp6','Camk2a-tTA') # Mouse Line 1 Abbreviation +line1=null : enum('','Nestin-Cre','Nestin-CreER(W)','Nestin-CreER(J)','Wfs1-CreER','ChAT-Cre','Viaat-Cre','SST-Cre','PV-Cre','VIP-Cre','GAD67-GFP','KOPRCS','Ai9','R-EYFP','R-ChR2-EYFP','R-ChR2-tdTomato','R-TVA/G','R-Arch','R-GCaMP3','Confetti','Nuc4','Nuc24','Cyt47','C57Bl/6','Fvb','Etv1-CreER','TH-Cre','Hist GFP','Ntsr1-Cre','CamKII-Cre','DBH Cre','Ai96_GCaMP6s','tetO-GCaMP6s','PronucRosaTw','mESC Twitch','Halo','Emx-1 Cre','Ai93_GCamp6','Ai94_GCamp6','Camk2a-tTA','ZtTA','CD1','Thy1 (GP5.17)','mCherry (H2B-mCherry)','DREADD','Bact-Cre','FRT-EGFP','Ai148_GCamp6') # Mouse Line 1 Abbreviation genotype1 : enum('homozygous','heterozygous','hemizygous','positive','negative','wild type','') # genotype for line 1 -line2=null : enum('','Nestin-Cre','Nestin-CreER(W)','Nestin-CreER(J)','Wfs1-CreER','ChAT-Cre','Viaat-Cre','SST-Cre','PV-Cre','VIP-Cre','GAD67-GFP','KOPRCS','Ai9','R-EYFP','R-ChR2-EYFP','R-ChR2-tdTomato','R-TVA/G','R-Arch','R-GCaMP3','Confetti','Nuc4','Nuc24','Cyt47','C57Bl/6','Fvb','Etv1-CreER','TH-Cre','Hist GFP','Ntsr1-Cre','CamKII-Cre','DBH Cre','Ai96_GCaMP6s','tetO-GCaMP6s','PronucRosaTw','mESC Twitch','Halo','Emx-1 Cre','Ai93_GCamp6','Ai94_GCamp6','Camk2a-tTA') # Mouse Line 2 Abbreviation +line2=null : enum('','Nestin-Cre','Nestin-CreER(W)','Nestin-CreER(J)','Wfs1-CreER','ChAT-Cre','Viaat-Cre','SST-Cre','PV-Cre','VIP-Cre','GAD67-GFP','KOPRCS','Ai9','R-EYFP','R-ChR2-EYFP','R-ChR2-tdTomato','R-TVA/G','R-Arch','R-GCaMP3','Confetti','Nuc4','Nuc24','Cyt47','C57Bl/6','Fvb','Etv1-CreER','TH-Cre','Hist GFP','Ntsr1-Cre','CamKII-Cre','DBH Cre','Ai96_GCaMP6s','tetO-GCaMP6s','PronucRosaTw','mESC Twitch','Halo','Emx-1 Cre','Ai93_GCamp6','Ai94_GCamp6','Camk2a-tTA','ZtTA','CD1','Thy1 (GP5.17)','mCherry (H2B-mCherry)','DREADD','Bact-Cre','FRT-EGFP','Ai148_GCamp6') # Mouse Line 2 Abbreviation genotype2=null : enum('homozygous','heterozygous','hemizygous','positive','negative','wild type','') # genotype for line 2 -line3=null : enum('','Nestin-Cre','Nestin-CreER(W)','Nestin-CreER(J)','Wfs1-CreER','ChAT-Cre','Viaat-Cre','SST-Cre','PV-Cre','VIP-Cre','GAD67-GFP','KOPRCS','Ai9','R-EYFP','R-ChR2-EYFP','R-ChR2-tdTomato','R-TVA/G','R-Arch','R-GCaMP3','Confetti','Nuc4','Nuc24','Cyt47','C57Bl/6','Fvb','Etv1-CreER','TH-Cre','Hist GFP','Ntsr1-Cre','CamKII-Cre','DBH Cre','Ai96_GCaMP6s','tetO-GCaMP6s','PronucRosaTw','mESC Twitch','Halo','Emx-1 Cre','Ai93_GCamp6','Ai94_GCamp6','Camk2a-tTA') # Mouse Line 3 Abbreviation +line3=null : enum('','Nestin-Cre','Nestin-CreER(W)','Nestin-CreER(J)','Wfs1-CreER','ChAT-Cre','Viaat-Cre','SST-Cre','PV-Cre','VIP-Cre','GAD67-GFP','KOPRCS','Ai9','R-EYFP','R-ChR2-EYFP','R-ChR2-tdTomato','R-TVA/G','R-Arch','R-GCaMP3','Confetti','Nuc4','Nuc24','Cyt47','C57Bl/6','Fvb','Etv1-CreER','TH-Cre','Hist GFP','Ntsr1-Cre','CamKII-Cre','DBH Cre','Ai96_GCaMP6s','tetO-GCaMP6s','PronucRosaTw','mESC Twitch','Halo','Emx-1 Cre','Ai93_GCamp6','Ai94_GCamp6','Camk2a-tTA','ZtTA','CD1','Thy1 (GP5.17)','mCherry (H2B-mCherry)','DREADD','Bact-Cre','FRT-EGFP','Ai148_GCamp6') # Mouse Line 3 Abbreviation genotype3=null : enum('homozygous','heterozygous','hemizygous','positive','negative','wild type','') # genotype for line 3 request_notes=null : varchar(4096) # other comments request_ts=CURRENT_TIMESTAMP: timestamp # automatic diff --git a/schemas/+opt/Thumbs.db b/schemas/+opt/Thumbs.db deleted file mode 100644 index f3b8a7a..0000000 Binary files a/schemas/+opt/Thumbs.db and /dev/null differ diff --git a/schemas/+psy/MovieClipStore.m b/schemas/+psy/MovieClipStore.m new file mode 100644 index 0000000..c176d8f --- /dev/null +++ b/schemas/+psy/MovieClipStore.m @@ -0,0 +1,34 @@ +%{ +psy.MovieClipStore (imported) # clips from movies +-> psy.MovieInfo +clip_number : int # clip index +----- +file_name : varchar(255) # full file name +clip : longblob # +%} + +classdef MovieClipStore < dj.Relvar + + methods + function filenames = export(obj) + + [file_names, clips] = fetchn(obj, 'file_name', 'clip'); + path = getLocalPath(fetch1(psy.MovieInfo & obj, 'path')); + if ~exist(path, 'dir') + mkdir(path) + end + + filenames = cell(length(file_names), 1); + for ifile = 1:length(file_names) + filenames{ifile} = fullfile(path, file_names{ifile}); + if exist(filenames{ifile}, 'file'); + delete(filenames{ifile}); + end + fid = fopen(filenames{ifile}, 'w'); + fwrite(fid, clips{ifile}, 'int8'); + fclose(fid); + end + + end + end +end \ No newline at end of file diff --git a/schemas/+psy/MovieInfo.m b/schemas/+psy/MovieInfo.m index ad37613..a4b2165 100644 --- a/schemas/+psy/MovieInfo.m +++ b/schemas/+psy/MovieInfo.m @@ -2,20 +2,23 @@ psy.MovieInfo (manual) # movies used for generating clips and stills movie_name : char(8) # short movie title ----- -movie_title : varchar(255) # full movie title -path_template : varchar(255) # filename template with full path +movie_class : enum('madmax','object3d','mousecam') # movie type +path : varchar(255) # path for movies +original_file : varchar(255) # original long movie clip +file_template : varchar(255) # filename template with full path file_duration : float # (s) duration of each file (must be equal) -frame_rate : float # frames per second -frame_width : int # (pixels) -frame_height : int # (pixels) +codec : varchar(255) # codec parameters for ffmpeg compression +movie_description : varchar(255) %} - classdef MovieInfo < dj.Relvar methods function fill(self) self.inserti({ - 'MadMax' 'Mad Max: Fury Road (2015)' '~/stimuli/movies/madmax/madmax_%03u.avi' 60 30 255 144 + 'MadMax' 'madmax' '~/stimuli/movies' ... + 'madmax.avi' 'madmax_%03u.mov' 60 ... + '-c:v libx264 -preset slow -crf 5' ... + 'Mad Max: Fury Road (2015)' }) end end diff --git a/schemas/+psy/MovieParams.m b/schemas/+psy/MovieParams.m new file mode 100644 index 0000000..58940b0 --- /dev/null +++ b/schemas/+psy/MovieParams.m @@ -0,0 +1,140 @@ +%{ +psy.MovieParams (imported) # clips from movies +-> psy.MovieInfo +----- +frame_rate : float # frames per second +frame_width : int # (pixels) +frame_height : int # (pixels) +params : longblob # movie parameters +%} + + +classdef MovieParams < dj.Relvar & dj.AutoPopulate + properties + popRel = psy.MovieInfo + end + + methods (Access=protected) + function makeTuples(self,key) + [path,file,file_temp,dur,codec] = fetch1(psy.MovieInfo & key,'path','original_file','file_template','file_duration','codec'); + + infile = getLocalPath(fullfile(path,file)); + info = ffmpeginfo(infile); + clip_number = floor(info.duration/dur); + tuple = key; + + % read data file + csvname = [infile(1:end-3) 'csv']; + if exist(csvname,'file') + data = csvread(csvname,1,0); + fileID = fopen(csvname,'r'); + names = textscan(fileID, '%s', 1, 'delimiter', '\n', 'headerlines', 0); + fclose(fileID); + names = textscan(names{1}{1},'%s','delimiter',','); + names = names{1}; + tuple.params = []; + for iname = 1:length(names) + eval(['tuple.params.' names{iname} '=data(:,iname);']); + end + end + + % insert movie info + tuple.frame_rate = info.streams.codec.fps; + tuple.frame_width = info.streams.codec.size(1); + tuple.frame_height = info.streams.codec.size(2); + self.insert(tuple) + + % process & insert clips + for iclip = 1:clip_number + tuple = key; + tuple.clip_number = iclip; + tuple.file_name = sprintf(file_temp,iclip); + if exists(psy.MovieClipStore & tuple);continue;end + + % create file + start = (iclip-1)*dur; + outfile = getLocalPath(fullfile(path,tuple.file_name)); + if ~exist(outfile,'file') + argstr = sprintf('-i %s -ss %d -t %d %s %s',infile,start,dur,codec,outfile); + ffmpegexec(argstr) + end + + % load file & insert + fid = fopen(getLocalPath(fullfile(path,tuple.file_name))); + tuple.clip = fread(fid,'*int8'); + fclose(fid); + insert(psy.MovieClipStore,tuple) + end + end + end + + methods + function filenames = export(obj) + + [file_names,clips] = fetchn(obj,'file_name','clip'); + path = getLocalPath(fetch1(psy.MovieInfo & obj,'path')); + if ~exist(path,'dir');mkdir(path);end + + filenames = cell(length(file_names),1); + for ifile = 1:length(file_names) + filenames{ifile} = fullfile(path,file_names{ifile}); + if exist(filenames{ifile}, 'file');delete(filenames{ifile});end + fid = fopen(filenames{ifile},'w'); + fwrite(fid,clips{ifile},'int8'); + fclose(fid); + end + + if length(filenames)==1; filenames = filenames{1};end + + end + + function plotPos(obj) + params = fetch1(obj,'params'); + figure + hold on + px = interpn(params.frames,params.camera_pos_x,1:params.frames(end),'cubic'); + pz = interpn(params.frames,params.camera_pos_z,1:params.frames(end),'cubic'); + + fps = fetch1(obj,'frame_rate'); + tbin = 500; % in msec + bin = fps*tbin/1000; % in frames + + trials = 200; + nsz = floor(length(px)/bin)*bin; + px = px(1:nsz); + pz = pz(1:nsz); + nx = reshape(px,bin,nsz/bin); + nz = reshape(pz,bin,nsz/bin); + [~,idx] = sort(nx(1,:)); + nz = nz(:,idx); + nx = nx(:,idx); + + + range = floor(linspace(1,size(nx,2),trials)); + try + colors = cbrewer('qual','Set3',length(range)); + catch + colors = hsv(length(range)); + end + idx = randperm(size(colors,1)); + colors = colors(idx,:); + idx = 0; + + for i = range + px = nx(:,i); + pz = nz(:,i); + idx = idx+1; + plot(interpn(px,3,'cubic'),interpn(pz,3,'cubic'),'color',colors(idx,:),'linewidth',1) + + end + + xlim([min(nx(:)) max(nx(:))]) + ylim([min(nz(:)) max(nz(:))]) + set(gca,'xtick',[],'ytick',[]) + xlabel('X dimension') + ylabel('Y dimension') + title(['Object trajectories (' num2str(tbin) 'msec)']) + + end + end +end \ No newline at end of file diff --git a/schemas/+psy/Thumbs.db b/schemas/+psy/Thumbs.db new file mode 100644 index 0000000..34335b6 Binary files /dev/null and b/schemas/+psy/Thumbs.db differ diff --git a/visual-stimuli/+stims/+analysis/flipAmpsToNums.m b/visual-stimuli/+stims/+analysis/flipAmpsToNums.m deleted file mode 100644 index 9276092..0000000 --- a/visual-stimuli/+stims/+analysis/flipAmpsToNums.m +++ /dev/null @@ -1,30 +0,0 @@ -function flipNums = flipAmpsToNums(flipAmps) -% given a sequence of flip amplitudes with encoded numbers, -% assign cardinal numbers to as many flips as possible. - -flipNums = nan(size(flipAmps)); - -% find threshold for positive flips (assumed stable) -ix = find(flipAmps>0); -thresh = (quantile(flipAmps(ix),0.1) + quantile(flipAmps(ix),0.9))/2; - -frame = 16; % 16 positive flips -nFrames = 5; % must be odd. 3 or 5 are most reasonable -iFlip = 1; -quitFlip = length(flipAmps)-frame*nFrames*2-2; -while iFlip < quitFlip - amps = flipAmps(iFlip+(0:frame*nFrames-1)*2); - if all(amps>0) % only consider positive flips - bits = amps < thresh; % big flips are for zeros - nums = bin2dec(char(fliplr(reshape(bits, [frame nFrames])')+48)); - if all(diff(nums)==1) % found sequential numbers - %fill out the numbers of the flips in the middle frame - ix = iFlip + floor(nFrames/2)*frame*2 + (0:frame*2-1); - nums = nums((nFrames+1)/2)*frame*2 + (1:frame*2); - flipNums(ix) = nums; - iFlip = iFlip + frame*2-1; - end - end - iFlip = iFlip+1; -end -end \ No newline at end of file diff --git a/visual-stimuli/+stims/+analysis/getFlips.m b/visual-stimuli/+stims/+analysis/getFlips.m deleted file mode 100644 index a88f6cc..0000000 --- a/visual-stimuli/+stims/+analysis/getFlips.m +++ /dev/null @@ -1,21 +0,0 @@ -function [flipIdx, flipAmps] = getFlips(x, fs, frameRate) -% INPUTS: -% x - photodiode signal -% fs - (Hz) sampling frequency -% frameRate (Hz) monitor frame rate - -T = fs/frameRate*2; % period of oscillation measured in samples -% filter flips -n = floor(T/4); % should be T/2 or smaller -k = hamming(n); -k = [k;0;-k]/sum(k); -x = fftfilt(k,[double(x);zeros(n,1)]); -x = x(n+1:end); -x([1:n end+(-n+1:0)])=0; % remove edge artifacts - -% select flips -flipIdx = ne7.dsp.spaced_max(abs(x),0.22*T); -thresh = 0.15*quantile( abs(x(flipIdx)),0.99); -flipIdx = flipIdx(abs(x(flipIdx))>thresh)'; -flipAmps = x(flipIdx); -end \ No newline at end of file diff --git a/visual-stimuli/+stims/+analysis/sync.m b/visual-stimuli/+stims/+analysis/sync.m deleted file mode 100644 index 542c775..0000000 --- a/visual-stimuli/+stims/+analysis/sync.m +++ /dev/null @@ -1,77 +0,0 @@ -function sync_info = sync(key, photodiode_signal, photodiode_fs, fps) -% given the photodiode signal, returns a structure describing visual -% stimulus trials that were displayed and exact timing synchronization. -% The photodiode signal is assumed to be uniformly sampled in time. - -trialTable = psy.Trial; - -% detect flips in the recorded photodiode_signal signal -[photodiode_flip_indices, photodiode_flip_numbers] = ... - stims.analysis.whichFlips(photodiode_signal, photodiode_fs, fps); - -% remove duplicated numbers due to terminated programs -ix = ~isnan(photodiode_flip_numbers); -photodiode_flip_indices = photodiode_flip_indices(ix); -photodiode_flip_numbers = photodiode_flip_numbers(ix); -ix = find(photodiode_flip_numbers(2:end) <= photodiode_flip_numbers(1:end-1), 1, 'last'); -if ~isempty(ix) - photodiode_flip_indices = photodiode_flip_indices(ix+1:end); - photodiode_flip_numbers = photodiode_flip_numbers(ix+1:end); -end - -% consider all trials with flip nums within the min and max of detected flip nums -trials = trialTable & key & ... - sprintf('last_flip_count between %d and %d', min(photodiode_flip_numbers), max(photodiode_flip_numbers)); - -% get all flip times for each trial, also get the number of the last flip in the trial -[psy_id, last_flip_in_trial, trial_flip_times] = fetchn(trials,... - 'psy_id', 'last_flip_count', 'flip_times', 'ORDER BY trial_idx'); - -if any(psy_id ~= psy_id(1)) - warning 'Multiple psy.Sessions per scan: not allowed.' - same_session = mode(psy_id)==psy_id; - psy_id = psy_id(same_session); - last_flip_in_trial = last_flip_in_trial(same_session); - trial_flip_times = trial_flip_times(same_session); -end -key.psy_id = psy_id(1); -sync_info = key; - -% fill in the flip numbers within each trial (counting up to the last flip in the trial) -trial_flip_numbers = arrayfun(@(last_flip, flip_times) ... - last_flip+(1-length(flip_times{1}):0), last_flip_in_trial, trial_flip_times, 'uni', false); -trial_flip_numbers = cat(2, trial_flip_numbers{:}); -trial_flip_times = [trial_flip_times{:}]; -assert(length(trial_flip_times)==length(trial_flip_numbers)); - -% Select only the matched flips -ix = ismember(photodiode_flip_numbers, trial_flip_numbers); -assert(sum(ix)>100, 'Insufficient matched flips (%d)', sum(ix)) -photodiode_flip_indices = photodiode_flip_indices(ix); -photodiode_flip_numbers = photodiode_flip_numbers(ix); -trial_flip_times = trial_flip_times(ismember(trial_flip_numbers, photodiode_flip_numbers)); - -% regress the photodiode_signal indices against the stimulus times to get the -% photodiode_signal signal time on stimulus clock. Assumes uninterrupted uniform sampling of photodiode_signal!!! -photodiode_flip_times = photodiode_flip_indices/photodiode_fs; -b = robustfit(photodiode_flip_times, trial_flip_times-trial_flip_times(1)); -sync_info.signal_start_time = b(1) + trial_flip_times(1); -sync_info.signal_duration = length(photodiode_signal)/photodiode_fs*b(2); -time_discrepancy = (b(1) + photodiode_flip_times*b(2)) - (trial_flip_times(:)-trial_flip_times(1)); -assert(max(abs(time_discrepancy)) < 0.02, ... - 'Incorrectly detected flips. Time discrepancy = %f s', max(abs(time_discrepancy))) - -% find first and last trials overlapping signal -trials = fetch(trialTable & key, 'trial_idx', 'flip_times', 'ORDER BY trial_idx'); -i=1; -while trials(i).flip_times(end) < sync_info.signal_start_time - i=i+1; -end -sync_info.first_trial = trials(i).trial_idx; -i=length(trials); -while trials(i).flip_times(1) > sync_info.signal_start_time + sync_info.signal_duration - i=i-1; -end -sync_info.last_trial = trials(i).trial_idx; - -end \ No newline at end of file diff --git a/visual-stimuli/+stims/+analysis/whichFlips.m b/visual-stimuli/+stims/+analysis/whichFlips.m deleted file mode 100644 index 6a1e5ee..0000000 --- a/visual-stimuli/+stims/+analysis/whichFlips.m +++ /dev/null @@ -1,11 +0,0 @@ -function [flipIdx, flipNums] = whichFlips(x, fs, fps) -% given a photodiode signal x with sampling rate fs, decode photodiode -% flips numbers. The monitor frame rate is fps. -% -% returns: -% flipIdx: the indices of the detected flips in x and their encoded -% flipNums: the sequential numbers of the detected indices - -[flipIdx, flipAmps] = stims.analysis.getFlips(x, fs, fps); -flipNums = stims.analysis.flipAmpsToNums(flipAmps); -end diff --git a/visual-stimuli/+stims/+core/Logger.m b/visual-stimuli/+stims/+core/Logger.m deleted file mode 100644 index 7783ef0..0000000 --- a/visual-stimuli/+stims/+core/Logger.m +++ /dev/null @@ -1,93 +0,0 @@ -% stims.core.Logger -- log stimulus data into specified DataJoint tables - -% -- Dimitri Yatsenko, 2012 - -classdef Logger < handle - - properties(SetAccess=private) - % DataJoint tables for session information. Structure with fields - % 'session', 'trial', 'condition', 'paramaters' - sessionTable - condTable - trialTable - parentKey % primary key of session's parent - sessionKey - - trialIdName = 'trial_idx' - trialIdx - unsavedTrials - end - - methods - function self = Logger(sessionTable, condTable, trialTable) - self.sessionTable = sessionTable; - self.trialTable = trialTable; - self.condTable = condTable; - end - - - function init(self, parentKey, constants) - if ~isempty(self.parentKey) - disp 'logger already initialized' - else - self.parentKey = parentKey; - - % log session - idname = setdiff(self.sessionTable.primaryKey, fieldnames(parentKey)); - assert(length(idname)==1, 'invalid key') - idname = idname{1}; - nextId = max(fetchn(self.sessionTable & parentKey, idname))+1; %autoincrement - if isempty(nextId) - nextId = 1; - end - self.sessionKey = parentKey; - self.sessionKey.(idname) = nextId; - self.sessionTable.insert(dj.struct.join(self.sessionKey, constants)) - - self.trialIdName = setdiff(self.trialTable.primaryKey, fieldnames(self.sessionKey)); - assert(length(self.trialIdName)==1, 'invalid trial table') - self.trialIdName = self.trialIdName{1}; - self.trialIdx = 0; - - disp **logged** - disp(self.sessionKey) - end - end - - - function lastFlip = getLastFlip(self) - % flip counts are unique per animal - lastFlip = max(fetchn(self.trialTable & self.parentKey, 'last_flip_count')); - if isempty(lastFlip) - lastFlip = 0; - end - end - - - function conditions = logConditions(self, conditions, paramTable) - lastCond = max(fetchn(self.condTable & self.sessionKey, 'cond_idx')); - if isempty(lastCond) - lastCond = 0; - end - [conditions(:).cond_idx] = deal(nan); - for iCond = 1:length(conditions) - condIdx = iCond + lastCond; - conditions(iCond).cond_idx = condIdx; - tuple = self.sessionKey; - tuple.cond_idx = condIdx; - self.condTable.insert(tuple); - attrs = [paramTable.primaryKey paramTable.nonKeyFields]; - paramTable.insert(dj.struct.join(tuple, dj.struct.pro(conditions(iCond), attrs{:}))) - end - end - - - function logTrial(self, tuple) - self.trialIdx = self.trialIdx + 1; - key = self.sessionKey; - key.(self.trialIdName)=self.trialIdx; - tuple = dj.struct.join(key, tuple); - self.trialTable.insertParallel(tuple) - end - end -end \ No newline at end of file diff --git a/visual-stimuli/+stims/+core/Screen.m b/visual-stimuli/+stims/+core/Screen.m deleted file mode 100644 index 0ab63c8..0000000 --- a/visual-stimuli/+stims/+core/Screen.m +++ /dev/null @@ -1,209 +0,0 @@ -% stims.core.Screen manages the visual stimulus display, incuding the coded -% photodiode signal in the corner of the screen for synchronization. - -% -- Dimitri Yatsenko, 2012, 2016 - - -classdef Screen < handle - - properties(Constant) - flipSize = [0.05 0.06]; % the relative size of the photodiode texture - end - - properties - frameStep=1 % 1=full fps, 2=half, 3=third, etc - end - - properties(SetAccess=private) - rect % (pixels) window rectangle - win % window pointer - fps % frames per second - frameInterval % (seconds) - flipCount % the index of the last flip - prevFlip % (seconds) - contrastEnabled % when false, disables contrast and brightness settings and uses default monitor settings - end - - properties(Access=private) - isOpened = false - contrast % currently set contrast - luminance % currently set luminance - binaryGray % if true, use black and white images (e.g. square gratings) - gammaData % gamma table loaded from file - savedSettings % saved settings to restore upon closing - flipTimes % the flip times of the recent flips - flipTex % photodiode textures - flipRect % photodiode rectangle - end - - methods - - function open(self) - if ~self.isOpened - disp 'Configuring display...' - AssertOpenGL - sca - % pix screen with the largest screen number - screen = max(Screen('Screens')); - [self.win, self.rect] = Screen('OpenWindow',screen,127,[],[],[],[],[], ... - mor(kPsychNeedFastBackingStore,kPsychNeed16BPCFloat)); - AssertGLSL - fprintf 'Screen Rectangle :' - disp(self.rect) - self.fps = Screen(screen, 'FrameRate',[]); - self.frameInterval = Screen('GetFlipInterval', self.win); - Priority(MaxPriority(self.win)); - - % Set luminance and contrast - if self.contrastEnabled - disp 'Loading gamma' - self.savedSettings.gammaTable = Screen('ReadNormalizedGammaTable',self.win); - self.gammaData = load('~/stimulation/gammatable.mat'); - self.setContrast(self.gammaData.luminance(end)/10, 0.5) % while waiting, darken the screen to 1/10 of its max luminance - end - - % create photodiode flip textures - self.flipRect = round(self.rect(3:4).*self.flipSize); - x = 1:self.flipRect(1); - self.flipTex(1) = Screen('MakeTexture', self.win, x*0); - self.flipTex(2) = Screen('MakeTexture', self.win, mod(x,2)*255); - self.flipTex(3) = Screen('MakeTexture', self.win, x*0+255); - self.isOpened = true; - end - end - - - function enableContrast(self, yes) - self.contrastEnabled = yes; - end - - - function setContrast(self, luminance, contrast, binaryGray) - % luminance = cd/m^2 - % contrast = Michelson contrast between 0 and 1 - % if binaryGray=true - stepwise contrast to make sine gratings appear as square gratings - if ~self.contrastEnabled - return - end - binaryGray = nargin>=4 && binaryGray; - if isempty(self.luminance) || isepmty(self.contrast) || ... - contrast~=self.contrast || luminance~=self.luminance || self.binaryGray~=binaryGray - - gammaTable = self.gammaData.gammaVals(:,1); - lumTab = self.gammaData.luminance; - minLum = lumTab(1); - maxLum = lumTab(end); - minLumNew = (1 - contrast) * luminance; - maxLumNew = 2 * luminance - minLumNew; - x0 = 255 * (minLumNew - minLum) / (maxLum - minLum); - x255 = 255 * (maxLumNew - minLum) / (maxLum - minLum); - - if ~binaryGray - ramp = linspace(x0, x255, 254); - else - ramp = x0+(x255-x0)*(1:254 > 127); - ramp(127)=(x255+x0)/2; % middle level to be used as background - end - assert(x0 >= 0 && x255 <= 255 ,'SlimStim:invalidContrast', ... - 'Contrast/luminance combination is out of range of current monitor settings: (%.1f, %.1f) cd/m^2', ... - lumTab(1),lumTab(end)) - gammaTable = [0; interp1(0:255, gammaTable, ramp, 'pchip')'; 1]; - Screen('LoadNormalizedGammaTable', self.win, gammaTable * ones(1, 3)); - end - end - - - function close(self) - if self.contrastEnabled - disp 'restoring gamma' - Screen('LoadNormalizedGammaTable', self.win, self.savedSettings.gammaTable); - end - Screen('Close',self.win); - ShowCursor; - self.savedSettings = []; - sca - self.isOpened = false; - end - - - function setFlipCount(self, flipCount) - self.flipCount = flipCount; - end - - function flipTimes = clearFlipTimes(self) - flipTimes = self.flipTimes; - self.flipTimes = []; - end - - - function flip(self, dontLogFlips, dontClearScreen, dontCheckDroppedFrames) - % defaults: self.flip(false, false, false) - dontLogFlips = nargin>=2 && dontLogFlips; - dontClearScreen = nargin>=3 && dontClearScreen; - dontCheckDroppedFrames = nargin>=4 && dontCheckDroppedFrames; - - if ~dontLogFlips - self.flipCount = self.flipCount + 1; - end - - % draw coded photodiode flip texture - if ~isempty(self.flipCount) - Screen('DrawTexture', self.win, ... - self.flipTex(flipCode(self.flipCount)), [],... - [0 0 self.flipRect(1) self.flipRect(2)]); - end - % update screen - when = self.prevFlip+self.frameStep*self.frameInterval; - flipTime = Screen('Flip', self.win, when - 0.5*self.frameInterval, double(dontClearScreen)); - if ~isempty(when) - droppedFrames = round((flipTime - when)/self.frameInterval); - if ~dontCheckDroppedFrames - % indicated dropped frames by a '$" or $(n) for n dropped frames - if droppedFrames>5 - fprintf('$(%d)', droppedFrames) - else - fprintf(repmat('$',1,droppedFrames)); - end - end - end - self.prevFlip = flipTime; - if ~dontLogFlips - self.flipTimes(end+1) = flipTime; - end - end - end - - - methods(Static) - function ret = escape - % Returns true if escape has been pressed. - % To clear, invoke without output arguments. - persistent ESC - ESC = ~isempty(ESC) && ESC && nargout; % reset - if ~ESC - [keyPressed, ~, keys] = KbCheck; - if keyPressed && keys(KbName('ESCAPE')) - ESC = true; - disp --escaped!! - end - end - ret = ESC; - end - end -end - - - -function a = flipCode(n) -% Encodes the flip number n in the flip amplitude a. -% Every 32 sequential flips encode 32 21-bit flip numbers. -% Thus each n is a 21-bit flip number: -% FFFFFFFFFFFFFFFFCCCCP -% P = parity, only P=1 encode bits -% C = the position within F -% F = the current block of 32 flips -% -% a= 1 (black) or 2 (F bit=1) or 3 (white, F bit=0) - -a = 1+bitand(n,1)*(2-bitget(n,bitand(floor(n/2),15)+6)); -end diff --git a/visual-stimuli/+stims/+core/Visual.m b/visual-stimuli/+stims/+core/Visual.m deleted file mode 100644 index a7f3e66..0000000 --- a/visual-stimuli/+stims/+core/Visual.m +++ /dev/null @@ -1,91 +0,0 @@ -classdef Visual < handle - % stims.core.Visual is an abstract class from which visual stimuli are derived - % A stims.core.Visual object manages the graphics window, iterates through - % trial conditions and calls the showTrial method for each trial. - % The object optionally logs the data into datajoint tables. - - % -- Dimitri Yatsenko, 2012-2015 - - properties(Constant) - DEBUG = true - screen = stims.core.Screen % all stimuli share one static screen object - end - - properties(Dependent) - win - rect - end - - properties(SetAccess=protected) - params % structure of cell arrays from which conditions will be derived - conditions % list of conditions derived from params - end - - properties(Access=protected) - constants % fields to be inserted into the session table - paramTable - end - - - methods(Abstract) - showTrial(self, condition) % implement a trial block in subclass - end - - - methods(Access = protected) - - function prepare(self) %#ok - % override this function to do extra work before logging conditions. - % For example this could compute a lookup table that the - % condition table will then reference. - % This callback is called when self.conditions have been - % generated but not logged yet. - % Here, populate tables that psy.Condition (or similar) can - % refer to. - - % do nothing by default. - end - - end - - methods - - function win = get.win(self) - win = self.screen.win; - end - - - function rect = get.rect(self) - rect = self.screen.rect; - end - - - function init(self, logger, constants) - if isempty(self.conditions) - % not yet initialized - assert(~isempty(self.params), 'Use setParams first') - disp 'generating conditions' - self.constants = constants; - self.conditions = stims.core.makeFactorialConditions(self.params); - self.prepare() - if ~isempty(logger) - % assign cond_idx to each condition - self.conditions = logger.logConditions(self.conditions, self.paramTable); - end - disp 'conditions ready' - end - end - - - function self = setParams(self, paramTable, varargin) - % set parameters for generating the conditions - self.paramTable = paramTable; - self.params = struct(varargin{:}); - end - end - -end - - - - diff --git a/visual-stimuli/+stims/+core/makeFactorialConditions.m b/visual-stimuli/+stims/+core/makeFactorialConditions.m deleted file mode 100644 index 0f4f585..0000000 --- a/visual-stimuli/+stims/+core/makeFactorialConditions.m +++ /dev/null @@ -1,65 +0,0 @@ -function conditions = makeFactorialConditions(params) -% conditions = makeFactorialConditions(params) makes a structure array with all -% permutations of field values in the structure params. -% -% For example, -% >> params.f1 = 1 -% >> params.f2 = [1 2 3]; -% >> params.f3 = {'one','two'} -% >> conditions = makeFactorialConditions(params) -% -% results in -% -% conditions(1) = -% f1: 1 -% f2: 1 -% f3: 'one' -% conditions(2) = -% f1: 1 -% f2: 2 -% f3: 'one' -% conditions(3) = -% f1: 1 -% f2: 3 -% f3: 'one' -% conditions(4) = -% f1: 1 -% f2: 1 -% f3: 'two' -% conditions(5) = -% f1: 1 -% f2: 2 -% f3: 'two' -% conditions(6) = -% f1: 1 -% f2: 3 -% f3: 'two' - -fields = fieldnames(params); - -% turn all numeric arrays into cell arrays -for iField = 1:length(fields) - n = fields{iField}; - v = params.(n); - if ~iscell(v) - if ischar(v) - params.(n) = {v}; - else - params.(n) = num2cell(v); - end - end -end - -% cartesian product of field values -dims = structfun(@(x) size(x,2), params)'; -[subs{1:length(dims)}] = ind2sub(dims, 1:prod(dims)); -conditions = repmat(cell2struct(repmat({[]}, size(fields)), fields), dims); -for iField = 1:length(fields) - field = fields{iField}; - vals = params.(field); - for idx=1:prod(dims) - conditions(idx).(field) = vals{subs{iField}(idx)}; - end -end -conditions = conditions(:); -end \ No newline at end of file diff --git a/visual-stimuli/+stims/+core/run.m b/visual-stimuli/+stims/+core/run.m deleted file mode 100644 index 6172f39..0000000 --- a/visual-stimuli/+stims/+core/run.m +++ /dev/null @@ -1,94 +0,0 @@ -function run(menu, key) - -% blank the screen and set default luminance -stims.core.Visual.screen.open; -stims.core.Visual.screen.setContrast(3, 0.5); - -% get user input -ch = ' '; -protocol = []; -while ch~='q' - FlushEvents - ch = GetChar; - fprintf('Pressed %c\n', ch) - if ch=='q' - break - elseif ismember(ch, '1':char('0'+length(menu))) - protocol = menu(str2double(ch)); - fprintf('Selected stimulus %c\n', ch); - initProtocol(protocol, key) - disp 'ready to run' - elseif ch=='r' && ~isempty(protocol) - runProtocol(protocol) - end -end -stims.core.Visual.screen.close -end - - -function initProtocol(protocol, key) -init(protocol.logger, key, protocol.constants); -rect = stims.core.Visual.screen.rect; -if ~stims.core.Visual.DEBUG && any([protocol.constants.resolution_x protocol.constants.resolution_y] ~= rect(3:4)) - disp 'Mismatching screen size' - fprintf('Stimulus specifies [%d,%d]\n', protocol.constants.resolution_x, protocol.constants.resolution_y) - fprintf('Screen resolution is [%d,%d]\n', rect(3), rect(4)) - stims.core.Visual.screen.close - error 'incorrect screen resolution' -else - assert(iscell(protocol.stim), 'protocol.stim must be a cell array of structures') - for stim = protocol.stim(:)' - stim{1}.init(protocol.logger, protocol.constants) - end -end -end - - -function runProtocol(protocol) -screen = stims.core.Visual.screen; - -% open parallel pool for trial inserts -if isempty(gcp('nocreate')) - parpool('local', 2); -end - -if ~stims.core.Visual.DEBUG - HideCursor; - Priority(MaxPriority(screen.win)); % Use realtime priority for better temporal precision: -end - -% merge conditions from all display classes into one array and -% append field obj_ to conditions to point back to the displaying class -allConditions = cellfun(@(stim) arrayfun(@(r) r, ... - dj.struct.join(stim.conditions, struct('obj_', stim)), ... - 'uni', false), protocol.stim, 'uni', false); -allConditions = cat(1, allConditions{:}); - -% configure photodiode flips -screen.clearFlipTimes; % just in case -screen.setFlipCount(protocol.logger.getLastFlip) - -screen.escape; % clear the escape -for iBlock = 1:protocol.blocks - for iCond = randperm(length(allConditions)) - cond = dj.struct.join(allConditions{iCond}, protocol.constants); - screen.flip(true, false, true) % clear screen - screen.frameStep = 1; % reset to full frame rate - if screen.escape, break, end - cond.obj_.showTrial(cond) %%%%%% SHOW STIMULUS - if screen.escape, break, end - fprintf . - protocol.logger.logTrial(struct(... - 'cond_idx', cond.cond_idx, ... - 'flip_times', screen.clearFlipTimes, ... - 'last_flip_count', screen.flipCount)) - end - screen.flip(true, false, true) % clear screen at the end of each block - screen.clearFlipTimes; % clean up in case of interrupted trial - if screen.escape, break, end -end - -% restore normal function -Priority(0); -ShowCursor; -end diff --git a/visual-stimuli/+stims/DotMap.m b/visual-stimuli/+stims/DotMap.m deleted file mode 100644 index f6ef1df..0000000 --- a/visual-stimuli/+stims/DotMap.m +++ /dev/null @@ -1,117 +0,0 @@ -classdef DotMap < stims.core.Visual - - properties - nBlocks = 1 - - % DataJoint tables for data logging - logger = stims.core.Logger(psy.Session, psy.Condition, psy.Trial, psy.DotMap) - - % stimulus settings - constants = struct(... - 'stimulus', 'dot map', ... - 'monitor_distance', nan, ... (cm) - 'monitor_size', 19, ... (inches) diagonal - 'monitor_aspect', 1.25, ... - 'resolution_x', 1280, ... (pixels) - 'resolution_y', 1024 ... (pixels) - ) - - params = struct(... - 'rng_seed', 1:44, ... RNG seed - 'luminance', 5, ... cd/m^2 - 'contrast', 0.95, ... Michelson's 0-1 - 'bg_color', 96, ... (0-255) the index of the background color - 'tex_xdim', 15, ... (pixels) texture dimension - 'tex_ydim', 12, ... (pixels) texture dimension - 'frame_downsample', 3, ... 1=60 fps, 2=30 fps, 3=20 fps, 4=15 fps, etc - 'dots_per_frame', 1, ... number of new dots displayed in each frame - 'linger_frames', 5 ... the number of frames each dot persists - ) - end - - - - - methods(Access=protected) - - function showTrial(self, cond) - % execute a single trial with a single cond - % See PsychToolbox DriftDemo4.m for API calls - assert(~isnan(self.constants.monitor_distance), 'monitor distance is not set') - - assert(all(ismember({ - 'rng_seed' - 'luminance' - 'contrast' - 'bg_color' - 'tex_ydim' - 'tex_xdim' - 'frame_downsample' - 'dots_per_frame' - 'linger_frames' - }, fieldnames(cond)))) - - self.screen.setContrast(cond.luminance, cond.contrast) - self.frameStep = cond.frame_downsample; - self.saveAfterEachTrial = true; - - - Screen('FillRect', self.win, cond.bg_color, self.rect) - - [x, y, color] = stims.DotMap.makeDots(cond); - nDots = length(x); - width = self.rect(3)/cond.tex_xdim; - height = self.rect(4)/cond.tex_ydim; - x = x*width; - y = y*height; - rects = [x' y' x'+width y'+height]; - - nFrames = length(x)/cond.dots_per_frame+cond.linger_frames+1; - iDot = 0; - iBlot = -cond.linger_frames*cond.dots_per_frame; - for i=1:nFrames - if self.escape, break, end - for j=1:cond.dots_per_frame - iDot = iDot+1; - iBlot = iBlot+1; - if iDot<=nDots - Screen('FillOval', self.win, color(iDot), rects(iDot,:)) - end - if iBlot>=1 && iBlot<=nDots - Screen('FillOval', self.win, cond.bg_color, rects(iBlot,:)) - end - end - if self.escape, break, end - self.flip(false, true, i==1) - end - if self.escape - self.flip(true, false, true); - end - end - end - - methods(Static) - function [x, y, c] = makeDots(cond) - % set random number generator - r = RandStream.create('mt19937ar', 'Seed', cond.rng_seed); - - % generate non-overlapping dots - success = false; - while ~success - queue = r.randperm(cond.tex_ydim*cond.tex_xdim*2)-1; - pos = bitshift(queue,-1); - success = true; - % prevent dots from occupying the same spot around the same time - for i=1:cond.linger_frames*cond.dots_per_frame-1 - if any(pos(1:end-i) == pos(1+i:end)) - success = false; - break - end - end - end - c = bitand(queue,1)*254; - x = floor(pos/cond.tex_ydim); - y = mod(pos, cond.tex_ydim); - end - end -end \ No newline at end of file diff --git a/visual-stimuli/+stims/FlashingBar.m b/visual-stimuli/+stims/FlashingBar.m deleted file mode 100644 index 442cdca..0000000 --- a/visual-stimuli/+stims/FlashingBar.m +++ /dev/null @@ -1,39 +0,0 @@ -classdef FlashingBar < stims.core.Visual - - - methods - - function showTrial(self, cond) - patterns = [0 31 0 31 10 21 10 21 3 28 6 25 12 19 24 7 17 14]; - ncells = ceil(log2(max(patterns))); - self.screen.setContrast(cond.luminance, cond.contrast) - self.screen.flip(true, false, true) - WaitSecs(cond.pre_blank); - - self.screen.frameStep = round(self.screen.fps/cond.pattern_frequency); - nFrames = floor(cond.trial_duration*self.screen.fps/self.screen.frameStep); - theta = (cond.orientation-90)/180*pi; % 0 = north, 90 = east - - scale = norm(self.rect(3:4))/2; - halfWidth = scale*cond.width; - halfLength = 0.9*scale; - - current_pattern = 1; - for i=1:nFrames - Screen('FillRect', self.win, cond.bg_color, self.rect) % background - if self.screen.escape, break, end - if i0 - if cond.second_photodiode - rectSize = [0.05 0.06].*self.rect(3:4); - rect = [self.rect(3)-rectSize(1), 0, self.rect(3), rectSize(2)]; - Screen('FillRect', self.win, 0, rect); - end - - % display black photodiode rectangle during the pre-blank - self.screen.flip(false, false, true) - WaitSecs(cond.pre_blank); - end - - % update direction to correspond to 0=north, 90=east, 180=south, 270=west - direction = cond.direction + 90; - - - % display drifting grating - driftFrames1 = floor(cond.trial_duration * (1-cond.phase2_fraction) * self.screen.fps); - driftFrames2 = floor(cond.trial_duration * cond.phase2_fraction * self.screen.fps); - phaseIncrement1 = cond.temp_freq/self.screen.fps; - phaseIncrement2 = cond.phase2_temp_freq/self.screen.fps; - offset = [cond.aperture_x cond.aperture_y]*norm(self.rect(3:4))/2; - destRect = self.rect + [offset offset]; - % display phase1 grating - for frame = 1:driftFrames1 - if self.screen.escape, break, end - Screen('DrawTexture', self.win, self.grating, [], destRect, direction, [], [], [], [], ... - kPsychUseTextureMatrixForRotation, [phase*360, freq, 0.495, 0]); - if ~isempty(self.mask) - Screen('DrawTexture', self.win, self.mask); - end - if cond.second_photodiode - rectSize = [0.05 0.06].*self.rect(3:4); - rect = [self.rect(3)-rectSize(1), 0, self.rect(3), rectSize(2)]; - if frame/self.screen.fps >= cond.second_photodiode_time - color = (cond.second_photodiode+1)/2*255; - Screen('FillRect', self.win, color, rect); - else - Screen('FillRect', self.win, 0, rect); - end - end - phase = phase + phaseIncrement1; - self.screen.flip(false, false, frame==1) - end - % display phase2 grating - for frame = 1:driftFrames2 - if self.screen.escape, break, end - Screen('DrawTexture', self.win, self.grating, [], destRect, direction, [], [], [], [], ... - kPsychUseTextureMatrixForRotation, [phase*360, freq, 0.495, 0]); - if ~isempty(self.mask) - Screen('DrawTexture', self.win, self.mask); - end - phase = phase + phaseIncrement2; - self.screen.flip(false, false, frame==1) - end - end - end -end \ No newline at end of file diff --git a/visual-stimuli/+stims/Looming.m b/visual-stimuli/+stims/Looming.m deleted file mode 100644 index 56bd275..0000000 --- a/visual-stimuli/+stims/Looming.m +++ /dev/null @@ -1,79 +0,0 @@ -classdef Looming < stims.core.Visual - - properties - - nBlocks = 20 - - % DataJoint tables for data logging - logger = stims.core.Logger(psy.Session, psy.Condition, psy.Trial, psy.Looming) - - tables = struct(... - 'session', psy.Session, ... - 'condition', psy.Condition, ... - 'parameters', psy.Looming, ... - 'trial', psy.Trial) - - % stimulus settings - constants = struct(... - 'stimulus', 'looming disk', ... - 'monitor_distance', nan, ... (cm) - 'monitor_size', 7, ... (inches) diagonal - 'monitor_aspect', 1.7, ... (physical aspect ratio W/H) - 'resolution_x', 1024, ... (pixels) - 'resolution_y', 600 ... (pixels) - ) - - params = struct(... - 'luminance', 5, ... : cd/m^2 - 'contrast', 0.95, ... : float # 0 .. 1 - 'bg_color', 0.5, ... # 0 .. 1 - 'color', 0, ... : float # 0 .. 1 - 'pre_blank', 6, ... : float # seconds - blank screen duration - 'looming_rate', [0.5 1 2], ... : float # 1/sec -- speed / object size - 'loom_duration', 2, ... : float # seconds - 'final_radius', 30 ... : float # degrees - ) - end - - - - methods(Access=protected) - - function showTrial(self, cond) - % execute a single trial with a single cond - % See PsychToolbox DriftDemo4.m for API calls - assert(~isnan(self.constants.monitor_distance), 'monitor distance is not set') - - assert(all(ismember({ - 'luminance' - 'contrast' - 'bg_color' - 'color' - 'pre_blank' - 'looming_rate' - 'loom_duration' - 'final_radius' - }, fieldnames(cond)))) - - self.screen.setContrast(cond.luminance, cond.contrast) - self.flip(true, false, true) - WaitSecs(cond.pre_blank); - - nFrames = floor(cond.loom_duration*self.screen.fps); - - center = self.rect(3:4)/2; - monitorHeight = self.constants.monitor_size/sqrt(self.constants.monitor_aspect.^2+1)*2.54; % cm - pixDistance = self.rect(4)/monitorHeight*self.constants.monitor_distance; % distance to monitor in pixels - pixFinalRadius = pixDistance*tan(cond.final_radius*pi/180); - for i=1:nFrames - if self.escape, break, end - Screen('FillRect', self.win, round(cond.bg_color*255), self.rect) - remainingTime = cond.loom_duration-(i-1)/self.screen.fps; - radius = pixFinalRadius/(1 + cond.looming_rate*remainingTime*pixFinalRadius/pixDistance); - rect = [center center] + [-radius -radius radius radius]; - Screen('FillOval', self.win, round(cond.color*255), rect); - self.flip(false, false, i==1) - end - end - end -end \ No newline at end of file diff --git a/visual-stimuli/+stims/Movie.m b/visual-stimuli/+stims/Movie.m deleted file mode 100644 index 36157d5..0000000 --- a/visual-stimuli/+stims/Movie.m +++ /dev/null @@ -1,21 +0,0 @@ -classdef Movie < stims.core.Visual - methods - function showTrial(self, cond) - moviename = sprintf(cond.path_template, cond.clip_number); - disp(moviename) - movie = Screen('OpenMovie', self.win, moviename); - Screen('PlayMovie', movie,1); - for i=1:ceil(cond.cut_after*self.screen.fps) - if self.screen.escape, break, end - tex = Screen('GetMovieImage', self.win, movie); - if tex<=0 - break - end - Screen('DrawTexture', self.win, tex, [], self.rect) - self.screen.flip(false, false, i==1) - Screen('close',tex) - end - Screen('CloseMovie',movie) - end - end -end \ No newline at end of file diff --git a/visual-stimuli/+stims/MovieClip.m b/visual-stimuli/+stims/MovieClip.m deleted file mode 100644 index 7612bbf..0000000 --- a/visual-stimuli/+stims/MovieClip.m +++ /dev/null @@ -1,39 +0,0 @@ -classdef MovieClip < stims.core.Visual - - methods(Access = protected) - - function prepare(self) - % precompute the filenames for all conditions - filenames = cell(size(self.conditions)); - for i=1:length(self.conditions) - filenames{i} = sprintf(... - fetch1(psy.MovieInfo & self.conditions(i), 'path_template'), ... - self.conditions(i).clip_number); - if ~exist(filenames{i}, 'file') - stims.core.Visual.screen.close() - error('Could not find file %s', filenames{i}) - end - end - [self.conditions.filename] = deal(filenames{:}); - end - end - - methods - - function showTrial(self, cond) - movie = Screen('OpenMovie', self.win, cond.filename); - Screen('PlayMovie', movie,1); - for i=1:ceil(cond.cut_after*self.screen.fps) - if self.screen.escape, break, end - tex = Screen('GetMovieImage', self.win, movie); - if tex<=0 - break - end - Screen('DrawTexture', self.win, tex, [], self.rect) - self.screen.flip(false, false, i==1) - Screen('close',tex) - end - Screen('CloseMovie',movie) - end - end -end \ No newline at end of file diff --git a/visual-stimuli/+stims/MovieSeq.m b/visual-stimuli/+stims/MovieSeq.m deleted file mode 100644 index d779121..0000000 --- a/visual-stimuli/+stims/MovieSeq.m +++ /dev/null @@ -1,45 +0,0 @@ -classdef MovieSeq < stims.core.Visual - - methods(Access = protected) - - function prepare(self) - sequences = cell(size(self.conditions)); - for i=1:length(self.conditions) - assert(count(psy.MovieStillStore & self.conditions(i))==1, ... - 'There should be one MovieStillStore') - ids = fetchn(psy.MovieStill & self.conditions(i), 'still_id')'; - rng(self.conditions(i).rng_seed); - sequences{i} = randsample(ids, self.conditions(i).seq_length); - end - [self.conditions.movie_still_ids] = deal(sequences{:}); - end - end - - - methods - - function showTrial(self, cond) - for id = cond.movie_still_ids - img = fetch1(psy.MovieStill & cond & struct('still_id',id), 'still_frame'); - - % blank the screen if there is a blanking period - if cond.pre_blank_period>0 - if cond.second_photodiode - rectSize = [0.05 0.06].*self.rect(3:4); - rect = [self.rect(3)-rectSize(1), 0, self.rect(3), rectSize(2)]; - Screen('FillRect', self.win, 0, rect); - end - % display black photodiode rectangle during the pre-blank - self.screen.flip(false, false, true) - WaitSecs(cond.pre_blank_period); - end - - tex = Screen('MakeTexture', self.win, img); - Screen('DrawTexture', self.win, tex, [], self.rect) - self.screen.flip(false, false, true) - Screen('close',tex) - WaitSecs(cond.duration); - end - end - end -end \ No newline at end of file diff --git a/visual-stimuli/+stims/MovieStill.m b/visual-stimuli/+stims/MovieStill.m deleted file mode 100644 index 8df6a46..0000000 --- a/visual-stimuli/+stims/MovieStill.m +++ /dev/null @@ -1,27 +0,0 @@ -classdef MovieStill < stims.core.Visual - - methods - - function showTrial(self, cond) - img = fetch1(psy.MovieStill & cond, 'still_frame'); - - % blank the screen if there is a blanking period - if cond.pre_blank_period>0 - if cond.second_photodiode - rectSize = [0.05 0.06].*self.rect(3:4); - rect = [self.rect(3)-rectSize(1), 0, self.rect(3), rectSize(2)]; - Screen('FillRect', self.win, 0, rect); - end - % display black photodiode rectangle during the pre-blank - self.screen.flip(false, false, true) - WaitSecs(cond.pre_blank_period); - end - - tex = Screen('MakeTexture', self.win, img); - Screen('DrawTexture', self.win, tex, [], self.rect) - self.screen.flip(false, false, true) - Screen('close',tex) - WaitSecs(cond.duration); - end - end -end \ No newline at end of file diff --git a/visual-stimuli/+stims/MovingBar.m b/visual-stimuli/+stims/MovingBar.m deleted file mode 100644 index 9eefd82..0000000 --- a/visual-stimuli/+stims/MovingBar.m +++ /dev/null @@ -1,88 +0,0 @@ -classdef MovingBar < stims.core.Visual - - properties - - - % stimulus settings - - params = struct(... - 'pre_blank', 0, ... (s) blank period preceding trials - 'luminance', 5, ... cd/m^2 mid-value luminance" - 'contrast', 0.95, ... Michelson contrast - 'bg_color', 127, ... 0-254 - 'bar_color', 254, ... 0-254 - 'direction', 0:45:359, ... (degrees) 0=north, 90=east - 'bar_length', 1, ... in units of half-diagonal - 'bar_width', 0.04, ... in units of half-diagonal - 'bar_offset', 0, ... offset to the right (when facing in direction of motion) in units of half-diagonal - 'start_pos', -1, ... the starting position of the bar moviement. 1 is the distance from the center to corner" - 'end_pos', 1, ... (-1 1) the ending position of the bar movement - 'trial_duration', 6 ... (s) movement duration - ) - end - - properties(Access=private) - grating - end - - - methods - function d = degPerPix(self) - % assume isometric pixels - d = 180/pi*self.constants.monitor_size*2.54/norm(self.rect(3:4))/self.constants.monitor_distance; - end - end - - - methods(Access=protected) - - function showTrial(self, cond) - % execute a single trial with a single cond - % See PsychToolbox DriftDemo4.m for API calls - assert(~isnan(self.constants.monitor_distance), 'monitor distance is not set') - - assert(all(ismember({ - 'pre_blank' - 'luminance' - 'contrast' - 'bg_color' - 'bar_color' - 'direction' - 'bar_length' - 'bar_width' - 'bar_offset' - 'start_pos' - 'end_pos' - 'trial_duration' - }, fieldnames(cond)))) - - self.screen.setContrast(cond.luminance, cond.contrast) - self.flip(true, false, true) - WaitSecs(cond.pre_blank); - - nFrames = floor(cond.trial_duration*self.screen.fps); - theta = (cond.direction-90)/180*pi; % 0 = north, 90 = east - - scale = norm(self.rect(3:4))/2; - tex = Screen('MakeTexture', self.win, cond.bar_color); - halfWidth = scale*cond.bar_width; - halfLength = scale*cond.bar_length; - - for i=1:nFrames - if self.escape, break, end - - Screen('FillRect', self.win, cond.bg_color, self.rect) - y0= cond.bar_offset; - x0= cond.start_pos + (cond.end_pos-cond.start_pos)*(i-1)/(nFrames-1); - - x = x0*cos(theta) - y0*sin(theta); - y = x0*sin(theta) + y0*cos(theta); - x = x*scale + self.rect(3)/2; - y = y*scale + self.rect(4)/2; - - Screen('DrawTexture', self.win, tex, [], [x-halfWidth, y-halfLength, x+halfWidth, y+halfLength], cond.direction-90) - self.flip(false, false, i==1) - end - end - end -end \ No newline at end of file diff --git a/visual-stimuli/+stims/MovingNoise.m b/visual-stimuli/+stims/MovingNoise.m deleted file mode 100644 index 9135278..0000000 --- a/visual-stimuli/+stims/MovingNoise.m +++ /dev/null @@ -1,58 +0,0 @@ -classdef MovingNoise < stims.core.Visual - - methods(Access=protected) - - function d = degPerPix(self) - % assume isometric pixels - rect = self.rect; - if isempty(rect) - rect = [0 0 1024 600]; - end - d = 180/pi*self.constants.monitor_size*2.54/norm(rect(3:4))/self.constants.monitor_distance; - end - - function prepare(self) - if ~isfield(self.conditions, 'movie') - % pre-compute movies - disp 'making movies' - rect = self.rect; - if isempty(rect) - rect = [0 0 1024 600]; - end - fps = self.screen.fps; - if isempty(fps) - disp 'Not using display. Using 60 fps default' - fps = 60; - end - newConditions = []; - for iCond=1:length(self.conditions) - fprintf . - cond = self.conditions(iCond); - lookup = psy.MovingNoiseLookup; - [movie, key] = ... - lookup.lookup(cond, self.degPerPix*rect(3:4), ... - fps/cond.frame_downsample); - cond = dj.struct.join(self.conditions(iCond), key); - cond.movie = max(1, min(254, movie)); % 0 and 255 are reserved for flips - newConditions = [newConditions; cond]; %#ok - end - fprintf \n - self.conditions = newConditions; - end - end - end - - methods - function showTrial(self, cond) - self.screen.setContrast(cond.luminance, cond.contrast) - self.screen.frameStep = cond.frame_downsample; - for i=1:size(cond.movie,3) - if self.screen.escape, break, end - tex = Screen('MakeTexture', self.win, cond.movie(:,:,i)); - Screen('DrawTexture',self.win, tex, [], self.rect) - self.screen.flip(false, false, i==1) - Screen('close',tex) - end - end - end -end \ No newline at end of file diff --git a/visual-stimuli/+stims/NaturalMovie.m b/visual-stimuli/+stims/NaturalMovie.m deleted file mode 100644 index d80afd7..0000000 --- a/visual-stimuli/+stims/NaturalMovie.m +++ /dev/null @@ -1,112 +0,0 @@ -classdef NaturalMovie < stims.core.Visual - - properties - nBlocks = 1 - - params = struct(... - 'type', 'nat', ... natural or phase scrambled - 'luminance', 5, ... cd/m^2 - 'contrast', 0.95, ... Michelson's 0-1 - 'movie_path', '~/Desktop/', ...file path for the movies - 'movie_number', 7, ... (int) the number of movie - 'aperture_radius', 0.63, ... % in units of half-diagonal, 0=no aperture - 'aperture_x', 0, ... % 0=center, in units of half-diagonal - 'aperture_y', 0, ... % 0=center, in units of half-diagonal - 'frame_downsample', 2, ... 1=60 fps, 2=30 fps, 3=20 fps, 4=15 fps, etc - 'duration', 10, ... (s) trial duration - 'pre_blank', 1 ... (s) pre trial blank duration - ) - end - - - methods - function d = degPerPix(self) - % assume isometric pixels - d = 180/pi*self.constants.monitor_size*2.54/norm(self.rect(3:4))/self.constants.monitor_distance; - end - - - function init(self, varargin) - init@stims.core.Visual(self, varargin{:}); - if ~isfield(self.conditions, 'movie') - % pre-compute movies - disp 'making movies' - - movies = cell(size(self.conditions)); - for iCond=1:length(self.conditions) - fprintf . - cond = self.conditions(iCond); - movies{iCond} = ... - stims.NaturalMovie.makeMovie(cond, self.screen.fps/cond.frame_downsample); - end - fprintf \n - [self.conditions(:).movie] = deal(movies{:}); - end - end - end - - methods(Access=protected) - - function showTrial(self, cond) - % execute a single trial with a single cond - % See PsychToolbox DriftDemo4.m for API calls - assert(~isnan(self.constants.monitor_distance), 'monitor distance is not set') - - assert(all(ismember({ - 'type' - 'luminance' - 'contrast' - 'movie_path' - 'movie_number' - 'aperture_radius' - 'aperture_x' - 'aperture_y' - 'frame_downsample' - 'duration' - 'pre_blank' - 'movie' - }, fieldnames(cond)))) - - % display black syn photodiode rectange during the pre blank - if cond.pre_blank>0 - % display black photodiode rectangle during the pre-blank - self.flip(false, false, true) - WaitSecs(cond.pre_blank); - end -% self.screen.setContrast(cond.luminance, cond.contrast) - self.screen.frameStep = cond.frame_downsample; - self.saveAfterEachTrial = true; - for i=1:size(cond.movie,3) - if self.escape, break, end - tex = Screen('MakeTexture', self.win, cond.movie(:,:,i)); - Screen('DrawTexture',self.win, tex, [], self.rect) - self.flip(false, false, i==1) - end - end - end - - - - methods(Static) - function m = makeMovie(cond, fps) - % load movie - % INPUTS: - % cond - condition parameters - % fps - frames per second - - % create gaussian movie - nFrames = round(cond.duration*fps/2)*2; - % load movie - movie_name = [cond.movie_path 'mov' num2str(cond.movie_number) '_' cond.type '.avi']; - movieObj = VideoReader(movie_name); - sz = get(0,'screensize'); sz = sz(3:4); - for ii = 1:nFrames - temp_img = read(movieObj,ii); - temp_img = temp_img(:,:,1); - m(:,:,ii) = imresize(temp_img,[sz(2),sz(1)]); - end - - end - - end -end \ No newline at end of file diff --git a/visual-stimuli/+stims/NoiseMap.m b/visual-stimuli/+stims/NoiseMap.m deleted file mode 100644 index bd4b56d..0000000 --- a/visual-stimuli/+stims/NoiseMap.m +++ /dev/null @@ -1,86 +0,0 @@ -classdef NoiseMap < stims.core.Visual - - properties - nBlocks = 1 - - params = struct(... - 'rng_seed', 1:150, ... RNG seed - 'luminance', 10, ... cd/m^2 - 'contrast', 0.95, ... Michelson's 0-1 - 'tex_ydim', 150, ... (pixels) texture dimension - 'tex_xdim', 256, ... (pixels) texture dimension - 'spatial_freq_half', 0.05, ... (cy/deg) spatial frequency modulated to 50 - 'spatial_freq_stop',0.2, ... (cy/deg), spatial lowpass cutoff - 'temp_bandwidth',12, ... (Hz) temporal bandwidth - 'contrast_mod_freq', 1/6, ... (Hz) raised cosine contrast modulation - 'contrast_slope', 5, ... onset slope - 'modulation_shift', 0.2, ... shift of the signamoid argument (cosine value) - 'frame_downsample', 1, ... 1=60 fps, 2=30 fps, 3=20 fps, 4=15 fps, etc - 'duration', 6 ... (s) trial duration - ) - end - - - methods - function d = degPerPix(self) - % assume isometric pixels - d = 180/pi*self.constants.monitor_size*2.54/norm(self.rect(3:4))/self.constants.monitor_distance; - end - end - - methods(Access=protected) - - function prepare(self) - if ~isfield(self.conditions, 'movie') - % pre-compute movies - disp 'making movies' - newConditions = []; - for iCond=1:length(self.conditions) - fprintf . - cond = self.conditions(iCond); - lookup = psy.NoiseMapLookup; - [movie, key] = ... - lookup.lookup(cond, self.degPerPix*self.rect(3:4), ... - self.screen.fps/cond.frame_downsample); - cond = dj.struct.join(self.conditions(iCond), key); - cond.movie = movie; - newConditions = [newConditions; cond]; %#ok - end - fprintf \n - self.conditions = newConditions; - end - end - - function showTrial(self, cond) - % execute a single trial with a single cond - % See PsychToolbox DriftDemo4.m for API calls - assert(~isnan(self.constants.monitor_distance), 'monitor distance is not set') - - assert(all(ismember({ - 'rng_seed' - 'luminance' - 'contrast' - 'tex_ydim' - 'tex_xdim' - 'spatial_freq_half' - 'spatial_freq_stop' - 'temp_bandwidth' - 'contrast_mod_freq' - 'duration' - 'frame_downsample' - 'movie' - }, fieldnames(cond)))) - - self.screen.setContrast(cond.luminance, cond.contrast) - self.frameStep = cond.frame_downsample; - self.saveAfterEachTrial = true; - for i=1:size(cond.movie,3) - if self.escape, break, end - tex = Screen('MakeTexture', self.win, cond.movie(:,:,i)); - Screen('DrawTexture',self.win, tex, [], self.rect) - self.flip(false, false, i==1) - Screen('close',tex) - end - end - end -end \ No newline at end of file diff --git a/visual-stimuli/+stims/Pause.m b/visual-stimuli/+stims/Pause.m deleted file mode 100644 index 9f001a7..0000000 --- a/visual-stimuli/+stims/Pause.m +++ /dev/null @@ -1,19 +0,0 @@ -classdef Pause - properties - duration % seconds - end - - methods - function self = Pause(duration) - self.duration = duration; - end - - function init(varargin) - % do nothin' - end - - function run(self) - WaitSecs(self.duration); - end - end -end \ No newline at end of file diff --git a/visual-stimuli/+stims/Trippy.m b/visual-stimuli/+stims/Trippy.m deleted file mode 100644 index 37dcf1e..0000000 --- a/visual-stimuli/+stims/Trippy.m +++ /dev/null @@ -1,64 +0,0 @@ -classdef Trippy < stims.core.Visual - - methods(Access=protected) - - function d = degPerPix(self) - % assume isometric pixels - rect = self.rect; - if isempty(rect) - rect = [0 0 1024 600]; - end - d = 180/pi*self.constants.monitor_size*2.54/norm(rect(3:4))/self.constants.monitor_distance; - end - - - function prepare(self) - if ~isfield(self.conditions, 'movie') - disp 'precomuting movies...' - rect = self.rect; - if isempty(rect) - rect = [0 0 1024 600]; - end - fps = self.screen.fps; - if isempty(fps) - fps = 60; - end - newConditions = []; - for iCond=1:length(self.conditions) - fprintf . - cond = self.conditions(iCond); - cond.packed_phase_movie = ... - psy.Trippy.make_packed_phase_movie(... - cond, fps/cond.frame_downsample, self.degPerPix*rect(3:4)); - cond.version = psy.Trippy.version; - newConditions = [newConditions; cond]; %#ok - end - fprintf \n - self.conditions = newConditions; - end - end - end - - methods - function showTrial(self, cond) - % execute a single trial with a single cond - fps = self.screen.fps; - if isempty(fps) - fps = 60; - end - assert(~isnan(self.constants.monitor_distance), 'monitor distance is not set') - self.screen.setContrast(cond.luminance, cond.contrast) - self.screen.frameStep = cond.frame_downsample; - movie = psy.Trippy.interp_time(cond.packed_phase_movie, cond, fps/cond.frame_downsample); - for i=1:size(movie,1) - if self.screen.escape, break, end - m = psy.Trippy.interp_space(movie(i,:), cond); - m = (cos(2*pi*m)+1)/2*253+1; - tex = Screen('MakeTexture', self.win, m); - Screen('DrawTexture', self.win, tex, [], self.rect) - self.screen.flip(false, false, i==1) - Screen('close', tex) % delete the texture - end - end - end -end \ No newline at end of file diff --git a/visual-stimuli/+stims/VanGogh.m b/visual-stimuli/+stims/VanGogh.m deleted file mode 100644 index fcabbc5..0000000 --- a/visual-stimuli/+stims/VanGogh.m +++ /dev/null @@ -1,76 +0,0 @@ -classdef VanGogh < stims.core.Visual - - methods(Access=protected) - - function d = degPerPix(self) - % assume isometric pixels - rect = self.rect; - if isempty(rect) % hack for precomputing - rect = [0 0 1024 600]; - end - d = 180/pi*self.constants.monitor_size*2.54/norm(rect(3:4))/self.constants.monitor_distance; - end - - - function prepare(self) - if ~isfield(self.conditions, 'movie') - % pre-compute movies - disp 'making movies' - newConditions = []; - for iCond=1:length(self.conditions) - fprintf . - cond = self.conditions(iCond); - lookup = psy.VanGoghLookup; - rect = self.rect; - if isempty(rect) - rect = [0 0 1024 600]; % hack! - end - fps = self.screen.fps; - if isempty(fps) - fps = 60; % hack! - end - [movie, key] = ... - lookup.lookup(cond, self.degPerPix*rect(3:4), ... - fps/cond.frame_downsample); - cond = dj.struct.join(self.conditions(iCond), key); - cond.movie = max(1,min(254, movie)); % 0 and 255 are reserved for flips - newConditions = [newConditions; cond]; %#ok - end - fprintf \n - self.conditions = newConditions; - end - end - end - - - methods - function showTrial(self, cond) - % execute a single trial with a single cond - % See PsychToolbox DriftDemo4.m for API calls - assert(~isnan(self.constants.monitor_distance), 'monitor distance is not set') - - assert(all(ismember({ - 'rng_seed' - 'luminance' - 'contrast' - 'tex_ydim' - 'tex_xdim' - 'spatial_freq_half' - 'spatial_freq_stop' - 'temp_bandwidth' - 'frame_downsample' - 'movie' - }, fieldnames(cond)))) - - self.screen.setContrast(cond.luminance, cond.contrast) - self.screen.frameStep = cond.frame_downsample; - for i=1:size(cond.movie,3) - if self.escape, break, end - tex = Screen('MakeTexture', self.win, cond.movie(:,:,i)); - Screen('DrawTexture',self.win, tex, [], self.rect) - self.screen.flip(false, false, i==1) - Screen('close',tex) - end - end - end -end \ No newline at end of file diff --git a/visual-stimuli/+stims/cajalmenu.m b/visual-stimuli/+stims/cajalmenu.m deleted file mode 100644 index 1028efb..0000000 --- a/visual-stimuli/+stims/cajalmenu.m +++ /dev/null @@ -1,249 +0,0 @@ -function choices = cajalmenu() - -logger = @() stims.core.Logger(psy.Session, psy.Condition, psy.Trial); - -stims.core.Visual.screen.enableContrast(false); % when false, disables contrast and brightness settings and uses default monitor settings - -constants = struct(... - 'monitor_distance', 15, ... (cm) - 'monitor_size', 25, ... (inches) diagonal - 'monitor_aspect', 1.78, ... (physical aspect ratio W/H) - 'resolution_x', 1920, ... (pixels) - 'resolution_y', 1080 ... (pixels) - ); - - -quadrantGrating = struct(... - 'prompt', 'Shan''s quadrant grating (960 s)', ... - 'logger', logger(), ... - 'constants', setfield(constants, 'stimulus', 'grating'), ... - 'blocks', 8, ... - 'stim', {{ - setParams(stims.Grating, psy.Grating, ... - 'pre_blank', 3, ... - 'luminance', 10, ... - 'contrast', 0.95, ... - 'trial_duration', 2, ... - 'direction', [90, 180], ... - 'init_phase', 0, ... - 'grating', 'sqr', ... 'sqr or 'sin' - 'aperture_radius', 0.15, ... - 'aperture_x', [-0.4,0.2], ... - 'aperture_y', [-0.36,0.32], ... - 'temp_freq', 4, ... - 'spatial_freq', 0.08, ... - 'phase2_fraction', 0, ... between 0 and 1 - 'phase2_temp_freq', 2, ... - 'second_photodiode', 0, ... 1 = paint white photodiode patch, -1=black, 0=none - 'second_photodiode_time', 0 ... (s) time delay of the second photodiode to the onset of the stimulus - ) - }}); %#ok - - -flashingBar = struct(... - 'prompt', 'flashing bar (3 min)', ... - 'logger', logger(), ... - 'constants', setfield(constants, 'stimulus', 'flashing bar'), ... - 'blocks', 2, ... - 'stim', {{ - setParams(stims.FlashingBar, psy.FlashingBar, ... - 'pre_blank', 1.0, ... (s) blank period preceding trials - 'luminance', 30, ... cd/m^2 mid-value luminance" - 'contrast', 0.99, ... Michelson contrast - 'bg_color', 127, ... 0-254 - 'orientation', [0 90], ... (degrees) 0=north, 90=east - 'offset', -linspace(-0.6, 0.6, 30), ... normalized by half-diagonal - 'width', 0.02, ... normalized by half-diagonal - 'trial_duration', 0.5, ... (s) ON time of flashing bar - 'pattern_frequency', 20 ... (Hz) will be rounded to nearest fraction of fps - ) - }}); %#ok - - -movingNoise = struct(... - 'prompt', 'Monet (30 min)', ... - 'logger', logger(), ... - 'constants', setfield(constants, 'stimulus', 'grating'), ... - 'blocks', 1, ... % 100 for imaging @38000 frames - 'stim', {{ - setParams(stims.MovingNoise, psy.MovingNoise, ... - 'rng_seed', 1:30, ... RNG seed 1:30 - 'luminance', 10, ... cd/m^2 - 'contrast', 0.95, ... Michelson's 0-1 - 'tex_ydim', 90, ... (pixels) texture dimension - 'tex_xdim', 160, ... (pixels) texture dimension - 'spatial_freq_half', 0.04, ... deprecated in version 3 -- (cy/deg) spatial frequency modulated to 50 - - 'spatial_freq_stop',0.08, ... (cy/deg), spatial lowpass cutoff - 'temp_bandwidth',4, ... (Hz) temporal bandwidth - 'frame_downsample', 1, ... 1=60 fps, 2=30 fps, 3=20 fps, 4=15 fps, etc - 'n_dirs', 16, ... number of directions of motion - 'ori_bands', 2, ... orientation width expressed in units of 2*pi/n_dirs. Must be integer - 'ori_modulation', 1, ... mix-in proportion of oriented noise - 'ori_on_secs', 1.0, ... seconds of movement and orientation bias - 'ori_off_secs', 2.75, ... second with no movement or orientation bias - 'speed', 20 ... degrees per second - ) - }}); %#ok - - -vanGogh = struct(... - 'prompt', 'Van Gogh (30 min)', ... - 'logger', logger(), ... - 'constants', setfield(constants, 'stimulus', 'vangogh'), ... - 'blocks', 1, ... - 'stim', {{ - setParams(stims.VanGogh, psy.VanGogh, ... - 'rng_seed', 1:60, ... RNG seed 1:150 - 'frame_downsample', 1, ... 1=60 fps, 2=30 fps, 3=20 fps, 4=15 fps, etc - 'luminance', 10, ... cd/m^2 - 'contrast', 0.95, ... Michelson's 0-1 - 'duration', 30, ... (seconds) - 'tex_ydim', 90, ... (pixels) texture dimension - 'tex_xdim', 160, ... (pixels) texture dimension - 'spatial_freq_half', 0.04, ... (cy/deg) spatial frequency modulated to 50 - deprecated in version 3 - 'spatial_freq_stop', 0.3, ... (cy/deg), spatial lowpass cutoff - 'temp_bandwidth', 4, ... (Hz) temporal bandwidth - 'ori_bandwidth', pi / 20, ... (rad) bandwidth of orientation filter - 'ori_map_spatial_bandwidth', 0.05, ... (cy/deg) spatial bandwidth for ori map - 'ori_map_temp_bandwidth', 1, ... (Hz) temporal bandwidth for ori map - 'contrast_spatial_bandwidth', 0.03, ... (cy/deg) spatial bandwidth of contrast map - 'contrast_temp_bandwidth', 1, ... (Hz) temporal bandwidth of contrast map - 'contrast_exponent', 1/3 ... exponent of power function for contrast map - ) - }}); %#ok - -trippy = struct(... - 'prompt', 'Trippy (30 mins)', ... - 'logger', logger(), ... - 'constants', setfield(constants, 'stimulus', 'trippy'), ... - 'blocks', 1, ... - 'stim', {{ - setParams(stims.Trippy, psy.Trippy, ... - 'rng_seed', 1:30, ... RNG seed 1:150 - 'frame_downsample', 1, ... 1=60 fps, 2=30 fps, 3=20 fps, 4=15 fps, etc - 'luminance', 10, ... cd/m^2 - 'contrast', 0.95, ... Michelson's 0-1 - 'duration', 60, ... (seconds) - 'tex_ydim', 90, ... (pixels) texture dimension - 'tex_xdim', 160, ... (pixels) texture dimension - 'xnodes', 8, ... % x dimension of low-res phase movie - 'ynodes', 6, ... % y dimension of low-res phase movie - 'up_factor', 24, ... % upscale factor from low-res to texture dimensions - 'temp_freq', 2.5, ... % (Hz) temporal frequency if the phase pattern were static - 'temp_kernel_length', 61, ... % length of Hanning kernel used for temporal filter. Controls the rate of change of the phase pattern. - 'spatial_freq', 0.06 ... % (cy/degree) approximate max. Actual frequency spectrum ranges propoprtionally. - )}}); %#ok - - -trippyMonet = struct( ... - 'prompt', 'TrippyMonet (40 mins)', ... - 'logger', logger(), ... - 'constants', setfield(constants, 'stimulus', 'grating'), ... - 'blocks', 1, ... - 'stim', {{ - setParams(stims.Trippy, psy.Trippy, ... - 'rng_seed', 1:20, ... RNG seed 1:150 - 'frame_downsample', 1, ... 1=60 fps, 2=30 fps, 3=20 fps, 4=15 fps, etc - 'luminance', 10, ... cd/m^2 - 'contrast', 0.95, ... Michelson's 0-1 - 'duration', 60, ... (seconds) - 'tex_ydim', 90, ... (pixels) texture dimension - 'tex_xdim', 160, ... (pixels) texture dimension - 'xnodes', 8, ... % x dimension of low-res phase movie - 'ynodes', 6, ... % y dimension of low-res phase movie - 'up_factor', 24, ... % upscale factor from low-res to texture dimensions - 'temp_freq', 2.5, ... % (Hz) temporal frequency if the phase pattern were static - 'temp_kernel_length', 61, ... % length of Hanning kernel used for temporal filter. Controls the rate of change of the phase pattern. - 'spatial_freq', 0.06 ... % (cy/degree) approximate max. Actual frequency spectrum ranges propoprtionally. - ) - setParams(stims.MovingNoise, psy.MovingNoise, ... - 'rng_seed', 1:20, ... RNG seed 1:60 - 'luminance', 10, ... cd/m^2 - 'contrast', 0.95, ... Michelson's 0-1 - 'tex_ydim', 90, ... (pixels) texture dimension - 'tex_xdim', 160, ... (pixels) texture dimension - 'spatial_freq_half', 0.04, ... deprecated in version 3 -- (cy/deg) spatial frequency modulated to 50 - - 'spatial_freq_stop',0.08, ... (cy/deg), spatial lowpass cutoff - 'temp_bandwidth',4, ... (Hz) temporal bandwidth - 'frame_downsample', 1, ... 1=60 fps, 2=30 fps, 3=20 fps, 4=15 fps, etc - 'n_dirs', 16, ... number of directions of motion - 'ori_bands', 2, ... orientation width expressed in units of 2*pi/n_dirs. Must be integer - 'ori_modulation', 0, ... mix-in proportion of oriented noise - 'ori_on_secs', 1.75, ... seconds of movement and orientation bias - 'ori_off_secs', 2, ... second with no movement or orientation bias - 'speed', 0 ... degrees per second - ) - }}); %#ok - -s = RandStream('mt19937ar','Seed','shuffle'); -madmax = struct( ... - 'prompt', 'Madmax (2 hours)', ... - 'logger', logger(), ... - 'constants', setfield(constants, 'stimulus', 'madmax'), ... - 'blocks', 1, ... - 'stim', {{ - - setParams(stims.MovieClip, psy.MovieClipCond, ... - 'movie_name', 'MadMax', ... - 'clip_number', 1:110, ... - 'cut_after', 60 ... - ) - - setParams(stims.MovieClip, psy.MovieClipCond, ... - 'movie_name', 'MadMax', ... - 'clip_number', sort(repmat(randperm(s,110,2),1,30)), ... 10 sec each - 'cut_after', 10 ... - ) - - }}); %#ok - - -s = RandStream('mt19937ar','Seed','shuffle'); -madseq = struct( ... - 'prompt', 'MadSeq (120 mins)', ... - 'logger', logger(), ... - 'constants', setfield(constants, 'stimulus', 'madseq'), ... - 'blocks', 1, ... - 'stim', {{ - - setParams(stims.MovieClip, psy.MovieClipCond, ... - 'movie_name', 'MadMax', ... - 'clip_number', 1:2:100, ... - 'cut_after', 60 ... - ) - - setParams(stims.MovieClip, psy.MovieClipCond, ... - 'movie_name', 'MadMax', ... - 'clip_number', sort(repmat(randperm(s,110,2),1,30)), ... 10 sec each - 'cut_after', 10 ... - ) - - setParams(stims.MovieStill, psy.MovieStillCond, ... - 'movie_name', 'MadMax', ... - 'pre_blank_period', 0, ... - 'duration', 0.5, ... - 'still_id', 1:2:12000 ... - ) - - setParams(stims.MovieSeq, psy.MovieSeqCond, ... - 'movie_name', 'MadMax', ... - 'rng_seed', repmat([1 2], 30, 1), ... - 'pre_blank_period', 0, ... - 'duration', 0.5, ... - 'seq_length', 20 ... - ) - - }}); %#ok - - - -choices = [ - quadrantGrating - flashingBar - movingNoise - vanGogh - trippy - trippyMonet - madmax - madseq - ]; diff --git a/visual-stimuli/+stims/pick.m b/visual-stimuli/+stims/pick.m deleted file mode 100644 index cd1649d..0000000 --- a/visual-stimuli/+stims/pick.m +++ /dev/null @@ -1,39 +0,0 @@ -function pick(menu) % stims.pick allows picking one of several preconfigured visual stimuli� - -fprintf '\n\n\nWelcome to stims.pick\n' -parentTable = common.Animal; - -% enter primary key -while true - try - for keyField = parentTable.primaryKey - key.(keyField{1}) = input(sprintf('Enter %s: ', keyField{1})); - assert(~isempty(key.(keyField{1})), 'cannot have empty key') - end - disp 'Entered:' - disp(key) - assert(count(parentTable & key)==1, 'not found in database') - break - catch err - disp(err.message) - end -end - -assert(isempty(javachk('desktop')), 'no MATLAB desktop! Restart.') -fprintf '\nAt runtime, press numbers to select stimulus, "r"=run, "q"=quit:\n' -for i = 1:length(menu) - fprintf('%d. %s\n', i, menu(i).prompt) -end -fprintf \n\n - -disp 'While the screen is blanked you can:' -disp ' press 1-9 to select or change the stimulus (memorize them now)' -disp ' press "r" to run the selected stimulus' -disp ' press ESC to stop an ongoing stimulus (only while frames are flipping)' -disp ' press "q" to quit' -disp ' ' -disp 'Now press any key when you are ready to blank the screen.' - -pause -stims.core.run(menu, key) -end \ No newline at end of file diff --git a/visual-stimuli/+stims/precompute.m b/visual-stimuli/+stims/precompute.m deleted file mode 100644 index f6586dd..0000000 --- a/visual-stimuli/+stims/precompute.m +++ /dev/null @@ -1,9 +0,0 @@ -function precompute(menu) -% simulates running all the protocols, triggering precomputation of conditions - -for protocol = menu(:)' - fprintf('Protocol: %s:\n', protocol.constants.stimulus) - for i=1:length(protocol.stim) - init(protocol.stim{i}, [], protocol.constants); - end -end \ No newline at end of file diff --git a/visual-stimuli/README.txt b/visual-stimuli/README.txt deleted file mode 100644 index 072d3b3..0000000 --- a/visual-stimuli/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -This simple visual stimulus program works with DataJoint 2.0+ to log stimulus data. - -Synchronization is performed using coded photodiode flips.