Code covered by the BSD License  

Highlights from
Comprehensive Polar Plots

image thumbnail

Comprehensive Polar Plots

by

 

Polar plots with handle graphics type parameter setting. Includes log radius support.

out=mmpolar(varargin)
function out=mmpolar(varargin)
%MMPOLAR Polar Plot with Settable Properties.
% MMPOLAR(Theta,Rho) creates a polar coordinate plot using the angle Theta
% in RADIANS and radius in Rho. Rho can contain negative values.
% MMPOLAR(Theta,Rho,S) creates the plot using the line spec given by S. See
% the function PLOT for information about S.
% MMPOLAR(Theta1,Rho1,S1,Theta2,Rho2,S2,...) plots all the defined curves.
%
% MMPOLAR(Theta1,Rho1,S1,...,'PName',PValue,...) plots all defined curves,
% and sets plot property names to the corresponding property values.
% MMPOLAR(Theta1,Rho1,S1,...,P) plots all the defined curves, and uses the
% structure P having fieldnames equal to plot property names to set
% corresponding property values contained in the associated fields.
%
% H=MMPOLAR(Theta,Rho,...) returns handles to lines or lineseries objects.
% For example, set(H,'LineWidth',2) sets all linewidths to 2 points.
% Note: 'LineWidth' is NOT a property that can be set with MMPOLAR. It must
% be set as shown above by using the SET function on the line handles H.
%
% MMPOLAR('PName',PValue,...) sets the property names to the corresponding
% property values. See below for property name/value pairs. Just as with
% the function SET 'PName' is case insensitive and need only be unique.
% MMPOLAR with no input argument returns a structure with fieldnames equal
% to property names each containing the associated property values.
% MMPOLAR(P) sets property values using the structure P as described above.
% MMPOLAR('PName') returns the property value associated with 'PName'.
% MMPOLAR({'PName1','PName2',...}) returns multiple property values in a
% cell array.
% MMPOLAR(Hax,...) uses the axes having handle Hax.
%
% Examples: MMPOLAR(Theta,Rho,S,'Style','compass') creates a polar plot with
% theta=0 pointing North and theta increasing in the clockwise direction.
%
% MMPOLAR(Theta,Rho,S) creates a cartesian polar plot where theta=0 is along
% the x-axis and theta increases in the counterclockwise direction.
%
% MMPOLAR works with HOLD, XLABEL, YLABEL, TITLE, ZOOM, SUBPLOT
% but does not work with AXIS, GRID (Use MMPOLAR properties to set these)
%
% See also POLAR, PLOT, HOLD
%
% PROPERTY          VALUE {Default}  DESCRIPTION
% Style             {cartesian} | compass  shortcut to two common polar
%                     styles. Cartesian: theta=0 points east and increases
%                     going north. Compass: theta=0 points north and
%                     increases going east. See TDirection and TZeroDirection.
% Axis              {on} | off  shortcut for grids, ticks, border,
%                     backgroundcolor, visibility
% Border            {on} | off  shortcut for axis border, tick mark visibility.
% Grid              {on} | off  shortcut for visibility of rho and theta grids
% RLimit            [Rmin Rmax] rho axis limits, may be negative values
% TLimit            [Tmin Tmax] theta axis limits in RADIANS
% RTickUnits        {''} string added to last rho tick label to denote units
% TTickScale        {degrees} | radians  theta axis tick label scaling
% TDirection        cw | {ccw} direction of increasing theta
% TZeroDirection    North | {East} | South | West  theta=0 axis direction
%
% BackgroundColor   {w}  colorspec for axis background color
% BorderColor       {k} colorspec for axis border and tick mark colors
% FontName          string  font name for tick labels
% FontSize          scalar  font size for tick labels
% FontWeight        {normal} | bold  font weight for tick labels
% TickLength        {.02} normalized length of rho and theta axis tick marks
%
% RGridColor        {k} colorspec for rho axis grid color
% RGridLineStyle    - | -- | {:} | -.  rho axis grid line style
% RGridLineWidth    {0.5}  rho axis grid line width in points
% RGridVisible      {on} | off  rho axis grid visibility
% RTickAngle        [scalar]  angular position of rho axis tick labels in
%                             TTickScale units
% RTickOffset       {.04} Normalized radial offset for rho tick labels
% RTickLabel        string cell array containing rho axis tick labels
% RTickLabelVisible {on} | off  visibility of rho axis tick labels
% RTickLabelHalign  {center} | left | right  horizontal
%                             alignment of rho axis tick labels
% RTickLabelValign  {middle} | top | cap | baseline | bottom  vertical
%                             alignment of rho axis tick labels
% RTickValue        [vector]  vector containing rho axis tick positions
% RTickVisible      {on} | off  rho axis tick visibility
%
% TGridColor        colorspec for theta axis grid color
% TGridLineStyle    - | -- | {:} | -.  theta axis grid line style
% TGridLineWidth    {0.5}  theta axis grid line width in points
% TGridVisible      {on} | off  theta axis grid visibility
% TTickDelta        theta axis tick spacing in TTickScale units
%                   {15 degrees or pi/12 radians}
% TTickDirection    {in} | out  direction of theta tick marks
% TTickOffset       {.08} normalized radial offset of theta tick labels
% TTickLabel        string cell array containing theta axis tick labels
% TTickLabelVisible {on} | off  visiblity of theta axis tick labels
% TTickSign         {+-} | + sign of theta tick labels
% TTickValue        [vector]  vector of theta ticks in TTickScale units
% TTickVisible      {on} | off  theta axis tick visibility

% D.C. Hanselman, University of Maine, Orono, ME 04469
% MasteringMatlab@yahoo.com
% Mastering MATLAB 7
% 2005-04-25, 2006-01-18, 2006-04-06, 2006-05-17, 2006-05-18
% 2006-10-03, 2007-03-04, 2008-03-18

%--------------------------------------------------------------------------
% Parse Inputs                                                 Parse Inputs
%--------------------------------------------------------------------------
% Find MMPOLAR axes if it exists
nargi=nargin;
% find MMPOLAR axes if it is supplied or if it is the current axes
if nargi>0 && isscalar(varargin{1}) && ishandle(varargin{1})
   HAxes=varargin{1}; % see if first argument is an MMPOLAR axes
   if strcmp(get(HAxes,'Tag'),'MMPOLAR_Axes')
      HFig=ancestor(HAxes,'figure');
      HoldIsON=strcmp(get(HAxes,'nextplot'),'add')...
            && strcmp(get(HFig,'nextplot'),'add');
      P=getappdata(HAxes,'MMPOLAR_Properties');
      Pfn=fieldnames(P);
      varargin(1)=[]; % strip initial axes handle off varargin
      nargi=nargi-1;  % varargin now contains rest of input arguments
   else
      local_error('First Argument is Not a Valid MMPOLAR Axes Handle.')
   end
else % see if MMPOLAR axes is current axes
   HFig=get(0,'CurrentFigure');
   if isempty(HFig)
      HAxes=[];
      Pfn=fieldnames(local_getDefaults);
      HoldIsON=false;
   else
      HAxes=get(HFig,'CurrentAxes');
      if isempty(HAxes)
         Pfn=fieldnames(local_getDefaults);
         HoldIsON=false;
      else
         if strcmp(get(HAxes,'Tag'),'MMPOLAR_Axes')
            HoldIsON=strcmp(get(HAxes,'nextplot'),'add')...
                  && strcmp(get(HFig,'nextplot'),'add');
            P=getappdata(HAxes,'MMPOLAR_Properties');
            Pfn=fieldnames(P);
         else % no MMPOLAR axes exists
            HAxes=[];
            Pfn=fieldnames(local_getDefaults);
            HoldIsON=false;
            set(HAxes,'NextPlot','replace') % hold off
         end
      end
   end
