Skip to content

Commit

Permalink
Initial commit of clabel_along an improved clabel for MATLAB
Browse files Browse the repository at this point in the history
clabel_along( C, X, Y ) labels all contours in C, placing labels
at the intersections between the contours and the curve in X, Y.
Labels are rotated to align with the contour.
  • Loading branch information
ramcdona committed Mar 25, 2021
1 parent bf1e0dd commit 450f7c7
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 0 deletions.
51 changes: 51 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# MATLAB contour labels along a curve

The placement of contour labels by MATLAB's `clabel` can be very
frustrating. Some control can be gained with `'LabelSpacing'`, but
`clabel` still has a mind of its own. The user can take full control
with `'manual'` mode, but that doesn't work well in terms of
automation and consistency.

This tool, `clabel_along`, allows the user to specify a curve along
which to place the contour labels.

![Example clabel_along result](example.png)

## Example Use

[c, h] = contour( peaks );
clabel_along( c, [1 37], [40 1] );
clabel_along( c, [25 25], [37.5 30] );
clabel_along( c, [27.5 27.5], [27 25] );

## Documentation

H = clabel_along( C, X, Y ) labels all contours in C, placing labels
at the intersections between the contours and the curve in X, Y.
Labels are rotated to align with the contour.

H = clabel_along( C, X, Y, V ) as above, but only labels the contours
with levels contained in vector V. If V is empty (default), then all
contours are labeled.

H = clabel_along( C, X, Y, V, ROTATE ) as above, but ROTATE is a
boolean flag to enable label rotation. If ROTATE is TRUE (default),
then the labels are rotated. The rotation angle is based on the slope
of the contour at the intersection point and is corrected for the
aspect ratio of the data and the plot.

If the data or plot aspect ratios change significantly after the call
to clabel_along, the labels may not look properly aligned.

The graphics handles for all of the labels are returned in H.

## Dependencies

`clabel_along` requires Douglas Schwarz's
[intersections](https://www.mathworks.com/matlabcentral/fileexchange/11837)
routine to calculate the intersectinos between the curve and the contours.

## License

This software is Copyright (c) Rob McDonald 2021 and is released under the terms specified in the [license](license.txt).

120 changes: 120 additions & 0 deletions clabel_along.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
function h = clabel_along( c, x, y, varargin )
%CLABEL_ALONG Label contours along a curve
% H = CLABEL_ALONG( C, X, Y ) labels all contours in C, placing labels
% at the intersections between the contours and the curve in X, Y.
% Labels are rotated to align with the contour.
%
% H = CLABEL_ALONG( C, X, Y, V ) as above, but only labels the contours
% with levels contained in vector V. If V is empty (default), then all
% contours are labeled.
%
% H = CLABEL_ALONG( C, X, Y, V, ROTATE ) as above, but ROTATE is a
% boolean flag to enable label rotation. If ROTATE is TRUE (default),
% then the labels are rotated. The rotation angle is based on the slope
% of the contour at the intersection point and is corrected for the
% aspect ratio of the data and the plot.
%
% If the data or plot aspect ratios change significantly after the call
% to CLABEL_ALONG, the labels may not look properly aligned.
%
% The graphics handles for all of the labels are returned in H.
%
% CLABEL_ALONG requires Douglas Schwarz's INTERSECTIONS routine to
% calculate the intersectinos between the curve and the contours. It is
% available from the Matlab File Exchange
% https://www.mathworks.com/matlabcentral/fileexchange/11837
%
% Example:
% [c, h] = contour( peaks );
% CLABEL_ALONG( c, [1 37], [40 1] );
% CLABEL_ALONG( c, [25 25], [37.5 30] );
% CLABEL_ALONG( c, [27.5 27.5], [27 25] );
%
% See also CONTOUR, CONTOURF, CONTOURC, CLABEL, INTERSECTIONS, DASPECT, PBASPECT.

% Rob McDonald
% [email protected]
% 25 March 2021 v. 1.0 -- Original version.

if ( ~exist( 'intersections', 'file' ) )
error( 'clabel_along:intersections_not_found',...
'clabel_along could not find intersections.\nIt is available from the MATLAB file exchange:\nhttps://www.mathworks.com/matlabcentral/fileexchange/11837' );
end

% Handle values of contours to label. Empty for all (default).
if ( nargin < 4 )
v = [];
else
v = varargin{1};
end

% Handle rotation disabling flag. True to rotate (default).
if ( nargin < 5 )
rotate = true;
else
rotate = varargin{2};
end

% Grab aspect ratios to correct rotation
% Data aspect ratio
da = daspect();
ard = da(2) / da(1);
% Plot aspect ratio
pa = pbaspect();
arp = pa(2) / pa(1);

% Initialize handle array
h = [];

% Loop over contours in c array
nlimit = size( c , 2 );
icont = 1;
while( icont < nlimit )

% Pull out contour level and number of points in this contour line
level = c( 1, icont );
n = c( 2, icont );

% Only proceed for empty v (all) or contour in v
if ( isempty( v ) || any( level == v ) )

% Pick off contour points
xc = c( 1, icont+1:icont+n );
yc = c( 2, icont+1:icont+n );

% Calculate the intersection points between the contours and the
% guide curve using Douglas Schwarz's routine
% https://www.mathworks.com/matlabcentral/fileexchange/11837
[ xint, yint, iout ] = intersections( xc, yc, x, y );

% Loop over all intersections
nint = length( xint );
for iint = 1:nint
th = 0;
if ( rotate )
% Calculate text rotation angle based on curve slope and
% plot and data aspect ratios.
iprev = floor( iout( iint ) );
if ( iprev == length(xc) )
iprev = iprev - 1;
end
inext = iprev + 1;

% Calculate aspect ratio adjusted slope
dx = ( xc( inext ) - xc( iprev ) );
dy = ( yc( inext ) - yc( iprev ) ) * ard * arp;

% Calculate angle
th = atan( dy / dx ) * 180.0 / pi;
end

hh = text( xint(iint), yint(iint), num2str( level ), 'rotation', th, 'HorizontalAlignment', 'center', 'VerticalAlignment', 'middle' );

% Append text handle
h = [h hh];
end
end

% Increment to next contour line
icont = icont + n + 1;
end
Binary file added example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 450f7c7

Please sign in to comment.