function NR = esvm_show_transfer_figure(I, models, topboxes, overlays, ...
                                        current_rank, corr)
% Show a figure with the detections of the exemplar svm model
% NOTE(TJM): this function needs cleanup, but works in the pipeline
%
% Copyright (C) 2011-12 by Tomasz Malisiewicz
% All rights reserved.
%
% This file is part of the Exemplar-SVM library and is made
% available under the terms of the MIT license (see COPYING file).
% Project homepage: https://github.com/quantombone/exemplarsvm

topboxes = topboxes(1:min(2,size(topboxes,1)),:);

%if enabled, try to transfer objects too
%add_one = 1;
add_one = 0;

figure(1)
clf
if add_one == 1
  ha = tight_subplot(2, 2, .05, ...
                     .1, .01);
  NR = [2 2];
else
  ha = tight_subplot(1, 2, .05, ...
                     .01, .01);
  %hb = tight_subplot(1, 2, .05, ...
  %                   .1, .01);
  NR = [2 2];

end

PADDER = 100;
Ipad = pad_image(I,PADDER);

%Cut out detection chunks
for q = size(topboxes,1):-1:1
  if q>size(topboxes,1)
    continue
  end

  bb = topboxes(q,1:4);

  bb = bb + PADDER;
  r1 = [round(bb(2)) round(bb(4))];
  r2 = [round(bb(1)) round(bb(3))];
  r1 = cap_range(r1,1,size(Ipad,1));
  r2 = cap_range(r2,1,size(Ipad,2));

  mask = zeros(size(Ipad,1),size(Ipad,2));
  mask(r1(1):r1(2), r2(1):r2(2))=1;
  mask = logical(mask);
  chunks{q} = maskCropper(Ipad, mask);
end

%%NOTE: below is a loop, but we only process the first element
%since we only show the top association
N = min(1,size(topboxes,1));
for i = 1:N

  mid = topboxes(i,6);
  flip = topboxes(i,7);
  hogpic = HOGpicture(models{topboxes(i,6)}.model.w);
  hogpic = jettify(hogpic);
  if flip == 1
    hogpic = flip_image(hogpic);
  end

  Iex = esvm_get_exemplar_icon(models, mid, topboxes(i,7));

  Iex1 = imresize(chunks{i},[size(Iex,1) size(Iex,2)]);
  Iex1 = max(0.0,min(1.0,Iex1));

  Iex1 = imresize(hogpic,[size(Iex1,1) size(Iex,2)], 'nearest');
  Iex1 = max(0.0,min(1.0,Iex1));

  PPP = round(size(Iex,1)*.2);
  Iex2 = Iex1(1:PPP,:,:)*0+1;
  Ishow = cat(1,Iex1,Iex2,Iex);

  SHOW_SEG = 1;
  if SHOW_SEG == 1

    Ia = (overlays{1}.mini_overlay.I.* ...
              repmat(overlays{1}.mini_overlay.alphamask,[1 1 3]));
    Ib = Iex;
    alphamap = overlays{1}.mini_overlay.alphamask;
    alphamap(alphamap>0) = .5;
    alphamap(alphamap==0) = .7;
    alphamap = repmat(alphamap,[1 1 3]);
    Itotal = Ia.*alphamap + Ib.*(1-alphamap);

    Imeta = Itotal;
    offset = [0 size(Ishow,1)+size(Iex2,1)];

    %Ishow = cat(1,Ishow,Iex2,Imeta);

  elseif strcmp(models{mid}.cls,'bus')
    m1 = repmat(double(overlays{1}.mini_overlay.alphamask>0)*.8,[1 ...
                    1 3]);
    m2 = repmat(double(overlays{1}.mini_overlay.alphamask>0)*.2,[1 ...
                    1 3]);
    m2(m2(:)==0) = 1;

    Imeta = overlays{1}.mini_overlay.I.*m1 +...
            Iex.*m2;
    offset = [0 size(Ishow,1)+size(Iex2,1)]
    overlays{1}.mini_overlay.faces = ...
        cellfun2(@ ...
                 (x)bsxfun(@plus,x,offset),overlays{1}.mini_overlay.faces);

    %Ishow = cat(1,Ishow,Iex2,Imeta);
  end

  bb1 = [1 1 size(Iex,2) size(Iex,1)];
  bb2 = bb1;

  bb2([2 4]) = bb2([2 4]) + size(Iex,1) + PPP;
  axes(ha(1));
  imagesc(Ishow)

  axis image
  axis off

  bouter = [1 1 size(Ishow,2) size(Ishow,1)];
  bouter(1) = bouter(1) - round(size(Ishow,2)*.05);
  bouter(2) = bouter(2) - round(size(Ishow,1)*.05);
  bouter(3) = bouter(3) + round(size(Ishow,2)*.05);
  bouter(4) = bouter(4) + round(size(Ishow,1)*.05);
  plot_bbox(bouter, '', [0 0 0], [0 0 0], 0, [2 1])

  if isfield(overlays{1}.mini_overlay,'faces')
    plot_faces(overlays{1}.mini_overlay.faces);
  end

  axis image
  curcolor = [0 1 0];
  if corr == 0
    curcolor = [1 0 0 ];
  end

  plot_bbox(bb1, sprintf('Exemplar-SVM %s %d',models{mid}.cls,mid), ...
            curcolor, curcolor, 0, [2 1])

  %sprintf('Exemplar.%d',mid)

  plot_bbox(bb2, sprintf('Exemplar Image %d',mid), [1 1 0], [1 1 0], 0, [2 1])

  id_string = '';
  if isfield(models{abs(mid)},'curid')
    try
      oid = models{abs(mid)}.objectid;
    catch
      oid = -1;
    end
    id_string = sprintf('%s.%d',models{abs(mid)}.curid, ...
                        oid);
  else
    id_string = sprintf('%s@%s',models{abs(mid)}.models_name,models{abs(mid)}.cls);
  end
  lrstring='';
  if flip == 1
    lrstring = '.LR';
  end

  sprintf('Exemplar: %s%s',id_string,lrstring);