end
%--------------------------------------------------------------------------
% Consider input arguments                         Consider input arguments
%--------------------------------------------------------------------------
if nargi==0   % MMPOLAR() MMPOLAR() MMPOLAR() MMPOLAR() MMPOLAR() MMPOLAR()
   if ~isempty(HAxes)
      out=P; % return property structure if it exists
      return
   else
      local_error('No MMPOLAR Axes exists or is not Current Axes.')
   end
end
if nargi==1   % Consider SET and GET Requests Consider SET and GET Requests
   if ~isempty(HAxes)
      arg=varargin{1};
      if ischar(arg)   % MMPOLAR('Pname') MMPOLAR('Pname') MMPOLAR('Pname')
         [fn,errmsg]=local_isfield(Pfn,arg);
         error(errmsg)
         out=P.(fn);
         return
      elseif iscellstr(arg)              % MMPOLAR({'PName1','PName2',...})
         nc=length(arg);
         out=cell(1,nc);
         for k=1:nc
            [fn,errmsg]=local_isfield(Pfn,arg{k});
            error(errmsg)
            out{k}=P.(fn);
         end
         return
      elseif isstruct(arg)    % MMPOLAR(S) MMPOLAR(S) MMPOLAR(S) MMPOLAR(S)
         Sfn=fieldnames(arg);
         for k=1:length(Sfn)
            [fn,errmsg]=local_isfield(Pfn,Sfn{k});
            error(errmsg)
            S.(fn)=arg.(Sfn{k});
         end
         local_updatePlot(HAxes,S);
         return
      else
         local_error('Unknown Input Argument.')
      end
   else
      local_error('No MMPOLAR exists or is not Current Axes.')
   end
end
%           MMPOLAR('PName1',PValue1,'PName2',PValue2,'PName3',PValue3,...)
if rem(nargi,2)==0 && ischar(varargin{1}) && ~isempty(HAxes)
   for k=1:2:nargi-1
      PName=varargin{k};
      if ischar(PName)
         [fn,errmsg]=local_isfield(Pfn,PName);
         error(errmsg)
         S.(fn)=varargin{k+1};
      else
         local_error('String Input Property Name Argument Expected.')
      end
   end
   local_updatePlot(HAxes,S)
   return
elseif ischar(varargin{1})      % Unknown Input Unknown Input Unknown Input
   local_error('Unknown Input Arguments or NO MMPOLAR Axes Exists.')
   
elseif isnumeric(varargin{1})%MMPOLAR(Theta,Rho,...) MMPOLAR(Theta,Rho,...)
   % find out if there are appended 'PName',PValue pairs or a structure P
   last=[];
   k=3; % 'Pname' or P can't appear before 3rd argument
   while k<=nargi 
      vark=varargin{k};
      k=k+1;
      if ischar(vark)
         fn=local_isfield(Pfn,vark);
         if ~isempty(fn)
            if isempty(last)
               last=k-1;
            end
            S.(fn)=varargin{k};
            k=k+1; % skip known PValue
         end
      elseif isstruct(vark) % found appended structure
         if isempty(last)
            last=k-1;
         end
         Sfn=fieldnames(vark);
         for ki=1:length(Sfn)
            [fn,errmsg]=local_isfield(Pfn,Sfn{ki});
            error(errmsg)
            S.(fn)=vark.(Sfn{ki});
         end
      end
   end
   if ~isempty(last)
      varargin(last:end)=[]; % strip properties and values from input
   end
else
   local_error('Unknown Input Arguments.')
end
%--------------------------------------------------------------------------
% Now have valid data for plotting         Now have valid data for plotting
%--------------------------------------------------------------------------
if HoldIsON % a current held plot exists
   
   D=getappdata(HAxes,'MMPOLAR_Data');                    % get stored data
   P=getappdata(HAxes,'MMPOLAR_Properties');
   
   tmpaxes=axes('Position',get(HAxes,'Position'));
   try % the plot function should work with new data
      Hlines=plot(tmpaxes,varargin{:});
   catch
      delete(tmpaxes)
      local_error('Input Arguments Not Understood.')
   end
   D.TData=[D.TData; get(Hlines,{'XData'})];   % add to held data
   D.RData=[D.RData; get(Hlines,{'YData'})];
   D.LineColor=[D.LineColor; get(Hlines,{'Color'})];
   D.LineStyle=[D.LineStyle; get(Hlines,{'LineStyle'})];
   D.Marker=[D.Marker; get(Hlines,{'Marker'})];
   D.NumLines=length(D.TData);
   
   delete(Hlines)                % got the data, lines are no longer needed
   delete(D.HLines)              % delete original lines as well
   
   set(tmpaxes,'NextPlot','add') % hold on
   for k=1:D.NumLines        % plot ALL data to find new RTicks and RLimits
      plot(tmpaxes,D.TData{k},D.RData{k})
   end
   P.RLimit=get(tmpaxes,'YLim');                          % Rho axis limits
   P.RTickValue=get(tmpaxes,'YTick');              % Default Rho axis ticks
   delete(tmpaxes)                        % Temporary axes no longer needed
   [P,D]=local_getRTickValue(HAxes,P,D);              % get rho tick values
   
   D.RDataN=cell(D.NumLines,1);
   for k=1:D.NumLines % normalize rho data for plotting
      D.TData(k)={mod(D.TData{k},2*pi)}; % map theta into [0 2*pi]
      D.RDataN(k)={(D.RData{k}-D.RMin)/D.RLimitDiff};
   end
   
   P.TLimit=[0 2*pi];                                    % plot full circle
   [P,D]=local_getTTickValue(P,D);                  % get theta tick values
   [P,D]=local_placeAxesPatch(HAxes,P,D,1);% draw axes patch, border, ticks
   [P,D]=local_placeRGrid(HAxes,P,D,1);                     % Draw Rho Grid
   [P,D]=local_placeTGrid(HAxes,P,D,1);                   % Draw Theta Grid
   [P,D]=local_placeTTickLabel(HAxes,P,D,1);        % Add Theta Tick Labels
   [P,D]=local_placeRTickLabel(HAxes,P,D,1);         % Add Rho Tick Lablels
      
else % Hold is OFF
   
   try % the plot function should work now
      HAxes=newplot; % create axes
      D.HLines=plot(HAxes,varargin{:});
   catch
      delete(gcf)
      local_error('Input Arguments Not Understood.')
   end
   HFig=ancestor(HAxes,'figure');
   D.NumLines=length(D.HLines);                  % get all data for storage
   D.TData=get(D.HLines,{'XData'});
   D.RData=get(D.HLines,{'YData'});
   D.LineColor=get(D.HLines,{'Color'});
   D.LineStyle=get(D.HLines,{'LineStyle'});
   D.Marker=get(D.HLines,{'Marker'});
   
   P=local_getDefaults;          % get default properties, update as needed
   
   P.RLimit=get(HAxes,'YLim');                            % Rho axis limits
   P.RTickValue=get(HAxes,'YTick');                % Default Rho axis ticks
   [P,D]=local_getRTickValue(HAxes,P,D);              % get rho tick values
   
   D.RDataN=cell(D.NumLines,1);
   for k=1:D.NumLines                              % Condition plotted data
      % wrap angles into first revolution
      D.TData{k}=mod(D.TData{k},2*pi);
      % normalize rho data for plotting
      D.RDataN(k)={(D.RData{k}-D.RMin)/D.RLimitDiff};
   end
   P.TLimit=[0 2*pi];                                    % plot full circle
   [P,D]=local_getTTickValue(P,D);                  % get theta tick values
   delete(D.HLines)         % clear cartesian lines, then create polar axes
   [P,D]=local_placeAxesPatch(HAxes,P,D);  % draw axes patch, border, ticks
   [P,D]=local_placeRGrid(HAxes,P,D);                       % Draw Rho Grid
   [P,D]=local_placeTGrid(HAxes,P,D);                     % Draw Theta Grid
   [P,D]=local_placeTTickLabel(HAxes,P,D);          % Add Theta Tick Labels
   [P,D]=local_placeRTickLabel(HAxes,P,D);           % Add Rho Tick Lablels

