Code covered by the BSD License  

Highlights from
2d and 3d brain plots

image thumbnail

2d and 3d brain plots

by

 

11 Apr 2012 (Updated )

Quickly and easily create 2d and 3d plots of fMRI data.

PATCH_3Darray(varargin)
function [varargout] = PATCH_3Darray(varargin)
% PATCH_3Darray  Plot a 3D array using patch to create a quadrangular surface mesh
%==========================================================================
% FILENAME:          PATCH_3Darray.m
% AUTHOR:            Adam H. Aitkenhead
% INSTITUTION:       The Christie NHS Foundation Trust
% CONTACT:           adam.aitkenhead@physics.cr.man.ac.uk
% DATE:              17th August 2010
% PURPOSE:           Plot a 3D array using patch to create a quadrangular
%                    surface mesh
%
% USAGE:             [hpat] = PATCH_3Darray(gridINPUT)
%           ..or..   [hpat] = PATCH_3Darray(gridINPUT,cmap)
%           ..or..   [hpat] = PATCH_3Darray(gridINPUT,gridX,gridY,gridZ)
%           ..or..   [hpat] = PATCH_3Darray(gridINPUT,gridX,gridY,gridZ,cmap)
%           ..or..   [hpat] = PATCH_3Darray(gridINPUT,gridX,gridY,gridZ,'col')
%           ..or..   [hpat] = PATCH_3Darray(gridINPUT,gridX,gridY,gridZ,'sym')
%           ..or..   [hpat] = PATCH_3Darray(gridINPUT,gridX,gridY,gridZ,cmap,'col')
%           ..or..   [hpat] = PATCH_3Darray(gridINPUT,gridX,gridY,gridZ,cmap,'sym')
%           ..or..   [hpat,hcbar] = PATCH_3Darray(gridINPUT,gridX,gridY,gridZ,cmap,'sym')
%
% INPUT PARAMETERS:
%   gridINPUT        - 3D array of size (P,Q,R)
%                      If not using the flags 'col' or 'sym', then
%                      gridINPUT should be a logical array.  If using the
%                      flags 'col' or 'sym', then gridINPUT should be a
%                      numeric array where voxels which are not to be
%                      displayed contain the value NaN. 
%   gridX (optional) - A 1xP array  - List of the X axis coordinates.
%   gridY (optional) - A 1xQ array  - List of the Y axis coordinates.
%   gridZ (optional) - A 1xR array  - List of the Z axis coordinates.
%   gridZ (optional) - A 1xR array  - List of the Z axis coordinates.
%   cmap  (optional) - A Nx3 array  - The colormap definition.  When
%                      plotting using the 'col' or 'sym' flag, cmap must be
%                      an Nx3 array, eg jet(32).  When plotting a logical
%                      array, cmap must be an RGB triplet, eg [0.5,0.5,0]. 
%
% ADDITIONAL INPUT FLAGS:
%   'col'  (optional) - When this flag is present, the colour of each
%                       facet corresponds to the value of the voxel.  In
%                       the input array gridINPUT, voxels which are not to 
%                       be displayed should have a value of NaN.
%   'sym'  (optional) - Similar to the flag 'col', except that the
%                       colorbar is symmetric about zero.
%   'barN' (optional) - Display a colorbar on North of plot.
%   'barE' (optional) - Display a colorbar on East of plot.
%   'barS' (optional) - Display a colorbar on South of plot.
%   'barW' (optional) - Display a colorbar on West of plot.
%
% OUTPUT PARAMETERS:
%   hpat  (optional)  - Handle to the patch object.
%   hcbar (optional)  - Handle to the colorbar.
%==========================================================================

%==========================================================================
% VERSION  USER  CHANGES
% -------  ----  -------
% 100817   AHA   Original version
% 101126   AHA   Better handling of objects which are only 1 pixel wide.
% 110310   AHA   Can now produce plots where the colour of each facet
%                corresponds to the value of the voxel.
% 110311   AHA   The user can now specify the colour map for the display of
%                a 3D numeric array.
% 110316   AHA   Set the facet edges to be a darker version of the face
%                colour.
% 110324   AHA   Bugfix:  Ensure the facet values lie within [1:cres]
%                rather than [0:cres].  Otherwise the 3D object will have a
%                hole, since any 0-value facets will not be plotted.
% 110401   AHA   Minor speed up by reducing number of calls to ind2sub.
% 110407   AHA   Added control of the colorbar position.
%==========================================================================


