Code covered by the BSD License  

Highlights from
quiver2.m v1.2 (Nov 2009)

image thumbnail
from quiver2.m v1.2 (Nov 2009) by Carlos Adrian Vargas Aguilera
Same as QUIVER, QUIVER3 or FEATHER but with colored, normalized, widened and ARROW's!

quiver2(varargin)
function [HQ,HCB,HL] = quiver2(varargin)
%QUIVER   Same as quiver but with customizations.
%
%   SYNTAX:
%                   quiver2(U,V)
%                   quiver2(U,V,W)
%                   quiver2(U,V,S)
%                   quiver2(U,V,W,S)
%                   quiver2(x,y,U,V)
%                   quiver2(x,y,z,U,V,W)
%                   quiver2(x,y,z,U,V,W,S)
%                   quiver2(...,LINESPEC)
%                   quiver2(...,'filled')
%                   quiver2(...,'c=',CMAP)        % colored arrows
%                   quiver2(...,'w=',WLIM)        % widened
%                   quiver2(...,'n=',MAG)         % normalized
%                   quiver2(...,'l=',LLIM)        % limitized
%                   quiver2(...,'s=','screen')    % slanted by (U,V) angle!
%                   quiver2(...,'t=','quiver')    % try 'feather' or 'b'
%                   quiver2(...,'a@','fancy')     % Uses ARROW function!
%                   quiver2(...,'x@',SAXIS)       % try 'x'
%                   quiver2(...,'f@','Edge')      % try 'Face'
%                   quiver2(...,'l@',Length)      % see ARROW for details
%                   quiver2(...,'b@',BaseAngle)
%                   quiver2(...,'t@',TipAngle)
%                   quiver2(...,'w@',Width)
%                   quiver2(...,'p@',Page)
%                   quiver2(...,'c@',CrossDir)
%                   quiver2(...,'n@',NormalDir)
%                   quiver2(...,'e@',Ends)
%                   quiver2(...,P/V) % QUIVER optional pairs input
%                   quiver2(AX,...)
%              HQ = quiver2(...);
%        [HQ,HCB] = quiver2(...);
%     [HQ,HCB,HL] = quiver2(...);
%
%   INPUT:
%     U        - X component (with/without NaNs).
%     V        - Y component (with/without NaNs).
%     W        - Z component (with/without NaNs).
%                DEFAULT: [] (not used)
%     x        - X axis (matrix or vector).
%                DEFAULT: 1:size(U,2)
%     y        - Y axis (matrix or vector).
%                DEFAULT: 1:size(U,1)
%     z        - Z axis (matrix or vector).
%                DEFAULT: 1
%     S        - Arrow scaling (see QUIVER for details). Recommended not to
%                use it and use 'n=',MAG instead.
%                DEFAULT: 0 (do not scales)
%     LINESPEC - Arrow line and marker style (see QUIVER and PLOT for
%                details). For example: '.' draws lines instead of arrows.
%                DEFAULT: (draws normal arrows)
%     'filled' - Fills the arrow markers.
%                DEFAULT (do not fills)
%     'c='     - Colors arrows according to (U,V) magnitude with the
%                colormap CMAP. CMAP may be [] to use blue color. 
%                DEFAULT: (is used by default with the current colormap)
%     'w='     - Widens arrows according to (U,V) magnitude with
%                WLIM=[Wmin Wmax] pixel limits widths.  
%                DEFAULT: (is used by default with WLIM=[0.5 2.5])
%     'n='     - Draws arrows with normalized lengths to MAG. Use MAG=0 to
%                not normalize.
%                DEFAULT: 1 (by default the arrows are normalized!)
%     'l='     - Draws arrows squeezed to this LLIM limits for length.
%                DEFAULT: (not used by default)
%     's='     - Slants arrows accordingly to (U,V) angle. That is, a 45
%                arrow will do have a 45 slope on 'screen'. Use 'normal'
%                for default QUIVER slant.
%                DEFAULT: (is used by default with 'screen')
%     't='     - Function type. One of 'quiver' or 'feather' way (adds an
%                horizontal line). May be a LINESPEC instead of 'feather'!.
%                Use 'feather-date' or [LINESPEC '-date'] to treat xticks
%                as dates.
%                DEFAULT: (used with 'quiver' but 'feather' if x or y = [])
%     'a@'     - ARROWs custom type. One of 'fancy', '90' or 'normal'.
%                Write one of yours inside this file. See ARROW for details
%                in this '@' optional inputs.
%                DEFAULT: (not used)
%     'x@'     - ARROWs with tips parallel to specified axes: 'x', 'y' or
%                'z'. Or negative as '-x'.
%                DEFAULT: (not used)
%     'f@'     - ARROWs with colored 'face' (default) or 'edge'. Use of
%                'filled' colored both.
%                DEFAULT: (not used)
%     'l@'     - ARROWs Length property.
%                DEFAULT: (not used)
%     'b@'     - ARROWs BaseLine property.
%                DEFAULT: (not used)
%     't@'     - ARROWs TipAngle property.
%                DEFAULT: (not used)
%     'w@'     - ARROWs Width property.
%                DEFAULT: (not used)
%     'p@'     - ARROWs Page property. 
%                DEFAULT: (not used)
%     'c@'     - ARROWs CrossDir property. 
%                DEFAULT: (not used)
%     'n@'     - ARROWs NormalDir property.
%                DEFAULT: (not used)
%     'e@'     - ARROWs Ends property.
%                DEFAULT: (not used)
%     P/V      - Property/Value optional QUIVER function pairs inputs.
%                DEFAULT: (not use any)
%     AX       - Draws arrows on axes with handle AX instead of current
%                one. 
%                DEFAULT: gca (current axes)
%
%   OUTPUT:
%     HQ  - Returns quiver handle.
%     HCB - Returns generated COLORBAR handle.
%     HL  - Handle of line when 'feather' is used.
%
%   DESCRIPTION:
%     This programs is the same as QUIVER and QUIVER3 but with the colors,
%     lengths, widths and arrows customization.
%
%     Besides, it works like FEATHER function when y is [].
%
%   NOTE:
%     * Optional inputs use its DEFAULT value when not given or [].
%     * Optional outputs may or not be called.
%     * ADDITIONAL NOTES are included inside this file.
%
%   EXAMPLE:
%     % EXAMPLE 1. quiver2 vs quiver
%      % Data (45 field + NaNs):
%       Nx=50; Ny=10; PNAN=50;
%       [x,y]   = meshgrid((1:Nx)/2,(1:Ny)*2);
%       U       = 10*reshape(sort(rand(Nx*Ny,1)),Ny,Nx);
%       A       = repmat(45*pi/180,Ny,Nx);
%       [u,v]   = pol2cart(A,U); 
%       inan    = randperm(Nx*Ny); inan = inan(1:floor((PNAN/100)*Nx*Ny));
%       u(inan)=NaN; v(inan)=NaN;
%      % quiver2:
%       a = subplot(221);
%       quiver2(x,y,u,v,'filled','n=',2)   % augmented length by 2
%       title '45 colored QUIVER2 field vs ...'
%      % quiver:
%       b = subplot(223);
%       quiver(x,y,u,v), title '... same? 45 QUIVER field'
%       linkaxes([a b]), zoom on
%
%     % EXAMPLE 2. quiver2 vs feather
%       theta=(-90:10:90)*pi/180; r=2*ones(size(theta)).*theta;
%       t     = (0:(length(theta)-1))/24 + now; % time/date axis
%       [u,v] = pol2cart(theta,r);
%       subplot(222)
%        set(gca,'XTick',t(1:4:end))
%        quiver2(t,[],u,v,'t=','k-date','x@','x')
%        title 'QUIVER2 + ARROW vs ...'
%       subplot(224)
%        feather(u,v), title '... FEATHER'
%     
%   SEE ALSO:
%     QUIVER, QUIVER3, FEATHER
%     and
%     ARROW by Erik Johnson and CMAPPING, TLABEL by Carlos Vargas
%     at http://www.mathworks.com/matlabcentral/fileexchange
%
%
%   ---
%   MFILE:   quiver2.m
%   VERSION: 1.2 (Nov 12, 2009) (<a href="matlab:web('http://www.mathworks.com/matlabcentral/fileexchange/authors/11258')">download</a>) 
%   MATLAB:  7.7.0.471 (R2008b)
%   AUTHOR:  Carlos Adrian Vargas Aguilera (MEXICO)
%   CONTACT: nubeobscura@hotmail.com