end

xylims=[-1 1]*1.08;
% Finalize Axes View                                     Finalize Axes View
set(HAxes,'DataAspectRatio',[1 1 1],....
          'XLimMode','manual','YLimMode','manual',...
          'XLim',xylims,'YLim',xylims,...
          'Visible','Off','Tag','MMPOLAR_Axes')
Hlabels=get(HAxes,{'Xlabel','YLabel', 'Title'});
set([Hlabels{:}],'Visible','on') % make labels visible

% Plot the Data                                               Plot the Data
D.HLines=zeros(D.NumLines,1);      % storage for lineseries handles
set([HFig,HAxes],'NextPlot','add') % hold on
for k=1:D.NumLines                 % plot the normalized data
   tdata=D.TData{k};
   rdata=D.RDataN{k};
   xdata=rdata.*cos(tdata);
   ydata=rdata.*sin(tdata);
   D.HLines(k)=plot(HAxes,xdata,ydata,...
                  'Color',D.LineColor{k},...
                  'LineStyle',D.LineStyle{k},...
                  'Marker',D.Marker{k});
end
if HoldIsON
   set([HFig,HAxes],'NextPlot','add') % hold on
else
   set([HFig,HAxes],'NextPlot','replace') % hold off
end

% Store Data                                                     Store Data
setappdata(HAxes,'MMPOLAR_Properties',P)
setappdata(HAxes,'MMPOLAR_Data',D)

if nargout % output handles if requested
   out=D.HLines;
end

% Update Plot with 'PName' PValue pairs if they exist
if exist('S','var')==1
   local_updatePlot(HAxes,S)
end
%--------------------------------------------------------------------------
%--------------------------------------------------------------------------
% Local Functions                                           Local Functions
%--------------------------------------------------------------------------
function local_updatePlot(HAxes,S)              % local_updatePlot(HAxes,S)
% update MMPOLAR plot properties
% S contains known properties

P=getappdata(HAxes,'MMPOLAR_Properties');
D=getappdata(HAxes,'MMPOLAR_Data');
Sfn=fieldnames(S);

