Skip to content

Commit

Permalink
update vis.checkers, exp.inferParameters
Browse files Browse the repository at this point in the history
  • Loading branch information
nsteinme committed May 27, 2018
1 parent 8e96027 commit a8ee0e4
Show file tree
Hide file tree
Showing 6 changed files with 274 additions and 5 deletions.
19 changes: 18 additions & 1 deletion +exp/inferParameters.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,20 @@
% create some signals just to pass to the definition function and track
% which parameter names are used

% if ischar(expdef) && file.exists(expdef)
% expdeffun = fileFunction(expdef);
% else
% expdeffun = expdef;
% expdef = which(func2str(expdef));
% end
if ischar(expdef) && file.exists(expdef)
expdeffun = fileFunction(expdef);
[funcDir, mfile] = fileparts(expdef); addpath(funcDir);
funArgs = nargin(str2func(mfile));
else
expdeffun = expdef;
expdef = which(func2str(expdef));
funArgs = nargin(expdeffun);
end

net = sig.Net;
Expand All @@ -24,7 +33,15 @@
e.outputs = net.subscriptableOrigin('outputs');

try
expdeffun(e.t, e.events, e.pars, e.visual, e.inputs , e.outputs, e.audio);

rig = 0;
if funArgs == 7
expdeffun(e.t, e.events, e.pars, e.visual, e.inputs, e.outputs, e.audio);
else
expdeffun(e.t, e.events, e.pars, e.visual, e.inputs, e.outputs, e.audio, rig);
end

% expdeffun(e.t, e.events, e.pars, e.visual, e.inputs , e.outputs, e.audio);
% paramNames will be the strings corresponding to the fields of e.pars
% that the user tried to reference in her expdeffun.
paramNames = e.pars.Subscripts.keys';
Expand Down
4 changes: 2 additions & 2 deletions +srv/StimulusControl.m
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,8 @@ function onWSReceived(obj, ~, eventArgs)
notify(obj, 'ExpStarting', srv.ExpEvent('starting', ref));
case 'completed'
%experiment stopped without any exceptions
ref = data{2}; aborted = data{3};
notify(obj, 'ExpStopped', srv.ExpEvent('completed', ref, aborted));
ref = data{2};
notify(obj, 'ExpStopped', srv.ExpEvent('completed', ref));
case 'expException'
%experiment stopped with an exception
ref = data{2}; err = data{3};
Expand Down
2 changes: 1 addition & 1 deletion alyx-matlab
2 changes: 1 addition & 1 deletion cortexlab/+vis/checker6.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function elem = checker3(t)
function elem = checker6(t)
%vis.checker A grid of rectangles
% Detailed explanation goes here

Expand Down
126 changes: 126 additions & 0 deletions cortexlab/+vis/checkerLeft.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
function elem = checkerLeft(t)
%vis.checker A grid of rectangles
% Detailed explanation goes here

elem = t.Node.Net.subscriptableOrigin('checker');

%% make initial layers to be used as templates
maskTemplate = vis.emptyLayer();
maskTemplate.isPeriodic = false;
maskTemplate.interpolation = 'nearest';
maskTemplate.show = true;
maskTemplate.colourMask = [false false false true];

maskTemplate.textureId = 'checkerMaskPixel';
[maskTemplate.rgba, maskTemplate.rgbaSize] = vis.rgba(0, 0);
maskTemplate.blending = '1-source'; % allows us to lay down our zero alpha value

stencilTemplate = maskTemplate;
stencilTemplate.textureId = 'checkerStencilPixel';
[stencilTemplate.rgba, stencilTemplate.rgbaSize] = vis.rgba(1, 1);
stencilTemplate.blending = 'none';

% pattern layer uses the alpha values laid down by mask layers
patternLayer = vis.emptyLayer();
patternLayer.textureId = sprintf('~checker%i', randi(2^32));
patternLayer.isPeriodic = false;
patternLayer.interpolation = 'nearest';
patternLayer.blending = 'destination'; % use the alpha mask gets laid down before this