%   ADDITIONAL NOTES:
%     * By default, QUIVER2 normalizes, colored and widens arrows
%       according to its length. To get normal behavior of QUIVER or
%       QUIVER3 use empties on '=' entries or 
%         quiver2(...,'c=','b','w=',0.5,'s=','normal')
%       and 't=','feather' respectively.
%     * Default properties of QUIVER2 are at the top of this file, type
%         edit quiver2
%       to see/change them. For example, if ARROW is used and its 'Length'
%       property not ('l@'), this programs generates tip arrows with 33%
%       the size of the whole arrow (like QUIVER does). There, you can
%       change it to 50% with alpha=0.50.
%     * ARROW function by Erik Johnson is highly recommended on the
%       Mathworks FileExchange for arrows creation. Download it and make
%       your own customized arrows with the '@' optional inputs. Type 
%         arrow properties
%       to get more details.
%     * This programs may also works with CMAPPING and TLABEL from the
%       FileExchange.

%   REVISIONS:
%   1.0      Released. (Jun 30, 2009)
%   1.1      Fixed bug with inputs check in and on a error message, thanks
%            to Ayal Anis. (Oct 23, 2009)
%   1.2      Fixed bug with MAG=0 value, thanks to Ayal Anis. Spell
%            checked. (Nov 12, 2009) 

%   DISCLAIMER:
%   quiver2.m is provided "as is" without warranty of any kind, under the
%   revised BSD license.

%   Copyright (c) 2009 Carlos Adrian Vargas Aguilera


% INPUTS CHECK-IN
% -------------------------------------------------------------------------

% Defaults.
AX        = [];        % Gets current axes.
CMAP      = [];        % Gets figure colormap.
WLIM      = [0.5 2.5]; % Line width limits according to U,V length.
MAG       = 1;         % Normalization.
LLIM      = [];        % Not used by default.
SLANT     = 'screen';  % Slant 'screen' or 'normal'
TYPE      = 'quiver';  % May change according to x,y inputs.
S         = 0;         % Scaling factor
LINESPEC  = {};        % LINESPEC for line arrows
filled    = {};        % 'filled'?
visible   = 'on';      % 'visible'?
K         = 0.1;       % Increase factor for limits
Aopt      = {};        % ARROWs default P/V options ------
alpha     = 0.33;      % Length of arrow head with respect of length
EorF      = 'Edge';    % Draw 'Face' or 'Edge'
CUSTOM    = [];        % 'fancy', for example
SAXES     = [];        % 'x' for example