for kk=1:length(Sfn)
   switch Sfn{kk}
   case 'Axis'                                                       % Axis
      [istrue,onoff]=local_isonoff(S.Axis);
      if istrue
         set(D.HAPatch,'Visible',onoff)
         set(D.HRGrid,'Visible',onoff)
         set(D.HTGrid,'Visible',onoff)
         set(D.HRTick,'Visible',onoff)
         set(D.HTTick,'Visible',onoff)
         set(D.HRTickLabel,'Visible',onoff)
         set(D.HTTickLabel,'Visible',onoff)
         P.RGridVisible=onoff;
         P.TGridVisible=onoff;
         P.RTickLabelVisible=onoff;
         P.TTickLabelVisible=onoff;         
      else
         local_error('Unknown ''Axis'' Property Value.')
      end
   case 'BackgroundColor'                                 % BackgroundColor
      [istrue,cs]=local_iscolorspec(S.BackgroundColor);
      if istrue
         set(D.HAPatch,'FaceColor',cs)
         P.BackgroundColor=cs;
      else
         local_error('Unknown ''BackgroundColor'' Property Value.')
      end
   case 'Border'                                                   % Border
      [istrue,onoff]=local_isonoff(S.Border);
      if istrue && strcmp(onoff,'on')
         set(D.HAPatch,'EdgeColor',P.BorderColor)
         set(D.HTTick,'Visible','on')
         set(D.HRTick,'Visible','on')
         P.RTickVisible='on';
         P.TTickVisibel='on';
      elseif istrue && strcmp(onoff,'off')
         set(D.HAPatch,'EdgeColor','none')
         set(D.HTTick,'Visible','off')
         set(D.HRTick,'Visible','off')
         P.RTickVisible='off';
         P.TTickVisibel='off';
      else
         local_error('Unknown ''Border'' Property Value.')
      end
   case 'BorderColor'                                         % BorderColor
      [istrue,cs]=local_iscolorspec(S.BorderColor);
      if istrue
         P.BorderColor=cs;
         set(D.HAPatch,'EdgeColor',cs)
         set(D.HRTick,'Color',cs)
         set(D.HTTick,'Color',cs)
      else
         local_error('Unknown ''BorderColor'' Property Value.')
      end
   case 'FontName'                                               % FontName
      if ischar(S.FontName) && any(strcmpi(listfonts,S.FontName))
         set([D.HRTickLabel; D.HTTickLabel],'FontName',S.FontName)
         P.FontName=S.FontName;
      else
         local_error('Unknown ''FontName'' Property Value.')
      end
   case 'FontSize'                                               % FontSize
      if isnumeric(S.FontSize) && isscalar(S.FontSize)
         set([D.HRTickLabel; D.HTTickLabel],'FontSize',S.FontSize)
         P.FontSize=S.FontSize;
      else
         local_error('Unknown ''FontSize'' Property Value.')
      end
   case 'FontWeight'                                           % FontWeight
      if ischar(S.FontWeight) && ...
            (strncmpi(S.FontWeight,'normal',3)...
            ||strncmpi(S.FontWeight,'bold',3))
         set([D.HRTickLabel; D.HTTickLabel],'FontWeight',S.FontWeight)
         P.FontWeight=S.FontWeight;
      else
         local_error('Unknown ''FontWeight'' Property Value.')
      end      
   case 'Grid'                                                       % Grid
      [istrue,onoff]=local_isonoff(S.Grid);
      if istrue
         set(D.HRGrid,'Visible',onoff)
         set(D.HTGrid,'Visible',onoff)
         P.Grid=onoff;
         P.RGridVisible=onoff;
         P.TGridVisible=onoff;
      else
         local_error('Unknown ''Grid'' Property Value.')
      end
   case 'RGridColor'                                           % RGridColor
      [istrue,cs]=local_iscolorspec(S.RGridColor);
      if istrue
         set(D.HRGrid,'Color',cs)
         set(D.HRTickLabel,'Color',cs)
         P.RGridColor=cs;
      else
         local_error('Unknown ''RGridColor'' Property Value.')
      end
   case 'RGridLineStyle'                                   % RGridLineStyle
      if local_islinespec(S.RGridLineStyle)
         set(D.HRGrid,'LineStyle',S.RGridLineStyle)
         P.RGridLineStyle=S.RGridLineStyle;
      else
         local_error('Unknown ''RGridLineStyle'' Property Value.')
      end               
   case 'RGridLineWidth'                                   % RGridLineWidth
      if isnumeric(S.RGridLineWidth) && isscalar(S.RGridLineWidth)
         set(D.HRGrid,'LineWidth',S.RGridLineWidth)
         P.RGridLineWidth=S.RGridLineWidth;
      else
         local_error('Unknown ''RGridLineWidth'' Property Value.')
      end
   case 'RGridVisible'                                       % RGridVisible
      [istrue,onoff]=local_isonoff(S.RGridVisible);
      if istrue
         set(D.HRGrid,'Visible',onoff)
         P.RGridVisible=onoff;
      else
         local_error('Unknown ''RGridVisible'' Property Value.')
      end      
   case 'RLimit'                                                   % RLimit
      if isnumeric(S.RLimit) && numel(S.RLimit)==2
         S.RLimit=[min(S.RLimit) max(S.RLimit)];
         S.RLimit(isinf(S.RLimit))=P.RLimit(isinf(S.RLimit));
         [P,D]=local_getRTickValue(HAxes,P,D,S);
         [P,D]=local_placeRGrid(HAxes,P,D,S);
         [P,D]=local_placeRTickLabel(HAxes,P,D,S);
         % rescale rho data to new limits
         for k=1:length(D.RData)
            D.RDataN(k)={(D.RData{k}-D.RMin)/D.RLimitDiff};
            D.RDataN{k}(D.RDataN{k}>1)=NaN; % hide data outside limits
            D.RDataN{k}(D.RDataN{k}<0)=NaN;
            theta=D.TData{k};
            xdata=D.RDataN{k}.*cos(theta);
            ydata=D.RDataN{k}.*sin(theta);
            set(D.HLines(k),'XData',xdata,'YData',ydata)
         end
      else
         local_error('Unknown ''RLimit'' Property Value.')
      end               
   case 'RTickAngle'                                           % RTickAngle
      if isnumeric(S.RTickAngle) && isscalar(S.RTickAngle)
         rad=S.RTickAngle;
         if strcmp(P.TTickScale,'degrees')
            rad=S.RTickAngle*pi/180;
         end
         if P.TLimit(1)>P.TLimit(2) && (rad<P.TLimit(2) || rad>P.TLimit(1))
            P.RTickAngle=S.RTickAngle;
            D.RTickAngle=rad;
         elseif rad>P.TLimit(1) && rad<P.TLimit(2)
            P.RTickAngle=S.RTickAngle;
            D.RTickAngle=rad;            
         else
            local_error('RTickAngle not within Theta Axis Limits.')
         end
         for k=1:D.RTickLabelN % ignore innermost tick
            xdata=(P.RTickOffset+D.RTickRadius(k))*cos(D.RTickAngle);
            ydata=(P.RTickOffset+D.RTickRadius(k))*sin(D.RTickAngle);
            set(D.HRTickLabel(k),'Position',[xdata ydata])
         end
         phi=asin(P.TickLength./(2*D.RTickRadius));
         tdata=[D.RTickAngle-phi; D.RTickAngle+zeros(size(D.RTickRadius))
                D.RTickAngle+phi; NaN(size(D.RTickRadius))];
         rdata=[D.RTickRadius; D.RTickRadius
                D.RTickRadius; NaN(size(D.RTickRadius))];
         xdata=rdata(:).*cos(tdata(:));
         ydata=rdata(:).*sin(tdata(:));
         set(D.HRTick,'XData',xdata,'YData',ydata) % move rho ticks
      else
         local_error('Unknown ''RTickAngle'' Property Value.')
      end
   case 'RTickLabel'                                           % RTickLabel
      if iscellstr(S.RTickLabel)
         NumS=length(S.RTickLabel);
         for k=1:D.RTickLabelN
            str=S.RTickLabel{rem(k-1,NumS)+1};
            set(D.HRTickLabel(k),'String',str)
         end         
         P.RTickLabel=S.RTickLabel;
      else
         local_error('Unknown ''RTickLabel'' Property Value.')
      end
   case 'RTickLabelHalign'                               % RTickLabelHalign
      fnames={'left' 'center' 'right'};
      out=local_isfield(fnames,S.RTickLabelHalign);
      if ~isempty(out)
         P.RTickLabelHalign=out;
         set(D.HRTickLabel,'HorizontalAlignment',out)
      else
         local_error('Unknown ''RTickLabelHalign'' Property Value.')
      end         
   case 'RTickLabelValign'                               % RTickLabelValign
      fnames={'top' 'cap' 'middle' 'baseline' 'bottom'};
      out=local_isfield(fnames,S.RTickLabelValign);
      if ~isempty(out)
         P.RTickLabelValign=out;
         set(D.HRTickLabel,'VerticalAlignment',out)
      else
         local_error('Unknown ''RTickLabelValign'' Property Value.')
      end
   case 'RTickLabelVisible'                             % RTickLabelVisible
      [istrue,onoff]=local_isonoff(S.RTickLabelVisible);
      if istrue
         set(D.HRTickLabel,'Visible',onoff)
         P.RTickLabelVisible=onoff;
      else
         local_error('Unknown ''RTickLabelVisible'' Property Value.')
      end
   case 'RTickOffset'                                         % RTickOffset
      if isnumeric(S.RTickOffset) && isscalar(S.RTickOffset)
         P.RTickOffset=S.RTickOffset;
         for k=1:D.RTickLabelN
            xdata=(P.RTickOffset+D.RTickRadius(k))*cos(D.RTickAngle);
            ydata=(P.RTickOffset+D.RTickRadius(k))*sin(D.RTickAngle);
            set(D.HRTickLabel(k),'Position',[xdata ydata])
         end
      else
          local_error('Unknown ''RTickOffset'' Property Value.')
      end
   case 'RTickUnits'                                           % RTickUnits
      if ischar(S.RTickUnits)
         tmp=char(get(D.HRTickLabel(end),'String'));
         if ~isempty(P.RTickUnits)
            idx=strfind(tmp,P.RTickUnits);
            tmp=[tmp(1:idx(end)-1) S.RTickUnits];
         else
            tmp=[tmp S.RTickUnits]; %#ok
         end
         set(D.HRTickLabel(end),'String',tmp)
         P.RTickUnits=S.RTickUnits;
      else
         local_error('Unknown ''RTickUnits'' Property Value.')
      end
   case 'RTickValue'                                           % RTickValue
      if isnumeric(S.RTickValue) && numel(S.RTickValue)>0
         S.RTickValue=S.RTickValue(S.RTickValue>=P.RLimit(1)...
            & S.RTickValue<=P.RLimit(2));
         if length(S.RTickValue)>1
            P.RTickValue=S.RTickValue;
            D.RTickLabelN=length(P.RTickValue);
            D.RTickRadius=(P.RTickValue-D.RMin)/D.RLimitDiff;
            [P,D]=local_placeRGrid(HAxes,P,D,S);
            [P,D]=local_placeRTickLabel(HAxes,P,D,S);
         end
      else
         local_error('Unknown ''RTickValue'' Property Value.')
      end
   case 'RTickVisible'                                       % RTickVisible
      [istrue,onoff]=local_isonoff(S.RTickVisible);
      if istrue
         set(D.HRTick,'Visible',onoff)
         P.RTickVisible=onoff;
      else
         local_error('Unknown ''RTickVisible'' Property Value.')
      end
   case 'Style'                                                     % Style
      if strncmpi(S.Style,'cartesian',3)   % Cartesian style
         set(HAxes,'View',[0 90])
         P.TDirection='ccw';
         P.TZeroDirection='east';
         P.Style='cartesian';
      elseif strncmpi(S.Style,'compass',3) % Compass style
         set(HAxes,'View',[90 -90])
         P.TDirection='cw';
         P.TZeroDirection='north';
         P.Style='compass';
      else
         local_error('Unknown ''Style'' Property Value.')
      end
   case 'TDirection'                                           % TDirection
      if ischar(S.TDirection) && strcmpi(S.TDirection,'cw')
         P.TDirection='cw';
         if strcmp(P.TZeroDirection,'north')
            set(HAxes,'View',[90 -90])
         elseif strcmp(P.TZeroDirection,'east')
            set(HAxes,'View',[0 -90])
         elseif strcmp(P.TZeroDirection,'south')
            set(HAxes,'View',[270 -90])
         elseif strcmp(P.TZeroDirection,'west')
            set(HAxes,'View',[180 -90])
         end
      elseif ischar(S.TDirection) && strcmpi(S.TDirection,'ccw')
         P.TDirection='ccw';
         if strcmp(P.TZeroDirection,'north')
            set(HAxes,'View',[270 90])
         elseif strcmp(P.TZeroDirection,'east')
            set(HAxes,'View',[0 90])
         elseif strcmp(P.TZeroDirection,'south')
            set(HAxes,'View',[90 90])
         elseif strcmp(P.TZeroDirection,'west')
            set(HAxes,'View',[180 90])
         end
      else
         local_error('Unknown ''TDirection'' Property Value.')
      end
      P.Style='unknown';
   case 'TGridColor'                                           % TGridColor
      [istrue,cs]=local_iscolorspec(S.TGridColor);
      if istrue
         set(D.HTGrid,'Color',cs)
         set(D.HTTickLabel,'Color',cs)
         P.TGridColor=cs;
      else
         local_error('Unknown ''TGridColor'' Property Value.')
      end
   case 'TGridLineStyle'                                   % TGridLineStyle
      if local_islinespec(S.TGridLineStyle)
         set(D.HTGrid,'LineStyle',S.TGridLineStyle)
         P.TGridLineStyle=S.TGridLineStyle;
      else
         local_error('Unknown ''TGridLineStyle'' Property Value.')
      end
   case 'TGridLineWidth'                                   % TGridLineWidth
      if isnumeric(S.TGridLineWidth) && isscalar(S.TGridLineWidth)
         set(D.HTGrid,'LineWidth',S.TGridLineWidth)
         P.TGridLineWidth=S.TGridLineWidth;
      else
         local_error('Unknown ''TGridLineWidth'' Property Value.')
      end
   case 'TGridVisible'                                       % TGridVisible
      [istrue,onoff]=local_isonoff(S.TGridVisible);
      if istrue
         set(D.HTGrid,'Visible',onoff)
         P.TGridVisible=onoff;
      else
         local_error('Unknown ''TGridVisible'' Property Value.')
      end      
   case 'TickLength'                                           % TickLength
      if isnumeric(S.TickLength) && isscalar(S.TickLength)
         P.TickLength=max(min(abs(S.TickLength),0.1),.001);
         tdir=2*strcmp(P.TTickDirection,'in')-1;
         tdata=[D.TTickValue;D.TTickValue;NaN(1,D.TTickLabelN)];
         rdata=[ones(1,D.TTickLabelN)
                (1-tdir*P.TickLength)+zeros(1,D.TTickLabelN)
                NaN(1,D.TTickLabelN)];
         xdata=rdata(:).*cos(tdata(:));
         ydata=rdata(:).*sin(tdata(:));
         set(D.HTTick,'XData',xdata,'YData',ydata) % theta ticks
         phi=asin(P.TickLength./(2*D.RTickRadius));
         tdata=[D.RTickAngle-phi; D.RTickAngle+zeros(size(D.RTickRadius))
                D.RTickAngle+phi; NaN(size(D.RTickRadius))];
         rdata=[D.RTickRadius; D.RTickRadius
                D.RTickRadius; NaN(size(D.RTickRadius))];
         xdata=rdata(:).*cos(tdata(:));
         ydata=rdata(:).*sin(tdata(:));
         set(D.HRTick,'XData',xdata,'YData',ydata) % rho ticks
      else
         local_error('Unknown ''TickLength'' Property Value.')
      end
   case 'TLimit'                                                   % TLimit
      if isnumeric(S.TLimit) && numel(S.TLimit)==2
         if abs(diff(S.TLimit))>1.9*pi   % make full circle if close
            P.TLimit=[0 2*pi];
         else
            P.TLimit=mod(S.TLimit,2*pi); % move limits to range 0 to 2pi
         end
         [P,D]=local_getTTickValue(P,D,S);
         [P,D]=local_placeAxesPatch(HAxes,P,D,S);
         [P,D]=local_placeRGrid(HAxes,P,D,S);
         [P,D]=local_placeTGrid(HAxes,P,D,S);
         [P,D]=local_placeTTickLabel(HAxes,P,D,S);
         [P,D]=local_placeRTickLabel(HAxes,P,D,S);
         for k=1:length(D.TData) % hide data outside TLimits
            tdata=D.TData{k};
            if P.TLimit(1)>P.TLimit(2)
               tdata(tdata<P.TLimit(1) & tdata>P.TLimit(2))=NaN;
            else            
               tdata(tdata<P.TLimit(1) | tdata>P.TLimit(2))=NaN;
            end
            xdata=D.RDataN{k}.*cos(tdata);
            ydata=D.RDataN{k}.*sin(tdata);
            set(D.HLines(k),'XData',xdata,'YData',ydata)
         end
      else
         local_error('Unknown ''TLimit'' Property Value.')
      end
   case 'TTickDelta'                                           % TTickDelta
      if isnumeric(S.TTickDelta) && isscalar(S.TTickDelta)
         if strcmp(P.TTickScale,'degrees')
            P.TTickDelta=min(max(abs(S.TTickDelta),5),90);
         else
            P.TTickDelta=min(max(abs(S.TTickDelta),pi/36),pi/2);
         end
         [P,D]=local_getTTickValue(P,D,S);
         [P,D]=local_placeTGrid(HAxes,P,D,S);
         [P,D]=local_placeTTickLabel(HAxes,P,D,S);
      else
         local_error('Unknown ''TTickDelta'' Property Value.')
      end
   case 'TTickDirection'                                   % TTickDirection
      if ischar(S.TTickDirection) &&...
        (strcmpi(S.TTickDirection,'out') || strcmpi(S.TTickDirection,'in'))
         P.TTickDirection=S.TTickDirection;
         tdir=2*strcmp(P.TTickDirection,'in')-1;
         tdata=[D.TTickValue;D.TTickValue;NaN(1,D.TTickLabelN)];
         rdata=[ones(1,D.TTickLabelN)
                (1-tdir*P.TickLength)+zeros(1,D.TTickLabelN)
                NaN(1,D.TTickLabelN)];
         xdata=rdata(:).*cos(tdata(:));
         ydata=rdata(:).*sin(tdata(:));
         set(D.HTTick,'XData',xdata,'YData',ydata) % theta ticks
      else
         local_error('Unknown ''TTickDirection'' Property Value.')
      end
   case 'TTickLabel'                                           % TTickLabel
      if iscellstr(S.TTickLabel)
         NumS=length(S.TTickLabel);
         for k=1:D.TTickLabelN
            str=S.TTickLabel{rem(k-1,NumS)+1};
            set(D.HTTickLabel(k),'String',str)
         end         
         P.TTickLabel=S.TTickLabel;
      else
         local_error('Unknown ''TTickLabel'' Property Value.')
      end
   case 'TTickLabelVisible'                             % TTickLabelVisible
      [istrue,onoff]=local_isonoff(S.TTickLabelVisible);
      if istrue
         set(D.HTTickLabel,'Visible',onoff)
         P.TTickLabelVisible=onoff;
      else
         local_error('Unknown ''TTickLabelVisible'' Property Value.')
      end
   case 'TTickOffset'                                         % TTickOffset
      if isnumeric(S.TTickOffset) && isscalar(S.TTickOffset)
         P.TTickOffset=S.TTickOffset;
         for k=1:D.TTickLabelN
            xdata=(1+P.TTickOffset)*cos(D.TTickValue(k));
            ydata=(1+P.TTickOffset)*sin(D.TTickValue(k));
            set(D.HTTickLabel(k),'Position',[xdata ydata])
         end
      else
         local_error('Unknown ''TTickOffset'' Property Value.')
      end
   case 'TTickScale'                                           % TTickScale
      if ischar(S.TTickScale) && strncmpi(S.TTickScale,'degrees',3)...
                              && strcmp(P.TTickScale,'radians')
         P.TTickScale='degrees';
         P.TTickDelta=P.TTickDelta*180/pi;
         P.RTickAngle=P.RTickAngle*180/pi;
         [P,D]=local_getTTickValue(P,D,S);
         [P,D]=local_placeTTickLabel(HAxes,P,D,S);
      elseif ischar(S.TTickScale) && strncmpi(S.TTickScale,'radians',3)...
                                  && strcmp(P.TTickScale,'degrees')
         P.TTickScale='radians';
         P.TTickDelta=P.TTickDelta*pi/180;
         P.RTickAngle=P.RTickAngle*pi/180;
         [P,D]=local_getTTickValue(P,D,S);
         [P,D]=local_placeTTickLabel(HAxes,P,D,S);
      elseif ~ischar(S.TTickScale)
         local_error('Unknown ''TTickScale'' Property Value.')
      end
   case 'TTickSign'                                             % TTickSign
      if ischar(S.TTickSign)
         if strcmp(S.TTickSign,'+')
            P.TTickSign='+';
         else
            P.TTickSign='+-';
         end
         [P,D]=local_getTTickValue(P,D,S);
         [P,D]=local_placeTTickLabel(HAxes,P,D,S);
      else
         local_error('Unknown ''TTickSign'' Property Value.')
      end
   case 'TTickValue'                                           % TTickValue
      if isnumeric(S.TTickValue) && numel(S.TTickValue)>0
         TTick=S.TTickValue(:)';
         if strcmp(P.TTickScale,'degrees')
            TTick=TTick*pi/180;
         end
         if P.TLimit(1)>P.TLimit(2)
            idx=TTick<=P.TLimit(2) | TTick>=P.TLimit(1); % keepers
         else
            idx=TTick>=P.TLimit(1) & TTick<=P.TLimit(2); % keepers
         end
         S.TTickValue=S.TTickValue(idx);
         if length(S.TTickValue)>1
            P.TTickValue=S.TTickValue(:)';
            D.TTickValue=TTick(idx);
            D.TTickLabelN=length(P.TTickValue);
            [P,D]=local_placeTGrid(HAxes,P,D,S);
            [P,D]=local_placeTTickLabel(HAxes,P,D,S);
         end
      else
         local_error('Unknown ''TTickValue'' Property Value.')
      end
   case 'TTickVisible'                                       % TTickVisible
      [istrue,onoff]=local_isonoff(S.TTickVisible);
      if istrue
         set(D.HTTick,'Visible',onoff)
         P.TTickVisible=onoff;
      else
         local_error('Unknown ''RTickVisible'' Property Value.')
      end
   case 'TZeroDirection'                                   % TZeroDirection
      if ischar(S.TZeroDirection) && strncmpi(S.TZeroDirection,'north',1)
         P.TZeroDirection='north';
         if strcmp(P.TDirection,'ccw')
            set(HAxes,'View',[270 90])
         elseif strcmp(P.TDirection,'cw')
            set(HAxes,'View',[90 -90])
         end
      elseif ischar(S.TZeroDirection) && strncmpi(S.TZeroDirection,'east',1)
         P.TZeroDirection='east';
         if strcmp(P.TDirection,'ccw')
            set(HAxes,'View',[0 90])
         elseif strcmp(P.TDirection,'cw')
            set(HAxes,'View',[0 -90])
         end
      elseif ischar(S.TZeroDirection) && strncmpi(S.TZeroDirection,'south',1)
         P.TZeroDirection='south';
         if strcmp(P.TDirection,'ccw')
            set(HAxes,'View',[90 90])
         elseif strcmp(P.TDirection,'cw')
            set(HAxes,'View',[270 -90])
         end
      elseif ischar(S.TZeroDirection) && strncmpi(S.TZeroDirection,'west',1)
         P.TZeroDirection='west';
         if strcmp(P.TDirection,'ccw')
            set(HAxes,'View',[180 90])
         elseif strcmp(P.TDirection,'cw')
            set(HAxes,'View',[180 -90])
         end
      else
         local_error('Unknown ''TZeroDirection'' Property Value.')
      end
      P.Style='unknown';
   end