%% construct signals used to assemble layers
% N rows by cols signal is derived from the size of the pattern array but
% we skip repeats so that pattern changes don't update the mask layers
% unless the size has acutally changed
nRowsByCols = elem.pattern.flatten().map(@size).skipRepeats();
aziRange = elem.azimuthRange.flatten();
altRange = elem.altitudeRange.flatten();
sizeFrac = elem.rectSizeFrac.flatten();
% signal containing the masking layers
gridMaskLayers = mapn(nRowsByCols, aziRange, altRange, sizeFrac, ...
maskTemplate, stencilTemplate, @gridMask);
% signal contain the checker layer
checkerLayer = scan(elem.pattern.flatten(), @updatePattern,...
elem.colour.flatten(), @updateColour,...
elem.azimuthRange.flatten(), @updateAzi,...
elem.altitudeRange.flatten(), @updateAlt,...
elem.show.flatten(), @updateShow,...
patternLayer); % initial value
%% set default attribute values
elem.layers = [gridMaskLayers checkerLayer];
elem.azimuthRange = [-135 0];
elem.altitudeRange = [-37.5 37.5];
elem.rectSizeFrac = [1 1]; % horizontal and vertical size of each rectangle
elem.pattern = [
1 -1 1 -1
-1 0 0 0
1 0 0 0
-1 1 -1 1];
elem.show = true;
end

%% helper functions
function layer = updatePattern(layer, pattern)
% map pattern from -1 -> 1 range to 0->255, cast to 8 bit integers, then
% convert to RGBA texture format.
[layer.rgba, layer.rgbaSize] = vis.rgbaFromUint8(uint8(127.5*(1 + pattern)), 1);
end

function layer = updateColour(layer, colour)
layer.maxColour = [colour 1];
end

function layer = updateAzi(layer, aziRange)
layer.size(1) = abs(diff(aziRange));
layer.texOffset(1) = mean(aziRange);
end

function layer = updateAlt(layer, altRange)
layer.size(2) = abs(diff(altRange));
layer.texOffset(2) = mean(altRange);
end

function layer = updateShow(layer, show)
layer.show = show;
end

function layers = gridMask(nRowsByCols, aziRange, altRange, sizeFrac, mask, stencil)
gridDims = [abs(diff(aziRange)) abs(diff(altRange))];
cellSize = gridDims./flip(nRowsByCols);
nCols = nRowsByCols(2) + 1;
nRows = nRowsByCols(1) + 1;
midAzi = mean(aziRange);
midAlt = mean(altRange);
%% base layer to imprint area the checker can draw on (by applying an alpha mask)
stencil.texOffset = [midAzi midAlt];
stencil.size = gridDims;
if any(sizeFrac < 1)
%% layers for lines making up mask grid - masks out margins around each square
% make layers for vertical lines
if nCols > 1
azi = linspace(aziRange(1), aziRange(2), nCols);
else
azi = midAzi;
end
collayers = repmat(mask, 1, nCols);
for vi = 1:nCols
collayers(vi).texOffset = [azi(vi) midAlt];
end
[collayers.size] = deal([(1 - sizeFrac(1))*cellSize(1) gridDims(2)]);
% make layers for horizontal lines
if nRows > 1
alt = linspace(altRange(1), altRange(2), nRows);
else
alt = midAlt;
end
rowlayers = repmat(mask, 1, nRows);
for hi = 1:nRows
rowlayers(hi).texOffset = [midAzi alt(hi)];
end
[rowlayers.size] = deal([gridDims(1) (1 - sizeFrac(2))*cellSize(2)]);
%% combine the layers and return
layers = [stencil collayers rowlayers];
else % no mask grid needed as each cell is full size
layers = stencil;
end

end
126 changes: 126 additions & 0 deletions cortexlab/+vis/checkerRight.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
function elem = checkerRight(t)
%vis.checker A grid of rectangles
% Detailed explanation goes here

elem = t.Node.Net.subscriptableOrigin('checker');

%% make initial layers to be used as templates
maskTemplate = vis.emptyLayer();
maskTemplate.isPeriodic = false;
maskTemplate.interpolation = 'nearest';
maskTemplate.show = true;
maskTemplate.colourMask = [false false false true];

maskTemplate.textureId = 'checkerMaskPixel';
[maskTemplate.rgba, maskTemplate.rgbaSize] = vis.rgba(0, 0);
maskTemplate.blending = '1-source'; % allows us to lay down our zero alpha value

stencilTemplate = maskTemplate;
stencilTemplate.textureId = 'checkerStencilPixel';
[stencilTemplate.rgba, stencilTemplate.rgbaSize] = vis.rgba(1, 1);
stencilTemplate.blending = 'none';

% pattern layer uses the alpha values laid down by mask layers
patternLayer = vis.emptyLayer();
patternLayer.textureId = sprintf('~checker%i', randi(2^32));
patternLayer.isPeriodic = false;
patternLayer.interpolation = 'nearest';
patternLayer.blending = 'destination'; % use the alpha mask gets laid down before this