%======================================================
% CHECK THE INPUTS
%======================================================

checkchar = false(nargin,1);
checknl   = false(nargin,1);
for loopC = 1:nargin
  checkchar(loopC) = ischar(varargin{loopC});
  checknl(loopC)   = isnumeric(varargin{loopC}) + islogical(varargin{loopC});
end

%Check for numeric or logical inputs
if sum(checknl)==1
  checknlIND = find(checknl==1);
  gridINPUT  = varargin{checknlIND};
  gridSIZE   = size(gridINPUT);
  gridX      = [1:gridSIZE(1)];
  gridY      = [1:gridSIZE(2)];
  gridZ      = [1:gridSIZE(3)];
elseif sum(checknl)==2
  checknlIND = find(checknl==1);
  gridINPUT  = varargin{checknlIND(1)};
  gridSIZE   = size(gridINPUT);
  gridX      = [1:gridSIZE(1)];
  gridY      = [1:gridSIZE(2)];
  gridZ      = [1:gridSIZE(3)];
  cmap       = varargin{checknlIND(2)};
elseif sum(checknl)==4
  checknlIND = find(checknl==1);
  gridINPUT  = varargin{checknlIND(1)};
  gridSIZE   = size(gridINPUT);
  gridX      = varargin{checknlIND(2)};
  gridY      = varargin{checknlIND(3)};
  gridZ      = varargin{checknlIND(4)};
elseif sum(checknl)==5
  checknlIND = find(checknl==1);
  gridINPUT  = varargin{checknlIND(1)};
  gridSIZE   = size(gridINPUT);
  gridX      = varargin{checknlIND(2)};
  gridY      = varargin{checknlIND(3)};
  gridZ      = varargin{checknlIND(4)};
  cmap       = varargin{checknlIND(5)};
else
  error('Incorrect number of numeric/logical inputs.')
end

%Set defaults for colormap and colorbar options
symYN = 0;
colYN = 0;
cbar  = 0;
  
%Check for character inputs
if sum(checkchar)>=1
  checkcharIND = find(checkchar==1);
  for loopCH = 1:sum(checkchar)
    if strncmpi('sym',varargin{checkcharIND(loopCH)},3)==1
      symYN    = 1;
      colYN = 1;
    elseif strncmpi('col',varargin{checkcharIND(loopCH)},3)==1
      colYN = 1;
    elseif strcmpi('barno',varargin{checkcharIND(loopCH)})==1
      cbar = 0;
    elseif strcmpi('barN',varargin{checkcharIND(loopCH)})==1
      cbar = 1;
    elseif strcmpi('barE',varargin{checkcharIND(loopCH)})==1
      cbar = 2;
    elseif strcmpi('barS',varargin{checkcharIND(loopCH)})==1
      cbar = 3;
    elseif strcmpi('barW',varargin{checkcharIND(loopCH)})==1
      cbar = 4;
    end
  end
end

%Check that the colormap is a 1x3 array if a logical array is to be plotted
if colYN==0 && exist('cmap','var')==1 && numel(cmap)~=3
  error('When displaying a logical array, the colour map must be a 1x3 RGB triplet.')
end

%Check the size of the grid
if size(gridX,1)>size(gridX,2)
  gridX = gridX';
end
if size(gridY,1)>size(gridY,2)
  gridY = gridY';
end
if size(gridZ,1)>size(gridZ,2)
  gridZ = gridZ';
end

if ~isequal(gridSIZE,[numel(gridX),numel(gridY),numel(gridZ)])
  error('The dimensions of gridINPUT do not match the dimensions of gridX, gridY, gridZ.')
end


%======================================================
% OBTAIN A LOGICAL ARRAY FROM gridINPUT
%======================================================

if colYN == 1;
  gridINPUTlogical = ~isnan(gridINPUT);