end
setappdata(HAxes,'MMPOLAR_Properties',P)
setappdata(HAxes,'MMPOLAR_Data',D)
%--------------------------------------------------------------------------
%--------------------------------------------------------------------------
function [out,errmsg]=local_isfield(fnames,str)             % local_isfield
% compare str to fnames, if found, return complete fieldname
% otherwise return error and empty string.
% fnames is cell array, str is a string
% outputs are strings

% look for exact match first
idx=find(strcmpi(fnames,str));

if isempty(idx) % no exact match, so look for more general match
   idx=find(strncmpi(str,fnames,max(length(str),2)));
end
if numel(idx)==1 % unique match found
   out=fnames{idx};
   errmsg='';
else             % trouble
   out='';
   errmsg=sprintf('Unknown or Not Unique Property: %s',str);
end
%--------------------------------------------------------------------------
function [istrue,cs]=local_iscolorspec(arg)             % local_iscolorspec
% see if arg is a valid color specification including 'none'
rgb={[1 0 0],[0 1 0],[0 0 1],[0 1 1],[1 0 1],[1 1 0],[0 0 0],[1 1 1],'none'};
cc='rgbcmykwn';
istrue=false;
cs=[];
if ~isempty(arg) && ischar(arg)
   idx=find(arg(1)==cc);
   if ~isempty(idx)
      istrue=true;
      cs=rgb{idx};
   end 
