Contents
function [cbar,QuiverHandel,Par]=QuiverColorGHG(x,y,u,v,Par,varargin)
Plot velocity using colours/colors
Just a wrapper around quiver to generate coloured arrow field with a colorbar.
[cbar,QuiverHandel,Par]=QuiverColorGHG(x,y,u,v,Par,varargin)
x , y , u , v : vectors of same length. But if using regular velocity grid, x and y can be grid vectors. (In MATLAB speak grid vectors xg and yg are a set of vectors that serve as a compact representation of a grid in ndgrid format. For example, [X,Y] = ndgrid(xg,yg) )
Par.RelativeVelArrowSize : affects the size of the velocity arrows. by default Par.RelativeVelArrowSize=1. Increase value for larger arrows. Par.QuiverColorSpeedLimits=[min max] : Speed range being colored, leave empty for auto. Note however that when plotting using log10 scaling the min speed colored will be some fraction of the max speed based on the value of Par.QuiverColorPowRange : scaling factor for arrow size, default value is 1 Par.VelArrowColorSteps : number of coloring steps, default is 20 Par.VelColorBarTitle : default value is '(m a^{-1})' ; Par.PlotXYscale : default value is 1 Par.VelColorMap : default value is 'jet' Par.MinSpeedToPlot : where speed is less, speed is not plotted, default value is zero Par.VelPlotIntervalSpacing='lin'|'log10' : lin or log10 vel scale Par.MaxPlottedSpeed : When plotting, speed above this value is set equal to this value, i.e. this is the maximum plotted speed Default is max(speed(:)) Par.MinPlottedSpeed : When plotting, speed below this value is set equal to this value, i.e. this is the mainimum plotted speed Default is min(speed(:)). However, if using log10 the minimum plotted speed is never smaller than 10^QshouldiverColorPowRange times MaxPlottedSpeed Par.SpeedTickLabels : numerical array of values Par.QuiverColorPowRange : when using log10 velocity bar, this is the creates possible range of magnitudes shown in colobar. Default is Par.QuiverColorPowRange=3, i.e. the smallest colored speed is 10^3 smaller than the largest speed Par.QuiverSameVelocityScalingsAsBefore : set to true (ie 1) to get same velocity scaling as in previous call.
varargin is passed on to quiver
Examples:
figure
load('CrackRestartfileExample.mat','CtrlVarInRestartFile','MUA','F','BCs','GF')
QuiverColorGHG(MUA.coordinates(:,1),MUA.coordinates(:,2),F.ub,F.vb);
Plot all velocities with arrows of equal length:
load('CrackRestartfileExample.mat','CtrlVarInRestartFile','MUA','F','BCs','GF')
CtrlVar=CtrlVarInRestartFile;
speed=sqrt(F.ub.*F.ub+F.vb.*F.vb);
Par.MinPlottedSpeed=max(speed);
Par.VelColorBarTitle=' ';
Par.PlotXYscale=CtrlVar.PlotXYscale
figure
QuiverColorGHG(MUA.coordinates(:,1),MUA.coordinates(:,2),F.ub,F.vb,Par);
hold on ; PlotMuaBoundary(CtrlVar,MUA,'k')
Plot velocities at approx equally spaced intervals:
load('CrackRestartfileExample.mat','CtrlVarInRestartFile','MUA','F','BCs','GF') CtrlVar=CtrlVarInRestartFile; x=MUA.coordinates(:,1); y=MUA.coordinates(:,2); [X,Y]=ndgrid(linspace(min(x),max(x),20),linspace(min(y),max(y),20)); I=nearestNeighbor(MUA.TR,[X(:) Y(:)]); % finds nodes within computational grid closest to the regularly shaped X and Y grid points. FigVelocities=figure; Par.PlotXYscale=CtrlVar.PlotXYscale ; Par.MinPlottedSpeed=0; QuiverColorGHG(MUA.coordinates(I,1),MUA.coordinates(I,2),F.ub(I),F.vb(I),Par); hold on ; PlotMuaBoundary(CtrlVar,MUA,'k')
Plot velocities using logarithmic scaling.
load('CrackRestartfileExample.mat','CtrlVarInRestartFile','MUA','F','BCs','GF') CtrlVar=CtrlVarInRestartFile; FigVelocities=figure; CtrlVar.VelPlotIntervalSpacing='log10' ; QuiverColorGHG(MUA.coordinates(:,1),MUA.coordinates(:,2),F.ub,F.vb,CtrlVar); hold on ; PlotMuaBoundary(CtrlVar,MUA,'k')
Plotting velocities on top of FE mesh:
load('CrackRestartfileExample.mat','CtrlVarInRestartFile','MUA','F','BCs','GF') CtrlVar=CtrlVarInRestartFile; PlotMuaMesh(CtrlVar,MUA) hold on QuiverColorGHG(x,y,F.ub,F.vb,CtrlVar);
Two calls with same velocity scaling:
[cbar,~,Par]=QuiverColorGHG(x,y,u,v,Par) ; % first call, here Par is not strictly needed as an input Par.QuiverSameVelocityScalingsAsBefore=1; QuiverColorGHG(x,y,u,v,Par) ; % second call uses same scaling as previous one
Note: When doing further contour plots on top of velocity plot, MATLAB will possibly change the limits of the colorbar and the position of the ticklables will no longer be correct. If this happens then reset range and ticks, for example:
[~,~,Par]=QuiverColorGHG(x,y,ub,vb); ...some other plots that affect the colorbar labels, colors, etc... cbar=colorbar; cbar.Ticks=Par.QuiverTicks*(cbar.Limits(2)-cbar.Limits(1))+cbar.Limits(1); cbar.TickLabels=Par.QuiverTickLabels; title(cbar,'(m/d)') ;
Note: The variable Par is modified in the call and will, in general, be modified on return. If the same Par variable is then used again as an input to a subsequent call to QuiverColorGHG, those (modified) parameter values might affect the plot. The problem can be avoided by re-setting Par=[] in the second call, or by setting
Par.QuiverSameVelocityScalingsAsBefore=false ; Par.MaxPlottedSpeed=[] ; Par.MinPlottedSpeed=[] ; Par.QuiverColorSpeedLimits=[];
ahead of a second call when using Par from a previous call.
persistent SpeedPlotIntervals uvPlotScale QuiverTickLabels QuiverTicks QuiverCmap if ~Par.QuiverSameVelocityScalingsAsBefore SpeedPlotIntervals=[]; uvPlotScale=[]; QuiverTickLabels=[]; QuiverTicks=[]; QuiverCmap=[]; % if nargin>4 % % Par.MaxPlottedSpeed=[] ; % Par.MinPlottedSpeed=[] ; % % Par.QuiverColorSpeedLimits=[] ; % % Par.VelPlotIntervalSpacing=[] ; % % Par.VelArrowColorSteps=[] ; % % Par.VelColorMap =[] ; % % Par.SpeedTickLabels=[] ; % % end end cbar=[]; QuiverHandel=[]; if isempty(x) || isempty(y) || isempty(u) || isempty(v) return end if size(u,2)== 1 && (numel(x) ~= numel(y)) error('Ua:QuiverColorGHG:xyDimensionsNotCompatible','x and y must have the same number of elements.') end if numel(u) ~= numel(v) error('Ua:QuiverColorGHG:uvDimensionsNotCompatible','u and v must have the same number of elements.') end % % The expected typical usage is to plot one-dimensional arrays of velocities % But u, v, x ,and y can also be given on a grid. % If u and v is given on a grid, create vectors if size(u,1)> 1 && size(u,2)>1 && ((size(x,2)==1 && size(y,2)==1) || (size(x,1)==1 && size(y,1)==1 )) % u and v are matrices , x and y are vectors x=x(:) ; y=y(:) ; if size(u)==size(v) if (size(x,1)==size(u,1)) && (size(y,1)==size(u,2)) [X,Y]=ndgrid(x,y) ; x=X(:) ; y=Y(:) ; u=u(:) ; v=v(:); clear X Y elseif (size(x,1)==size(u,2)) && (size(y,1)==size(u,1)) warning('QuiverColorGHG:wrongdimensions','x and y are not grid vectors') [X,Y]=meshgrid(x,y) ; x=X(:) ; y=Y(:) ; u=u(:) ; v=v(:); clear X Y end end end x=x(:) ; y=y(:) ; u=u(:) ; v=v(:); speed=sqrt(u.*u+v.*v); % speed is never scaled, so I can use speed to color velocity field based on values if isinf(max(speed)) fprintf(' Max of speed is infinite\n') I=isinf(speed); u(I)=NaN ; v(I)=NaN ; speed(I)=NaN; fprintf(' Seeting all such velocity values to NaN \n') end % now check Par fields, use all user-defined values where available, use default values otherwise % and put in some reasonable for the remaining fields if nargin>4 && ~isempty(Par) if ~isfield(Par,'QuiverColorPowRange') Par.QuiverColorPowRange=3; end if ~isfield(Par,'MaxPlottedSpeed') || isempty(Par.MaxPlottedSpeed) if isfield(Par,'QuiverColorSpeedLimits') && ~isempty(Par.QuiverColorSpeedLimits) Par.MaxPlottedSpeed=Par.QuiverColorSpeedLimits(2); else if all(speed==0) ticks=logticks(speed,Par.QuiverColorPowRange); Par.MaxPlottedSpeed=max(ticks); else %Par.MaxPlottedSpeed=max(speed(:))*1.001; Par.MaxPlottedSpeed=max(speed(:)); end end end if ~isfield(Par,'MinPlottedSpeed') || isempty(Par.MinPlottedSpeed) Par.MinPlottedSpeed=0; end if ~isfield(Par,'VelPlotIntervalSpacing') || isempty(Par.VelPlotIntervalSpacing) Par.VelPlotIntervalSpacing='lin'; end if ~isfield(Par,'QuiverColorSpeedLimits') || isempty(Par.QuiverColorSpeedLimits) switch Par.VelPlotIntervalSpacing case 'log10' ticks=logticks(speed,Par.QuiverColorPowRange,12); Par.QuiverColorSpeedLimits(1)=min(ticks); Par.QuiverColorSpeedLimits(2)=max(ticks); case 'lin' Par.QuiverColorSpeedLimits(1)=min(speed); Par.QuiverColorSpeedLimits(2)=max(speed); end end if ~isfield(Par,'uvPlotScale') Par.uvPlotScale=[]; end if ~isfield(Par,'RelativeVelArrowSize') || isempty(Par.RelativeVelArrowSize) Par.RelativeVelArrowSize=1; % larger value makes vel arrows larger end if ~isfield(Par,'VelColorMap') Par.VelColorMap='jet'; end if ~isfield(Par,'PlotXYscale') Par.PlotXYscale=1; end if ~isfield(Par,'VelArrowColorSteps') Par.VelArrowColorSteps=50; end if ~isfield(Par,'VelColorBarTitle') Par.VelColorBarTitle="($\mathrm{m \, yr^{-1}}$)" ; end if ~isfield(Par,'MinSpeedToPlot') Par.MinSpeedToPlot=0; end if ~isfield(Par,'SpeedTickLabels') Par.SpeedTickLabels=[]; end if ~isfield(Par,'QuiverCmap') Par.QuiverCmap=[]; end if ~isfield(Par,'QuiverSameVelocityScalingsAsBefore') Par.QuiverSameVelocityScalingsAsBefore=false ; end if Par.QuiverSameVelocityScalingsAsBefore if ~isempty(uvPlotScale) Par.uvPlotScale=uvPlotScale ; Par.SpeedPlotIntervals=SpeedPlotIntervals ; Par.QuiverTickLabels=QuiverTickLabels; Par.QuiverTicks=QuiverTicks ; Par.QuiverCmap=QuiverCmap; else Par.QuiverSameVelocityScalingsAsBefore=false ; fprintf('In QuiverColorGHG same scaling as in a previous call is requested, but the velocity scaling factor is not defined.\n') fprintf('Therefore, setting QuiverSameVelocityScalingsAsBefore=false \n') end end else Par.RelativeVelArrowSize=1; % larger value makes vel arrows larger Par.VelArrowColorSteps=50; Par.uvPlotScale=[]; Par.VelColorBarTitle="($\mathrm{m \, yr^{-1}}$)" ; Par.PlotXYscale=1; Par.VelColorMap='jet'; Par.MaxPlottedSpeed=max(speed(:)); Par.MinPlottedSpeed=min(speed(:)); Par.VelPlotIntervalSpacing='lin'; Par.QuiverColorSpeedLimits(1)=min(speed(:)); Par.QuiverColorSpeedLimits(2)=max(speed(:)); Par.MinSpeedToPlot=0; Par.SpeedTickLabels=[]; Par.QuiverColorPowRange=3; Par.QuiverCmap=[]; Par.QuiverSameVelocityScalingsAsBefore=0; end
now all input variables should be OK
N=Par.VelArrowColorSteps; if Par.QuiverSameVelocityScalingsAsBefore colormap(QuiverCmap) if isempty(Par.uvPlotScale) || ~isfield(Par,'uvPlotScale') fprintf('In QuiverColorGHG same scaling as in a previous call is requested, but the velocity scaling factor is not defined.\n') fprintf('Use parameters from previous call in this call!\n') error('Ua:QuiverColorGHG','The field uvPlotScale is not defiend') end else if strcmp(Par.VelPlotIntervalSpacing,'log10')==1 % create a `logarithmic' colormap if ~isnumeric(Par.VelColorMap) NN=10*N ; cmap=colormap(sprintf('%s(%i)',Par.VelColorMap,NN)); else cmap=Par.VelColorMap ; NN=size(cmap,1); end index=fix((NN-1)*(exp((0:N-1)/(N-1))-1)/(exp(1)-1)+1); cmap=colormap(cmap(index,:)); else if ~isnumeric(Par.VelColorMap) cmap=colormap(sprintf('%s(%i)',Par.VelColorMap,N)); else cmap=Par.VelColorMap ; N=size(cmap,1); end end switch Par.VelPlotIntervalSpacing case 'log10' ticks=logticks(speed,Par.QuiverColorPowRange,12,Par.QuiverColorSpeedLimits); MinTick=min(ticks); if Par.QuiverColorSpeedLimits(1)<MinTick %Par.MinPlottedSpeed=MinTick; Par.QuiverColorSpeedLimits(1)=MinTick; end Par.SpeedPlotIntervals=logspace(log10(Par.QuiverColorSpeedLimits(1)),log10(Par.QuiverColorSpeedLimits(2)),N+1); case 'lin' %Par.SpeedPlotIntervals=linspace(Par.MinPlottedSpeed,Par.MaxPlottedSpeed,N+1); Par.SpeedPlotIntervals=linspace(Par.QuiverColorSpeedLimits(1),Par.QuiverColorSpeedLimits(2),N+1); otherwise fprintf(' which case {log10,lin}?' ) error('QuiverColorGHG:VelPlotIntervalSpacing','case not reckognized') end Par.QuiverCmap=cmap; % scaling of velocity to get reasonably sized arrows Np=(sqrt(numel(x))/10); if Np<30 ; Np=30 ; end ps=min([max(x)-min(x) max(y)-min(y)])/Par.PlotXYscale*Par.RelativeVelArrowSize/Np; Par.uvPlotScale = Par.QuiverColorSpeedLimits(2)/ps ; end uplot=u ; vplot=v; % set velocities within plotting range Ind=speed > Par.MaxPlottedSpeed; uplot(Ind)=uplot(Ind)*Par.MaxPlottedSpeed./speed(Ind); vplot(Ind)=vplot(Ind)*Par.MaxPlottedSpeed./speed(Ind); Ind=speed < Par.MinPlottedSpeed; uplot(Ind)=uplot(Ind)*Par.MinPlottedSpeed./speed(Ind); vplot(Ind)=vplot(Ind)*Par.MinPlottedSpeed./speed(Ind); %fprintf('QuiverColorGHG: uvPlotScale=%f \n',Par.uvPlotScale) uplot=uplot/Par.uvPlotScale; vplot=vplot/Par.uvPlotScale; %SpeedPlot=sqrt(uplot.*uplot+vplot.*vplot); %sc=log(1+SpeedPlot)./x ; I=isnan(sc) ; sc(I)=1; % end for J=1:numel(Par.SpeedPlotIntervals)-1 switch J case 1 I=speed <= Par.SpeedPlotIntervals(J+1) & speed>Par.MinSpeedToPlot; case N I=speed>Par.SpeedPlotIntervals(J) & speed>Par.MinSpeedToPlot; otherwise I=speed>Par.SpeedPlotIntervals(J) & speed <= Par.SpeedPlotIntervals(J+1) & speed>Par.MinSpeedToPlot; end if numel(x(I))>0 % This should not really be needed, but % results in errors in Matlab2016a QuiverHandel=quiver(x(I)/Par.PlotXYscale,y(I)/Par.PlotXYscale,uplot(I),vplot(I),0,... 'color',Par.QuiverCmap(J,:),varargin{:}) ; hold on end end nPowRange=Par.QuiverColorPowRange; if ~Par.QuiverSameVelocityScalingsAsBefore if verLessThan('matlab','8.4') %pre 2014b version cbar=colorbar; title(cbar,Par.VelColorBarTitle,"interpreter","latex") ; if strcmp(Par.VelPlotIntervalSpacing,'log10')==1 ms=fix(log10(Par.MaxPlottedSpeed)); ticklabel=logspace(0,ms,ms+1); tickpos=1+N*log10(ticklabel)/log10(Par.SpeedPlotIntervals(N+1)); set(cbar,'Ytick',tickpos,'YTicklabel',ticklabel); else clim([0 max(Par.SpeedPlotIntervals)]); end else if strcmp(Par.VelPlotIntervalSpacing,'log10')==1 if ~isempty(Par.SpeedTickLabels) ticklabel=log10(Par.SpeedTickLabels); else % this is for more pleasing interval between labels (but needs to be improved) %D=(max(sp)-min(sp))/10 ; D=10.^round(log10(D)) ; ticklabel=unique(D*round(sp/D)); ticklabel=logticks(speed,nPowRange,12,Par.SpeedPlotIntervals); %ticks=logticks(speed,12,Par.QuiverColorPowRange); end tickpos=(log10(ticklabel)-min(log10(Par.SpeedPlotIntervals)))/(max(log10(Par.SpeedPlotIntervals))-min(log10(Par.SpeedPlotIntervals))); else if ~isempty(Par.SpeedTickLabels) ticklabel=Par.SpeedTickLabels; else % this is for (hopefully) a more pleasing interval between labels D=(max(Par.SpeedPlotIntervals)-min(Par.SpeedPlotIntervals)); if D==0 % special case if all values same or all values zero D=mean(Par.SpeedPlotIntervals); if D==0 ticklabel=[-1 0 1]; tickpos=(ticklabel+1)/2; else ticklabel=[D/2 D 1.5*D]; tickpos=(ticklabel-D/2)/D; end else D=double(10.^floor(log10(D)))/4 ; first=D*floor(Par.SpeedPlotIntervals(1)/D); last=D*ceil(Par.SpeedPlotIntervals(end)/D); ticklabel=first:D:last; tickpos=(ticklabel-min(Par.SpeedPlotIntervals))/(max(Par.SpeedPlotIntervals)-min(Par.SpeedPlotIntervals)); %tickpos=(ticklabel-first)/(last-first); if numel(ticklabel)>10 ticklabel=ticklabel(1:2:end) ; tickpos=tickpos(1:2:end) ; end end %ticklabel=unique(D*round(sp/D)); end end if any(isnan(tickpos)) warning('QuiverColorGHG:NANinTickPos','calculated positions of ticks on the colorbar contain NaNs') end [tickpos,ia]=unique(tickpos); ticklabel=ticklabel(ia); colormap(Par.QuiverCmap) cbar=colorbar ; %cbar.TickLabels=ticklabel ; if ~any(isnan(tickpos)) Ticks=tickpos*(cbar.Limits(2)-cbar.Limits(1))+cbar.Limits(1); %cbar.Ticks=Ticks; % tickpos*(cbar.Limits(2)-cbar.Limits(1))+cbar.Limits(1); end axis equal Par.QuiverTickLabels=ticklabel; Par.QuiverTicks=Ticks; end end if isempty(cbar) cbar=colorbar; end title(cbar,Par.VelColorBarTitle,"interpreter","latex") ; cbar.TickLabels=Par.QuiverTickLabels; cbar.Ticks=Par.QuiverTicks; % Par.QuiverColorSpeedLimits=[min(Par.SpeedPlotIntervals) max(Par.SpeedPlotIntervals)]; % Par.QuiverColorSpeedLimits=[]; % don't reuse these setting in next call axis equal % axis([min(x)/Par.PlotXYscale max(x)/Par.PlotXYscale min(y)/Par.PlotXYscale max(y)/Par.PlotXYscale]) uvPlotScale=Par.uvPlotScale ; SpeedPlotIntervals=Par.SpeedPlotIntervals ; QuiverTickLabels=Par.QuiverTickLabels; QuiverTicks=Par.QuiverTicks ; QuiverCmap=Par.QuiverCmap;
end