end

extraI = overlays{1}.I;

clipped_top = clip_to_image(topboxes(1,:),[1 1 size(extraI,2) ...
                    size(extraI,1)]);
clipped_top([1 2]) = clipped_top([1 2])+2;
clipped_top([3 4]) = clipped_top([3 4])-2;

axes(ha(2));

PPP = round(size(I,1)*.05);
I2 = I(1:PPP,:,:)*0+1;
Ishow = cat(1,I,I2,extraI);
%Ishow = extraI;

imagesc(Ishow)
axis image
axis off
%title(sprintf('Detection (Rank=%d, Score=%.3f)',current_rank, ...
%              topboxes(1,end)))

curcolor = [0 1 0];
if corr == 0
  curcolor = [1 0 0 ];
end

plot_bbox(clipped_top,sprintf('%s: %.3f',models{1}.cls,clipped_top(end)),...
          curcolor, curcolor,0,[2 1]);

if 0
  %%NOTE: not sure why this is not working?
%% find xform from exemplar onto new detection
start_box = [1 1 size(Iex,2) size(Iex,1)];
end_box = topboxes(1,1:4);
xform = find_xform(start_box,end_box);

faces2 = cellfun2(@(x)apply_xform(x,xform), ...
                  overlays{1}.mini_overlay.faces);

offset = [0 size(I,1)+size(I2,1)];
offset = [0 0];
faces2 = cellfun2(@ ...
                  (x)bsxfun(@plus,x,offset),faces2);
end
%plot_faces(faces2);

%axes(ha(3));
%imagesc(extraI);

%sprintf('Exemplar.%d',mid)
%orig green
clipped_top([2 4]) = clipped_top([2 4]) + size(I,1)+size(I2,1);

%dont do yellow box for segmentation
if 1 %%~strcmp(models{mid}.cls,'bus')
  plot_bbox(clipped_top,'Exemplar',[1 1 0],[1 1 0],0,[2 1]);
end
axis image
axis off
%title('Appearance Transfer')%sprintf('Exemplar Inpainting: %.3f',topboxes(1,end)))
%title(sprintf('Exemplar Inpainting: %.3f',topboxes(1,end)))

title('Exemplar-SVM detection','FontSize',12);

if add_one == 1
  %transfer objects here

  is_complement = sum(ismember(models{1}.cls,{'bicycle', ...
                    'motorbike','horse'}));

  if isfield(exemplar_overlay,'friendbb') & ...
        size(exemplar_overlay.friendbb,1)>0

    axes(ha(4));

    imagesc(I)
    axis image
    axis off

    c = jet(20);

    for q = 1:size(exemplar_overlay.friendbb,1)
      [aa,bb] = find(ismember(VOCopts.classes, ...
                              exemplar_overlay.friendclass{q}));
      curcolor = c(aa,:);
      %Yellow color always
      curbb = exemplar_overlay.friendbb(q,:);
      curbb = clip_to_image(curbb,[1 1 size(I,2) size(I,1)]);

      plot_bbox(curbb,...
                exemplar_overlay.friendclass{q},curcolor,curcolor,1,[2 ...
                    1]);

      [aa,bb] = find(ismember(VOCopts.classes, ...
                              models{1}.cls));
      curcolor = c(aa,:);
      curcolor = [1 1 0];
      curcolor = [0 1 0];
      if corr == 0
        curcolor = [1 0 0 ];
      end

      curbb = clip_to_image(topboxes(1,:),[1 1 size(I,2) size(I, ...
                                                  1)]);

      plot_bbox(curbb,models{1}.cls,curcolor,curcolor,0,[2 1]);
      title(sprintf('Detection: Predicted %s', ...
                    exemplar_overlay.friendclass{1}));

    end
  elseif ~is_complement && isfield(exemplar_overlay,'overlay2')
    %% SHOW TRANSFERRED BUSES
    axes(ha(4));
    imagesc(exemplar_overlay ...
            .overlay2.segI);
    title(exemplar_overlay.overlay2.title);
    axis image
    axis off

    %Faces are for transferring geometry
    if isfield(exemplar_overlay.overlay2,'faces')
      faces = exemplar_overlay.overlay2.faces;
      for q = 1:length(faces)
        if length(faces{q})>0
          f = faces{q};
          %%estimate Xform here:
          source = topboxes(1,:);
          target = models{source(6)}.gt_box;

          if topboxes(1,7) == 1
            target = flip_box(target,models{source(6)}.sizeI);
            f = flip_faces(f,models{source(6)}.sizeI);

            fprintf(1,'got here for a flip')
            %source = flip_box(source,size(I));
          end

          %%BUG: we should be using the new find_xform function...
          clear xs ys
          xs(:,1) = target([1 2])';
          xs(:,2) = target([3 2])';
          xs(:,3) = target([1 4])';
          xs(:,4) = target([3 4])';

          ys(:,1) = source([1 2])';
          ys(:,2) = source([3 2])';
          ys(:,3) = source([1 4])';
          ys(:,4) = source([3 4])';

          xs(3,:) = 1;
          ys(3,:) = 1;

          A=ys*pinv(xs);
          A(abs(A)<.000001) = 0;

          f2 = f';
          f2(3,:) = 1;

          f2 = A*f2;
          f2(3,:) = [];
          f = f2';

          hold on;
          plot([f(:,1); f(1,1)],[f(:,2); f(1,2)],'k','LineWidth', ...
               4);

        end
      end
    end

  else
    %% SHOW FRIENDS
    axes(ha(4))
    imagesc(I)
    axis image
    axis off

    titler = sprintf('Detection');
    if isfield(models{mid},'friendclass')
      titler = [titler sprintf(': No %s',models{mid}.friendclass)];
    end
    title(titler);

    [aa,bb] = find(ismember(VOCopts.classes, ...
                            models{1}.cls));
    c = jet(20);
    curcolor = c(aa,:);
    curcolor = [1 1 0];

    clipped_top = clip_to_image(topboxes(1,:),[1 1 size(extraI,2) ...
                    size(extraI,1)]);
    clipped_top([1 2]) = clipped_top([1 2])+2;
    clipped_top([3 4]) = clipped_top([3 4])-2;
    plot_bbox(clipped_top,models{1}.cls,curcolor,curcolor,0,[2 1]);
  end