% Customized ARROWs (add your owns).
Anames = {'fancy' ,{'BaseAngle',50};...
          '90'    ,{'BaseAngle',90};...
          'normal',{'Length'   ,[],...
                    'BaseAngle',[],...
                    'TipAngle' ,[],...
                    'Width'    ,[],...
                    'Page'     ,[],...
                    'CrossDir' ,[],...
                    'NormalDir',[],...
                    'Ends'     ,[]}};

% Checks number of inputs and outputs.
if     nargin<2
 error('CVARGAS:quiver2:notEnoughInputs',...
  'At least 2 inputs are required.')
elseif nargout>3 
 error('CVARGAS:quiver2:tooManyOutputs',...
  'At most 3 output are allowed.')
end

% Checks AX input.
if (length(varargin{1})==1) && ~ishandle(varargin{1}) && ...
  strcmp(get(varargin{1},'Type'),'axes')
 AX = varargin{1}; varargin(1) = [];
 if length(varargin)<2
  error('CVARGAS:quiver2:notEnoughInputsAfterHandle',...
  'At least 2 inputs plus handle are required.')
 end
end

% Checks numeric x,y,z,U,V,W,S 7 inputs.
% Note: this is done here to reduce memory use.
% Fixed bug, thanks to Ayal Anis. Oct 2009.
Nopt = {[],[],[],[],[],[],S};
temp = 0;
for k = 1:min(7,length(varargin)) 
 if ischar(varargin{k}), temp = 1; break, end 
end
k = k-temp;
if k<2
 error('CVARGAS:quiver2:incorrectNumericInputs',...
  'At least the first two inputs must be numerical.')
end
if k==2,                    Nopt(4:5) = varargin(1:2);
elseif k==3,                Nopt(4:5) = varargin(1:2);
 if numel(varargin{3})~=1,  Nopt(6)   = varargin(3);
 else                       Nopt(7)   = varargin(3);
  if numel(varargin{1})==1
   error('CVARGAS:quiver2:undefinedNumericOption',...
    ['3rd numerical option may be W or S. '...
    'Use empties x,y (and z, W) to avoid confusion.'])
  end
 end
elseif k==4
 if numel(varargin{4})==1,  Nopt(4:7) = varargin(1:4);
  if numel(varargin{3})==1
   error('CVARGAS:quiver2:undefinedNumericOption',...
    ['4rd numerical option may be V or S. '...
    'Use empties x,y (and z, W) to avoid confusion.'])
  end
 else                       Nopt([1 2 4 5])   = varargin(1:4);
 end
elseif k==5,                Nopt([1 2 4 5 7]) = varargin(1:5);
elseif k==6,                Nopt(1:6)         = varargin(1:6);
elseif k==7,                Nopt(1:7)         = varargin(1:7);
end
varargin(1:k) = [];
[x,y,z,U,V,W,S] = Nopt{:}; clear Nopt

% Checks U,V,W.
su=size(U);  sv=size(V);  sw=size(W);
nu=prod(su); nv=prod(sv); nw=prod(sw);
sm=max([su;sv;sw],[],1);  nm=prod(sm);
if any([length(su) length(sv) length(sw)]~=2)
 error('CVARGAS:quiver2:incorrectUvwDimensions',...
  'U,V(,W) must be 2-dimensional matrix or vectors.')
elseif isempty(U)
 if nargout>0
  HQ=[]; HCB=[]; HL=[];
 end
 return
elseif (nm>1) && any([nu nv nw]==1)
 if nu==1
  U = repmat(U,sm); su=sm; nu=nm;
 elseif nv==1
  V = repmat(V,sm);
 elseif nw==1
  W = repmat(W,sm);
 end
elseif (nu~=nv) || (~isempty(W) && (nu~=nw))
 error('CVARGAS:quiver2:incorrectUvwLengths',...
  'U,V(,W) must be have the same number of elements or W=[].')
else
 if ~all(su==sv)
  su = [nu 1]; % If vector, forces column wisee
  U=U(:); V=V(:);
  if ~isempty(W)
   W=W(:);
  end
 else
  if ~isempty(W) && ~all(su==sw)
   error('CVARGAS:quiver2:incorrectUvwShapes',...
  'U,V,W must be have equal shape.')
  end
 end
end

% Checks S.
if (S<0) || ~isfinite(S)
 error('CVARGAS:quiver2:incorrectSValue',...
  'S must be a positive scalar.')
end
 