elseif colYN == 0;
  gridINPUTlogical = gridINPUT;
  nanvoxels = isnan(gridINPUT);
  nancount  = sum(nanvoxels(:));
  if nancount>0
    gridINPUTlogical(~nanvoxels) = 1;
    gridINPUTlogical(nanvoxels)  = 0;
  end
  gridINPUTlogical = logical(gridINPUTlogical);
end


%======================================================
% REMOVE ANY OUTER UNUSED AREAS FROM gridINPUT
%======================================================

objectIND                 = find(gridINPUTlogical);
[objectX,objectY,objectZ] = ind2sub(gridSIZE,objectIND);

if objectX(1)~=objectX(end)
  gridINPUT        = gridINPUT(min(objectX):max(objectX),:,:);
  gridINPUTlogical = gridINPUTlogical(min(objectX):max(objectX),:,:);
  gridX            = gridX(min(objectX):max(objectX));
end
if objectY(1)~=objectY(end)
  gridINPUT        = gridINPUT(:,min(objectY):max(objectY),:);
  gridINPUTlogical = gridINPUTlogical(:,min(objectY):max(objectY),:);
  gridY            = gridY(min(objectY):max(objectY));
end
if objectZ(1)~=objectZ(end)
  gridINPUT        = gridINPUT(:,:,min(objectZ):max(objectZ));
  gridINPUTlogical = gridINPUTlogical(:,:,min(objectZ):max(objectZ));
  gridZ            = gridZ(min(objectZ):max(objectZ));
end

gridSIZE = size(gridINPUT);


%======================================================
% DEFINE THE LOWER AND UPPER LIMITS OF EACH VOXEL
%======================================================

if gridSIZE(1)==1
  gridXlower = gridX;
  gridXupper = gridX;
else
  gridXsteps = gridX(2:end)-gridX(1:end-1);
  gridXlower = gridX-[gridXsteps(1),gridXsteps]/2;
  gridXupper = gridX+[gridXsteps,gridXsteps(end)]/2;
end

if gridSIZE(2)==1
  gridYlower = gridY;
  gridYupper = gridY;
else
  gridYsteps = gridY(2:end)-gridY(1:end-1);
  gridYlower = gridY-[gridYsteps(1),gridYsteps]/2;
  gridYupper = gridY+[gridYsteps,gridYsteps(end)]/2;
end

if gridSIZE(3)==1
  gridZlower = gridZ;
  gridZupper = gridZ;
else
  gridZsteps = gridZ(2:end)-gridZ(1:end-1);
  gridZlower = gridZ-[gridZsteps(1),gridZsteps]/2;
  gridZupper = gridZ+[gridZsteps,gridZsteps(end)]/2;
end

%======================================================
% FOR EACH VOXEL, IDENTIFY WHETHER ITS 6 NEIGHBOURS ARE WITHIN THE OBJECT.
% IF ANY NEIGHBOUR IS OUTSIDE THE OBJECT, DRAW FACETS BETWEEN THE VOXEL AND
% THAT NEIGHBOUR.
%======================================================

gridINPUTshifted = false(gridSIZE);
if gridSIZE(1)>2
  gridINPUTwithborder = cat(1,false(1,gridSIZE(2),gridSIZE(3)),gridINPUTlogical,false(1,gridSIZE(2),gridSIZE(3)));         %Add border
  gridINPUTshifted    = cat(1,false(1,gridSIZE(2),gridSIZE(3)),gridINPUTshifted,false(1,gridSIZE(2),gridSIZE(3)));      %Add border
  gridINPUTshifted    = gridINPUTshifted + circshift(gridINPUTwithborder,[-1,0,0]) + circshift(gridINPUTwithborder,[1,0,0]);
  gridINPUTshifted    = gridINPUTshifted(2:end-1,:,:);  %Remove border