elseif ~isempty(arg) && isnumeric(arg)
   istrue=all(size(arg)==[1 3])...
      && all(arg>=0) && all(arg<=1);
   cs=arg;
else
   istrue=false;
end
%--------------------------------------------------------------------------
function istrue=local_islinespec(arg)                    % local_islinespec
% see if arg is a valid line style specification
str={'-','-.','--',':'};
if isempty(arg)
   istrue=false;
elseif ischar(arg) && length(arg)<3
   istrue=any(strncmp(str,arg,length(arg)));
else
   istrue=false;
end
%--------------------------------------------------------------------------
function [istrue,s]=local_isonoff(arg)                      % local_isonoff
% see if arg is either on or off
istrue=false;
s='';
if ~isempty(arg) && ischar(arg) && strcmpi(arg,'on')
   istrue=true;
   s='on';
elseif ~isempty(arg) && ischar(arg) && strcmpi(arg,'off')
   istrue=true;
   s='off';
end
%--------------------------------------------------------------------------
function local_error(arg)  
% Add message identifier to error message and post error
if ~isempty(arg) && ischar(arg)
   error('MMPOLAR:error',arg)
end
%--------------------------------------------------------------------------
function [P,D]=local_placeAxesPatch(HAxes,P,D,S)  %#ok local_placeAxesPatch
% Draw Axes Border and Patch
tinc=pi/250;
if P.TLimit(1)>P.TLimit(2)
   theta=[P.TLimit(1):tinc:(P.TLimit(2)+2*pi-eps) P.TLimit(2)+2*pi];
else
   theta=[P.TLimit(1):tinc:P.TLimit(2)-eps P.TLimit(2)];
end   
costheta=cos(theta);
sintheta=sin(theta);
if abs(diff(P.TLimit))<2*(1-eps)*pi; % less than 4 quadrant box
   xdata=[0 costheta 0];
   ydata=[0 sintheta 0];
else % four quadrant box
   xdata=costheta;
   ydata=sintheta;
end
% let the axes grow for less than 4 quadrant box
set(HAxes,'Xlim',[min(xdata) max(xdata)],'Ylim',[min(ydata) max(ydata)])
if nargin==3 % new plot
   D.HAPatch=patch('XData',xdata,'YData',ydata,...
      'Parent',HAxes,...
      'LineStyle','-',...
      'Linewidth',2*P.RGridLineWidth,...
      'EdgeColor',P.BorderColor,...
      'FaceColor',P.BackgroundColor,...
      'HandleVisibility','off',...
      'HitTest','off');