end


function data = read_line_by_line(FID);

% first pass, find the number of lines
cnt = 1;
while 1
    tmp = fgetl(FID);
    if tmp == -1
        break;
    else
        cnt = cnt + 1;
    end
end

% second pass, read the data
frewind(FID);
data = cell(cnt-1,1);
cnt = 1;
while 1
    tmp = fgetl(FID);
    if tmp == -1
        break;
    else
        data{cnt} = tmp;
        cnt = cnt + 1;
    end
end


function hout=suptitle(str,varargin)
    % biafra ahanonu
    % started updating: 2016.03.10
    % this is an overloaded suptitle to remove focus stealing

    %SUPTITLE puts a title above all subplots.
    %
    %	SUPTITLE('text') adds text to the top of the figure
    %	above all subplots (a "super title"). Use this function
    %	after all subplot commands.
    %
    %   SUPTITLE is a helper function for yeastdemo.

    %   Copyright 2003-2010 The MathWorks, Inc.

    % Warning: If the figure or axis units are non-default, this
    % will break.

    %========================
    % Amount of the figure window devoted to subplots
    options.plotregion = 0.94;
    % Y position of title in normalized coordinates
    options.titleypos = 0.96;
    % font size
    options.fontSize = [];
    % Str or rgb vector: color of suptitle
    options.Color = 'k';
	% Str: interpreter, latex or tex
	options.Interpreter = 'latex';
    % get options
    options = ciapkg.io.getOptions(options,varargin);
    % display(options)
    % unpack options into current workspace
    % fn=fieldnames(options);
    % for i=1:length(fn)
    %   eval([fn{i} '=options.' fn{i} ';']);
    % end
    %========================

    % Parameters used to position the supertitle.

    % Amount of the figure window devoted to subplots
    plotregion = options.plotregion;

    % Y position of title in normalized coordinates
    titleypos  = options.titleypos;

    % Fontsize for supertitle
    if isempty(options.fontSize)
        fs = get(gcf,'defaultaxesfontsize')+4;
    else
        fs = options.fontSize;
    end

    % Fudge factor to adjust y spacing between subplots
    fudge=1;

    haold = gca;
    figunits = get(gcf,'units');

    % Get the (approximate) difference between full height (plot + title
    % + xlabel) and bounding rectangle.

    if (~strcmp(figunits,'pixels')),
        set(gcf,'units','pixels');
        pos = get(gcf,'position');
        set(gcf,'units',figunits);
    else
        pos = get(gcf,'position');
    end
    ff = (fs-4)*1.27*5/pos(4)*fudge;

    % The 5 here reflects about 3 characters of height below
    % an axis and 2 above. 1.27 is pixels per point.

    % Determine the bounding rectangle for all the plots

    % h = findobj('Type','axes');

    % findobj is a 4.2 thing.. if you don't have 4.2 comment out
    % the next line and uncomment the following block.

    h = findobj(gcf,'Type','axes');  % Change suggested by Stacy J. Hills

    max_y=0;
    min_y=1;
    oldtitle = NaN;
    numAxes = length(h);
    thePositions = zeros(numAxes,4);
    for i=1:numAxes
        pos=get(h(i),'pos');
        thePositions(i,:) = pos;
        if (~strcmp(get(h(i),'Tag'),'suptitle')),
            if (pos(2) < min_y)
                min_y=pos(2)-ff/5*3;
            end;
            if (pos(4)+pos(2) > max_y)
                max_y=pos(4)+pos(2)+ff/5*2;
            end;
        else
            oldtitle = h(i);
        end
    end
    if max_y > plotregion,
        scale = (plotregion-min_y)/(max_y-min_y);
        for i=1:numAxes
            pos = thePositions(i,:);
            pos(2) = (pos(2)-min_y)*scale+min_y;
            pos(4) = pos(4)*scale-(1-scale)*ff/5*3;
            set(h(i),'position',pos);
        end
    end

    np = get(gcf,'nextplot');
    set(gcf,'nextplot','add');
    if ishghandle(oldtitle)
        delete(oldtitle);
    end
    warning off
    axes('pos',[0 1 1 1],'visible','off','Tag','suptitle','SortMethod','depth');
    warning on
    ht = text('position',[.5 titleypos-1],'Interpreter',options.Interpreter,'String',str);
	set(ht,'horizontalalignment','center','fontsize',fs,'Color',options.Color);
	set(ht,'FontName',get(0,'DefaultAxesFontName'));
    set(gcf,'nextplot',np);
    % focus stealing occurs here, turn off
    set(gcf, 'CurrentAxes', haold)
    % axes(haold); %#ok<MAXES>
    if nargout,
        hout=ht;
    end