% Checks string inputs.
N = length(varargin);
k = 1;
while k<=N
 if isempty(varargin{k}) || ~ischar(varargin{k})
  % Empties!
  error('CVARGAS:quiver2:invalidNotCharInput',...
   'Input (name) must be an string.')
 end
 if (k~=N) && (length(varargin{k})==2) && strcmp(varargin{k}(2),'=')
  % QUIVER2 options with '='.
  switch lower(varargin{k}(1))
   case 'c', CMAP = varargin{k+1}; if isempty(CMAP), CMAP = [0 0 1]; end
   case 'w', WLIM = varargin{k+1}; if isempty(WLIM), WLIM = 0.5; end
   case 'n', MAG  = varargin{k+1}; if isempty(MAG),  MAG  = 0; end
   case 'l', LLIM = varargin{k+1}; if isempty(LLIM), LLIM = []; end
   case 't', TYPE = varargin{k+1}; if isempty(TYPE), TYPE = 'quiver'; end
   case 's', SLANT = varargin{k+1};if isempty(SLANT), SLANT = 'normal';end
   otherwise
    error('CVARGAS:quiver2:incorrectOptionalInputLength',...
    'Optional ''='' input must be preceded by one of ''cwnlts''.')
  end
  varargin(k:k+1) = []; N = N-2; k = k-1;
 elseif (k~=N) && (length(varargin{k})==2) && strcmp(varargin{k}(2),'@')
  % ARROW option with '@'.
  switch lower(varargin{k}(1))
   case 'a', CUSTOM = varargin{k+1};
   case 'x', SAXES = varargin{k+1};
   case 'f', EorF = varargin{k+1};
   case 'l', Aopt = {Aopt{:},'Length',varargin{k+1}};
   case 'b', Aopt = {Aopt{:},'BaseAngle',varargin{k+1}};
   case 't', Aopt = {Aopt{:},'TipAngle',varargin{k+1}};
   case 'w', Aopt = {Aopt{:},'Width',varargin{k+1}};
   case 'p', Aopt = {Aopt{:},'Page',varargin{k+1}};
   case 'c', Aopt = {Aopt{:},'CrossDir',varargin{k+1}};
   case 'n', Aopt = {Aopt{:},'NormalDir',varargin{k+1}};
   case 'e', Aopt = {Aopt{:},'Ends',varargin{k+1}};
   otherwise
    error('CVARGAS:quiver2:incorrectOptionalArrowInputLength',...
    'Optional ''@'' input must be preceded by one of ''axflbtwpcne''.')
  end
  varargin(k:k+1)=[]; N=N-2; k=k-1;
 elseif (k<=2) && strncmpi('filled',varargin{k},length(varargin{k}))
  % QUIVER 'filled' option.
  filled = {'filled'}; 
  varargin(k)=[]; N=N-1; k=k-1;
 elseif (k~=N) && ...
                 strncmpi('visible',varargin{k},max(2,length(varargin{k})))
  % QUIVER P/V option.
  visible = varargin{k+1};
  varargin(k:k+1)=[]; N=N-2; k=k-1;
 elseif (k~=N) && strncmpi('Parent',varargin{k},length(varargin{k}))
  % QUIVER P/V option.
  AX = varargin{k+1};
  varargin(k:k+1)=[]; N=N-2; k=k-1;
 elseif k==1
  % QUIVER LINESPEC option?
  tempf = get(0,'CurrentFigure');
  if ~isempty(tempf), tempa = get(tempf,'CurrentAxes'); end
  hf2 = figure('Visible','off','HandleVisibility','off');
  ha2 = axes('HandleVisibility','off','Parent',hf2);
  try
   hl2 = plot([0 1],[0 1],varargin{k},'Parent',ha2);
   % If no error continues to get LineStyle, Marker and Color.
   LINESPEC = {varargin{k}};
   LineStyle = get(hl2,'LineStyle');
   if strcmp(LineStyle,'-') && isempty(regexp(LINESPEC,'[-]','once')) 
    LineStyle = []; 
   end
   if strcmp(LineStyle,'none'), LineStyle = []; end
   Marker = get(hl2,'Marker');
   if strcmp(Marker,'none'), Marker = []; end
   icol  = regexp(lower(LINESPEC{1}),'[ymcrgbwk]');
   if ~isempty(icol), Color = 'ymcrgbwk'; Color = Color(icol);
   else Color = 'b'; end
   varargin(k)=[]; N=N-1; k=k-1;
  end
  delete(hf2)
  set(0,'CurrentFigure',tempf)
  if ~isempty(tempf), set(tempf,'CurrentAxes',tempa), end
 else
  error('CVARGAS:quiver2:incorrectStringInput',...
   'Incorrect string option.')
 end
 k = k+1;
end

% Checks AX.
if isempty(AX), AX = gca; end

% Checks CMAP.
if isempty(CMAP)
 % LINESPEC given, looks for colors.
 if ~isempty(LINESPEC) && ~isempty(Color)
  switch Color
   case 'y', CMAP = [1 1 0];
   case 'm', CMAP = [1 0 1];
   case 'c', CMAP = [0 1 1];
   case 'r', CMAP = [1 0 0];
   case 'g', CMAP = [0 1 0];
   case 'b', CMAP = [0 0 1];
   case 'w', CMAP = [1 1 1];
   case 'k', CMAP = [0 0 0];
  end
 else CMAP = colormap(AX); 
 end
elseif ~isnumeric(CMAP)
 if exist('cmapping.m','file')==2, CMAP = cmapping([],CMAP);
 else
  warning('CVARGAS:quiver2:cmappingNotFound',...
   {['Not found CMAPPING funtion, get it at ' ...
    'http://www.mathworks.com/matlabcentral/fileexchange']; ...
    'Used current COLORMAP instead of specified one.'})
  CMAP = colormap(AX);
 end
elseif (ndims(CMAP)~=2) || (size(CMAP,2)~=3)
 error('CVARGAS:quiver2:incorrectCmapRgb',...
  'Numeric CMAP must be a valid RGB colormap with 3 columns.')
end

% Checks WLIM.
if length(WLIM)==1, WLIM = [WLIM WLIM]; end
if (length(WLIM)~=2) || ~all(isfinite(WLIM)) || (WLIM(1)>WLIM(2)) || ...
  (WLIM(1)<=0) || (WLIM(2)<=0)
 error('CVARGAS:quiver2:incorrectWlimLimits',...
  'WLIM must have 2 increasing or a single positive scalar(s).')