end
if gridSIZE(2)>2
  gridINPUTwithborder = cat(2,false(gridSIZE(1),1,gridSIZE(3)),gridINPUTlogical,false(gridSIZE(1),1,gridSIZE(3)));         %Add border
  gridINPUTshifted    = cat(2,false(gridSIZE(1),1,gridSIZE(3)),gridINPUTshifted,false(gridSIZE(1),1,gridSIZE(3)));      %Add border
  gridINPUTshifted    = gridINPUTshifted + circshift(gridINPUTwithborder,[0,-1,0]) + circshift(gridINPUTwithborder,[0,1,0]);
  gridINPUTshifted    = gridINPUTshifted(:,2:end-1,:);  %Remove border
end
if gridSIZE(3)>2
  gridINPUTwithborder = cat(3,false(gridSIZE(1),gridSIZE(2),1),gridINPUTlogical,false(gridSIZE(1),gridSIZE(2),1));         %Add border
  gridINPUTshifted    = cat(3,false(gridSIZE(1),gridSIZE(2),1),gridINPUTshifted,false(gridSIZE(1),gridSIZE(2),1));      %Add border
  gridINPUTshifted    = gridINPUTshifted + circshift(gridINPUTwithborder,[0,0,-1]) + circshift(gridINPUTwithborder,[0,0,1]);
  gridINPUTshifted    = gridINPUTshifted(:,:,2:end-1);  %Remove border
end

%Identify the voxels which are at the boundary of the object:
edgevoxellogical = gridINPUTlogical & gridINPUTshifted<6;
edgevoxelindices = find(edgevoxellogical)';
edgevoxelcount   = numel(edgevoxelindices);

%Calculate the number of facets there will be in the final quadrangular mesh:
facetcount = (edgevoxelcount*6 - sum(gridINPUTshifted(edgevoxelindices)) );

%Create an array to record...
%Cols 1-6: Whether each edge voxel's 6 neighbours are inside or outside the object.
neighbourlist = false(edgevoxelcount,6);

%Initialise arrays to store the quadrangular mesh data:
facetsALL  = zeros(facetcount,3,4);
normalsALL = zeros(facetcount,3);
valuesALL  = zeros(facetcount,1);

%Create a counter to keep track of how many facets have been written as the
%following 'for' loop progresses:
facetcountsofar = 0;

[subXALL,subYALL,subZALL] = ind2sub(gridSIZE,edgevoxelindices);