end


% Configurations for the algorithsm
% Input:
%       configName:  Name of the config, corresponding to the desired
%       dataset
function config = readConfig(configName)

    if (nargin==0); configName = 'synthetic'; end

    if (strcmp(configName, 'synthetic'))
        config = readConfig_synthetic();

     % To be added
%     elseif (strcmp(configName, 'redwood'))
%         config = readConfigRedWood();
    end

end


function varargout = uplus(varargin)
%UPLUS   Unary plus for a DISKFUN.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

[varargout{1:nargout}] = uplus@separableApprox(varargin{:});

end


function refreshdisp(str,prevstr,iteration)

if ~exist('iteration','var')
    iteration=2;
end

if iteration==1
    fprintf(str)
else
    fprintf(char(8*ones(1,length(prevstr))));
    fprintf(str);
end


function structure = addLevelVersion(structure, level, version)
%  structure = addLevelVersion(structure, level, version)
%
% this function is used internally by TranslateSBML
%
% Takes
%
% 1. structure - any MATLAB_SBML structure
% 2. level - an integer for the value of the level field to be added
% 3. version - an integer for the value of the version field to be added
%
% Returns
%
% 1. structure - the original structure with additional fields 'level' and
%                           'version' added to this and every child
%                           structure
%
% Note:
%             The structure must contain a 'typecode' field

%<!---------------------------------------------------------------------------
% This file is part of libSBML.  Please visit http://sbml.org for more
% information about SBML, and the latest version of libSBML.
%
% Copyright (C) 2013-2018 jointly by the following organizations:
%     1. California Institute of Technology, Pasadena, CA, USA
%     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
%     3. University of Heidelberg, Heidelberg, Germany
%
% Copyright (C) 2009-2013 jointly by the following organizations:
%     1. California Institute of Technology, Pasadena, CA, USA
%     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
%
% Copyright (C) 2006-2008 by the California Institute of Technology,
%     Pasadena, CA, USA
%
% Copyright (C) 2002-2005 jointly by the following organizations:
%     1. California Institute of Technology, Pasadena, CA, USA
%     2. Japan Science and Technology Agency, Japan
%
% This library is free software; you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as
% published by the Free Software Foundation.  A copy of the license
% agreement is provided in the file named "LICENSE.txt" included with
% this software distribution and also available online as
% http://sbml.org/software/libsbml/license.html
%----------------------------------------------------------------------- -->

if ~isfield(structure, 'typecode')
    return;
end;
if length(structure) ~= 1 ||strcmp(structure.typecode, 'SBML_MODEL') ~= 1
    structure = addData(structure, level, version);
end;
for i = 1:length(structure)
    f = fieldnames(structure(i));
    for j = 1:length(f)
        if isstruct(structure(i).(f{j}))
            substr = structure(i).(f{j});
            structure(i).(f{j}) = addLevelVersion(substr, level, version);
        end;
    end;
end;

function str = addData(str, l, v)
f = fieldnames(str);
if sum(ismember(f, 'level')) > 0
    return;
end;
for i=1:length(str)
    str(i).level = l;
    str(i).version = v;
end;