end

% Checks MAG.
if (length(MAG)~=1) || ~isfinite(MAG) || (MAG<0) % Fixed bug v1.2
 error('CVARGAS:quiver2:incorrectMagValue',...
  'MAG must be a finite not negative scalar.')
end

% Checks LLIM.
if isempty(LLIM), % continue
elseif (length(LLIM)~=2) || (LLIM(1)>LLIM(2)) || (LLIM(1)<0) || ...
  (LLIM(2)==0)
 error('CVARGAS:quiver2:incorrectUvlimValue',...
  'LLIM must be empty [], or 2 positive valid length limits.')
end

% Checks TYPE.
if strncmpi('quiver',TYPE,length(TYPE)), TYPE = 'quiver';
else
 % continue, hopping it is a valid LINESPEC or 'feather' (plus '-d')
end

% Checks SLANT.
if     strncmpi('screen',SLANT,length(SLANT)), SLANT = 'screen';
elseif strncmpi('normal',SLANT,length(SLANT)), SLANT = 'normal';
else
 error('CVARGAS:quiver2:incorrectSlantValue',...
  'SLANT value must be one of ''screen'' or ''normal''.')
end

% Checks x,y,z sizes.
sx=size(x);  sy=size(y);  sz=size(z);
nx=prod(sx); ny=prod(sy); nz=prod(sz);
if any([length(sx) length(sy) length(sz)]~=2)
 % x,y,z must be vectors or 2D-matrix.
 error('CVARGAS:quiver2:incorrectXyDimensions',...
  'x,y(,z) must be 2-dimensional matrix or vectors or [].')
elseif ~all([isempty(W) isempty(z)]==true)
 % W and z must be both empties, not just one.
 error('CVARGAS:quiver2:incorrectWzempty',...
  'Both, W and z must be empty, not just one.')
elseif (nx==nu) && (ny==nu) && (isempty(z) || (nz==nu))
 % Same elements as U,V.
 x = reshape(x,su); y = reshape(y,su);
 if ~isempty(W), z = reshape(z,su); end
elseif (nx==su(2)) && (ny==su(1)) && (isempty(z) || (nz==1))
 % Axis to matrix.
 [x,y] = meshgrid(x(:),y(:));
 if ~isempty(z), z = repmat(z,su); end
elseif isempty(x) && isempty(y) && (isempty(z) || (nz==1))
 % x,y both [].
 [x,y] = meshgrid(1:su(2),1:su(1)); % default grid
 if ~isempty(z), z = repmat(z,su); end
elseif isempty(x) && (ny==nu) && (isempty(z) || (nz==1))
 % x [], but y matrix.
 x = repmat(1:su(2),su(1),1); y = reshape(y,su);
 if ~isempty(z), z = repmat(z,su); end
 if strcmp('quiver',TYPE), TYPE = 'feather'; end
elseif isempty(x) && (ny==su(1)) && (isempty(z) || (nz==1))
 % x [], but y axis.
 [x,y] = meshgrid(ones(su(2),1),y(:));
 if ~isempty(z), z = repmat(z,su); end
 if strcmp('quiver',TYPE), TYPE = 'feather'; end