for loopP = 1:edgevoxelcount
  
  subX = subXALL(loopP);
  subY = subYALL(loopP);
  subZ = subZALL(loopP);
  
  if subX==1
    neighbourlist(loopP,1) = 0;
  else
    neighbourlist(loopP,1) = gridINPUTlogical(subX-1,subY,subZ);
  end
  if subY==1
    neighbourlist(loopP,2) = 0;
  else
    neighbourlist(loopP,2) = gridINPUTlogical(subX,subY-1,subZ);
  end
  if subZ==gridSIZE(3)
    neighbourlist(loopP,3) = 0;
  else
    neighbourlist(loopP,3) = gridINPUTlogical(subX,subY,subZ+1);
  end
  if subY==gridSIZE(2)
    neighbourlist(loopP,4) = 0;
  else
    neighbourlist(loopP,4) = gridINPUTlogical(subX,subY+1,subZ);
  end
  if subZ==1
    neighbourlist(loopP,5) = 0;
  else
    neighbourlist(loopP,5) = gridINPUTlogical(subX,subY,subZ-1);
  end
  if subX==gridSIZE(1)
    neighbourlist(loopP,6) = 0;
  else
    neighbourlist(loopP,6) = gridINPUTlogical(subX+1,subY,subZ);
  end
  
  facetCOtemp         = zeros(6-sum(neighbourlist(loopP,:)),3,4);
  normalCOtemp        = zeros(6-sum(neighbourlist(loopP,:)),3);
  facetcountthisvoxel = 0;
  
  if neighbourlist(loopP,1)==0   %Neighbouring voxel in the -x direction
    facetcountthisvoxel                    = facetcountthisvoxel+1;
    facetcountsofar                        = facetcountsofar+1;
    facetCOtemp(facetcountthisvoxel,1:3,1) = [ gridXlower(subX),gridYlower(subY),gridZlower(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,2) = [ gridXlower(subX),gridYlower(subY),gridZupper(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,3) = [ gridXlower(subX),gridYupper(subY),gridZupper(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,4) = [ gridXlower(subX),gridYupper(subY),gridZlower(subZ) ];
    normalCOtemp(facetcountthisvoxel,1:3)  = [-1,0,0];
  end
  if neighbourlist(loopP,2)==0   %Neighbouring voxel in the -y direction
    facetcountthisvoxel                    = facetcountthisvoxel+1;
    facetcountsofar                        = facetcountsofar+1;
    facetCOtemp(facetcountthisvoxel,1:3,1) = [ gridXlower(subX),gridYlower(subY),gridZlower(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,2) = [ gridXupper(subX),gridYlower(subY),gridZlower(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,3) = [ gridXupper(subX),gridYlower(subY),gridZupper(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,4) = [ gridXlower(subX),gridYlower(subY),gridZupper(subZ) ];
    normalCOtemp(facetcountthisvoxel,1:3)  = [0,-1,0];
  end
  if neighbourlist(loopP,3)==0   %Neighbouring voxel in the +z direction
    facetcountthisvoxel                    = facetcountthisvoxel+1;
    facetcountsofar                        = facetcountsofar+1;
    facetCOtemp(facetcountthisvoxel,1:3,1) = [ gridXupper(subX),gridYlower(subY),gridZupper(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,2) = [ gridXupper(subX),gridYupper(subY),gridZupper(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,3) = [ gridXlower(subX),gridYupper(subY),gridZupper(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,4) = [ gridXlower(subX),gridYlower(subY),gridZupper(subZ) ];
    normalCOtemp(facetcountthisvoxel,1:3)  = [0,0,1];
  end
  if neighbourlist(loopP,4)==0   %Neighbouring voxel in the +y direction
    facetcountthisvoxel                    = facetcountthisvoxel+1;
    facetcountsofar                        = facetcountsofar+1;
    facetCOtemp(facetcountthisvoxel,1:3,1) = [ gridXupper(subX),gridYupper(subY),gridZlower(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,2) = [ gridXlower(subX),gridYupper(subY),gridZlower(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,3) = [ gridXlower(subX),gridYupper(subY),gridZupper(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,4) = [ gridXupper(subX),gridYupper(subY),gridZupper(subZ) ];
    normalCOtemp(facetcountthisvoxel,1:3)  = [0,1,0];
  end
  if neighbourlist(loopP,5)==0   %Neighbouring voxel in the -z direction
    facetcountthisvoxel                    = facetcountthisvoxel+1;
    facetcountsofar                        = facetcountsofar+1;
    facetCOtemp(facetcountthisvoxel,1:3,1) = [ gridXlower(subX),gridYlower(subY),gridZlower(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,2) = [ gridXlower(subX),gridYupper(subY),gridZlower(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,3) = [ gridXupper(subX),gridYupper(subY),gridZlower(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,4) = [ gridXupper(subX),gridYlower(subY),gridZlower(subZ) ];
    normalCOtemp(facetcountthisvoxel,1:3)  = [0,-1,0];
  end
  if neighbourlist(loopP,6)==0   %Neighbouring voxel in the +x direction
    facetcountthisvoxel                    = facetcountthisvoxel+1;
    facetcountsofar                        = facetcountsofar+1;
    facetCOtemp(facetcountthisvoxel,1:3,1) = [ gridXupper(subX),gridYupper(subY),gridZlower(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,2) = [ gridXupper(subX),gridYupper(subY),gridZupper(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,3) = [ gridXupper(subX),gridYlower(subY),gridZupper(subZ) ];
    facetCOtemp(facetcountthisvoxel,1:3,4) = [ gridXupper(subX),gridYlower(subY),gridZlower(subZ) ];
    normalCOtemp(facetcountthisvoxel,1:3)  = [1,0,0];
  end
  
  facetsALL(facetcountsofar-facetcountthisvoxel+1:facetcountsofar,:,:) = facetCOtemp;
  normalsALL(facetcountsofar-facetcountthisvoxel+1:facetcountsofar,:)  = normalCOtemp;
  valuesALL(facetcountsofar-facetcountthisvoxel+1:facetcountsofar)     = gridINPUT(edgevoxelindices(loopP));

end

%======================================================
% PLOT THE QUADRANGULAR SURFACE MESH
%======================================================

if colYN==1
  
  %Define the colormap and resolution
  if exist('cmap','var')
    cres = size(cmap,1);
  else
    cres = 16;
    cmap = jet(cres);
  end

  if symYN==1
    %Ensure that the colorbar is symmetric about zero
    valueMINMAX = max(abs([min(valuesALL(:)),max(valuesALL(:))]));
    valuesTEMP  = valuesALL + valueMINMAX;
    valuesTEMP  = 1 + round( (cres-1)*valuesTEMP./(2*valueMINMAX) );    % The '1 + ...' ensures that the values are within [1:16] rather than [0:16]
    crange      = [-valueMINMAX,valueMINMAX];
  elseif symYN==0
    %The colorbar does not need to be symmetric about zero
    valuesTEMP  = valuesALL - min(valuesALL(:));
    valuesTEMP  = 1 + round( (cres-1)*valuesTEMP./max(valuesTEMP(:)) );    % The '1 + ...' ensures that the values are within [1:16] rather than [0:16]
    crange      = [min(valuesALL(:)),max(valuesALL(:))];
  end

  if crange(1) ~= crange(end)
    %If the facets have a range of colours
    hpat = cell(1,cres);
    for loopJ = 1:cres
      xco         = squeeze( facetsALL(valuesTEMP==loopJ,1,:) )';
      yco         = squeeze( facetsALL(valuesTEMP==loopJ,2,:) )';
      zco         = squeeze( facetsALL(valuesTEMP==loopJ,3,:) )';
      hpat{loopJ} = patch(xco,yco,zco,cmap(loopJ,:));
      set(hpat{loopJ},'EdgeColor',cmap(loopJ,:)/2);
    end
    set(gca, 'CLim', crange);
    if cbar==1
      hcbar = colorbar('NorthOutside','YLim',crange);
    elseif cbar==2
      hcbar = colorbar('EastOutside','YLim',crange);
    elseif cbar==3
      hcbar = colorbar('SouthOutside','YLim',crange);
    elseif cbar==4
      hcbar = colorbar('WestOutside','YLim',crange);
    end
    colormap(cmap);
  else
    %If the facets are all the same colour
    xco  = squeeze( facetsALL(:,1,:) )';
    yco  = squeeze( facetsALL(:,2,:) )';
    zco  = squeeze( facetsALL(:,3,:) )';
    hpat = patch(xco,yco,zco,cmap(round(end/2),:));
    set(hpat,'EdgeColor',cmap(round(end/2),:)/2);
    set(gca,'CLim',crange+[-1,1]);
    if cbar==1
      hcbar = colorbar('NorthOutside','YLim',crange+[-1,1]);
    elseif cbar==2
      hcbar = colorbar('EastOutside','YLim',crange+[-1,1]);
    elseif cbar==3
      hcbar = colorbar('SouthOutside','YLim',crange+[-1,1]);
    elseif cbar==4
      hcbar = colorbar('WestOutside','YLim',crange+[-1,1]);
    end
    colormap(cmap);
  end

elseif colYN==0
  
  %Define the colormap and resolution
  if exist('cmap','var')==1
    cmap = cmap(:)';  %Ensure colourmap is a 1x3 RGB triplet
  else
    cmap = [0,0,1];
  end

  %Plot a simple logical array where all facets are the same colour
  xco  = squeeze( facetsALL(:,1,:) )';
  yco  = squeeze( facetsALL(:,2,:) )';
  zco  = squeeze( facetsALL(:,3,:) )';
  hpat = patch(xco,yco,zco,cmap);
  set(hpat,'EdgeColor',cmap/2);

end
axis equal tight;


%======================================================
% SET THE OUTPUT PARAMETERS
%======================================================

if nargout>=1
  varargout(1) = {hpat};
end
if nargout==2
  if exist('hcbar','var')==1
    varargout(2) = {hcbar};
  else
    varargout(2) = {[]};
  end
end

Contact us