function updateStackedplot(obj, plotIndex)

    %-------------------------------------------------------------------------%

    %-INITIALIZATIONS-%

    axIndex = obj.getAxisIndex(obj.State.Plot(plotIndex).AssociatedAxis);
    plotData = get(obj.State.Plot(plotIndex).Handle);
    lineData = plotData.LineProperties(end:-1:1);

    %-get trace data-%

    sourceTable = plotData.SourceTable;
    displayVariables = plotData.DisplayVariables;
    nTraces = length(plotData.AxesProperties);

    if isempty(sourceTable)
        xData = plotData.XData;
        for t = 1:nTraces
            n = nTraces - t + 1;
            yData{t} = plotData.YData(:, n);
        end

    else
        if istimetable(sourceTable)
            xData = date2NumData(sourceTable.Properties.RowTimes);
        else
            xData = 1:size(sourceTable, 1);
        end

        for t = 1:nTraces
            n = nTraces - t + 1;
            yData{t} = date2NumData(sourceTable.(displayVariables{n}));
        end
    end

    %-------------------------------------------------------------------------%

    %-UPDATE STACKEDPLOT AXIS-%
    updateStackedplotAxis(obj, plotIndex)

    %-------------------------------------------------------------------------%

    %-SET TRACES-%
    traceIndex = plotIndex;

    for t = 1:nTraces

        %-update current trace Index-%
        if t ~= 1
            obj.PlotOptions.nPlots = obj.PlotOptions.nPlots + 1;
            traceIndex = obj.PlotOptions.nPlots;
        end

        %-set current trace-%
        obj.data{traceIndex}.type = 'scatter';
        obj.data{traceIndex}.visible = strcmp(plotData.Visible,'on');
        obj.data{traceIndex}.name = plotData.DisplayLabels{t};
        obj.data{traceIndex}.xaxis = sprintf('x%d', 1);
        obj.data{traceIndex}.yaxis = sprintf('y%d', t);

        %-set current trace data-%
        obj.data{traceIndex}.x = xData;
        obj.data{traceIndex}.y = yData{t};

        %-set current trace marker-%
        switch lineData(t).PlotType
            case 'scatter'
                markerSize = ones(size(xData)) * lineData(t).MarkerSize;
                obj.data{traceIndex}.mode = 'markers';
                obj.data{traceIndex}.marker = extractLineMarker(lineData(t));
                obj.data{traceIndex}.marker.size = markerSize;
                obj.data{traceIndex}.marker.line.width = 1;
            otherwise
                obj.data{traceIndex}.mode = 'lines';
                obj.data{traceIndex}.line = extractLineLine(lineData(t));
        end

    end

    %-------------------------------------------------------------------------%
end

function updateStackedplotAxis(obj, plotIndex)

    %-------------------------------------------------------------------------%

    %-INITIALIZATIONS-%

    axIndex = obj.getAxisIndex(obj.State.Plot(plotIndex).AssociatedAxis);
    plotData = get(obj.State.Plot(plotIndex).Handle);

    %-------------------------------------------------------------------------%

    %-SET X-AXIS-%

    [xaxis, xExpoFormat] = getAxis(obj, plotIndex, 'X');
    obj.layout = setfield(obj.layout, 'xaxis1', xaxis{1});

    %-------------------------------------------------------------------------%

    %-SET Y-AXIS-%

    [yaxis, yExpoFormat] = getAxis(obj, plotIndex, 'Y');

    for a = 1:length(yaxis)
        obj.layout = setfield(obj.layout, sprintf('yaxis%d', a), yaxis{a});
    end

    %-------------------------------------------------------------------------%

    %-SET AXES ANOTATIONS-%

    %-trace title-%
    updateTitle(obj, plotData.Title, [1, 3]);

    %-exponent for x-axis-%
    updateExponentFormat(obj, xExpoFormat(1), [1,1], 'X');

    %-exponent for y-axis-%
    for a = 1:length(yExpoFormat)
        updateExponentFormat(obj, yExpoFormat(a), [1, a], 'Y');
    end
end

function [ax, expoFormat] = getAxis(obj, plotIndex, axName)

    %-------------------------------------------------------------------------%

    %-INITIALIZATIONS-%

    axIndex = obj.getAxisIndex(obj.State.Plot(plotIndex).AssociatedAxis);
    plotData = get(obj.State.Plot(plotIndex).Handle);

    lineFactor = obj.PlotlyDefaults.AxisLineIncreaseFactor;
    axisPos = plotData.Position;
    axisColor = getStringColor(zeros(1,3));
    lineWidth = 1;
    fontSize = plotData.FontSize;
    fontFamily = matlab2plotlyfont(plotData.FontName);;
    tickLen = 5;

    %-------------------------------------------------------------------------%

    %-Parse parameters accorging to axisName (X or Y)

    switch axName
        case {'x', 'X'}
            nAxis = 1;
            nTicks = [5, 12];
            axisLim{nAxis} = plotData.XLimits;
            axisLabel{nAxis} = plotData.XLabel;
            axisDomain{nAxis} = min([axisPos(1) sum(axisPos([1,3]))], 1);
            axisAnchor{nAxis} = 'y1';

        case {'x', 'Y'}
            nAxis = length(plotData.AxesProperties);
            yPos = linspace(axisPos(2), sum(axisPos([2,4])), nAxis+1);
            yOffset = diff(yPos)*0.1; yOffset(1) = 0;

            for a = 1:nAxis
                b = nAxis-a+1;
                axisLim{a} = plotData.AxesProperties(b).YLimits;
                axisLabel{a} = plotData.DisplayLabels{b};
                axisDomain{a} = min([yPos(a)+yOffset(a) yPos(a+1)], 1);
                axisAnchor{a} = 'x1';
            end

            if nAxis < 4
                nTicks = [5, 8];
            else
                nTicks = [3, 5];
            end
    end

    %-------------------------------------------------------------------------%

    %-GET EACH AXIS-%

    for a = 1:nAxis

        %-general-%
        ax{a}.domain = axisDomain{a};
        ax{a}.anchor = axisAnchor{a};
        ax{a}.range = date2NumData(axisLim{a});

        ax{a}.side = 'left';
        ax{a}.mirror = false;
        ax{a}.zeroline = false;

        ax{a}.linecolor = axisColor;
        ax{a}.linewidth = lineWidth;
        ax{a}.exponentformat = obj.PlotlyDefaults.ExponentFormat;

        %-grid-%
        if strcmp(plotData.GridVisible, 'on')
            ax{a}.showgrid = true;
            ax{a}.gridwidth = lineWidth;
            ax{a}.gridcolor = getStringColor(0.15*ones(1,3), 0.15);
        else
            ax{a}.showgrid = false;
        end

        %-ticks-%
        if isnumeric(axisLim{a})
            [tickVals, tickText, expoFormat(a)] = getNumTicks(axisLim{a}, nTicks);

            [tickVals, tickText] = rmTicks(ax{a}.range, tickVals, tickText, 's');
            [tickVals, tickText] = rmTicks(ax{a}.range, tickVals, tickText, 'e');

        elseif isduration(axisLim{a}) || isdatetime(axisLim{a})
            [tickVals, tickText] = getDateTicks(axisLim{a}, nTicks);
            expoFormat(a) = 0;

            [tickVals, tickText] = rmTicks(ax{a}.range, tickVals, tickText, 's');
        end

        ax{a}.showticklabels = true;
        ax{a}.ticks = 'inside';
        ax{a}.ticklen = tickLen;
        ax{a}.tickwidth = lineWidth;

        ax{a}.tickfont.size = fontSize;
        ax{a}.tickfont.family = fontFamily;
        ax{a}.tickfont.color = axisColor;

        ax{a}.tickvals = tickVals;
        ax{a}.ticktext = tickText;

        %-label-%
        if ~isempty(axisLabel{a})
            ax{a}.title = parseString(axisLabel{a});
            ax{a}.titlefont.color = axisColor;
            ax{a}.titlefont.size = fontSize;
            ax{a}.titlefont.family = fontFamily;
        end
    end

    %-------------------------------------------------------------------------%
