8

I would like to know how to plot multiple, 2D contour plots spaced apart in the z-axis, in a 3D figure like this:

blah

Amro
  • 123,847
  • 25
  • 243
  • 454
Krish
  • 110
  • 1
  • 9
  • The command you are probably looking for is [contourslice](http://www.mathworks.com/help/matlab/ref/contourslice.html). See documentation for further reference. – CitizenInsane Jul 08 '14 at 04:43
  • @CitizenInsane: that function is intended for visualizing volume data, I don't think the OP means to do that here. – Amro Jul 08 '14 at 05:31
  • @Amro Humm maybe was to easy to think data are volume-data. Your solution is nice. – CitizenInsane Jul 08 '14 at 07:47

1 Answers1

10

NOTE: The first part of this answer was meant for HG1 graphics. See the second part if you're working with MATLAB R2014b and up (HG2).


HG1:

The contour function internally creates a number of patch objects, and returns them as a combined hggroup object. So we could set the ZData of all patches by shifting in the Z-dimensions to the desired level (by default contour is shown at z=0).

Here is an example:

[X,Y,Z] = peaks;
surf(X, Y, Z), hold on       % plot surface

[~,h] = contour(X,Y,Z,20);   % plot contour at the bottom
set_contour_z_level(h, -9)
[~,h] = contour(X,Y,Z,20);   % plot contour at the top
set_contour_z_level(h, +9)

hold off
view(3); axis vis3d; grid on

multiple_contour_plots

Here is the code for the set_contour_z_level function used above:

function set_contour_z_level(h, zlevel)
    % check that we got the correct kind of graphics handle
    assert(isa(handle(h), 'specgraph.contourgroup'), ...
        'Expecting a handle returned by contour/contour3');
    assert(isscalar(zlevel));

    % handle encapsulates a bunch of child patch objects
    % with ZData set to empty matrix
    hh = get(h, 'Children');
    for i=1:numel(hh)
        ZData = get(hh(i), 'XData');   % get matrix shape
        ZData(:) = zlevel;             % fill it with constant Z value
        set(hh(i), 'ZData',ZData);     % update patch
    end
end

HG2:

The above solution doesn't work anymore starting with R2014b. In HG2, contour objects no longer have any graphic objects as children (Why Is the Children Property Empty for Some Objects?).

Fortunately there is an easy fix, with a hidden property of contours called ContourZLevel. You can learn more undocumented customizations of contours plots here and here.

So the previous example simply becomes:

[X,Y,Z] = peaks;
surf(X, Y, Z), hold on       % plot surface

[~,h] = contour(X,Y,Z,20);   % plot contour at the bottom
h.ContourZLevel = -9;
[~,h] = contour(X,Y,Z,20);   % plot contour at the top
h.ContourZLevel = +9;

hold off
view(3); axis vis3d; grid on

contours


Another solution that works in all versions would be to "parent" the contour to a hgtransform object, and transform that using a simple z-translation. Something like this:

t = hgtransform('Parent',gca);
[~,h] = contour(X,Y,Z,20, 'Parent',t);
set(t, 'Matrix',makehgtform('translate',[0 0 9]));
Amro
  • 123,847
  • 25
  • 243
  • 454
  • Thank you! This is exactly the type of figure which I wanted to plot. Is there a way to adjust the spacing/viewing angle such that the contours do not overlap? (I am plotting 3 levels of contours, like the diagram, however each of the contours overlap with each other with the current perspective) – Krish Jul 13 '14 at 17:56
  • you can [interactively rotate](http://www.mathworks.com/help/matlab/creating_plots/rotate-3d-interactive-rotation-of-3-d-views.html) the view in 3D, or do it programmatically with [`view(az,el)`](http://www.mathworks.com/help/matlab/ref/view.html): http://www.mathworks.com/help/matlab/visualize/setting-the-viewpoint-with-azimuth-and-elevation.html. You can also [control the camera](http://www.mathworks.com/help/matlab/visualize/view-control-with-the-camera-toolbar.html) for greater flexibility – Amro Jul 13 '14 at 18:45
  • 1
    I've updated the answer to show solutions for both HG1 and HG2 – Amro Dec 16 '16 at 01:19