%  Decode extra NIFTI header information into hdr.extra
%
%  Usage: hdr = extra_nii_hdr(hdr)
%
%  hdr can be obtained from load_nii_hdr
%
%  NIFTI data format can be found on: http://nifti.nimh.nih.gov
%
%  - Jimmy Shen (jimmy@rotman-baycrest.on.ca)
%
function hdr = extra_nii_hdr(hdr)

   switch hdr.dime.datatype
   case 1
      extra.NIFTI_DATATYPES = 'DT_BINARY';
   case 2
      extra.NIFTI_DATATYPES = 'DT_UINT8';
   case 4
      extra.NIFTI_DATATYPES = 'DT_INT16';
   case 8
      extra.NIFTI_DATATYPES = 'DT_INT32';
   case 16
      extra.NIFTI_DATATYPES = 'DT_FLOAT32';
   case 32
      extra.NIFTI_DATATYPES = 'DT_COMPLEX64';
   case 64
      extra.NIFTI_DATATYPES = 'DT_FLOAT64';
   case 128
      extra.NIFTI_DATATYPES = 'DT_RGB24';
   case 256
      extra.NIFTI_DATATYPES = 'DT_INT8';
   case 512
      extra.NIFTI_DATATYPES = 'DT_UINT16';
   case 768
      extra.NIFTI_DATATYPES = 'DT_UINT32';
   case 1024
      extra.NIFTI_DATATYPES = 'DT_INT64';
   case 1280
      extra.NIFTI_DATATYPES = 'DT_UINT64';
   case 1536
      extra.NIFTI_DATATYPES = 'DT_FLOAT128';
   case 1792
      extra.NIFTI_DATATYPES = 'DT_COMPLEX128';
   case 2048
      extra.NIFTI_DATATYPES = 'DT_COMPLEX256';
   otherwise
      extra.NIFTI_DATATYPES = 'DT_UNKNOWN';
   end

   switch hdr.dime.intent_code
   case 2
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_CORREL';
   case 3
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_TTEST';
   case 4
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_FTEST';
   case 5
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_ZSCORE';
   case 6
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_CHISQ';
   case 7
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_BETA';
   case 8
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_BINOM';
   case 9
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_GAMMA';
   case 10
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_POISSON';
   case 11
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_NORMAL';
   case 12
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_FTEST_NONC';
   case 13
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_CHISQ_NONC';
   case 14
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_LOGISTIC';
   case 15
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_LAPLACE';
   case 16
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_UNIFORM';
   case 17
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_TTEST_NONC';
   case 18
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_WEIBULL';
   case 19
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_CHI';
   case 20
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_INVGAUSS';
   case 21
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_EXTVAL';
   case 22
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_PVAL';
   case 23
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_LOGPVAL';
   case 24
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_LOG10PVAL';
   case 1001
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_ESTIMATE';
   case 1002
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_LABEL';
   case 1003
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_NEURONAME';
   case 1004
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_GENMATRIX';
   case 1005
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_SYMMATRIX';
   case 1006
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_DISPVECT';
   case 1007
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_VECTOR';
   case 1008
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_POINTSET';
   case 1009
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_TRIANGLE';
   case 1010
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_QUATERNION';
   case 1011
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_DIMLESS';
   otherwise
      extra.NIFTI_INTENT_CODES = 'NIFTI_INTENT_NONE';
   end

   extra.NIFTI_INTENT_NAMES = hdr.hist.intent_name;

   if hdr.hist.sform_code > 0
      switch hdr.hist.sform_code
      case 1
         extra.NIFTI_SFORM_CODES = 'NIFTI_XFORM_SCANNER_ANAT';
      case 2
         extra.NIFTI_SFORM_CODES = 'NIFTI_XFORM_ALIGNED_ANAT';
      case 3
         extra.NIFTI_SFORM_CODES = 'NIFTI_XFORM_TALAIRACH';
      case 4
         extra.NIFTI_SFORM_CODES = 'NIFTI_XFORM_MNI_152';
      otherwise
         extra.NIFTI_SFORM_CODES = 'NIFTI_XFORM_UNKNOWN';
      end

      extra.NIFTI_QFORM_CODES = 'NIFTI_XFORM_UNKNOWN';
   elseif hdr.hist.qform_code > 0
      extra.NIFTI_SFORM_CODES = 'NIFTI_XFORM_UNKNOWN';

      switch hdr.hist.qform_code
      case 1
         extra.NIFTI_QFORM_CODES = 'NIFTI_XFORM_SCANNER_ANAT';
      case 2
         extra.NIFTI_QFORM_CODES = 'NIFTI_XFORM_ALIGNED_ANAT';
      case 3
         extra.NIFTI_QFORM_CODES = 'NIFTI_XFORM_TALAIRACH';
      case 4
         extra.NIFTI_QFORM_CODES = 'NIFTI_XFORM_MNI_152';
      otherwise
         extra.NIFTI_QFORM_CODES = 'NIFTI_XFORM_UNKNOWN';
      end
   else
      extra.NIFTI_SFORM_CODES = 'NIFTI_XFORM_UNKNOWN';
      extra.NIFTI_QFORM_CODES = 'NIFTI_XFORM_UNKNOWN';
   end

   switch bitand(hdr.dime.xyzt_units, 7)	% mask with 0x07
   case 1
      extra.NIFTI_SPACE_UNIT = 'NIFTI_UNITS_METER';
   case 2
      extra.NIFTI_SPACE_UNIT = 'NIFTI_UNITS_MM';	% millimeter
   case 3
      extra.NIFTI_SPACE_UNIT = 'NIFTI_UNITS_MICRO';
   otherwise
      extra.NIFTI_SPACE_UNIT = 'NIFTI_UNITS_UNKNOWN';
   end

   switch bitand(hdr.dime.xyzt_units, 56)	% mask with 0x38
   case 8
      extra.NIFTI_TIME_UNIT = 'NIFTI_UNITS_SEC';
   case 16
      extra.NIFTI_TIME_UNIT = 'NIFTI_UNITS_MSEC';
   case 24
      extra.NIFTI_TIME_UNIT = 'NIFTI_UNITS_USEC';	% microsecond
   otherwise
      extra.NIFTI_TIME_UNIT = 'NIFTI_UNITS_UNKNOWN';
   end

   switch hdr.dime.xyzt_units
   case 32
      extra.NIFTI_SPECTRAL_UNIT = 'NIFTI_UNITS_HZ';
   case 40
      extra.NIFTI_SPECTRAL_UNIT = 'NIFTI_UNITS_PPM';	% part per million
   case 48
      extra.NIFTI_SPECTRAL_UNIT = 'NIFTI_UNITS_RADS';	% radians per second
   otherwise
      extra.NIFTI_SPECTRAL_UNIT = 'NIFTI_UNITS_UNKNOWN';
   end

   %  MRI-specific spatial and temporal information
   %
   dim_info = hdr.hk.dim_info;
   extra.NIFTI_FREQ_DIM = bitand(dim_info, 3);
   extra.NIFTI_PHASE_DIM = bitand(bitshift(dim_info, -2), 3);
   extra.NIFTI_SLICE_DIM = bitand(bitshift(dim_info, -4), 3);

   %  Check slice code
   %
   switch hdr.dime.slice_code
   case 1
      extra.NIFTI_SLICE_ORDER = 'NIFTI_SLICE_SEQ_INC';	% sequential increasing
   case 2
      extra.NIFTI_SLICE_ORDER = 'NIFTI_SLICE_SEQ_DEC';	% sequential decreasing
   case 3
      extra.NIFTI_SLICE_ORDER = 'NIFTI_SLICE_ALT_INC';	% alternating increasing
   case 4
      extra.NIFTI_SLICE_ORDER = 'NIFTI_SLICE_ALT_DEC';	% alternating decreasing
   case 5
      extra.NIFTI_SLICE_ORDER = 'NIFTI_SLICE_ALT_INC2';	% ALT_INC # 2
   case 6
      extra.NIFTI_SLICE_ORDER = 'NIFTI_SLICE_ALT_DEC2';	% ALT_DEC # 2
   otherwise
      extra.NIFTI_SLICE_ORDER = 'NIFTI_SLICE_UNKNOWN';
   end

   %  Check NIFTI version
   %
   if     ~isempty(hdr.hist.magic) & strcmp(hdr.hist.magic(1),'n') & ...
	( strcmp(hdr.hist.magic(2),'i') | strcmp(hdr.hist.magic(2),'+') ) & ...
	  str2num(hdr.hist.magic(3)) >= 1 & str2num(hdr.hist.magic(3)) <= 9

      extra.NIFTI_VERSION = str2num(hdr.hist.magic(3));
   else
      extra.NIFTI_VERSION = 0;
   end

   %  Check if data stored in the same file (*.nii) or separate
   %  files (*.hdr/*.img)
   %
   if isempty(hdr.hist.magic)
      extra.NIFTI_ONEFILE = 0;
   else
      extra.NIFTI_ONEFILE = strcmp(hdr.hist.magic(2), '+');
   end

   %  Swap has been taken care of by checking whether sizeof_hdr is
   %  348 (machine is 'ieee-le' or 'ieee-be' etc)
   %
   % extra.NIFTI_NEEDS_SWAP = (hdr.dime.dim(1) < 0 | hdr.dime.dim(1) > 7);

   %  Check NIFTI header struct contains a 5th (vector) dimension
   %
   if hdr.dime.dim(1) > 4 & hdr.dime.dim(6) > 1
      extra.NIFTI_5TH_DIM = hdr.dime.dim(6);
   else
      extra.NIFTI_5TH_DIM = 0;
   end

   hdr.extra = extra;

   return;					% extra_nii_hdr


function en = end(a,k,n)
% Overloaded end function for file_array objects.
% _______________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

%
% $Id$

dim = size(a);
if k>length(dim)
    en = 1;
else
    if n<length(dim),
    dim = [dim(1:(n-1)) prod(dim(n:end))];
    end;
    en = dim(k);
end;


function stop = optimplotfvalKsptot(~,optimValues,state,varargin)
% OPTIMPLOTFVAL Plot value of the objective function at each iteration.
%
%   STOP = OPTIMPLOTFVAL(X,OPTIMVALUES,STATE) plots OPTIMVALUES.fval.  If
%   the function value is not scalar, a bar plot of the elements at the
%   current iteration is displayed.  If the OPTIMVALUES.fval field does not
%   exist, the OPTIMVALUES.residual field is used.
%
%   Example:
%   Create an options structure that will use OPTIMPLOTFVAL as the plot
%   function
%     options = optimset('PlotFcns',@optimplotfval);
%
%   Pass the options into an optimization problem to view the plot
%     fminbnd(@sin,3,10,options)

%   Copyright 2006-2010 The MathWorks, Inc.

stop = false;
switch state
    case 'iter'
        if isfield(optimValues,'fval')
            if isscalar(optimValues.fval)
                plotscalar(optimValues.iteration,optimValues.fval);
            else
                plotvector(optimValues.iteration,optimValues.fval);
            end
        else
            plotvector(optimValues.iteration,optimValues.residual);
        end
end

function plotscalar(iteration,fval)
% PLOTSCALAR initializes or updates a line plot of the function value
% at each iteration.
persistent plotfval plotfvalParent

if iteration == 0
    plotfval = plot(iteration,fval,'kd','MarkerFaceColor',[1 0 1]);
    plotfvalParent = plotfval.Parent;
    title(getString(message('MATLAB:optimfun:funfun:optimplots:TitleCurrentFunctionValue',sprintf('%g',fval))),'interp','none');
    xlabel(getString(message('MATLAB:optimfun:funfun:optimplots:LabelIteration')),'interp','none');
    set(plotfval,'Tag','optimplotfval');
    ylabel(getString(message('MATLAB:optimfun:funfun:optimplots:LabelFunctionValue')),'interp','none')
else
%     plotfval = findobj(get(gca,'Children'),'Tag','optimplotfval');
%     plotfval.Parent = plotfvalParent;
    newX = [get(plotfval,'Xdata') iteration];
    newY = [get(plotfval,'Ydata') fval];
    set(plotfval,'Xdata',newX, 'Ydata',newY);
    set(get(plotfvalParent,'Title'),'String',getString(message('MATLAB:optimfun:funfun:optimplots:TitleCurrentFunctionValue',sprintf('%g',fval))));
end

function plotvector(iteration,fval)
% PLOTVECTOR creates or updates a bar plot of the function values or
% residuals at the current iteration.
persistent plotfval

if iteration == 0
    xlabelText = getString(message('MATLAB:optimfun:funfun:optimplots:LabelNumberOfFunctionValues0',sprintf('%g',length(fval))));
    % display up to the first 100 values
    if numel(fval) > 100
        xlabelText = {xlabelText,getString(message('MATLAB:optimfun:funfun:optimplots:LabelShowingOnlyFirst100Values'))};
        fval = fval(1:100);
    end
    plotfval = bar(fval);
    title(getString(message('MATLAB:optimfun:funfun:optimplots:TitleCurrentFunctionValues')),'interp','none');
    set(plotfval,'edgecolor','none')
    set(plotfvalParent,'xlim',[0,1 + length(fval)])
    xlabel(xlabelText,'interp','none')
    set(plotfval,'Tag','optimplotfval');
    ylabel(getString(message('MATLAB:optimfun:funfun:optimplots:LabelFunctionValue')),'interp','none')
else
%     plotfval = findobj(get(gca,'Children'),'Tag','optimplotfval');
    % display up to the first 100 values
    if numel(fval) > 100
        fval = fval(1:100);
    end
    set(plotfval,'Ydata',fval);
end


classdef DesignVariableAndMeshSaverFromRes < handle

    properties (Access = private)
        levelSet
        backgroundMesh
        iterationsNumber
    end

    properties (Access = private)
        testPath
        testName
    end

    methods (Access = public)

        function obj = DesignVariableAndMeshSaverFromRes(cParams)
            obj.init(cParams)
        end

        function save(obj)
            obj.readIterNumbers()
            for iter = 1:length(obj.iterationsNumber)
                obj.obtainLevelSetAndMesh(iter);
                obj.saveLevelSetAndMesh(iter);
            end
        end

    end

    methods (Access = private)

        function init(obj,cParams)
            obj.testPath  = cParams.testPath;
            obj.testName  = cParams.testName;
        end

        function readIterNumbers(obj)
            files = dir(fullfile(obj.testPath,'*.res'));
            nFiles = numel(files);
            iterN  = zeros(nFiles,1);
            for ifiles = 1:nFiles
                file = files(ifiles);
                iter = obj.getIter(file);
                iterN(ifiles) = iter;
            end
            obj.iterationsNumber = sort(iterN);
        end

        function obtainLevelSetAndMesh(obj,iter)
            it = obj.iterationsNumber(iter);
            s.fileName = [obj.testName,num2str(it)];
            s.folderPath = fullfile(obj.testPath);
            wM = WrapperMshResFiles(s);
            wM.compute();
            obj.levelSet       = wM.dataRes.DesignVar1;
            obj.backgroundMesh = wM.mesh;
        end

        function saveLevelSetAndMesh(obj,iter)
            x = obj.levelSet;
            mesh = obj.backgroundMesh;
            outputName = ['DesignVariable',num2str(iter)];
            outputFile = fullfile(obj.testPath,outputName);
            save(outputFile,'x','mesh');
        end

    end

    methods (Access = private, Static)

        function iter = getIter(file)
            fName = file.name;
            iterCell = regexp(fName,'[0-9]','match');
            iterM    = cell2mat(iterCell);
            iter     = str2double(iterM);
        end

    end

end


function exportDVHData(command)
%GUI to export a DVH data file starting with a DVH plot of one or more VOI's.
%VOI's must be renamed to agree with a standard list stored in optS.defaultVOINames.
%DVH data may then be exported to a delimited text file.
%
%KU 04/14/2006
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
% without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% See the GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with CERR.  If not, see <http://www.gnu.org/licenses/>.

global planC;
global stateS;
persistent exportPlots;
indexS = planC{end};

uicolor              = [.9 .9 .9];
units = 'normalized';

%Get DVH data.
h = findobj('tag', 'DVHPlot');
ud = get(h, 'userdata');
plots = ud.plots;

for i=1:length(plots)
    strNames{i} = plots(i).struct;
end
strNames = {strNames{:}};

%Get list of standard VOI names.
okList = stateS.optS.defaultVOINames;

if nargin == 0
    command = 'init';
end

switch lower(command)
    case 'init'
        hFig = findobj('tag', 'DVHExportFigure');
        if ~isempty(hFig)
            delete(hFig);
        end
        screenSize = get(0,'ScreenSize');
        units = 'normalized';
        hFig = figure('Name', 'DVH Data Export', 'position',[screenSize(3)/10 screenSize(4)/8 screenSize(3)/10*8 screenSize(4)/10*5], 'MenuBar', 'none', 'NumberTitle', 'off', 'resize', 'off', 'Tag', 'DVHExportFigure');

        stateS.handles.figure = hFig;

        %Init List Boxes
        ud.handles.DVHList = uicontrol('units',units,'BackgroundColor',uicolor, 'Position',[.05 .10 .25 .85],'String', strNames, 'Style','listbox','Tag','DVHList');
        ud.handles.myDVHList = uicontrol('callback', 'exportDVHData(''SelectDVH'');','units',units,'BackgroundColor',uicolor, 'Position',[.35 .10 .25 .85], 'String', [], 'Style','listbox', 'Enable', 'on', 'Tag','myDVHList');

        %Make labels for listboxes
        uicontrol('units',units,'BackgroundColor',uicolor, 'Position',[.05 .95 .15 .04],'String', 'Calculated DVHs: ', 'Style','text', 'horizontalalignment', 'left');
        uicontrol('units',units,'BackgroundColor',uicolor, 'Position',[.35 .95 .15 .04],'String', 'Selected For Export: ', 'Style','text', 'horizontalalignment', 'left');

        %make buttons for adding and removing DVH's from list boxes.
        uicontrol('callback', 'exportDVHData(''addDVH'');', 'units',units,'BackgroundColor',uicolor, 'Position',[.3 .65 .05 .05],'String','-->', 'Style','pushbutton','Tag','DVHAdd');
        uicontrol('callback', 'exportDVHData(''removeDVH'');', 'units',units,'BackgroundColor',uicolor, 'Position',[.3 .55 .05 .05],'String','<--', 'Style','pushbutton','Tag','DVHRemove');

        %Make frame for checking and renaming VOI's.
        uicontrol('units',units,'BackgroundColor',uicolor, 'Position',[.65 .45 .3 .5],'String','frame', 'Style','frame','Tag','renameFrame');

        %Add pop-up menus for renaming VOI's.
        ud.handles.myDVHpopup = uicontrol('callback', 'exportDVHData(''SelectPopupDVH'');','units',units,'BackgroundColor',uicolor, 'Position',[.67 .67 .12 .05],'String', {''}, 'Style','popupmenu','Tag','myDVHpopup');
        ud.handles.okDVHList = uicontrol('units',units,'BackgroundColor',uicolor, 'Position',[.81 .67 .12 .05], 'String', okList, 'Style','popupmenu','Tag','okDVHList');
        %Make labels for pop-up menus.
        uicontrol('units',units,'BackgroundColor',uicolor, 'Position',[.66 .72 .13 .05],'String', 'Select VOI to rename', 'Style','text', 'horizontalalignment', 'left');
        uicontrol('units',units,'BackgroundColor',uicolor, 'Position',[.81 .72 .13 .05],'String', 'Select name from list', 'Style','text', 'horizontalalignment', 'left');

        %Make buttons for checking VOI names and renaming.
        uicontrol('callback', 'exportDVHData(''checknames'');', 'units',units,'BackgroundColor',uicolor, 'Position',[.70 .87 .2 .05],'String','Check VOI Names', 'Style','pushbutton','Tag','namecheck');
        uicontrol('callback', 'exportDVHData(''rename'');', 'units',units,'BackgroundColor',uicolor, 'Position',[.75 .50 .1 .05],'String','Rename', 'Style','pushbutton','Tag','rename');

        %Make buttons for export and cancel.
        uicontrol('callback', 'exportDVHData(''export'');', 'units',units,'BackgroundColor',uicolor, 'Position',[.65 .35 .1 .05],'String','Export', 'Style','pushbutton','Tag','export');
        uicontrol('callback', 'exportDVHData(''cancel'');', 'units',units,'BackgroundColor',uicolor, 'Position',[.85 .35 .1 .05],'String','Cancel', 'Style','pushbutton','Tag','cancel');
        set(hFig, 'userdata', ud);
        return;

    case 'adddvh' %add current DVH to the "selected for export" list.
        hFig = findobj('tag', 'DVHExportFigure');
        ud = get(hFig, 'userdata');
		index_selected = get(ud.handles.DVHList,'Value');
        exportList = get(findobj('tag', 'myDVHList'), 'String');
        if isempty(exportList)
            exportPlots = plots(index_selected);
        else
            for i = 1:length(exportPlots)
                if isequal(plots(index_selected).volsV, exportPlots(i).volsV)
                    warndlg('That DVH has already been selected for export!', 'Warning', 'modal');
                    break
                elseif i == length(exportPlots)
                    exportPlots = [exportPlots, plots(index_selected)];
                end
            end
        end
        for i=1:length(exportPlots)
            exportNames{i} = exportPlots(i).struct;
        end
        exportNames = {exportNames{:}};
        set(findobj('tag', 'myDVHList'), 'String', exportNames);
        set(findobj('tag', 'myDVHpopup'), 'String', exportNames);

    case 'removedvh' %Remove DVH from the "selected for export" list.
        hFig = findobj('tag', 'DVHExportFigure');
        exportList = get(findobj('tag', 'myDVHList'), 'String');
        if isempty(exportList)
            return
        end

        ud = get(hFig, 'userdata');
		index_selected = get(ud.handles.myDVHList,'Value');
        exportPlots(index_selected) = [];

        if length(exportPlots) >= 1
            for i=1:length(exportPlots)
                exportNames{i} = exportPlots(i).struct;
            end
            exportNames = {exportNames{:}};
            set(findobj('tag', 'myDVHList'), 'String', exportNames);
            set(findobj('tag', 'myDVHpopup'), 'String', exportNames);
        else
            set(findobj('tag', 'myDVHList'), 'String', []);
            set(findobj('tag', 'myDVHpopup'), 'String', {''});
        end

        %Fix index if now out of range.
        if index_selected > length(exportPlots) && length(exportPlots) >= 1
            set(findobj('tag', 'myDVHList'), 'Value', index_selected-1);
            set(findobj('tag', 'myDVHpopup'), 'Value', index_selected-1);
        end

    case 'checknames'   %Check VOI names against standard list in optS.defaultVOINames.
        exportList = get(findobj('tag', 'myDVHList'), 'String');
        if isempty(exportList)
            warndlg('No DVHs have been selected for export!', 'Warning', 'modal');
            return
        end

        k = 0;
        for i = 1:length(exportPlots)
            for j = 1:length(okList)
                if strcmpi(exportPlots(i).struct, okList{j})
                    break
                elseif j == length(okList)
                    k = k+1;
                    badNames{k} = exportPlots(i).struct;
                end
            end
        end

        if k == 0
            sentence1 = ('Ready for export!');
            Zmsgbox=msgbox(sentence1, 'modal');
            waitfor(Zmsgbox);
        else
            sentence1 = {'The following VOIs must be renamed before the DVHs can be exported:',...
                '',...
                badNames{:}};
            Zmsgbox=msgbox(sentence1);
            waitfor(Zmsgbox);
        end

    case 'selectdvh'   %Synchronize selected DVH in export list and pop-up menu.
        hFig = findobj('tag', 'DVHExportFigure');
        ud = get(hFig, 'userdata');
        index_selected = get(ud.handles.myDVHList,'Value');
        if index_selected >=1
            set(findobj('tag', 'myDVHpopup'), 'Value', index_selected);
        else
            set(findobj('tag', 'myDVHList'), 'Value', 1);
        end

    case 'selectpopupdvh'   %Synchronize selected DVH in export list and pop-up menu.
        hFig = findobj('tag', 'DVHExportFigure');
        ud = get(hFig, 'userdata');
        index_selected = get(ud.handles.myDVHpopup,'Value');
        set(findobj('tag', 'myDVHList'), 'Value', index_selected);

    case 'rename'   %Rename VOI's
        hFig = findobj('tag', 'DVHExportFigure');
        exportList = get(findobj('tag', 'myDVHList'), 'String');
        if isempty(exportList)
            warndlg('Nothing to rename!', 'Warning', 'modal');
            return
        end

        ud = get(hFig, 'userdata');
        export_index = get(ud.handles.myDVHpopup,'Value');
        OK_index = get(ud.handles.okDVHList,'Value');

        Zquestion=questdlg({'Please confirm:',...
            '',...
            ['The exported DVH for  "' exportPlots(export_index).struct '"  will be renamed  "' okList{OK_index} '."']},...
            'Confirm name change', 'Rename', 'Cancel', 'Cancel');

        if strcmpi(Zquestion, 'rename')
            exportPlots(export_index).struct = okList{OK_index};

            for i=1:length(exportPlots)
                    exportNames{i} = exportPlots(i).struct;
            end
            exportNames = {exportNames{:}};
            set(findobj('tag', 'myDVHList'), 'String', exportNames);
            set(findobj('tag', 'myDVHpopup'), 'String', exportNames);
        end

    case 'export'   %Export to file.
        exportList = get(findobj('tag', 'myDVHList'), 'String');
        if isempty(exportList)
            warndlg('No DVHs have been selected for export!', 'Warning', 'modal');
            return
        end

        k = 0;
        for i = 1:length(exportPlots)   %Check that all the names are OK.
            for j = 1:length(okList)
                if strcmpi(exportPlots(i).struct, okList{j})
                    break
                elseif j == length(okList)
                    k = k+1;
                    badNames{k} = exportPlots(i).struct;
                end
            end
        end

        if k == 0   %%%% All the names are OK.  Do the export!!!!
            exportData = [];
            dlmwrite('tempfile', length(exportPlots));
            for i = 1:length(exportPlots)
                exportData(i).struct = exportPlots(i).struct;
                exportData(i).numDoseVals = length(exportPlots(i).xVals);
                exportData(i).array(:,1) = exportPlots(i).xVals';

                %Convert dose units from Gy to cGy.
                exportData(i).array(:,1) = 100*(exportData(i).array(:,1));

                exportData(i).array(:,2) = exportPlots(i).yVals';
                exportData(i).array(:,3) = [0;exportPlots(i).volsV'];

                %Write to temporary file
                fid = fopen('tempfile', 'a');
                fprintf(fid, '\n%s\n', exportData(i).struct);
                fclose(fid);
                dlmwrite('tempfile', exportData(i).numDoseVals, '-append');
                dlmwrite('tempfile', exportData(i).array, '-append', 'delimiter', '\t', 'precision', 6);
            end
            %Save file
            [pathstr, name, ext] = fileparts(stateS.CERRFile);
            if strcmpi(ext, '.bz2')
                [pathstr, name, ext] = fileparts(fullfile(pathstr,name));
            end
            [fname, pname] = uiputfile('*.txt', 'Save as', fullfile(pathstr,name));
            if isequal(fname,0) || isequal(pname,0)
                CERRStatusString('Save cancelled. Ready.');
                delete tempfile;
                return;
            end
            saveFile = fullfile(pname, fname);
            copyfile('tempfile', saveFile);
            delete tempfile;
            hFig = findobj('tag', 'DVHExportFigure');
            delete(hFig);
        else
            sentence1 = {'The following VOIs must be renamed before the DVHs can be exported:',...
                '',...
                badNames{:}};
            Zmsgbox=msgbox(sentence1);
            waitfor(Zmsgbox);
        end

    case 'cancel'
        hFig = findobj('tag', 'DVHExportFigure');
        delete(hFig);
end


function gen_mask_patch_cat_idx_for_super_res(patchified_mask)
    persistent mask_idx;
    if(isempty(mask_idx))
        global mem;
        [v, idx] = max(patchified_mask);
        idx_all = unique(idx);
        mask_idx = {};
        for m = 1:length(idx_all)
            mask_idx{m} = find(idx ==idx_all(m));
        end
        mem.mask_idx = mask_idx;
    end
end


classdef UniformGraphFuxin < AbstractGraph
%UNIFORMGRAPHFUXIN is a variant of UniformGraph, which generates graphs
% with seeds and unaries which are not dependent on image information (for
% instance unaries are only based on superpixel size). This class is
% derived from AbstractGraph. To undestand how unaries are generated, its
% worth seeing how AbstractGraph.prepare_graphs() calls create_unaries() in
% this class to compute unary values.
%
% @authors:     Fuxin Li
% @contact:     ahumayun@cc.gatech.edu
% @affiliation: Georgia Institute of Technology
% @date:        Fall 2013 - Summer 2014

    properties
    end

    methods
        function obj = UniformGraphFuxin(seg_obj, segm_index)
            obj.init(seg_obj, segm_index);
        end

        function create_unaries(obj, graph_sub_method, seed_sets)
            switch graph_sub_method
                case 'internal'
                    obj.generate_uniform_unaries('internal', seed_sets);
                case 'external'
                    obj.generate_uniform_unaries('external', seed_sets);
                case 'external2'
                    obj.generate_uniform_unaries('external2', seed_sets);
                case 'subframe'
                    error('UniformGraphFuxin:compute_graph', ...
                          '''subframe'' not implemented yet');
                otherwise
                    error('UniformGraphFuxin:compute_graph', ...
                          '''%s'' is an invalid graph method', ...
                          graph_sub_method);
            end
        end

        function generate_uniform_unaries(obj, internal_external, ...
                                          seed_sets)
            inside_frame = ~obj.seg_obj.sp_frame_set;

            funcs = create_unary_aux_funcs(obj, internal_external);

            % find the offset according to the number of unary graphs
            % already added to graph_unaries_all
            ofst = size(obj.graph_unaries_all.nonlambda_s,2);

            % initialize the matrices for holding all the unaries (see the
            % comment for this structure in AbstractGraph.prepare_graphs())
            obj.graph_unaries_all.nonlambda_s = ...
                [obj.graph_unaries_all.nonlambda_s, zeros(size(seed_sets))];
            obj.graph_unaries_all.nonlambda_t = ...
                [obj.graph_unaries_all.nonlambda_t, zeros(size(seed_sets))];
            obj.graph_unaries_all.lambda_s = ...
                [obj.graph_unaries_all.lambda_s, zeros(size(seed_sets))];
            obj.graph_unaries_all.lambda_t = ...
                [obj.graph_unaries_all.lambda_t, zeros(size(seed_sets))];

            % iterate over all seed locations
            for i = 1:size(seed_sets, 2)
                if strcmp(internal_external, 'internal')
                    [nonlambda_s, lambda_s, lambda_t] = ...
                        internal_uniform(obj, seed_sets(:,i), ...
                                         funcs.parametric_func);

                    obj.graph_unaries_all.nonlambda_s(:,ofst+i) = ...
                                                               nonlambda_s;
                    obj.graph_unaries_all.lambda_s(:,ofst+i) = lambda_s;
                    obj.graph_unaries_all.lambda_t(:,ofst+i) = lambda_t;
                elseif strcmp(internal_external, 'external')
                    [nonlambda_s, nonlambda_t, lambda_s, lambda_t] = ...
                        external_uniform(obj, seed_sets(:,i), ...
                                         inside_frame, ...
                                         funcs.parametric_func, ...
                                         funcs.frame_cost_func);

                    obj.graph_unaries_all.nonlambda_s(:,ofst+i) = ...
                                                               nonlambda_s;
                    obj.graph_unaries_all.nonlambda_t(:,ofst+i) = ...
                                                               nonlambda_t;
                    obj.graph_unaries_all.lambda_s(:,ofst+i) = lambda_s;
                    obj.graph_unaries_all.lambda_t(:,ofst+i) = lambda_t;
                else
                    [nonlambda_s, lambda_s, lambda_t] = ...
                        external_uniform2(obj, seed_sets(:,i), ...
                                          inside_frame, ...
                                          funcs.parametric_func, ...
                                          funcs.frame_cost_func);

                    obj.graph_unaries_all.nonlambda_s(:,ofst+i) = ...
                                                               nonlambda_s;
                    obj.graph_unaries_all.lambda_s(:,ofst+i) = lambda_s;
                    obj.graph_unaries_all.lambda_t(:,ofst+i) = lambda_t;
                end
            end
        end

        function [nonlambda_s, lambda_s, lambda_t] = ...
                internal_uniform(obj, the_rectangle, parametric_func, ...
                                 frame_cost_func)
            % see the comment for these output matrices in
            % AbstractGraph.prepare_graphs()
            nonlambda_s = zeros(length(the_rectangle),1);
            lambda_s = zeros(length(the_rectangle),1);
            lambda_t = zeros(length(the_rectangle),1);

            bground_pixels = ~the_rectangle;
%            frame_cost = frame_cost_func(the_rectangle);
% Internal is always without frame_cost
            nonlambda_s(the_rectangle) = inf;
            lambda_t(bground_pixels) = parametric_func(bground_pixels) / 2; %* obj.graph_seed_frame_weight;
            lambda_s(bground_pixels) = parametric_func(bground_pixels); %*obj.graph_seed_frame_weight;
        end

        function [nonlambda_s, nonlambda_t, lambda_s, lambda_t] = ...
                external_uniform(obj, the_rectangle, inside_frame, ...
                                 parametric_func, frame_cost_func)
            % see the comment for these output matrices in
            % AbstractGraph.prepare_graphs()
            nonlambda_s = zeros(length(the_rectangle),1);
            nonlambda_t = zeros(length(the_rectangle),1);
            lambda_s = zeros(length(the_rectangle),1);
            lambda_t = zeros(length(the_rectangle),1);

            inside_frame_but_rect = ~the_rectangle;
            lambda_weights = parametric_func(inside_frame_but_rect); %* obj.graph_seed_frame_weight;
%             bground_pixels = ~(inside_frame | obj.seg_obj.sp_frame_set);

            nonlambda_s(the_rectangle) = inf;
            lambda_s(inside_frame_but_rect) = lambda_weights;

            frame_cost = frame_cost_func(the_rectangle);
            % With frame cost
            nonlambda_t(obj.seg_obj.sp_frame_set) = ...
                frame_cost * 2 .* parametric_func(obj.seg_obj.sp_frame_set);
            lambda_t(inside_frame_but_rect) = lambda_weights / 256;
            % no frame edge if the frame superpixel is seed
            nonlambda_t(the_rectangle) = 0;
        end

        function [nonlambda_s, lambda_s, lambda_t] = ...
                external_uniform2(obj, the_rectangle, inside_frame, ...
                                  parametric_func, frame_cost_func)
            % see the comment for these output matrices in
            % AbstractGraph.prepare_graphs()
            nonlambda_s = zeros(length(the_rectangle),1);
            lambda_s = zeros(length(the_rectangle),1);
            lambda_t = zeros(length(the_rectangle),1);

            inside_frame_but_rect = ~the_rectangle;
            lambda_weights = parametric_func(inside_frame_but_rect); %* obj.graph_seed_frame_weight;

            % W/O frame cost
            nonlambda_s(the_rectangle) = inf;
            lambda_s(inside_frame_but_rect) = lambda_weights;
            lambda_t(inside_frame_but_rect) = lambda_weights / 256;
            % TODO: Want to add horiz/vert, these 2 are useful.
        end
    end
end


classdef LabelsPlot
  % timeline images/plots for UI

  methods (Static)

    function labels_plot = labelsPlot(t0,t1,nTL,nBeh,beh2TL,TL2beh,nflies)
      % labels_plot constructor

      n = t1-t0+1;

      labels_plot = struct();
      labels_plot.n = n;
      labels_plot.off = 1-t0;
      labels_plot.nflies = nflies;
      labels_plot.nbeh = nBeh;
      labels_plot.nTL = nTL;
      labels_plot.beh2TL = beh2TL;
      labels_plot.TL2beh = TL2beh;

      labels_plot.im = zeros(nTL,n,3);
      labels_plot.predicted_im = []; % image for predicted timeline
      labels_plot.suggest_xs = nan;
      labels_plot.error_xs = nan;
      labels_plot.suggest_gt = nan;
      %labels_plot.suggested_im = zeros([1,n,3]);
      %labels_plot.error_im = zeros([1,n,3]);
      labels_plot.x = nan(2,n,nBeh,nflies);
      labels_plot.y = nan(2,n,nBeh,nflies);
      labels_plot.predx = nan(2,n,nBeh,nflies);
      labels_plot.predy = nan(2,n,nBeh,nflies);
    end

    function labels_plot = labelsPlotClearXYLabels(labels_plot,ifly,iBeh,t0,t1)
      % Clear .x, .y for given flies/behaviors/time interval.
      % ifly: vector of fly indices. if -1, use 1:.nflies.
      % iBeh: vector of behavior indices. if -1, use 1:.nbeh.
      % t0, t1: scalar time indices

      if isequal(ifly,-1)
        ifly = 1:labels_plot.nflies;
      end
      if isequal(iBeh,-1)
        iBeh = 1:labels_plot.nbeh;
      end
      assert(t0<=t1);
      idx = (t0:t1)+labels_plot.off;

      labels_plot.x(:,idx,iBeh,ifly) = nan;
      labels_plot.y(:,idx,iBeh,ifly) = nan;
    end

    function labels_plot = labelsPlotWriteXYLabelsInterval(labels_plot,iFly,...
        iBeh,t0,t1,x,y)
      % Write a track (x,y) to .x, .y over a certain time interval.
      %
      % iFly: scalar fly index
      % iBeh: scalar behavior index
      % t0, t1: scalar time indices
      % x: vector of length t1-t0+2. NOTE: this is ONE LONGER than
      %   numel(t0:t1)
      % y: vector of length t1-t0+2. ONE LONGER than numel(t0:t1).

      assert(isscalar(iFly));
      assert(isscalar(iBeh));
      assert(t0<=t1);
      idx = (t0:t1)+labels_plot.off;
      n = t1-t0+1;
      assert(numel(x)==n+1);
      assert(numel(y)==n+1);
      x = x(:)';
      y = y(:)';

      labels_plot.x(:,idx,iBeh,iFly) = [x(1:end-1);x(2:end)];
      labels_plot.y(:,idx,iBeh,iFly) = [y(1:end-1);y(2:end)];
    end

    function labels_plot = labelsPlotWriteXYFull(labels_plot,ifly,x,y,...
        labelidx,predictedidx,scores,confThreshs)
      % Update labels_plot.x, .y, .predx, .predy from labels/predictions.
      %
      % ifly: scalar fly index (into eg labels_plot.x(:,:,:,ifly)
      % x, y: vectors, track positions
      % labelidx: .vals field from labelIdx structure. Values are in
      %   1:labels_plot.nbeh
      % predictedidx: optional, can be [] if no prediction. Values are in
      %   {0,1,2,1.5}, see JLabelData.GetPredictedIdx.
      % scores: optional, can be [] if no prediction. See GetPredictedIdx.
      % confThreshs: vector of length labels_plot.nbeh, or [] if no pred

      %MERGESTUPDATED

      assert(isscalar(ifly) && any(ifly==1:labels_plot.nflies));
      assert(isequal(numel(x),numel(y),labels_plot.n));
      assert(isequal([labels_plot.nTL labels_plot.n],size(labelidx)));
      tfPred = ~isempty(predictedidx);
      if tfPred
        assert(isequal([labels_plot.nTL labels_plot.n],size(predictedidx),size(scores)));
        assert(isvector(confThreshs)&&numel(confThreshs)==labels_plot.nbeh);
      end

      for ibeh = 1:labels_plot.nbeh
        iTL = labels_plot.beh2TL(ibeh);
        tfBeh = labelidx(iTL,:)==ibeh;

        idx = find(tfBeh);
        if isempty(idx)
          idx1 = double(labels_plot.n);
        else
          idx1 = min(idx+1,double(labels_plot.n));
        end
        labels_plot.x(1,idx,ibeh,ifly) = x(idx);
        labels_plot.x(2,idx,ibeh,ifly) = x(idx1);
        labels_plot.y(1,idx,ibeh,ifly) = y(idx);
        labels_plot.y(2,idx,ibeh,ifly) = y(idx1);
      end
      if tfPred
        for iTL = 1:labels_plot.nTL
          iBehs = labels_plot.TL2beh{iTL};
          assert(numel(iBehs)==2);
          iBehPos = iBehs(1);
          iBehNeg = iBehs(2);

          idxPos = predictedidx(iTL,:)==1 & ...
                    abs(scores(iTL,:))>confThreshs(iBehPos);
          idxNeg = predictedidx(iTL,:)==2 & ...
                    abs(scores(iTL,:))>confThreshs(iBehNeg);
          idxPos = find(idxPos);
          idxNeg = find(idxNeg);
          idxPos1 = min(idxPos+1,labels_plot.n);
          idxNeg1 = min(idxNeg+1,labels_plot.n);

          labels_plot.predx(1,idxPos,iBehPos,ifly) = x(idxPos);
          labels_plot.predx(2,idxPos,iBehPos,ifly) = x(idxPos1);
          labels_plot.predx(1,idxNeg,iBehNeg,ifly) = x(idxNeg);
          labels_plot.predx(2,idxNeg,iBehNeg,ifly) = x(idxNeg1);
          labels_plot.predy(1,idxPos,iBehPos,ifly) = y(idxPos);
          labels_plot.predy(2,idxPos,iBehPos,ifly) = y(idxPos1);
          labels_plot.predy(1,idxNeg,iBehNeg,ifly) = y(idxNeg);
          labels_plot.predy(2,idxNeg,iBehNeg,ifly) = y(idxNeg1);
        end
      end
    end

    % Note: labels_plot.x and .y are directly modified in
    % JLabel/SetLabelPlot

%     function labels_plot = labelsPlotWriteIm(labels_plot,t0,t1,labelidx,...
%         labelcolors,unkcolor)
%       % Write labels to labels_plot.im in time interval [t0,t1]. Image data
%       % outside that range is unaffected.
%       %
%       % labelidx: .vals, .imp, should be constrained to time interval [t0 t1]
%
%       assert(t0<=t1);
%       n = t1-t0+1;
%       assert(labelidx.nbeh==labels_plot.nbeh);
%       assert(isequal(size(labelidx.vals),size(labelidx.imp),...
%         [labels_plot.nTL n]));
%       assert(isequal(size(labelcolors),[labels_plot.nbeh 3]));
%
%       idx = (t0:t1)+labels_plot.off;
%       imslice = labels_plot.im(:,idx,:);
%       for chan = 1:3
%         imslice(:,:,chan) = unkcolor(chan);
%       end
%
%       % Permute image matrix to make it easier to assign behavior colors
%       imslice = permute(imslice,[3 1 2]); % imslice is now 3xnTLxn
%
%       for behaviori = 1:labels_plot.nbeh
%         tf = (labelidx.vals==behaviori) & labelidx.imp;
%         curColor = labelcolors(behaviori,:);
%         for channel = 1:3,
%           imslice(channel,tf) = curColor(channel);
%         end
%
%         tf = (labelidx.vals==behaviori) & ~labelidx.imp;
%         curColor = ShiftColor.decreaseIntensity(labelcolors(behaviori,:));
%         for channel = 1:3,
%           imslice(channel,tf) = curColor(channel);
%         end
%       end
%
%       labels_plot.im(:,idx,:) = permute(imslice,[2 3 1]);
%
%       % JLabel/SetLabelPlot does direct access to labels_plot.im
%     end

    function labels_plot = labelsPlotWriteImInterval(labels_plot,iTL,t0,t1,color)
      % Write a single color to a time interval
      %
      % iTL: vector of timeline indices. If equal to -1, use 1:nTL.
      % t0, t1: time indices
      % color: 3-element RGB color

      if isequal(iTL,-1)
        iTL = 1:labels_plot.nTL;
      end
      assert(t0<=t1);
      idx = (t0:t1)+labels_plot.off;
      for chan = 1:3
        labels_plot.im(iTL,idx,chan) = color(chan);
      end
    end

    function labels_plot = labelsPlotWriteIm(labels_plot,labelidx,labelcolors,unkcolor)
      % Write all labels from labelidx to labels_plot.

      assert(labels_plot.nbeh==labelidx.nbeh);
      assert(isequal(size(labelcolors),[labels_plot.nbeh 3]));

      for chan = 1:3
        labels_plot.im(:,:,chan) = unkcolor(chan);
      end

      % Permute image matrix to make it easier to assign behavior colors
      % MK-- permuting maybe slow, removing it.
%       im = permute(labels_plot.im,[3 1 2]); % im is now 3xnTLxn

      for behaviori = 1:labels_plot.nbeh
        curTL = labels_plot.beh2TL(behaviori);
        tf = (labelidx.vals(curTL,:) == behaviori) & labelidx.imp(curTL,:);
        curColor = labelcolors(behaviori,:);
        for channel = 1:3,
%           im(channel,tf) = curColor(channel); % if using the permute above.
          labels_plot.im(curTL,tf,channel) = curColor(channel);
        end

        tf = (labelidx.vals(curTL,:) == behaviori) & ~labelidx.imp(curTL,:);
        curColor = ShiftColor.decreaseIntensity(labelcolors(behaviori,:));
        for channel = 1:3,
%           im(channel,tf) = curColor(channel);
          labels_plot.im(curTL,tf,channel) = curColor(channel);
        end
      end

%       labels_plot.im = permute(im,[2 3 1]);

      % JLabel/SetLabelPlot does direct access to labels_plot.im
    end

    function labels_plot = labelsPlotSetPredIm(labels_plot,...
        scores,pred,confThresh,bottomType,bottomDist,...
        scores_bottom,pred_bottom,labelcolors,scorecolor)
      % Set labels_plot.predicted_im, single classifier version
      % - Top: binary prediction
      % - Middle: raw scores
      % - Bottom: configureable
      %
      % scores: 1 x n double, normalized scores
      % pred: 1 x n. 1==beh, 2==no-beh (also allowed, 0 or 1.5. See JLabelData.GetPredictedIdx)
      % confThresh: 1x2 array for beh/noBeh resp
      % bottomType: char enum
      % bottomDist: n-long vector, only used if bottomType=='Distance'
      % scores_bottom: 1 x n double
      % pred_bottom: 1 x n. 1==beh, 2==no-beh (not used if bottomType=='Distance')
      % labelcolors: nbeh x 3 (nbeh==2)
      % scorecolors: 63x3x3

      %MERGESTUPDATED

      assert(isequal(size(scores),size(pred),size(scores_bottom),size(pred_bottom)));
      assert(numel(confThresh)==2);
      %assert(size(labels_plot.predicted_im,1)==6);

      labels_plot.predicted_im = zeros(6,labels_plot.n,3);

      idxBottomScores = ~isnan(scores_bottom);
      bottomScoreNdx = ceil(scores_bottom(idxBottomScores)*31)+32;

      im = labels_plot.predicted_im;
%       im(:) = 0;
      for iBeh = 1:2
        idxScores = pred==iBeh;
        idxPredict = idxScores & abs(scores)>confThresh(iBeh);
        idxBottom = pred_bottom==iBeh;
        scoreNdx = ceil(scores(idxScores)*31)+32; % scoreNdx in [1,63]
        for channel = 1:3
          im(1,idxPredict,channel) = labelcolors(iBeh,channel);
          im(2,idxPredict,channel) = labelcolors(iBeh,channel);
          im(3,idxScores,channel) = scorecolor(scoreNdx,channel,1);
          im(4,idxScores,channel) = scorecolor(scoreNdx,channel,1);

          % Bottom row (configureable)
          if strcmp(bottomType,'Distance')
            im(5:6,:,channel) = repmat(1-bottomDist(:)',[2 1 1]);
            im(5:6,isnan(bottomDist(:)'),channel) = 0;
          else
            im(5,idxBottomScores,channel) = scorecolor(bottomScoreNdx,channel,1);
            im(6,idxBottom,channel) = labelcolors(iBeh,channel);
          end
        end
      end

      labels_plot.predicted_im = im;
    end

    function labels_plot = labelsPlotSetPredImMultiClsAnalog(labels_plot,scores,scorecolors)
      % scores: 1 x n double, normalized scores
      % scorecolors: cell vector with nclassifiers elements. Each element
      %   scorecolors{iCls} is 63x3x3

      nTL = labels_plot.nTL;
      assert(isequal(size(scores),[nTL labels_plot.n]));
      assert(numel(scorecolors)==nTL);

      scores(isnan(scores)) = 0;

      labels_plot.predicted_im = zeros(nTL,labels_plot.n,3);
      im = labels_plot.predicted_im;
      im(:) = 0;
      for iTL = 1:nTL
        scoreNdx = ceil(scores(iTL,:)*31)+32; % scoreNdx in [1,63]
        scoreclr = scorecolors{iTL};
        for channel = 1:3
          im(iTL,:,channel) = scoreclr(scoreNdx,channel,1);
        end
      end

      labels_plot.predicted_im = im;
    end

    function labels_plot = labelsPlotSetPredImMultiClsBinary(labels_plot,...
        predIdx,scores,confThreshs,labelcolors)
      % Set labels_plot.predicted_im, multiclass version
      % At the moment, we just show the predicted (binary) bouts, as the
      % regular tripartite timeline is likely too cluttered for multiple
      % classifiers.
      %
      % predIdx: ntimelines x nSamp array, values in {0,1,2,1.5}, see JLabelData.GetPredictedIdx
      % scores: ntimelines x nSamp
      % confThreshs: ntimelines x 2. confThreshs(i,:) is [lo hi] thresholds
      %   for ith classifier/timeline
      % labelcolors: nbehaviors x 3 color array

      %MERGESTUPDATED

      nTL = labels_plot.nTL;
      nSamp = labels_plot.n;
      assert(isequal([nTL nSamp],size(predIdx),size(scores)));
      assert(isequal(size(confThreshs),[nTL 2]));
      assert(isequal(size(labelcolors),[labels_plot.nbeh 3]));

      labels_plot.predicted_im = zeros(nTL,nSamp,3);
      %assert(isequal(size(labels_plot.predicted_im),[nTL labels_plot.n 3]));

      im = labels_plot.predicted_im;
      im(:) = 0;
      for iTL = 1:nTL
        iLbls = labels_plot.TL2beh{iTL};
        for i12 = [1 2]
          iBeh = iLbls(i12);
          ct = confThreshs(iBeh);
          assert(ct==confThreshs(iTL,i12));

          tfPred = predIdx(iTL,:)==i12 & abs(scores(iTL,:))>ct;

          curColor = labelcolors(iBeh,:);
          for channel = 1:3,
            im(iTL,tfPred,channel) = curColor(channel);
          end
        end
      end

      labels_plot.predicted_im = im;
    end

  end

end


function cycle_brent_test ( )

%*****************************************************************************80
%
%% CYCLE_BRENT_TEST tests the CYCLE_BRENT library.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    17 June 2012
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'CYCLE_BRENT_PRB\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  Test the CYCLE_BRENT library.\n' );

  cycle_brent_test01 ( );
  cycle_brent_test02 ( );
  cycle_brent_test03 ( );
  cycle_brent_test04 ( );
  cycle_brent_test05 ( );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'CYCLE_BRENT_PRB\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


% mff_importevents - import information from MFF 'eventsxxxxx.xml'
%                    files. If several files are detected, information
%                    from all files is imported.
%
% Usage:
%   [events, timezone] = mff_importevents(mffFile);
%
% Inputs:
%  mffFile - filename/foldername for the MFF file
%
% Output:
%  events   - EEGLAB event structure
%  timezone - time zone

% This file is part of mffmatlabio.
%
% mffmatlabio is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% mffmatlabio is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with mffmatlabio.  If not, see <https://www.gnu.org/licenses/>.

function [events, timeZone] = mff_importevents(mffFile, begTime, srate)

events = [];
timeZone = [];
p = fileparts(which('mff_importsignal.m'));
warning('off', 'MATLAB:Java:DuplicateClass');
javaaddpath(fullfile(p, 'MFF-1.2.2-jar-with-dependencies.jar'));
warning('on', 'MATLAB:Java:DuplicateClass');

% create a factory
mfffactorydelegate = javaObject('com.egi.services.mff.api.LocalMFFFactoryDelegate');
mfffactory = javaObject('com.egi.services.mff.api.MFFFactory', mfffactorydelegate);

% Create Signal object and read in event track file.
% Note that 3 is the value associated with the event track resource type.
eventFile = dir( fullfile(mffFile, 'Events_*.xml'));
if isempty(eventFile), return; end
timeZone = [];
eventCount = 1;
showWarning = true;

% use vararg2str to save events so they may be exported
eeglabExport = true;
if ~exist('vararg2str', 'file')
    eeglabExport = false;
end

for iEvent = 1:length(eventFile)
    eventtrackfilename = fullfile(mffFile, eventFile(iEvent).name);
    eventtracktype = javaObject('com.egi.services.mff.api.MFFResourceType', javaMethod('valueOf', 'com.egi.services.mff.api.MFFResourceType$MFFResourceTypes', 'kMFF_RT_EventTrack'));
    eventtrackObj = mfffactory.openResourceAtURI(eventtrackfilename, eventtracktype);

    if eventtrackObj.loadResource()

        name      = eventtrackObj.getName();
        trackType = eventtrackObj.getTrackType();
        eventlist = eventtrackObj.getEvents();
        nevents = eventlist.size();
        fprintf('Importing %d events from file %s...\n', nevents, eventFile(iEvent).name);

        % Read through each event track and inspect count of events
        % and beginTime for last event in each.
        if nevents>0

            multiplier = 24*60*60*srate;
            events(nevents).description = ''; % create last event

            for eventnum = 1:nevents

                eventObj = eventlist.get(eventnum-1);

                % Get keys for event and display key codes
                events(eventCount).begintime    = char(eventObj.getBeginTime());
                if events(eventCount).begintime(end-1) == '-'
                    events(eventCount).begintime = [ events(eventCount).begintime(1:end-1) '0' events(eventCount).begintime(end) ':00' ];
                elseif events(eventCount).begintime(end-2) == '-'
                    events(eventCount).begintime = [ events(eventCount).begintime(1:end-2) events(eventCount).begintime(end) ':00' ];
                end
                events(eventCount).classid      = char(eventObj.getClassID());
                events(eventCount).code         = char(eventObj.getCode());
                events(eventCount).description  = char(eventObj.getDescription());
                events(eventCount).duration     = eventObj.getDuration();
                events(eventCount).label        = char(eventObj.getLabel());
                events(eventCount).relativebegintime = eventObj.getRelativeBeginTime();
                events(eventCount).sourcedevice = char(eventObj.getSourceDevice());
                events(eventCount).name         = char(name);
                events(eventCount).tracktype    = char(trackType);

                % compute latency in days with ms -> convert to samples
                % eventCount = 1;
                events(eventCount).latency = (mff_decodetime(events(eventCount).begintime)-begTime)*multiplier;

                % dual time recoding
%                 tmp = mff_encodetime(events(eventCount).latency/multiplier+begTime, '08:00')
%                 fprintf('%s\n%s\n', events(eventCount).begintime, tmp);

                events(eventCount).type    = events(eventCount).code;

                % import keys
                keylist = eventObj.getKeys();
                events = mff_importkeys(events, eventCount, keylist, eeglabExport);

                eventCount = eventCount+1;

            end
        end
    else
        fprintf('Could not load event file %s\n', eventtrackfilename);
    end
end
if ~isempty(events)
    % get the time zone (duplicate code in mff_importevents and mff_importinfo)
    minusSign = find(events(end).begintime == '+');
    if isempty(minusSign)
        minusSign = find(events(end).begintime == '-');
        minusSign = minusSign(end);
    end
    timeZone = events(end).begintime(minusSign(end):end);
    if length(timeZone) > 6
        timeZone =  [];
        disp('Issue with decoding the time zone');
    end
end

% % same as above but 10% faster. Was not retained because the increased
% % complexitity. Does not support importing keys
%
% begintime         = cell(1,eventcount);
% classid           = cell(1,eventcount);
% code              = cell(1,eventcount);
% description       = cell(1,eventcount);
% duration          = cell(1,eventcount);
% label             = cell(1,eventcount);
% relativebegintime = cell(1,eventcount);
% sourcedevice      = cell(1,eventcount);
% eventkeys         = cell(1,eventcount);
% for eventnum = 1:eventcount
%
%     eventObj = eventlist.get(eventnum-1);
%
%     % Get keys for event and display key codes
%     begintime{eventnum}    = eventObj.getBeginTime();
%     classid{eventnum}      = eventObj.getClassID();
%     code{eventnum}         = eventObj.getCode();
%     description{eventnum}  = eventObj.getDescription();
%     duration{eventnum}     = eventObj.getDuration();
%     label{eventnum}        = eventObj.getLabel();
%     relativebegintime{eventnum} = eventObj.getRelativeBeginTime();
%     sourcedevice{eventnum} = eventObj.getSourceDevice();
%     eventkeys{eventnum}    = eventObj.getKeys();
%
% end
%
% disp('Converting events to Matlab format...')
% begintime    = cellfun(@(x)char(x), begintime, 'uniformoutput', false);
% begintime2   = cellfun(@(x)mff_decodetime(x), begintime, 'uniformoutput', false);
% classid      = cellfun(@(x)char(x), classid, 'uniformoutput', false);
% code         = cellfun(@(x)char(x), code, 'uniformoutput', false);
% description  = cellfun(@(x)char(x), description, 'uniformoutput', false);
% label        = cellfun(@(x)char(x), label, 'uniformoutput', false);
% relativebegintime = cellfun(@(x)char(x), relativebegintime, 'uniformoutput', false);
% sourcedevice = cellfun(@(x)char(x), sourcedevice, 'uniformoutput', false);
% eventkeys    = cellfun(@(x)char(x), eventkeys, 'uniformoutput', false);
%
% events = struct('begintime', begintime, 'latency', begintime2, 'classid', classid, 'code', code, 'description', description, ...
%                 'label', label, 'relativebegintime', relativebegintime, 'sourcedevice', sourcedevice, 'eventkeys', eventkeys);

% Save as above but not faster
% eventlist = eventlist.toArray;
% eventlist = cell(eventlist);
%
% begintime    = cellfun(@(x)char(x.getBeginTime()), eventlist, 'uniformoutput', false);
% begintime2   = cellfun(@(x)mff_decodetime(x), begintime, 'uniformoutput', false);
% classid      = cellfun(@(x)char(x.getClassID()), eventlist, 'uniformoutput', false);
% code         = cellfun(@(x)char(x.getCode()), eventlist, 'uniformoutput', false);
% description  = cellfun(@(x)char(x.getDescription()), eventlist, 'uniformoutput', false);
% label        = cellfun(@(x)char(x.getLabel()), eventlist, 'uniformoutput', false);
% sourcedevice = cellfun(@(x)char(x.getSourceDevice()), eventlist, 'uniformoutput', false);
% eventkeys    = cellfun(@(x)char(x.getKeys()), eventlist, 'uniformoutput', false);
%
% relativebegintime = cellfun(@(x)x.getRelativeBeginTime(), eventlist, 'uniformoutput', false);
% duration          = cellfun(@(x)x.getDuration(), eventlist, 'uniformoutput', false);
%
% events = struct('begintime', begintime, 'latency', begintime2, 'classid', classid, 'code', code, 'type', code, 'description', description, ...
%                 'label', label, 'duration', duration, 'relativebegintime', relativebegintime, 'sourcedevice', sourcedevice, 'eventkeys', eventkeys);


function out= cell_flaten(C, dim)
%CELL_FLATEN - Flaten all layers of a cell array
%
%Synopsis:
% CFLAT= cell_flaten(C)
% CFLAT= cell_flaten(C, DIM)
%
%Arguements:
%  C: Arbitrary cell array
%  DIM: Dimension in which CFLAT should live, default 2.
%
%Returns:
% CFLAT: Cell array, where each entry in CFLAT is a non-cell object.

% blanker@cs.tu-berlin.de

if nargin<2,
  dim= 2;
end

if ~iscell(C),
  out= {C};
  return;
end

out= {};
for ci= 1:length(C),
  out= cat(dim, out, cell_flaten(C{ci}));
end


function varargout=frq2midi(varargin)
%
% For calling details please see v_frq2midi.m
%
% This dummy routine is included for backward compatibility only
% and will be removed in a future release of voicebox. Please use
% v_frq2midi.m in future and/or update with v_voicebox_update.m
%
%      Copyright (C) Mike Brookes 2018
%      Version: $Id: frq2midi.m 10863 2018-09-21 15:39:23Z dmb $
%
if nargout
    varargout=cell(1,nargout);
    [varargout{:}]=v_frq2midi(varargin{:});
else
    v_frq2midi(varargin{:});
end


function lidar(fileName, sensorType, varName)

    %% Check if input is valid
    if ~isstring(fileName) && ~ischar(fileName)
        error("File name must a string or char array\n")
    end

    if ~strcmp(sensorType, "lidar")
       error("Wrong sensor selected\n")
    end

    if ~isvarname(varName)
        error("Invalid variable name\n")
    end

    %% Generate the python file
    file = fopen(strcat(fileName, '.py'), 'w');

    % Automatically genrates a python file containing the sensor call back
    % bindings
    fprintf(file, 'import numpy as np\n');
    fprintf(file, '\n');
    fprintf(file, 'def bindSensor(sensor):\n');
    fprintf(file, '    sensor.listen(lambda _image: do_something(_image))\n');
    fprintf(file, '\n');
    fprintf(file, 'def do_something(_image):\n');
    fprintf(file, '    global %s\n', varName);
    fprintf(file, '    data = np.frombuffer(_image.raw_data, dtype="float32")\n');
    fprintf(file, '\n');
    fprintf(file, '    # Pair up in [x,y,z] format\n');
    fprintf(file, '    data = np.reshape(data, (-1,4))\n');
    fprintf(file, '\n');
    fprintf(file, '    # Convert the data into MATLAB cast compatible type\n');
    fprintf(file, '    %s = np.ascontiguousarray(data)\n', varName);

    fclose(file);
end


% VARGPLVM_INIT Initialise the global options structure for a demo that runs the
% variational GP-LVM.
% COPYRIGHT: Andreas C. Damianou, 2012
% VARGPLVM

% Initialise options. If the field name of 'defaults' already exists as a
% variable, the globalOpt will take this value, otherwise the default one.

defaults.experimentNo = 404;
defaults.itNo =2000;
defaults.indPoints = 49;
defaults.latentDim = 40;
% Set to 1 to use dynamics or to 0 to use the standard var-GPLVM
defaults.dynUsed = 1;
defaults.fixedBetaIters = 0;
% Set to 1 to tie the inducing points with the latent vars. X
defaults.fixInd = 0;
defaults.dynamicKern = {'rbf', 'white', 'bias'};
defaults.mappingKern = 'rbfardjit'; % {'rbfard2', 'bias', 'white'};
defaults.reconstrIters = 1000;
% Leave empty {} for no dynamics.
% Other options are:
% 'time': temporal dynamics, based on input t
% 'labels': provided labels
% 'data': autoencoder
defaults.dynamicsConstrainType = {};
% 0.1 gives around 0.5 init.covars. 1.3 biases towards 0.
defaults.vardistCovarsMult=1.3;
defaults.dataSetSplit = 'everyTwo';
defaults.blockSize = 8;
% 720x1280
defaults.dataSetName = [];  % For vargplvmLoadData
defaults.dataSetField = []; % For vargplvmLoadData
defaults.testReoptimise = 1;
defaults.invWidthMultDyn = 100;
defaults.invWidthMult = 5;

% The values of this field are either strings, so that [@initX 'Embed']
% is called, or it can be a matrix of an a priori computed latent space.
% Other options for embedding:
% 'pca','isomap2','vargplvm','fgplvm','outputs'. The last requires that
% Q==D and initialises X=Y where the data is scaled so that it's 0 mean
% 1 variance
defaults.initX ='ppca';
defaults.regularizeMeans = 0;
defaults.initVardistIters = 0;
defaults.enableParallelism = false;
defaults.DgtN = 1;
defaults.doPredictions = false;
defaults.initSNR = 100;
defaults.scale2var1 = 0;
defaults.initVardistIters = 50;
defaults.diaryFile = [];
defaults.doGradChek = false;
% By default do not learn the variance of the dynamic kernel (this is
% basically applied to the matern class of kernels, hoping that the
% lengthscale will compensate for fixing this value)
defaults.learnDynKernelVariance = false;

% This allows to rewrite the standard form of the bound F + KL as
% 2*((1-fw)*F + fw*KL), where fw is the KLweight. This means that when fw
% is 0.5 there's no difference, otherwise the KL term can be more or less
% emphasized
defaults.KLweight = 0.5;

defaults.optimiser = 'scg2';

fnames = fieldnames(defaults);
 for i=1:length(fnames)
    if ~exist(fnames{i})
        globalOpt.(fnames{i}) = defaults.(fnames{i});
    else
        globalOpt.(fnames{i}) = eval(fnames{i});
    end
 end

 clear('defaults', 'fnames','i');


% LFMatlabPathSetup - convenience function to add the light field toolbox to matlab's path
%
% It may be convenient to add this to your startup.m file.
%
% User guide: LFToolbox.pdf

% Copyright (c) 2013-2020 Donald G. Dansereau

function LFMatlabPathSetup

if (~isdeployed)
	% Find the path to this script, and use it as the base path
	LFToolboxPath = fileparts(mfilename('fullpath'));

	fprintf('Adding paths for LF Toolbox ');
	addpath( fullfile(LFToolboxPath) );
	addpath( fullfile(LFToolboxPath, 'SupportFunctions') );
	addpath( fullfile(LFToolboxPath, 'SupportFunctions', 'CameraCal') );

	fprintf('%s, done.\n', LFToolboxVersion);
end


% LFDispSetup - helper function used to set up a light field display
%
% Usage:
%
%     [ImageHandle, FigureHandle] = LFDispSetup( InitialFrame )
%     [ImageHandle, FigureHandle] = LFDispSetup( InitialFrame, ScaleFactor )
%
%
% This sets up a figure for LFDispMousePan and LFDispVidCirc. New in 0.5: the display is set up in
% the curently active figure if one exists. It not, this creates a new one.  The function should handle both
% mono and colour images. You can have multiple open interactive LFDisp* figures.
%
%
% Inputs:
%
%     InitialFrame : a 2D image with which to start the display
%
% Optional Inputs:
%
%     ScaleFactor : Adjusts the size of the display -- 1 means no change, 2 means twice as big, etc.
%                   Integer values are recommended to avoid scaling artifacts.
%
% Outputs:
%
%     FigureHandle, ImageHandle : handles of the created objects
%
%
% User guide: LFToolbox.pdf
% See also:  LFDispVidCirc, LFDispMousePan

% Copyright (c) 2013-2020 Donald G. Dansereau

function [ImageHandle, FigureHandle] = LFDispSetup( InitialFrame, ScaleFactor )

%---
ScaleFactor = LFDefaultVal('ScaleFactor', 1);

%---
CurSize = [size(InitialFrame), ScaleFactor];
FigureHandle = get(0, 'CurrentFigure');

%---Check if window already existed with correct size---
RedoWindow = false;
if( ~isempty(FigureHandle) )
	PrevSize = FigureHandle.UserData;
	PrevTag = get(FigureHandle, 'Tag');
	if( strcmp(PrevTag, 'LFDisplay') || ~all(size(PrevSize)==size(CurSize)) || ~all(CurSize == PrevSize) )
		% either not tagged or incorrect size; clear the figure and rebuild it below
		clf( FigureHandle );
		RedoWindow = true;
	end
end

if( isempty(FigureHandle) || RedoWindow )
	% Get screen size
	set( 0, 'units','pixels' );
	ScreenSize = get( 0, 'screensize' );
	ScreenSize = ScreenSize(3:4);

	% Create the figure if one doesn't already exist
	if( isempty(FigureHandle) )
		FigureHandle = figure(...
			'doublebuffer','on',...
			'backingstore','off',...
			...%'menubar','none',...
			...%'toolbar','none',...
			'tag','LFDisplay');
	else
		% make sure it's set up correctly
		FigureHandle.set( 'doublebuffer','on',...
			'backingstore','off',...
			...%'menubar','none',...
			...%'toolbar','none',...
			'tag','LFDisplay');
	end

	FigureHandle.UserData = [size(InitialFrame), ScaleFactor];
	FigureHandle.NextPlot = 'add';

	% Set the axis position and size within the figure
	AxesPos = [0,0,size(InitialFrame,2),size(InitialFrame,1)];
	axes( ...
		'units','pixels',...
		'Position', AxesPos,...
		'xlimmode','manual',...
		'ylimmode','manual',...
		'zlimmode','manual',...
		'climmode','manual',...
		'alimmode','manual',...
		'layer','bottom' ...
		);

	ImageHandle = imshow(InitialFrame);

	% Scaling factor sets the size of the display
	% this has the nice side-effect of rescaling and, if needed, repositining the window
	truesize(floor(ScaleFactor*size(InitialFrame(:,:,1))));

else
	ImageHandle = findobj(FigureHandle,'type','image');
	set(ImageHandle,'cdata', InitialFrame);
end


function GUI = sessionGUI_plotTimeCourse(rois, scans, viewer);
%
%  GUI = sessionGUI_plotTimeCourse(<rois>, <scans=scan group>, <viewer>);
%
% Open a Time Course UI for the selected ROIs.
%
% If a viewer is open, will open a time course UI for the currently-selected ROI
% in the selected viewer. If no viewers are open, will open it for the
% selected ROI in the ROI listbox in the session GUI. These are both
% over-ridden if an roi list and/or viewer are manually specified.
%
%
%
% ras, 07/06.
mrGlobals2;

if notDefined('viewer')
    if isempty(GUI.settings.viewer) | GUI.settings.viewer==0
        viewer = 0;
    else
         viewer = GUI.viewers(GUI.settings.viewer);
    end
end

if notDefined('rois')
    if viewer==0 % no viewer, get from saved list
        rois = guiGet('selectedRois');
    else
        rois = {mrViewGet(viewer, 'selectedRoi')};
    end
end

if ~checkfields(GUI, 'controls', 'tcui')
    GUI.controls.tcui = [];
end

% check if an event-related scan group is assigned.
% If so, use that; otherwise use the GUI selected scans.
if notDefined('scans')
    scans = GUI.settings.scan;
    dt = GUI.settings.dataType;
    if isfield(dataTYPES(dt).scanParams(scans(1)), 'scanGroup') & ...
            ~isempty(dataTYPES(dt).scanParams(scans(1)).scanGroup)
        [scans dt] = er_getScanGroup(INPLANE{1});
    end
end

if notDefined('dt'), dt = guiGet('DataType'); end

% special case: for GLMs data type, the time series will be
% in a different d.t. We don't need to ask the user to confirm
% in this case, it should be understood.
if isequal(dataTYPES(dt).name, 'GLMs')
	queryFlag = 1;
else
	queryFlag = 0;
end

for i = 1:length(rois)
    tc = timeCourseUI(INPLANE{1}, rois{i}, scans, dt, queryFlag);
    GUI.controls.tcui(end+1) = tc.ui.fig;
end

return


function S_str = cell2str_v3(S,delimiter)
% S_str = cell2str_v3(S)
% Example: S_str = cell2str_v3(varargin)
if nargin<2, delimiter=', '; end
S = S(:)';
S_str = ''; for k=S, if isnumeric(k{1}), S_str =[S_str ', [' num2str(k{:}) ']']; else S_str =[S_str delimiter sprintf('%s',k{:})]; end; end
%S_str = S_str(3:end);


function test_bug1150

% MEM 2gb
% WALLTIME 00:10:00
% DEPENDENCY ft_sourcestatistics

load(dccnpath('/home/common/matlab/fieldtrip/data/test/bug1150.mat'));

% the following failed
% stat = ft_sourcestatistics(cfg, temp);
% which could be tracked down to the dimord being incorrect after
% ft_checkdata

% the data seems to be incosistent so the conversion fails.
temp.trial = temp.trial(1:10);
temp.cumtapcnt = temp.cumtapcnt(1:10);
temp.trialinfo = temp.trialinfo(1:10,:);

sourcenew  = ft_checkdata(temp, 'sourcerepresentation', 'new');
if ~isequal(size(sourcenew.pow), [38556 10])
  error('incorrect dimensions');
end


function varargout=imagehomog(varargin)
%
% For calling details please see v_imagehomog.m
%
% This dummy routine is included for backward compatibility only
% and will be removed in a future release of voicebox. Please use
% v_imagehomog.m in future and/or update with v_voicebox_update.m
%
%      Copyright (C) Mike Brookes 2018
%      Version: $Id: imagehomog.m 10863 2018-09-21 15:39:23Z dmb $
%
if nargout
    varargout=cell(1,nargout);
    [varargout{:}]=v_imagehomog(varargin{:});
else
    v_imagehomog(varargin{:});
end


function filter = tapas_physio_gui_filter()
% Creates sub-part for preproc filter options in Batch Editor GUI
%
%  tapas_physio_gui_filter
%
%
%   See also

% Author:   Lars Kasper
% Created:  2019-07-05
% Copyright (C) 2019 Institute for Biomedical Engineering
%                    University of Zurich and ETH Zurich
%
% This file is part of the TAPAS PhysIO Toolbox, which is released under
% the terms of the GNU General Public License (GPL), version 3. You can
% redistribute it and/or modify it under the terms of the GPL (either
% version 3 or, at your option, any later version). For further details,
% see the file COPYING or <http://www.gnu.org/licenses/>.

%--------------------------------------------------------------------------
% filter_type
%--------------------------------------------------------------------------
filter_type        = cfg_menu;
filter_type.tag    = 'type';
filter_type.name   = 'Filter Type';
filter_type.help   = {'Which infinite impulse response filter shall be used?'
    '   ''Chebychev Type II (cheby2)''    Chebychev Type II filter, use for steep transition from'
    '               start to stop band'
    '   ''Butterworth (butter)''    Butterworth filter, standard filter with maximally flat'
    '               passband (Infinite impulse response), but stronger'
    '               ripples in transition band'
};
filter_type.labels = {'Chebychev Type II', 'Butterworth'};
filter_type.values = {'cheby2', 'butter'};
filter_type.val    = {'cheby2'};

%--------------------------------------------------------------------------
% filter_stopband
%--------------------------------------------------------------------------
filter_stopband         = cfg_entry;
filter_stopband.tag     = 'stopband';
filter_stopband.name    = 'Stopband';
filter_stopband.help    = {
  '[f_min, f_max] frequency interval in Hz of all frequencies, s.th. frequencies'
  '                 outside this band should definitely *NOT* pass the filter'
  '                 Default: [] '
  '                 NOTE: only relevant for ''cheby2'' filter type'
  '                 if empty, and passband is empty, no filtering is performed'
  '                 if empty, but passband exists, stopband interval is'
  '                 10% increased passband interval'
    };
filter_stopband.strtype = 'e';
filter_stopband.num     = [0 Inf];
filter_stopband.val     = {[]};

%--------------------------------------------------------------------------
% filter_passband
%--------------------------------------------------------------------------
filter_passband         = cfg_entry;
filter_passband.tag     = 'passband';
filter_passband.name    = 'Passband';
filter_passband.help    = {
  '[f_min, f_max] frequency interval in Hz of all frequency that should'
  '                 pass the passband filter'
  '                   default: [0.3 9] (to remove slow drifts, breathing'
  '                                    and slice sampling artifacts)'
  '                 if empty, no filtering is performed'
      };
filter_passband.strtype = 'e';
filter_passband.num     = [0 Inf];
filter_passband.val     = {[0.3 9]};

%--------------------------------------------------------------------------
%% filter_no
%--------------------------------------------------------------------------

filter_no         = cfg_branch;
filter_no.tag  = 'no';
filter_no.name = 'No';
filter_no.val  = {};
filter_no.help = {'Cardiac data remains unfiltered before pulse detection.'};

%--------------------------------------------------------------------------
%% filter_yes
%--------------------------------------------------------------------------

filter_yes      = cfg_branch;
filter_yes.tag  = 'yes';
filter_yes.name = 'Yes';
filter_yes.val  = {filter_type, filter_passband, ...
filter_stopband};
filter_yes.help = {''};

%--------------------------------------------------------------------------
%% filter
%--------------------------------------------------------------------------

filter      = cfg_choice;
filter.tag  = 'filter';
filter.name = 'Filter Raw Cardiac Time Series';
filter.val  = {filter_no};
filter.values  = {filter_no, filter_yes};
filter.help = {
    'Filter properties for bandpass-filtering of cardiac signal before peak'
    'detection, phase extraction, and other physiological traces'
 };


%kkcolorspace 'Change the color space attribute on a data object'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros kcolorspace.pane file
%
% Parameters:
% InputFile: i 'Input ', required: 'First Input data object'
% MultiChoice: type 'Image Colorspace', default: 1: 'Type of colorspace to be applied to the input image'
%    Choices are:
%   1: 'Greyscale'
%   2: 'RGB Colorspace'
%   3: 'CMY Colorspace'
%   4: 'YIQ Colorspace'
%   5: 'HSV Colorspace'
%   6: 'HLS Colorspace'
%   7: 'IHS Colorspace'
%   8: 'XYZ Colorspace'
%   9: 'UVW Colorspace'
%   10: 'UCSUVW Colorspace'
%   11: 'UCSSOW Colorspace'
%   12: 'UCSLab Colorspace'
%   13: 'UCSLuv Colorspace'
%   14: 'User Defined Colorspace'
% OutputFile: o 'Output', required: 'Resulting output data object'
%
% Example: o = kkcolorspace(i, {'i','';'type',1;'o',''})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% kcolorspace - Change the color space attribute on a data object
%
%  DESCRIPTION
% .I kcolorspace
% is used to change the setting of the KCOLOR_COLORSPACE attribute on a data
% object to any of the allowed values. Note that changing the attribute using
% kcolorspace does not modify the data (say by actually performing an RGB to
% HLS converssion if the KCOLOR_COLORSPACE is changed from RGB to HLS). Instead,
% changing the attribute will cause the data in the object to be interpreted
% as to already be in the new color space.
%
%
%
%  EXAMPLES
% Consider an W=512 H=512 E=3 data object, with each of the WxH planes obtained
% from a color scanner using R, G, and B filters. Simply inserting these data
% planes into a "blank" data object will cause the data to be treated as
% three planes of greyscale data. To cause the data to be interpreted as RGB
% data (for those operations that perform color processing, including the
% display tools), use kcolorspace to change the setting to RGB.
%
%  "SEE ALSO"
%
%  RESTRICTIONS
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1993 - 1997, Khoral Research, Inc. ("KRI")  All rights reserved.
%

function varargout = kkcolorspace(varargin)
if nargin ==0
  Inputs={};arglist={'',''};
elseif nargin ==1
  Inputs=varargin{1};arglist={'',''};
elseif nargin ==2
  Inputs=varargin{1}; arglist=varargin{2};
else error('Usage: [out1,..] = kkcolorspace(Inputs,arglist).');
end
if size(arglist,2)~=2
  error('arglist must be of form {''ParameterTag1'',value1;''ParameterTag2'',value2}')
 end
narglist={'i', '__input';'type', 1;'o', '__output'};
maxval={0,0,0};
minval={0,0,0};
istoggle=[0,0,0];
was_set=istoggle * 0;
paramtype={'InputFile','MultiChoice','OutputFile'};
% identify the input arrays and assign them to the arguments as stated by the user
if ~iscell(Inputs)
Inputs = {Inputs};
end
NumReqOutputs=1; nextinput=1; nextoutput=1;
  for ii=1:size(arglist,1)
  wasmatched=0;
  for jj=1:size(narglist,1)
   if strcmp(arglist{ii,1},narglist{jj,1})  % a given argument was matched to the possible arguments
     wasmatched = 1;
     was_set(jj) = 1;
     if strcmp(narglist{jj,2}, '__input')
      if (nextinput > length(Inputs))
        error(['Input ' narglist{jj,1} ' has no corresponding input!']);
      end
      narglist{jj,2} = 'OK_in';
      nextinput = nextinput + 1;
     elseif strcmp(narglist{jj,2}, '__output')
      if (nextoutput > nargout)
        error(['Output nr. ' narglist{jj,1} ' is not present in the assignment list of outputs !']);
      end
      if (isempty(arglist{ii,2}))
        narglist{jj,2} = 'OK_out';
      else
        narglist{jj,2} = arglist{ii,2};
      end

      nextoutput = nextoutput + 1;
      if (minval{jj} == 0)
         NumReqOutputs = NumReqOutputs - 1;
      end
     elseif isstr(arglist{ii,2})
      narglist{jj,2} = arglist{ii,2};
     else
        if strcmp(paramtype{jj}, 'Integer') & (round(arglist{ii,2}) ~= arglist{ii,2})
            error(['Argument ' arglist{ii,1} ' is of integer type but non-integer number ' arglist{ii,2} ' was supplied']);
        end
        if (minval{jj} ~= 0 | maxval{jj} ~= 0)
          if (minval{jj} == 1 & maxval{jj} == 1 & arglist{ii,2} < 0)
            error(['Argument ' arglist{ii,1} ' must be bigger or equal to zero!']);
          elseif (minval{jj} == -1 & maxval{jj} == -1 & arglist{ii,2} > 0)
            error(['Argument ' arglist{ii,1} ' must be smaller or equal to zero!']);
          elseif (minval{jj} == 2 & maxval{jj} == 2 & arglist{ii,2} <= 0)
            error(['Argument ' arglist{ii,1} ' must be bigger than zero!']);
          elseif (minval{jj} == -2 & maxval{jj} == -2 & arglist{ii,2} >= 0)
            error(['Argument ' arglist{ii,1} ' must be smaller than zero!']);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} < minval{jj})
            error(['Argument ' arglist{ii,1} ' must be bigger than ' num2str(minval{jj})]);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} > maxval{jj})
            error(['Argument ' arglist{ii,1} ' must be smaller than ' num2str(maxval{jj})]);
          end
        end
     end
     if ~strcmp(narglist{jj,2},'OK_out') &  ~strcmp(narglist{jj,2},'OK_in')
       narglist{jj,2} = arglist{ii,2};
     end
   end
   end
   if (wasmatched == 0 & ~strcmp(arglist{ii,1},''))
        error(['Argument ' arglist{ii,1} ' is not a valid argument for this function']);
   end
end
% match the remaining inputs/outputs to the unused arguments and test for missing required inputs
 for jj=1:size(narglist,1)
     if  strcmp(paramtype{jj}, 'Toggle')
        if (narglist{jj,2} ==0)
          narglist{jj,1} = '';
        end;
        narglist{jj,2} = '';
     end;
     if  ~strcmp(narglist{jj,2},'__input') && ~strcmp(narglist{jj,2},'__output') && istoggle(jj) && ~ was_set(jj)
          narglist{jj,1} = '';
          narglist{jj,2} = '';
     end;
     if strcmp(narglist{jj,2}, '__input')
      if (minval{jj} == 0)  % meaning this input is required
        if (nextinput > size(Inputs))
           error(['Required input ' narglist{jj,1} ' has no corresponding input in the list!']);
        else
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        end
      else  % this is an optional input
        if (nextinput <= length(Inputs))
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end;
     else
     if strcmp(narglist{jj,2}, '__output')
      if (minval{jj} == 0) % this is a required output
        if (nextoutput > nargout & nargout > 1)
           error(['Required output ' narglist{jj,1} ' is not stated in the assignment list!']);
        else
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
          NumReqOutputs = NumReqOutputs-1;
        end
      else % this is an optional output
        if (nargout - nextoutput >= NumReqOutputs)
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end
     end
  end
end
if nargout
   varargout = cell(1,nargout);
else
  varargout = cell(1,1);
end
global KhorosRoot
if exist('KhorosRoot') && ~isempty(KhorosRoot)
w=['"' KhorosRoot];
else
if ispc
  w='"C:\Program Files\dip\khorosBin\';
else
[s,w] = system('which cantata');
w=['"' w(1:end-8)];
end
end
[varargout{:}]=callKhoros([w 'kcolorspace"  '],Inputs,narglist);


function [TorF, vstr, rdate] = have_feature_yalmip()
%HAVE_FEATURE_YALMIP  Detect availability/version info for YALMIP
%
%   Feature detection function implementing 'yalmip' tag for HAVE_FEATURE
%   to detect availability/version of YALMIP modeling platform
%   (https://yalmip.github.io).
%
%   See also HAVE_FEATURE, YALMIP.

%   MP-Opt-Model
%   Copyright (c) 2004-2020, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MP-Opt-Model.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://github.com/MATPOWER/mp-opt-model for more info.

TorF = exist('yalmip','file') == 2;
vstr = '';
rdate = '';
if TorF
    vstr = yalmip('version');
    if length(vstr) == 8
        yr = str2num(vstr(1:4));
        mo = str2num(vstr(5:6));
        dy = str2num(vstr(7:8));
        rdate = datestr([yr mo dy 0 0 0], 'dd-mmm-yyyy');
    end
end


function str= str_vec2str(v, fmt, inbetween)
%str= str_vec2str(v, <format, inbetween=', '>)
%
% v can be a vector of real numbers or a cell array of strings.
% the default for format is '%d' in the former and '%s' in the latter case.

%narginchk(1,3)
nargchk(1, 3, nargin);
misc_checkType(v,'DOUBLE[-]|CELL{CHAR}');
misc_checkTypeIfExists('fmt','CHAR');
misc_checkTypeIfExists('inbetween','CHAR');

if ~exist('fmt', 'var') || isempty(fmt),
  if iscell(v) || ischar(v),
    fmt='%s';
  else
    fmt='%d';
  end
end
if ~exist('inbetween', 'var'), inbetween=', '; end

if isempty(v),
  str= '[]';
elseif iscell(v),
  isprint= 1:length(v);
  for vi= 1:length(v),
    if ischar(v{vi}),
      fstr{vi}= ['%s' inbetween];
    elseif ~iscell(v{vi}) && ~isstruct(v{vi}),
      fstr{vi}= repmat([fmt inbetween], 1, length(v{vi}));
    else
      isprint= setdiff(isprint, vi,'legacy');
    end
  end
  if isempty(isprint), str=''; return; end
  v= {v{isprint}};
  fstr= {fstr{isprint}};
  if length(isprint)>1,
    str= [sprintf([fstr{1:end-1}], v{1:end-1}) ...
          sprintf(fstr{end}(1:end-length(inbetween)), v{end})];
  else
    str= sprintf(fstr{end}(1:end-length(inbetween)), v{end});
  end
else
  if length(v)==1 || ischar(v),
    str= sprintf(fmt, v);
  else
    str= [sprintf([fmt inbetween], v(1:end-1)) ...
          sprintf(fmt, v(end))];
  end
end


function plotb2east
% set the default plot direction of the x-axis

setMTEXpref('bAxisDirection','east');
setMTEXpref('aAxisDirection','');
setMTEXpref('aStarAxisDirection','');


function figure_handle = PTKGraphContextVsMetric(table, metric, context_list, patient_uids)
    % PTKGraphContextVsMetric. Plots a graph showing measurement values against lung regions for one or more subjects
    %
    % PTKGraphContextVsMetric creates a figure and plots a graph showing measurements for particular lung regions, for one or more patients.
    %
    % The data to plot must be held in a MimResultsTable. You specify which contexts (regions), which metric (measurement) and which patients to plot.
    % The contexts (regions) will be shown along the x-axis, and the values of the metric will be shown on the y-axis.
    %
    % Labels and ticks will be automatically generated from the data.
    %
    % Note the figure is optimised for exporting to a file, not for displaying on-screen. The on-screen figure is not intended for viewing and may have font and graphic sizes in the wrong proportions. To view the figure in its correct proportions, you should export the figure as a graphics file (e.g. png or jpg) and then view the file.
    %
    % Syntax:
    %     figure_handle = PTKGraphContextVsMetric(table, metric, context_list, patient_uids)
    %
    % Inputs:
    %     table - a MimResultsTable containing the data to plot. Only a subset of data will be plotted, determined by the other parameters.
    %     metric - a string containing the id of the metric to plot. This must correspond to the metic id in the table.
    %     context_list - Set to [] to plot all contexts, otherwise specify a set of one or more contexts or context sets to plot. Contexts will appear on the x-axis.
    %     patient_uids - Set to [] to plot all patients, otherwise specify a set of one of more patient UIDs to appear on the graph.
    %         Each patient will appear with different markers and will appear in the legend.
    %
    % Output:
    %     figure_handle - the handle of the generated figure. Use this handle to export the figure to an image file
    %
    %     Licence
    %     -------
    %     Part of the TD Pulmonary Toolkit. https://github.com/tomdoel/pulmonarytoolkit
    %     Author: Tom Doel, 2014.  www.tomdoel.com
    %     Distributed under the GNU GPL v3 licence. Please see website for details.
    %

    if nargin < 4
        patient_uids = table.NameMaps{1}.keys;
    end

    y_label = table.NameMaps{2}(metric);

    figure_title = y_label;

    if numel(patient_uids) == 1
        figure_title = [figure_title, ' : ', table.NameMaps{1}(patient_uids{1})];
    end

    if nargin < 3 || isempty(context_list)
        context_list = table.IndexMaps{3}.keys;
    end

    context_list = SortContexts(context_list);

    metrix_index = table.IndexMaps{2}(metric);

    number_of_subjects = numel(patient_uids);

    colours = {[0, 0.7, 0.7], [0, 0, 1], [1, 0, 0], [0.7, 0, 0.7], [0, 0.7, 0], [0, 0, 0]};
    while numel(colours) < number_of_subjects
        colours = [colours, colours];
    end

    symbols = {'^', 'd', 'p', 'h', 's', 'o', '^', '*', 'v', '+'};
    while numel(symbols) < number_of_subjects
        symbols = [symbols, symbols];
    end

    label_font_size = 10;
    x_tick_label_size = 10;
    y_tick_label_size = 8;
    x_lung_label_size = 8;
    if numel(context_list) > 10
        x_tick_label_size = 5;
    end

    right_lung_colour = [0.7, 0, 0];
    left_lung_colour = [0, 0, 0.7];

    legend_font_size = 5;
    widthheightratio = 4/3;
    page_width_cm = 13;
    font_name = PTKSoftwareInfo.GraphFont;
    marker_line_width = 1;
    context_line_width = 1;
    marker_size = 8;
    legend_marker_size = 6;

    legend_strings = {};

    max_y = 0;
    min_y = [];

    context_labels = {};

    for context_list_index = 1 : numel(context_list)
        if ~isempty(context_list{context_list_index})
            context_text_label = table.NameMaps{3}(char(context_list{context_list_index}));
            if length(context_text_label) > 2
                if strcmp(context_text_label(1:2), 'R_') || strcmp(context_text_label(1:2), 'L_')
                    context_text_label = context_text_label(3:end);
                end
            end
            context_labels{end + 1} = context_text_label;
        end
    end

    figure_handle = figure;
    set(figure_handle, 'Units', 'centimeters');
    graph_size = [page_width_cm, (page_width_cm/widthheightratio)];

    axes_handle = gca;
    set(figure_handle, 'Name', figure_title);
    set(figure_handle, 'PaperPositionMode', 'auto');
    set(figure_handle, 'position', [0,0, graph_size]);
    hold(axes_handle, 'on');

    x_ticks = [];
    max_x = 0;

    plots = [];
    right_lung_segments_label_position = [];
    left_lung_segments_label_position = [];

    x_ticks_color_map = containers.Map('KeyType', 'uint32', 'ValueType', 'any');
    x_ticks_label_map = containers.Map('KeyType', 'uint32', 'ValueType', 'any');

    for patient_iterator = 1 : number_of_subjects
        patient_uid = patient_uids{patient_iterator};
        patient_index = table.IndexMaps{1}(patient_uid);

        x_coords = [];
        y_coords = [];

        x_coord = 1;

        for context_list_index = 1 : numel(context_list)
            this_context = char(context_list{context_list_index});
            if ~isempty(this_context)
                context_colour = [0.1, 0.1, 0.1];
                if length(this_context) > 1
                    if strcmp(this_context(1:2), 'R_')
                        context_colour = right_lung_colour;
                    elseif strcmp(this_context(1:2), 'L_')
                        context_colour = left_lung_colour;
                    end
                end

                if strcmp(this_context, 'R_M')
                    right_lung_segments_label_position = x_coord + 0.5;
                elseif strcmp(this_context, 'L_IL')
                    left_lung_segments_label_position = x_coord;
                end
                context_table_index = table.IndexMaps{3}(char(this_context));
                result = table.ResultsTable{patient_index, metrix_index, context_table_index, :};
                if ~isempty(result)
                    x_coords(end + 1) = x_coord;
                    x_ticks = union(x_ticks, x_coord);
                    y_coords(end + 1) = result;
                    x_ticks_color_map(x_coord) = {context_colour};

                    context_text_label = table.NameMaps{3}(this_context);
                    if length(context_text_label) > 2
                        if strcmp(context_text_label(1:2), 'R_') || strcmp(context_text_label(1:2), 'L_')
                            context_text_label = context_text_label(3:end);
                        end
                    end
                    context_labels{end + 1} = context_text_label;

                    x_ticks_label_map(x_coord) = {context_text_label};
                end
            end
            x_coord = x_coord + 1;
        end

        colour = colours{patient_iterator};
        symbol = symbols{patient_iterator};
        marker_face_colour = min(1, colour + 0.5);

        plots_info = [];
        plots_info.X = x_coords;
        plots_info.Y = y_coords;
        plots_info.Symbol = symbol;
        plots_info.Colour = colour;
        plots_info.MarkerFaceColour = marker_face_colour;

        plots{patient_iterator} = plots_info;

        % Find the maxima and maxima
        if isempty(min_y)
            min_y = min(y_coords(:));
        else
            min_y = min(min_y, min(y_coords(:)));
        end

        max_y = max(max_y, max(y_coords(:)));

        max_x = max(max_x, x_coord);

        legend_strings{patient_iterator} = table.NameMaps{1}(patient_uid);
    end

    [y_tick_spacing, min_y, max_y] = MimGraphUtilities.GetOptimalTickSpacing(min_y, max_y);

    y_ticks = min_y : y_tick_spacing : max_y;

    % Draw lines for each context
    for x_tick_index = 1 : numel(x_ticks)
        x_tick = x_ticks(x_tick_index);
        context_line_colour = x_ticks_color_map(x_tick);

        h_line = line('Parent', axes_handle, 'XData', [x_tick, x_tick], 'YData', [min_y, max_y], 'Color', context_line_colour{1}, 'LineStyle', ':', 'LineWidth', context_line_width);
        set(get(get(h_line,'Annotation'),'LegendInformation'), 'IconDisplayStyle','off'); % Exclude line from legend

        y_offset_ticklabel = abs(max_y - min_y)/60;
        context_label = x_ticks_label_map(x_tick);
        text(x_tick, min_y - y_offset_ticklabel, context_label{1}, 'FontSize', x_tick_label_size, 'clipping', 'off', 'HorizontalAlignment', 'center', 'VerticalAlignment', 'top', 'Color', context_line_colour{1});
    end

    % Set the axes
    ylabel(axes_handle, y_label, 'FontName', font_name, 'FontSize', label_font_size);
    set(gca, 'XTick', [])
    set(gca, 'XTickLabel', '');
    set(gca, 'YTick', y_ticks, 'FontSize', y_tick_label_size)
    axis([0 max_x min_y max_y]);

    % Now draw the plots
    for patient_iterator = 1 : number_of_subjects
        plots_info = plots{patient_iterator};
        plot(axes_handle, plots_info.X, plots_info.Y, plots_info.Symbol, 'LineWidth', marker_line_width, 'MarkerEdgeColor', plots_info.Colour, 'Color', plots_info.Colour, 'MarkerSize', marker_size, 'MarkerFaceColor', plots_info.MarkerFaceColour);
    end

    if ~isempty(right_lung_segments_label_position) && ~isempty(left_lung_segments_label_position)
        y_offset = abs(max_y - min_y)/15;
        text(right_lung_segments_label_position, min_y - y_offset, 'Right lung', 'FontSize', x_lung_label_size, 'clipping', 'off', 'HorizontalAlignment', 'center', 'Color', right_lung_colour);
        text(left_lung_segments_label_position, min_y - y_offset, 'Left lung', 'FontSize', x_lung_label_size, 'clipping', 'off', 'HorizontalAlignment', 'center', 'Color', left_lung_colour);
    end

    % Create the legend
    legend_handle = legend(legend_strings, 'FontName', font_name, 'FontSize', legend_font_size, 'Location', 'NorthEast');
    legend_children = get(legend_handle, 'Children');
    for child = legend_children'
        if strcmp(get(child, 'Type'), 'line')
            if ~strcmp(get(child, 'Marker'), 'none')
                set(child, 'MarkerSize', legend_marker_size);
            end
        end
    end
end

function sorted_contexts = SortContexts(contexts)
    contexts_as_chars = [];
    for context = contexts
        contexts_as_chars{end + 1} = char(context);
    end
    contexts = contexts_as_chars;
    sorted_contexts = [];
    last_context_was_null = true;
    for context_set = GetContextLabels
        context = context_set{1};

        % We use null as a separator between groups of contexts
        if isempty(context)
            if ~last_context_was_null
                sorted_contexts{end + 1} = [];
                sorted_contexts{end + 1} = [];
            end
            last_context_was_null = true;
        else
            char_context = char(context);
            if ismember(char_context, contexts)
                sorted_contexts{end + 1} = char_context;
                contexts = setdiff(contexts, char_context);
                last_context_was_null = false;
            end
        end
    end
    sorted_contexts = [sorted_contexts, contexts];
end

function context_labels = GetContextLabels
    context_labels = {
        PTKContext.Lungs, PTKContext.RightLung, PTKContext.LeftLung, [], ...
        PTKContext.RightUpperLobe, PTKContext.RightMiddleLobe, PTKContext.RightLowerLobe, [], ...
        PTKContext.LeftUpperLobe, PTKContext.LeftLowerLobe, [], ...
        PTKContext.R_AP, PTKContext.R_P, PTKContext.R_AN, ... % Right upper lobe
        PTKContext.R_L, PTKContext.R_M, ... % Right middle lobe
        PTKContext.R_S, PTKContext.R_AB, PTKContext.R_LB, PTKContext.R_MB, PTKContext.R_PB, [], ... % Right lower lobe
        PTKContext.L_APP, PTKContext.L_APP2, PTKContext.L_AN, ... % Upper left lobe
        PTKContext.L_SL, PTKContext.L_IL, ... % Lingular of upper left lobe
        PTKContext.L_S, PTKContext.L_AMB, PTKContext.L_PB, PTKContext.L_LB}; % lower left lobe
end


function SO3F = times(SO3F1,SO3F2)
% overloads |SO3F1 .* SO3F2|
%
% Syntax
%   sF = SO3F1 .* SO3F2
%   sF = a .* SO3F2
%   sF = SO3F1 .* a
%
% Input
%  SO3F1, SO3F2 - @SO3FunBingham
%  a - double
%
% Output
%  SO3F - @SO3Fun
%

if isnumeric(SO3F1)
  SO3F = SO3F2;
  SO3F.weight = SO3F.weight .* SO3F1;
  return
end

SO3F = times@SO3Fun(SO3F1,SO3F2);

end


function tnet = vl_simplenn_tidy(net)
%VL_SIMPLENN_TIDY  Fix an incomplete or outdated SimpleNN network.
%   NET = VL_SIMPLENN_TIDY(NET) takes the NET object and upgrades
%   it to the current version of MatConvNet. This is necessary in
%   order to allow MatConvNet to evolve, while maintaining the NET
%   objects clean. This function ignores custom layers.
%
%   The function is also generally useful to fill in missing default
%   values in NET.
%
%   See also: VL_SIMPLENN().

% Copyright (C) 2014-15 Andrea Vedaldi.
% All rights reserved.
%
% This file is part of the VLFeat library and is made available under
% the terms of the BSD license (see the COPYING file).

tnet = struct('layers', {{}}, 'meta', struct()) ;

% copy meta information in net.meta subfield
if isfield(net, 'meta')
  tnet.meta = net.meta ;
end

if isfield(net, 'classes')
  tnet.meta.classes = net.classes ;
end

if isfield(net, 'normalization')
  tnet.meta.normalization = net.normalization ;
end

% copy layers
for l = 1:numel(net.layers)
  defaults = {'name', sprintf('layer%d', l), 'precious', false};
  layer = net.layers{l} ;

  % check weights format
  switch layer.type
    case {'conv', 'convt', 'bnorm'}
      if ~isfield(layer, 'weights')
        layer.weights = {...
          layer.filters, ...
          layer.biases} ;
        layer = rmfield(layer, 'filters') ;
        layer = rmfield(layer, 'biases') ;
      end
  end
  if ~isfield(layer, 'weights')
    layer.weights = {} ;
  end

  % check that weights inlcude moments in batch normalization
  if strcmp(layer.type, 'bnorm')
    if numel(layer.weights) < 3
      layer.weights{3} = ....
        zeros(numel(layer.weights{1}),2,'single') ;
    end
  end

  % fill in missing values
  switch layer.type
    case {'conv', 'pool'}
      defaults = [ defaults {...
        'pad', 0, ...
        'stride', 1, ...
        'opts', {}}] ;

    case 'convt'
      defaults = [ defaults {...
        'crop', 0, ...
        'upsample', 1, ...
        'numGroups', 1, ...
        'opts', {}}] ;

    case {'pool'}
      defaults = [ defaults {...
        'method', 'max', ...
        'pad', 0, ...
        'stride', 1, ...
        'opts', {}}] ;

    case 'relu'
      defaults = [ defaults {...
        'leak', 0}] ;

    case 'dropout'
      defaults = [ defaults {...
        'rate', 0.5}] ;

    case {'normalize', 'lrn'}
      defaults = [ defaults {...
        'param', [5 1 0.0001/5 0.75]}] ;

    case {'pdist'}
      defaults = [ defaults {...
        'noRoot', false, ...
        'aggregate', false, ...
        'p', 2, ...
        'epsilon', 1e-3, ...
        'instanceWeights', []} ];
  end

  for i = 1:2:numel(defaults)
    if ~isfield(layer, defaults{i})
      layer.(defaults{i}) = defaults{i+1} ;
    end
  end

  % save back
  tnet.layers{l} = layer ;
end