%% construct signals used to assemble layers
% N rows by cols signal is derived from the size of the pattern array but
% we skip repeats so that pattern changes don't update the mask layers
% unless the size has acutally changed
nRowsByCols = elem.pattern.flatten().map(@size).skipRepeats();
aziRange = elem.azimuthRange.flatten();
altRange = elem.altitudeRange.flatten();
sizeFrac = elem.rectSizeFrac.flatten();
% signal containing the masking layers
gridMaskLayers = mapn(nRowsByCols, aziRange, altRange, sizeFrac, ...
maskTemplate, stencilTemplate, @gridMask);
% signal contain the checker layer
checkerLayer = scan(elem.pattern.flatten(), @updatePattern,...
elem.colour.flatten(), @updateColour,...
elem.azimuthRange.flatten(), @updateAzi,...
elem.altitudeRange.flatten(), @updateAlt,...
elem.show.flatten(), @updateShow,...
patternLayer); % initial value
%% set default attribute values
elem.layers = [gridMaskLayers checkerLayer];
elem.azimuthRange = [0 135];
elem.altitudeRange = [-37.5 37.5];
elem.rectSizeFrac = [1 1]; % horizontal and vertical size of each rectangle
elem.pattern = [
1 -1 1 -1
-1 0 0 0
1 0 0 0
-1 1 -1 1];
elem.show = true;
end

%% helper functions
function layer = updatePattern(layer, pattern)
% map pattern from -1 -> 1 range to 0->255, cast to 8 bit integers, then
% convert to RGBA texture format.
[layer.rgba, layer.rgbaSize] = vis.rgbaFromUint8(uint8(127.5*(1 + pattern)), 1);
end

function layer = updateColour(layer, colour)
layer.maxColour = [colour 1];
end

function layer = updateAzi(layer, aziRange)
layer.size(1) = abs(diff(aziRange));
layer.texOffset(1) = mean(aziRange);
end

function layer = updateAlt(layer, altRange)
layer.size(2) = abs(diff(altRange));
layer.texOffset(2) = mean(altRange);
end

function layer = updateShow(layer, show)
layer.show = show;
end

function layers = gridMask(nRowsByCols, aziRange, altRange, sizeFrac, mask, stencil)
gridDims = [abs(diff(aziRange)) abs(diff(altRange))];
cellSize = gridDims./flip(nRowsByCols);
nCols = nRowsByCols(2) + 1;
nRows = nRowsByCols(1) + 1;
midAzi = mean(aziRange);
midAlt = mean(altRange);
%% base layer to imprint area the checker can draw on (by applying an alpha mask)
stencil.texOffset = [midAzi midAlt];
stencil.size = gridDims;
if any(sizeFrac < 1)
%% layers for lines making up mask grid - masks out margins around each square
% make layers for vertical lines
if nCols > 1
azi = linspace(aziRange(1), aziRange(2), nCols);
else
azi = midAzi;
end
collayers = repmat(mask, 1, nCols);
for vi = 1:nCols
collayers(vi).texOffset = [azi(vi) midAlt];
end
[collayers.size] = deal([(1 - sizeFrac(1))*cellSize(1) gridDims(2)]);
% make layers for horizontal lines
if nRows > 1
alt = linspace(altRange(1), altRange(2), nRows);
else
alt = midAlt;
end
rowlayers = repmat(mask, 1, nRows);
for hi = 1:nRows
rowlayers(hi).texOffset = [midAzi alt(hi)];
end
[rowlayers.size] = deal([gridDims(1) (1 - sizeFrac(2))*cellSize(2)]);
%% combine the layers and return
layers = [stencil collayers rowlayers];
else % no mask grid needed as each cell is full size
layers = stencil;
end

end

2 comments on commit a8ee0e4

@k1o0
Copy link
Contributor

@k1o0 k1o0 commented on a8ee0e4 Oct 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The purpose of the fileFunction step is to all the experiment definition to be run without adding its containing folder to the paths. The purpose of doing this I guess was to ensure that the wrong, identically named expdef wouldn't be run in the future by mistake. In this commit (in inferParameters) you add the expdef to the paths anyway before calling fileFunction. Do you remember why you did this?

@nsteinme
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I don't remember - I'm sure I was getting some error that seemed to be able the path and I just added it to try to fix it.... if it works without that then definitely feel free to go with your working version.

Please sign in to comment.