end

function [tickVals, tickText] = getDateTicks(axisLim, nTicks)

    %-by year-%
    yearLim = year(date2NumData(axisLim));
    isYear = length(unique(yearLim)) > 1;
    refYear = [1, 2, 5];

    if isYear
        yearTick = getTickVals(yearLim, refYear, 1, nTicks);

        for n = 1:length(yearTick)
            tickVals(n) = datenum(datetime(yearTick(n),1,1,'Format','yy'));
            tickText{n} = num2str(yearTick(n));
        end

        return;
    end

    %-by month-%
    monthLim = month(date2NumData(axisLim));
    isMonth = length(unique(monthLim)) > 1;

    if isMonth
        % TODO
        return
    end

    %-by day-%
    dayLim = day(date2NumData(axisLim));
    isDay = length(unique(dayLim)) > 1;
    refDay = [0.5, 1];

    if isDay
        dayTick = getTickVals(dayLim, refDay, 1, nTicks);
        hourTick = 24 * ( dayTick - fix(dayTick) );
        dayTick = fix(dayTick);

        for n = 1:length(dayTick)
            matDate = [yearLim(1),monthLim(1),dayTick(n),hourTick(n),0,0];
            tickVals(n) = datetime(matDate,'Format', 'MMM dd, HH:mm');
            tickText{n} = datestr(tickVals(n), 'mmm dd, HH:MM');
        end

        tickVals = datenum(tickVals);
        return;
    end
end

function [tickVals, tickText, expoFormat] = getNumTicks(axisLim, nTicks)
    refVals = [1, 2, 5];
    refPot = floor(log10(range(axisLim)));
    nonStop = true;

    fixAxisLim = fix(axisLim);

    if ~all(fixAxisLim == 0)
        expoFormat = floor(log10(max(1, range(fixAxisLim))));
    else
        expoFormat = refPot;
    end

    if abs(expoFormat) < 3 expoFormat = 0; end

    tickVals = getTickVals(axisLim, refVals, refPot, nTicks);

    for n = 1:length(tickVals)
        tickText{n} = num2str(tickVals(n)/10^expoFormat);
    end
end

function tickVals = getTickVals(axisLim, refVals, refPot, nTicks)
    done = false;

    for p = refPot:-1:refPot-1
        for v = refVals
            vp = v*10^p;

            startTick = axisLim(1) - mod(axisLim(1), vp);
            if startTick < axisLim, startTick = startTick + vp; end
            endTick = axisLim(2) - mod(axisLim(2), vp);
            nPoints = floor(range([startTick, endTick])/vp) + 1;

            tickVals = startTick:vp:endTick;
            lenTicks = length(tickVals);

            if lenTicks >= nTicks(1) && lenTicks <= nTicks(2)
                done = true;
                break;
            end
        end

        if done, break; end
    end
end

function updateTitle(obj, titleText, xySource)
    xaxis = eval(sprintf('obj.layout.xaxis%d', xySource(1)));
    yaxis = eval(sprintf('obj.layout.yaxis%d', xySource(2)));
    anIndex = 1;
    if ~isempty(titleText), titleText = parseString(titleText); end

    ann.showarrow = false;
    ann.text = sprintf('%s', titleText);
    ann.xref = 'paper';
    ann.yref = 'paper';
    ann.x = mean(xaxis.domain);
    ann.y = yaxis.domain(2);
    ann.xanchor = 'middle';
    ann.yanchor = 'bottom';
    ann.font.size = 1.5*xaxis.tickfont.size;
    ann.font.color = xaxis.tickfont.color;
    ann.font.family = xaxis.tickfont.family;

    obj.layout.annotations{anIndex} = ann;
