MATLAB: Drawing atop a surface plot

matlab, plot, surface

Solution

There may not be a direct way to specify the `z` position of the objects returned by `viscircles`, but in general there is (most of the time) a way to modify properties and position of any graphic object afterwards.

Method 1: modifying circles after creation.

If you plan to do modifications of a graphic object, the first thing to do is always to retrieve its `handle`. So in your case, you would have to call `viscircles` by specifying a return value (which will contain the `handle` you want).:

hg = viscircles(circle_pos, circle_rad);

I do not have the `Image Processing Toolbox` so I do not have access to the `viscircles` function. However I read from the documentation that the handle returned is an `hggroup`. An `hggroup` is simply a container containing one or more `handles` of more primitive graphic objects. In this case the `hggroup` contains the handles of 4 `lines` (your 4 circles).

The easiest way to transform all the objects in an `hggroup` is to use a `hgtransform` object. We will define a Translation transformation and the `hgtransform` will apply it to the 4 circles (all the children of the `hggroup`).

To define the translation, we will use a `makehgtform` object.

Here we go:

ht = hgtransform ;      % create the transform object
set(hg,'Parent',ht) ;   % make it a "parent" of the hggroup

zc = max(max(Z)) ;  % Find by how much we want to translate the circles on the Z axis
Tz = makehgtform('translate',[0 0 zc]) ;   % create the TRANSLATION transform

set(ht,'Matrix',Tz)     % apply the transformation (translation) to the hggroup/hgtransform

Done, your 4 circles should now be on top of your surface. Note that you can specify any other values for `zc` (not only the max of the surface).

Method 2: DIY

In case you do not want to be reliant on the image processing toolbox, or if you do not have it at all, it is relatively easy to create circles in a 3D space by yourself.

Here is a function which will create circles in a way comparable to `viscircles` but it also let you specify an optional `z` coordinate for the circle centre positions.

code for `circles_3D.m`:

function hg = circles_3d( pos , rad , varargin )

% get current axes handle and hold state
ax = gca ;
holdState = get(ax,'NextPlot') ;    % save state to reinstate after function
set(ax,'NextPlot','add') ;          % equivalent of "hold off"

tt = linspace(0,2*pi) ;
hg = hggroup(ax) ;
for k = 1:numel(rad)

    c = pos(k,:) ;
    r = rad(k) ;
    x = c(1) + r.*cos(tt) ;
    y = c(2) + r.*sin(tt) ;
    z = zeros(size(x)) ;
    if numel(c)==3 ; z = z + c(3) ; end

    plot3(hg,x,y,z,varargin{:}) ;
end

set(ax,'NextPlot',holdState) ; % restore axes hold state

You can now call this function instead of `viscircles`. I used the `varargin` parameter to transfer any `line` property to the circles created (so you can specify the `Color`, `LineWidth`, and any other typical parameter you like.

For the sake of an example, I need to recreate a surface comparable to your, with 4x "zero" poles distributed around the maxima:

pc = 0.5 ;  % pole centers
pw = 0.05 ; % pole widths

% surface definition
[X,Y] = meshgrid(-5:.1:5);
R = sqrt(X.^2 + Y.^2) + eps ;
Z = sin(R)./R;
% zero surface values around the defined poles
[idxPoles] = find(abs(X)>=pc-pw & abs(X)<=pc+pw & abs(Y)>=pc-pw & abs(Y)<=pc+pw ) ;
Z(idxPoles)= 0 ;
% display
hs = surf(X,Y,Z) ; shading interp

Which produces:

Now you can simply get your circles with the `circles_3D` function:

zc = max(max(Z)) ;
circle_pos = [ pc pc zc ; -pc -pc zc ; -pc +pc zc ; +pc -pc zc ] ;
circle_rad = 0.2 * ones(4,1);
h = circles_3d( circle_pos , circle_rad , 'Color','r','LineWidth',2) ;

and get:

Note that I made this function so it also return an `hggroup` object containing your lines (circles). So if you want to move them later, apply the same trick than in the first part of the answer.

Problem

I'm plotting an R^2 to R function in MATLAB as a surface plot, which I colormap and view from above. ``` surf(X, Y, data); colormap(jet); colobar; view(2); ``` It produces (with some additional code) something like though the true nature of the function (for the purpose of understanding this question) is better observed from an angle like: I want to plot a circle atop my original plot (seen from above). Something like... I can't seem to achieve this however, since plotting in-a-plane elements on plots makes them appear on the x-y axis, which is covered by my surface plot. For example, calling ``` circle_pos = [ +1 +1; -1 -1; -1 +1; +1 -1;] circle_rad = 0.2 * ones(4,1); viscircles(circle_pos, circle_rad); ``` after my surface plot results in no visible circles when viewed from the top. Zooming and rotating reveals these circles were plotted on the x-y plane, and so are invisible from above. How do I plot my circles on top of the surface plot, so that they are visible from above? A similar issue arises when plotting `text` atop the surface, but is remedied by specifying a z position value just above the underlying functions z value. There doesn't seem to be any way to specify the z position of these graphical elements.

Original source