else % old plot, update data
   set(D.HAPatch,'XData',xdata,'YData',ydata)
end
%--------------------------------------------------------------------------
function [P,D]=local_placeRGrid(HAxes,P,D,S)          %#ok local_placeRGrid
tinc=pi/250;
if P.TLimit(1)>P.TLimit(2)
   theta=[P.TLimit(1):tinc:(P.TLimit(2)+2*pi-eps) P.TLimit(2)+2*pi];
else
   theta=[P.TLimit(1):tinc:P.TLimit(2)-eps P.TLimit(2)];
end   
costheta=cos(theta);
sintheta=sin(theta);
xdata=[];
ydata=[];
% no outer grid if outer tick is at outer RLimit
D.RGridN=length(P.RTickValue(P.RTickValue<P.RLimit(2)));
for k=1:D.RGridN
   xdata=[xdata D.RTickRadius(k)*costheta NaN];  %#ok
   ydata=[ydata D.RTickRadius(k)*sintheta NaN];  %#ok
end
if nargin<4 % new grid
   D.HRGrid=line(xdata,ydata,...
      'Parent',HAxes,...
      'LineStyle',P.RGridLineStyle,...
      'LineWidth',P.RGridLineWidth,...
      'Color',P.RGridColor,...
      'HandleVisibility','off',...
      'HitTest','off');
else
   set(D.HRGrid,'Xdata',xdata,'YData',ydata)
end
% Draw Rho Axis Tick Marks
phi=asin(P.TickLength./(2*D.RTickRadius));
tdata=[D.RTickAngle-phi; D.RTickAngle+zeros(size(D.RTickRadius))
       D.RTickAngle+phi; NaN(size(D.RTickRadius))];
rdata=[D.RTickRadius; D.RTickRadius
       D.RTickRadius; NaN(size(D.RTickRadius))];
xdata=rdata(:).*cos(tdata(:));
ydata=rdata(:).*sin(tdata(:));
if nargin==3 % new plot
   D.HRTick=line(xdata,ydata,...
      'Parent',HAxes,...
      'LineStyle','-',...
      'LineWidth',2*P.RGridLineWidth,...
      'Color',P.BorderColor,...
      'HandleVisibility','off',...
      'HitTest','off');
else % old plot, update data
   set(D.HRTick,'XData',xdata,'YData',ydata)
end
%--------------------------------------------------------------------------
function [P,D]=local_placeRTickLabel(HAxes,P,D,S)%#ok local_placeRTickLabel
% Draw Rho Tick Labels
D.RScale=floor(log10(max(abs(P.RTickValue))));
if abs(D.RScale)<2
   D.RScale=0;
end
P.RTickLabel=cell(D.RTickLabelN,1);
if nargin==4 % delete old labels and create new ones
   delete(D.HRTickLabel)
end
D.HRTickLabel=zeros(D.RTickLabelN,1);
for k=1:D.RTickLabelN
   xdata=(P.RTickOffset+D.RTickRadius(k))*cos(D.RTickAngle);
   ydata=(P.RTickOffset+D.RTickRadius(k))*sin(D.RTickAngle);
   P.RTickLabel{k}=num2str(P.RTickValue(k)*10^(-D.RScale));
   if (k==D.RTickLabelN) && (D.RScale~=0)
      P.RTickLabel{k}=[P.RTickLabel{k} sprintf('\\times10^{%d}',D.RScale)];
   end
   D.HRTickLabel(k)=text(xdata,ydata,P.RTickLabel{k},...
      'Parent',HAxes,...
      'Color',P.TGridColor,...
      'FontName',P.FontName,...
      'FontSize',P.FontSize,...
      'FontWeight',P.FontWeight',...
      'HorizontalAlignment',P.RTickLabelHalign,...
      'VerticalAlignment',P.RTickLabelValign,...
      'Clipping','off',...
      'HandleVisibility','off',...
      'HitTest','off');
end
%--------------------------------------------------------------------------
function [P,D]=local_getRTickValue(HAxes,P,D,S)       % local_getRTickValue
% get RTicks
if nargin==4 % updating current ticks given new rho axis limits
   tmpaxes=axes('Position',get(HAxes,'Position'));
   line([0 1],S.RLimit,'Parent',tmpaxes);
   P.RTickValue=get(tmpaxes,'YTick');
   P.RLimit=S.RLimit;
   delete(tmpaxes) % got ticks, don't need axes anymore
end
%P.RTickValue(end)=P.RLimit(2); % place last tick at outer rho limit
NumRTick=length(P.RTickValue); % reduce ticks if too many
if NumRTick>6
   if rem(NumRTick,2)~=0  % odd number keep alternate ones
      P.RTickValue=P.RTickValue(1:2:end);
   else % even number, add one tick, then keep alternate ones
      if P.RTickValue(1)==0	% keep lowest tick if zero, add one at outside
         P.RTickValue=[P.RTickValue(1:2:end-1) ...
                        2*P.RTickValue(end)-P.RTickValue(end-1)];
         P.RTickValue(P.RTickValue>P.RLimit(2))=[]; % no label past limit
      else                    % add one tick at inside
         P.RTickValue=[2*P.RTickValue(1)-P.RTickValue(2)...
                        P.RTickValue(2:2:end)];
      end
      P.RLimit(1)=P.RTickValue(1); % make first tick lower axis limit
   end
end
if NumRTick<3
   m=sum(P.RTickValue)/2;
   P.RTickValue(3)=P.RTickValue(2);
   P.RTickValue(2)=m;
end
D.RLimitDiff=diff(P.RLimit);
D.RMin=P.RLimit(1);
if abs(P.RTickValue(1)-P.RLimit(1)) < abs(D.RLimitDiff)/100
   P.RTickValue(1)=[]; % throw out inner tick if at inner axis limit
end
D.RTickRadius=(P.RTickValue-D.RMin)/D.RLimitDiff;
D.RTickLabelN=length(P.RTickValue);
%--------------------------------------------------------------------------
function [P,D]=local_placeTGrid(HAxes,P,D,S)          %#ok local_placeTGrid
xdata=[];
ydata=[];
costheta=cos(D.TTickValue);
sintheta=sin(D.TTickValue);
% no grid on first or last ticks are axis limits if less than 4 quadrants
ki=1;
ke=length(D.TTickValue);
if abs(diff(P.TLimit))<2*(1-eps)*pi; % less than 4 quadrant box
   ki=1+(D.TTickValue(1)==P.TLimit(1));
   ke=length(D.TTickValue)-(D.TTickValue(end)==P.TLimit(2));
end
D.TGridN=ke-ki+1;
for k=ki:ke
   xdata=[xdata 0 costheta(k) NaN];  %#ok
   ydata=[ydata 0 sintheta(k) NaN];  %#ok
end
if nargin<4 % new grid
   D.HTGrid=line(xdata,ydata,...
      'Parent',HAxes,...
      'LineStyle',P.TGridLineStyle,...
      'LineWidth',P.TGridLineWidth,...
      'Color',P.TGridColor,...
      'HandleVisibility','off',...
      'HitTest','off');
else
   set(D.HTGrid,'Xdata',xdata,'YData',ydata)
end
% Draw Theta Axis Tick Marks
tdir=2*strcmp(P.TTickDirection,'in')-1;
tdata=[D.TTickValue; D.TTickValue; NaN(1,D.TTickLabelN)];
rdata=[ones(1,D.TTickLabelN)
       (1-tdir*P.TickLength)+zeros(1,D.TTickLabelN)
       NaN(1,D.TTickLabelN)];
xdata=rdata(:).*cos(tdata(:));
ydata=rdata(:).*sin(tdata(:));
if nargin==3 % new plot
   D.HTTick=line(xdata,ydata,...
      'Parent',HAxes,...
      'LineStyle','-',...
      'LineWidth',2*P.RGridLineWidth,...
      'Color',P.BorderColor,...
      'Clipping','off',...
      'HandleVisibility','off',...
      'HitTest','off');