end

function updateExponentFormat(obj, expoFormat, xySource, axName)

    axName = lower(axName);
    xaxis = eval(sprintf('obj.layout.xaxis%d', xySource(1)));
    yaxis = eval(sprintf('obj.layout.yaxis%d', xySource(2)));
    anIndex = obj.PlotlyDefaults.anIndex + 1;

    if expoFormat ~= 0
        exponentText = sprintf('\\times10^%d', expoFormat);
        exponentText = parseString(exponentText, 'tex');
        % exponentText = ['
' exponentText '
'];

        ann.showarrow = false;
        ann.text = exponentText;
        ann.xref = 'paper';
        ann.yref = 'paper';
        ann.font.size = eval(sprintf('%saxis.tickfont.size', axName));
        ann.font.color = eval(sprintf('%saxis.tickfont.color', axName));
        ann.font.family = eval(sprintf('%saxis.tickfont.family', axName));
        ann.xanchor = 'left';

        switch axName
            case 'x'
                ann.yanchor = 'bottom';
                ann.x = xaxis.domain(2);
                ann.y = yaxis.domain(1);

            case 'y'
                ann.yanchor = 'bottom';
                ann.x = xaxis.domain(1);
                ann.y = yaxis.domain(2);
        end

        obj.layout.annotations{anIndex} = ann;
        obj.PlotlyDefaults.anIndex = anIndex;
    end
end

function [tickVals, tickText] = rmTicks(axisLim, tickVals, tickText, rmCase)
    rangeLim = range(axisLim);

    switch rmCase
        case 's'
            if abs(axisLim(1)-tickVals(1)) < rangeLim * 0.01
                tickVals = tickVals(2:end);
                tickText = tickText(2:end);
            end

        case 'e'
            if abs(axisLim(end)-tickVals(end)) < rangeLim * 0.01
                tickVals = tickVals(1:end-1);
                tickText = tickText(1:end-1);
            end

    end
end


% Template Matlab script to create a BIDS compatible:
%
%   sub-01_ses-01_recording-ManualFullExample_blood.tsv
%   sub-01_ses-01_recording-ManualFullExample_blood.json
%
% This example lists all REQUIRED, RECOMMENDED and OPTIONAL fields.

% Writing json files relies on the JSONio library
% https://github.com/bids-standard/bids-matlab
%
% Make sure it is in the matab/octave path
try
    bids.bids_matlab_version;
catch
    warning('%s\n%s\n%s\n%s', ...
            'Writing the JSON file seems to have failed.', ...
            'Make sure that the following library is in the matlab/octave path:', ...
            'https://github.com/bids-standard/bids-matlab');
end

clear;

this_dir = fileparts(mfilename('fullpath'));
root_dir = fullfile(this_dir, '..', filesep, '..');

project = 'templates';

sub_label = '01';
ses_label = '01';
recording_label = 'ManualFullExample';

name_spec.modality = 'pet';
name_spec.suffix = 'blood';
name_spec.ext = '.tsv';
name_spec.entities = struct('sub', sub_label, ...
                            'ses', ses_label, ...
                            'recording', recording_label);

% using the 'use_schema', true
% ensures that the entities will be in the correct order
bids_file = bids.File(name_spec, 'use_schema', true);

% Contrust the fullpath version of the filename
tsv_file_name = fullfile(root_dir, project, bids_file.bids_path, bids_file.filename);
json_file_name = fullfile(root_dir, project, bids_file.bids_path, bids_file.json_filename);

%% Write TSV
tsv.time = 0;
tsv.plasma_radioactivity = 0;
tsv.metabolite_parent_fraction = 0;
tsv.metabolite_polar_fraction = 0;
tsv.hplc_recovery_fractions = 0;
tsv.whole_blood_radioactivity = 0;

bids.util.tsvwrite(tsv_file_name, tsv);

%% Write JSON
json.PlasmaAvail = '';
json.MetaboliteAvail = '';
json.WholeBloodAvail = '';
json.DispersionCorrected = '';
json.WithdrawalRate = '';
json.TubingType = '';
json.TubingLength = '';
json.DispersionConstant = '';
json.Haematocrit = '';
json.BloodDensity = '';
json.PlasmaFreeFraction = '';
json.PlasmaFreeFractionMethod = '';
json.MetaboliteMethod = '';
json.MetaboliteRecoveryCorrectionApplied = '';

% get the definition of several columns,
% use the bids.Schema class from bids matlab
schema = bids.Schema;

columns = {'time'
           'plasma_radioactivity'
           'metabolite_parent_fraction'
           'metabolite_polar_fraction'
           'hplc_recovery_fractions'
           'whole_blood_radioactivity'};

for i = 1:numel(columns)
    def = schema.get_definition(columns{i});
    json.(columns{i}).Description = def.description;
    if isfield(def, 'unit')
        json.(columns{i}).Unit = def.unit;
    end
end

json.plasma_radioactivity.unit = 'kBq/ml';
json.whole_blood_radioactivity.unit = 'kBq/ml';
json.metabolite_parent_fraction.unit = 'unitless';
json.metabolite_polar_fraction.unit = 'unitless';

%% Write JSON
% Make sure the directory exists
bids.util.mkdir(fileparts(json_file_name));
bids.util.jsonencode(json_file_name, json);


function ui = mrViewRemoveOverlay(ui,o);
%
% ui = mrViewRemoveOverlay([ui],[o]);
%
% Close/remove an overlay from a mrViewer UI.
% o is the index into the overlay; if omitted
% it removes the last overlay.
%
% ras 07/05.
if ~exist('ui','var') | isempty(ui), ui = mrViewGet;            end
if ~exist('o','var') | isempty(o), o = length(ui.overlays);     end

% new overlay order
newInd = setdiff(1:length(ui.overlays),o);

% close the UI panel if it exists
if checkfields(ui,'panels','overlays') & ishandle(ui.panels.overlays(o))
    % first check if it's in its own window: if it is, close the
    % window too
    pos = get(ui.panels.overlays(o),'Position');
    if isequal(pos,[0 0 1 1])
        par = get(ui.panels.overlays(o),'Parent');
        delete(par);
    else
        mrvPanelToggle(ui.panels.overlays(o),'off');
        delete(ui.panels.overlays(o));
    end
end

% remove the menu option to toggle this overlay
if checkfields(ui,'menus','overlayToggle') & ...
   ishandle(ui.menus.overlayToggle(o))
    delete(ui.menus.overlayToggle(o));
    ui.menus.overlayToggle = ui.menus.overlayToggle(newInd);
end

% remove the overlay field
ui.overlays = ui.overlays(newInd);

ui = mrViewRefresh(ui);

return


function dtiWriteAlgoHeader(headers, fid)

numalgos = length( headers );

for a = 1:numalgos
    algoH = headers(a);

    numchars = length( algoH.name );
    for c = 1:min([numchars 255-1])
        fwrite(fid,algoH.name(c),'char');
    end
    fwrite(fid,char(0),'char');
    for c = min([numchars+2 255+1]):255
        fwrite(fid,'g','char');
    end

    numchars = length( algoH.comments );
    for c = 1:min([numchars 255-1])
        fwrite(fid,algoH.comments(c),'char');
    end
    fwrite(fid,char(0),'char');
    for c = min([numchars+2 255+1]):255
        fwrite(fid,'g','char');
    end

    fwrite(fid,algoH.unique_id,'uint');

    % Write garbage at end for word alignment
    garb_size = dtiGetAlgoHeaderSizeWordAligned() - dtiGetAlgoHeaderSize();
    garbV = zeros(1,garb_size);
    fwrite(fid,garbV,'char');
end


function datatype = GetDatatype(handles)
global maingui

datatype=0;

if nargin==0
    return
end
if isempty(handles)
    return
end

plotRawVal  = get(handles.radiobuttonPlotRaw, 'value');
plotODVal   = get(handles.radiobuttonPlotOD, 'value');
plotConcVal = get(handles.radiobuttonPlotConc, 'value');
plotHRFVal  = get(handles.checkboxPlotHRF, 'value');

c = maingui.buttonVals;

if plotRawVal && ~plotHRFVal
    datatype      = c.RAW;
elseif plotRawVal && plotHRFVal
    datatype      = c.RAW_HRF;
elseif plotODVal && ~plotHRFVal
    datatype      = c.OD;
elseif plotODVal && plotHRFVal
    datatype      = c.OD_HRF;
elseif plotConcVal && ~plotHRFVal
    datatype      = c.CONC;
elseif plotConcVal && plotHRFVal
    datatype      = c.CONC_HRF;
end
maingui.datatype = datatype;


function s = getAlgorithmsHeaderSize(this)
%
%
% I am sorry, but this is pathetic.
% BW.
%
s = 255 + 255 + 2 + 4;


%% gray2RGBColorMap
% Below is a demonstration of the features of the |gray2RGBColorMap| function

%%
clear; close all; clc;

%% Syntax
% |[C]=gray2RGBColorMap(varargin);|

%% Description
% UNDOCUMENTED
%% Examples
%
%%
%
% <<gibbVerySmall.gif>>
%
% _*GIBBON*_
% <www.gibboncode.org>
%
% _Kevin Mattheus Moerman_, <gibbon.toolbox@gmail.com>
%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program 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.
%
% This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.


function planC = reviveRS(planC,planCDir,numExt,scanNum)
% Usage: planC = reviveRS(planC,planCDir,numExt,scanNum)
% Extract structure masks in planC and re-import them to eliminate inconsistencies in older versions of saved structures.
% EML 2020-11-26

if ~exist('numExt','var')
    numExt = 0;
end

if ~exist('scanNum','var')
    scanNum = 1;
end

indexS = planC{end};
structureListC = {planC{indexS.structures}.structureName};

for i = 1:numel(structureListC)
    strName = structureListC{i};
    disp(['Processing structure: ' strName]);
    updatedStructureListC = {planC{indexS.structures}.structureName};
    structNum = getMatchingIndex(lower(strName),lower(updatedStructureListC),'exact');
    strMask3M = getStrMask(structNum, planC);

    planC = deleteStructure(planC,structNum);
    planC = maskToCERRStructure(strMask3M,0,scanNum,strName,planC);
end
disp('Generating DICOM UID Relationships');
planC = generate_DICOM_UID_Relationships(planC);
disp('Exporting RTSTRUCT');
export_RS_IOD(planC,planCDir,numExt);