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.
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.
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).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With