else % old plot, update data
   set(D.HTTick,'XData',xdata,'YData',ydata)
end
%--------------------------------------------------------------------------
function [P,D]=local_placeTTickLabel(HAxes,P,D,S)%#ok local_placeTTickLabel
% Draw Theta Ticks
if nargin==4 % delete old labels and create new ones
   delete(D.HTTickLabel)
end
P.TTickLabel=cell(D.TTickLabelN,1);
D.HTTickLabel=zeros(D.TTickLabelN,1);
for k=1:D.TTickLabelN % label ticks at theta axis limits
   xdata=(1+P.TTickOffset)*cos(D.TTickValue(k));
   ydata=(1+P.TTickOffset)*sin(D.TTickValue(k));
   if strcmp(P.TTickScale,'radians')
      [n,d]=rat(P.TTickValue(k)/pi); % ticks as fractions
      if n==0
         Tstr='0';
      elseif n==1 && d==1
         Tstr='\pi';
      elseif n==-1 && d==1
         Tstr='-\pi';
      elseif n==1
         Tstr=['\pi/' num2str(d)];
      elseif n==-1
         Tstr=['-\pi/' num2str(d)];
      elseif d==1
         Tstr=[num2str(n) '\pi'];
      else
         Tstr=[num2str(n) '\pi/' num2str(d)];
      end
      P.TTickLabel{k}=Tstr;
   else % degrees
      P.TTickLabel{k}=[num2str(P.TTickValue(k)) '\circ'];
      if P.TTickValue(k)==-180
         P.TTickLabel{k}=['\pm' P.TTickLabel{k}(2:end)];
      end
   end
   D.HTTickLabel(k)=text(xdata,ydata,P.TTickLabel{k},...
      'Parent',HAxes,...
      'Color',P.TGridColor,...
      'FontName',P.FontName,...
      'FontSize',P.FontSize,...
      'FontWeight',P.FontWeight',...
      'HorizontalAlignment','center',...
      'VerticalAlignment','middle',...
      'Clipping','off',...
      'HandleVisibility','off',...
      'HitTest','off');
end
%--------------------------------------------------------------------------
function [P,D]=local_getTTickValue(P,D,S)          %#ok local_getTTickValue
% Get Theta Ticks
if strcmp(P.TTickScale,'degrees') % ticks are in degrees
   TTick=0:P.TTickDelta:360; % possible ticks
   if P.TLimit(1)>P.TLimit(2)
      idx=TTick<=P.TLimit(2)*180/pi | TTick>=P.TLimit(1)*180/pi; % keepers
   else
      idx=TTick>=P.TLimit(1)*180/pi & TTick<=P.TLimit(2)*180/pi; % keepers
   end
   P.TTickValue=TTick(idx);
   P.TTickValue=unique(rem(P.TTickValue,360)); % get unique ticks
   D.TTickValue=P.TTickValue*pi/180; % store ticks in radians
   if strcmp(P.TTickSign,'+-')
      tmp=P.TTickValue>=180;
      P.TTickValue(tmp)=P.TTickValue(tmp)-360;
   end
else                          % ticks are in radians
   TTick=(0:P.TTickDelta*180/pi:360)*pi/180; % possible ticks
   if P.TLimit(1)>P.TLimit(2)
      idx=TTick<=P.TLimit(2) | TTick>=P.TLimit(1); % keepers
   else
      idx=TTick>=P.TLimit(1) & TTick<=P.TLimit(2); % keepers
   end
   P.TTickValue=TTick(idx);
   P.TTickValue=unique(rem(P.TTickValue,2*pi)); % get unique ticks
   D.TTickValue=P.TTickValue; % store ticks in radians for plotting
   if strcmp(P.TTickSign,'+-')
      tmp=P.TTickValue>=pi;
      P.TTickValue(tmp)=P.TTickValue(tmp)-2*pi;
   end
end
D.TTickLabelN=length(D.TTickValue);
kmid=max(1,floor(length(P.TTickValue)/2));
P.RTickAngle=(D.TTickValue(kmid)+D.TTickValue(kmid+1))/2;
D.RTickAngle=P.RTickAngle;
if strcmp(P.TTickScale,'degrees')
   P.RTickAngle=P.RTickAngle*180/pi;
end
%--------------------------------------------------------------------------
function out=local_getDefaults                          % local_getDefaults
out.Style='cartesian';
out.Axis='on';
out.Border='on';
out.Grid='on';
out.RLimit=[0 1];
out.TLimit=[0 2*pi];
out.RTickUnits='';
out.TTickScale='degrees';
out.TDirection='ccw';
out.TZeroDirection='east';

out.BackgroundColor=get(0,'defaultaxescolor');
out.BorderColor=[0 0 0];
out.FontName=get(0,'defaultaxesfontname');
out.FontSize=get(0,'defaultaxesfontsize');
out.FontWeight=get(0,'defaultaxesfontweight');
out.TickLength=0.02;

out.RGridColor=get(0,'defaultaxesycolor');
out.RGridLineStyle=get(0,'defaultaxesgridlinestyle');
out.RGridLineWidth=get(0,'defaultaxeslinewidth');
out.RGridVisible='on';
out.RTickAngle=0;
out.RTickOffset=0.04;
out.RTickLabel='0|0.5|1.0';
out.RTickLabelHalign='center';
out.RTickLabelValign='middle';
out.RTickLabelVisible='on';
out.RTickValue=[0 .5 1];
out.RTickVisible='on';

out.TGridColor=get(0,'defaultaxesxcolor');
out.TGridVisible='on';
out.TGridLineStyle=get(0,'defaultaxesgridlinestyle');
out.TGridLineWidth=get(0,'defaultaxeslinewidth');
out.TTickOffset=0.08;
out.TTickDelta=15;
out.TTickDirection='in';
out.TTickLabel='';
out.TTickLabelVisible='on';
out.TTickSign='+-';
out.TTickValue=0:15:359;
out.TTickVisible='on';
%--------------------------------------------------------------------------
% Description of Plot Data Stored           Description of Plot Data Stored
%--------------------------------------------------------------------------
%
% VARIABLE        TYPE        DESCRIPTION
% D.TData         Cell        Raw input theta data
% D.RData         Cell        Raw input rho data
% D.RDataN        Cell        Normalized rho data
% D.LineColor     Cell        Line colors of plotted data
% D.LineStyle     Cell        Line styles of plotted data
% D.Marker        Cell        Markers of plotted data
% D.RLimitDiff    Double      Rho axis limit difference
% D.RMin          Double      Rho axis minimum
% D.RScale        Double      Power of ten scaling rho axis ticks
% D.RTickAngle    Double      Angle of rho tick labels in radians
% D.RTickRadius   Double      Radial position of rho tick labels
% D.RGridN        Double      Number of rho axis grid lines
% D.RTickLabelN   Double      Number of rho axis tick labels
% D.TGridN        Double      Number of theta axis grid lines      
% D.TTickLabelN   Double      Number of theta axis tick labels
% D.TTickValue    Double      Theta tick values in RADIANS
%--------------------------------------------------------------------------
% Description of Stored Handles               Description of Stored Handles
%--------------------------------------------------------------------------
%
% HANDLE          TYPE        DESCRIPTION
% D.HAPatch       Patch       Axis background and border
% D.HTTick        Line        Theta tick marks
% D.HRTick        Line        Rho tick marks
% D.HRGrid        Line        Rho grid
% D.HTTickLabel   Text        Theta Tick Labels
% D.HRTIckLabel   Text        Rho Tick Labels
% D.HLines        Line        Plotted Data
%
%--------------------------------------------------------------------------

Contact us