elseif (nx==nu) && isempty(y) && (isempty(z) || (nz==1))
 % x matrix, but y [].
 x = reshape(x,su); y = repmat((0:su(1)-1)',1,su(2));
 if ~isempty(z), z = repmat(z,su); end
 if strcmp('quiver',TYPE), TYPE = 'feather'; end
elseif (nx==su(2)) && isempty(y) && (isempty(z) || (nz==1))
 % x vector, but y [].
 [x,y] = meshgrid(x(:),zeros(su(1),1));
 if ~isempty(z), z = repmat(z,su); end
 if strcmp('quiver',TYPE), TYPE = 'feather'; end
else
 error('CVARGAS:quiver2:incorrectXyInput',...
  'Incorrect x,y(,z) inputs shapes.')
end

% Checks CUSTOM arrows.
if ~isempty(CUSTOM)
 k = 1;
 while k<=size(Anames,1) 
  if strncmpi(Anames{k,1},CUSTOM,min(length(Anames{k,1}),length(CUSTOM)))
   temp = Anames{k,2}; Aopt = {Aopt{:} temp{:}}; break
  end
  k = k+1;
 end
 if k>size(Anames,1)
  error('CVARGAS:quiver2:unrecognizedCustomArrowsName',...
   ['Unrecognized custom ARROWs name. Must be one of '...
   '''fancy'',''90'',''normal'' or user created inside this function.'])
 end
end
if ~isempty(SAXES)
 switch lower(SAXES)
  case 'x',  vec = [1 0 0];
  case 'y',  vec = [0 1 0];
  case 'z',  vec = [0 0 1];
  case '-x', vec = -[1 0 0];
  case '-y', vec = -[0 1 0];
  case '-z', vec = -[0 0 1];
  otherwise
   error('CVARGAS:quiver2:unrecognizedSaxesArrowsInput',...
   ['Unrecognized SAXES string. Must be one of ''xyz'' or '...
    '''-x'', ''-y'', ''-z''.'])
 end
 Aopt = {Aopt{:},'CrossDir',vec};
end
if strncmpi('face',EorF,length(EorF)),     EorF = 'Face';
elseif strncmpi('edge',EorF,length(EorF)), EorF = 'Edge';
else
 error('CVARGAS:quiver2:unrecognizedFaceEdgeInput',...
  '@f input mus be followed by ''face'' or ''edge''.')
end

% -------------------------------------------------------------------------
% MAIN
% -------------------------------------------------------------------------

% Checks 2D quiver.
do2d = isempty(W);

% Checks ARROWs.
doarrows = ~isempty(Aopt);
if doarrows && ~(exist('arrow.m','file')==2)
 warning('CVARGAS:quiver2:notFoundArrowFunction',...
  ['You must download ARROW function from the FileExchange '... % Fixed bug
   'to use the ''@'' properties. Normal QUIVER was used instead.'])
  doarrows = false;
end

% Checks complex.
doreal = false;
if ~isreal(U), U = real(U); doreal = true; end
if ~isreal(V), V = real(V); doreal = true; end
if ~isreal(W), W = real(W); doreal = true; end
if ~isreal(x), x = real(x); doreal = true; end
if ~isreal(y), y = real(y); doreal = true; end
if ~isreal(z), z = real(z); doreal = true; end
if doreal
 error('CVARGAS:quiver2:ignoredImaginaryPart',...
  'Ignored imaginary part(s).')
end

% Arrows length.
L = hypot(U,V); if ~do2d, L = hypot(L,W); end

% Do not plots NaN (not even a single dot).
inan = ~isfinite(U) | ~isfinite(V);
if ~do2d, inan = inan | ~isfinite(W); end
x(inan)=NaN; y(inan)=NaN; z(inan)=NaN;
U(inan)=NaN; V(inan)=NaN; W(inan)=NaN; L(inan)=NaN;
if all(inan(:))
 if nargout>0, HQ=[]; HCB=[]; HL=[]; end
 return
end

% Normalizes.
if (MAG~=0) && strcmp('quiver',TYPE)
 bad = (L==0) | inan;
 U(~bad)=U(~bad)./L(~bad)*MAG;     V(~bad)=V(~bad)./L(~bad)*MAG;
 if ~do2d, W(~bad)=W(~bad)./L(~bad)*MAG; end
end

% Gets limits.
Lmin = min(L(:)); Lmax = max(L(:));
if ~isempty(LLIM)
 if isfinite(LLIM(1)), Lmin = LLIM(1); end
 if isfinite(LLIM(2)), Lmax = LLIM(2); end
end

% Color bands.
Nc = size(CMAP,1);
dL = (Lmax-Lmin)/Nc;
if dL<eps*10^6; dL = 0; Nc = 1; end

% Gets modes before any changes.
autoxlim = strcmp(get(AX,'XLimMode' ),'auto');
autoylim = strcmp(get(AX,'YLimMode' ),'auto');
autozlim = strcmp(get(AX,'ZLimMode' ),'auto');
autoxtic = strcmp(get(AX,'XTickMode'),'auto');
autoytic = strcmp(get(AX,'YTickMode'),'auto');
autoztic = strcmp(get(AX,'ZTickMode'),'auto');
autoclim = strcmp(get(AX,'CLimMode' ),'auto');
ihold    = ishold(AX);
if ~autoxlim, limx2  = get(AX,'XLim' ); limx = limx2; end
if ~autoylim, limy2  = get(AX,'YLim' ); limy = limy2; end
if ~autozlim, limz2  = get(AX,'ZLim' ); limz = limz2; end
if ~autoxtic, xtick2 = get(AX,'XTick'); end

% Prepares for x-axis for 'feather'.
if ~strcmp(TYPE,'quiver')
 xlim = [min(x(:)) max(x(:))];
 if ((su(2)==1) && (sum(~inan(:))==1) && all(diff(x(~inan(:)))==0)) || ...
   (xlim(1)==xlim(2))
  x(~inan(:)) = 1;
  if ~autoxlim, limx  = limx2-xlim(1)+1; end
  if ~autoxtic, xtick = xtick2-xlim(1)+1; end
 else
  x(~inan(:)) = interp1(xlim,[1 su(2)],x(~inan(:)),'linear','extrap');
  if ~autoxlim, limx = interp1(xlim,[1 su(2)],limx2 ,'linear','extrap');end
  if ~autoxtic, xtick= interp1(xlim,[1 su(2)],xtick2,'linear','extrap');end
 end
end

% Start to draw arrows. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Initializes handles.
HQ = NaN(Nc,1);

% First color band.
if Nc==1, ind = (L<Inf);
else      ind = (L<(Lmin+dL)); end
if ~isempty(ind)
 if do2d
  HQ(1) = quiver(AX,x(ind),y(ind),U(ind),V(ind),S,...
      LINESPEC{:},filled{:},varargin{:},'Color',CMAP(1,:),'Visible','off');
 else
  HQ(1) =quiver3(AX,x(ind),y(ind),z(ind),U(ind),V(ind),W(ind),S,...
      LINESPEC{:},filled{:},varargin{:},'Color',CMAP(1,:),'Visible','off');
 end
else
 % do nothing
 if do2d
  quiver(AX,NaN,NaN,1,1,S,...
   LINESPEC{:},filled{:},varargin{:},'Visible','off'); 
 else
  quiver3(AX,NaN,NaN,NAN,1,1,1,S,...
   LINESPEC{:},filled{:},varargin{:},'Visible','off');
 end
end
% Bands between.
hold(AX,'on')
for k = 2:Nc-1
 ind = (L>=(Lmin+dL*(k-1))) & (L<(Lmin+dL*k));
 if ~isempty(ind)
  if do2d
   HQ(k) = quiver(AX,x(ind),y(ind),U(ind),V(ind),S,...
      LINESPEC{:},filled{:},varargin{:},'Color',CMAP(k,:),'Visible','off');
  else
   HQ(k) = quiver3(AX,x(ind),y(ind),z(ind),U(ind),V(ind),W(ind),S,...
      LINESPEC{:},filled{:},varargin{:},'Color',CMAP(k,:),'Visible','off');
  end
 end
end
% Last band
if Nc==1, ind = [];
else      ind = (L>=(Lmin+dL*(Nc-1))); end
if ~isempty(ind)
 if do2d
  HQ(Nc) = quiver(x(ind),y(ind),U(ind),V(ind),S,...
     LINESPEC{:},filled{:},varargin{:},'Color',CMAP(Nc,:),'Visible','off');
 else
  HQ(Nc) = quiver3(x(ind),y(ind),z(ind),U(ind),V(ind),W(ind),S,...
     LINESPEC{:},filled{:},varargin{:},'Color',CMAP(Nc,:),'Visible','off');
 end
end

% Finishes to draw arrows.  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Good handles.
igood = ishandle(HQ);
HQ    = HQ(igood);
if isempty(HQ)
 if nargout<1, clear(HQ)
 else HCB = []; HL  = []; end
 return
end
CMAP = CMAP(igood,:);
Nc   = size(CMAP,1);

% Draws lines for 'feathers'.
if ~strcmp('quiver',TYPE)
 % Looks for '-d'
 ind = strfind(lower(TYPE),'-d');
 if (length(TYPE)>1) && ~isempty(ind)
  dodate = true; TYPE = TYPE(1:ind-1);
 else
  dodate = false;
 end
 if strncmpi('feather',TYPE,length(TYPE)), FLINESPEC = {};
 else                                      FLINESPEC = {TYPE}; end
 try
  if do2d
    HL = plot([NaN(su(1),1), x, NaN(su(1),1)].',...
              [NaN(su(1),1), y, NaN(su(1),1)].',...
              FLINESPEC{:},'Parent',AX);
             % If an error occurs maybe is because 
             % TYPE was not a valid LINESPEC.
  else
   HL = plot3([NaN(su(1),1), x, NaN(su(1),1)].',...
              [NaN(su(1),1), y, NaN(su(1),1)].',...
              [NaN(su(1),1), z, NaN(su(1),1)].',...
              FLINESPEC{:},'Parent',AX);
            % If an error occurs maybe is because 
            % TYPE was not a valid LINESPEC.
  end
 catch
  error('CVARGAS:quiver2:unrecognizedLinespecFeather',...
   'Unrecognized ''t='',LINESPEC for the feather horizontal line.')
 end
else  HL = [];
end

if ~ihold, hold(AX,'off'), end

% Widens line.
if Nc==1, set(HQ(1),'LineWidth',WLIM(1))
else
 for k = 1:Nc, set(HQ(k),'LineWidth',interp1([1 Nc],WLIM,k)), end
end

% Changes colormap and limits.
if Nc>1
 if autoclim, caxis(AX,[Lmin Lmax]), end
 colormap(AX,CMAP) % forces COLORBAR generation
 HCB = colorbar('Peer',AX);
else HCB = [];
end

% Changes SLANT.
if strcmp('screen',SLANT), axis(AX,'equal'), end

% Changes Limits.
axis(AX,'tight'), xyz = axis(AX);
if ~autoxlim, set(AX,'XLim' ,limx ) 
else
 dx = xyz(2)-xyz(1); set(AX,'XLim',xyz(1:2)+K*dx*[-1 1])
 if autoxtic && strcmp('quiver',TYPE)
  set(AX,'XTickMode','auto','XTickLabelMode','auto')
 end
end
if ~autoylim, set(AX,'YLim' ,limy )
else
 dy = xyz(4)-xyz(3); set(AX,'YLim',xyz(3:4)+K*dy*[-1 1])
 if autoytic, set(AX,'YTickMode','auto','YTickLabelMode','auto'), end
end
if ~autozlim, set(AX,'ZLim' ,limz )
elseif ~do2d && (length(xyz)==6)
 dz = xyz(6)-xyz(5); set(AX,'XLim',xyz(5:6)+K*dz*[-1 1])
 if autoztic, set(AX,'ZTickMode','auto','ZTickLabelMode','auto'), end
end
if ~autoxtic, set(AX,'XTick',xtick), end
%if ~autoytic, set(AX,'YTick',ytick), end
%if ~autoztic, set(AX,'ZTick',ztick), end

% Sets feather x-ticks.
if ~strcmp(TYPE,'quiver') && ~all(x(:)==(1:numel(x))')
 if autoxlim
  limx = get(AX,'XLim');
  if all(x(~inan(:))==1), limx2  = (limx-1)+xlim(1);
  else limx2 = interp1([1 su(2)],xlim,limx,'linear','extrap'); end
 end
 if autoxtic
  xtick = get(AX,'XTick');
  if all(x(~inan(:))==1), xtick2 = (xtick-1)+xlim(1);
  else xtick2 = interp1([1 su(2)],xlim,xtick,'linear','extrap'); end
 end
 tempa = gca;
 ha2 = axes(...
  'HandleVisibility','off',...
  'Visible'         ,'off',...
  'Parent'          ,ancestor(AX,{'figure','uipanel'}),...
  'Units'           ,get(AX,'Units'),...
  'Position'        ,get(AX,'Position'),...
  'XLim'            ,limx2);
 if ~autoxtic, set(ha2,'XTick',xtick2), end
 if dodate
  if autoxtic
   if exist('tlabel.m','file')==2, tlabel(ha2,'x','keeplimits')
   else datetick(ha2,'x','keeplimits'), end
  else
   if exist('tlabel.m','file')==2, tlabel(ha2,'x','keeplimits','keepticks')
   else datetick(ha2,'x','keeplimits','keepticks'), end
  end
 end
 if autoxtic
  if all(x(~inan(:))==1), xtick = get(ha2,'XTick')-xlim(1)+1;
  else
   xtick = interp1(xlim,[1 su(2)],get(ha2,'XTick'),'linear','extrap');
  end
 end
 set(AX,'XTick',xtick,'XTickLabel',get(ha2,'XTickLabel'))
 % In case TLABEL was used.
 temp = get(get(ha2,'XLabel'),'String');
 if ~isempty(temp) && isempty(get(get(AX,'XLabel'),'String'))
  set(get(AX,'XLabel'),'String',temp);
 end
 delete(ha2)
 axes(tempa)
end

% Do ARROWs.
if doarrows
 HQ = mat2cell(HQ,ones(Nc,1),1);
 % Gets LINESPEC properties.
 if ~isempty(LINESPEC)
  if ~isempty(LineStyle), LineStyle = {'LineStyle',LineStyle};
  else                    LineStyle = {}; end
  if ~isempty(Marker),    Marker = {'Marker',Marker};
  else                    Marker = {};    end
 else
  LineStyle = {}; Marker = {};
 end
 % It need to create an invisible axes because ARROW functions does not
 % accept 'Parent' property.
 tempf = get(0    ,'CurrentFigure'); % Gets current figure handle
 tempa = get(tempf,'CurrentAxes');   % Gets current axes handle
 AF    = ancestor(AX,{'figure','uipanel'});
 hf2 = figure(...                    % Generates invisible figure
  'Visible' ,'on',...
  'Units'   ,get(AF,'Units'),...
  'Position',get(AF,'Position'));
 ha2 = axes(...                      % Generates invisible axes
  'Parent'  ,hf2,...
  'Units'   ,get(AX,'Units'),...
  'Position',get(AX,'Position'),...
  'XLim'    ,get(AX,'XLim'),...
  'YLim'    ,get(AX,'YLim'),...
  'ZLim'    ,get(AX,'ZLim'));
 set(ha2,'Units','Pixels')
 l2p = get(ha2,'Position');
 l2p = min(l2p(3:4)./[diff(get(ha2,'XLim')) diff(get(ha2,'YLim'))]);
 set(ha2,'Units',get(AX,'Units'))
 hold(ha2,'on')
 kbad = false(Nc,1);
 lw   = zeros(Nc,1);
 if strcmpi('Edge',EorF), ForE = 'Face'; else ForE = 'Edge'; end
 for k = 1:Nc
  % Start to draw invisible ARROWs
  HL = get(HQ{k},'Children');
  xa = get(HL(1),'XData'); xa = xa(:);
  ya = get(HL(1),'YData'); ya = ya(:);
  za = get(HL(1),'ZData'); za = za(:);
  lw(k) = get(HL(1),'LineWidth');
  delete(HQ{k})
  if isempty(xa) || isempty(ya)
   kbad(k) = true;
   continue
  end
  if isempty(za)
   Start = [xa(1:3:end) ya(1:3:end)];
   Stop  = [xa(2:3:end) ya(2:3:end)];
   u     = hypot(Stop(:,1)-Start(:,1),Stop(:,2)-Start(:,2));
   u     = max(u);
  else
   Start = [xa(1:3:end) ya(1:3:end) za(1:3:end)];
   Stop  = [xa(2:3:end) ya(2:3:end) za(2:3:end)];
   u     = hypot(Stop(:,1)-Start(:,1),Stop(:,2)-Start(:,2));
   u     = hypot(u,Stop(:,3)-Start(:,3));
   u     = max(u);
  end
  if u<eps*10^6
   kbad(k) = true;
   continue
  end
  if isempty(filled)
   HQ{k} = arrow(Start,Stop,'Length',alpha*l2p*u,Aopt{:},...
    [EorF 'Color'],CMAP(k,:),[ForE 'Color'],'none',...
    LineStyle{:}, Marker{:},varargin{:});
  else
   HQ{k} = arrow(Start,Stop,'Length',alpha*l2p*u,Aopt{:},...
    'FaceColor',CMAP(k,:),'EdgeColor',CMAP(k,:),...
    LineStyle{:}, Marker{:},varargin{:});
  end
 end
 clear xa ya za Start Stop
 lw(kbad) = [];
 HQ(kbad) = [];
 Nc       = length(HQ);
 % Draws the ARROWS on AX:
 ihold = ishold(AX);
 hold(AX,'on')
 for k = 1:Nc
  set(HQ{k},...
   {'Parent'}   ,{AX},...
   {'LineWidth'},{lw(k)},...
   {'Clipping'},{'on'})
 end
 if ~ihold, hold(AX,'off'), end
 delete(hf2)
 figure(tempf)
 axes(tempa)
else
 % USE QUIVER instead of ARROW.
 for k = 1:Nc, set(HQ(k),'Visible',visible), end
end


% OUTPUTS CHECK-OUT
% -------------------------------------------------------------------------

% Check nargout.
if nargout==0, clear HQ, end


% [EOF]   quiver2.m

Contact us at files@mathworks.com