How to add a 2D plot to an existing 3D plot by sharing the same axes?

Dear Matlab Community,
I am wondering how to replicate a plot that I have seen in a journal paper. The 3D plot can be created using various functions (mesh, contour3, surf etc.) but I am unable to add another plot in a way that they both use the same axes? Has anyone come across a solution for this?

5 Comments

That isn't one axes but two, both 3D, just no z axis on the one. I don't think Matlab is going to be able to do that effectively; the only hope would be with the tiledlayout, but it is designed solely with tiling in a plane; whether you would be able to manipulate the arrangement satisfactorily is, I'd venture, not likely.
Another approach; also use two 3D axes in the same figure, but set the data to NaN for the areas of the other dataset so they aren't plotted on the alternate. In this case, the two would overlay each other physically.
Looks like something <TecPlot> may have produced; it is lightyears beyond in its capabilities...
@dpb Thank you! I'll have a check. This is a plot from 2018 which makes me wonder whether Matlab was advanced enough to come up with this plot in the first place or whether an alternative software has been used.
Nothing great and different since 2018 w/ MATLAB, certainly, as far as this kind of a presentation other than tiledlayout (R2019b), but while it is somewhat more user friendly and capable than subplot, it is still a rectangular grid of axes into which one can insert various plot axes. There is no way to
[X,Y] = meshgrid(-5:.5:5);
Z = Y.*sin(X) - X.*cos(Y);
hT=tiledlayout(1,2);
nexttile
hS = surf(X,Y,Z,'FaceAlpha',0.5);
nexttile
hS(2) = surf(X,Y,Z,'FaceAlpha',0.5);
hAx=hT.Children
hAx =
2x1 Axes array: Axes Axes
hAx.Position
ans = 1×4
0.5875 0.1100 0.3175 0.8150
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
ans = 1×4
0.1300 0.1100 0.3175 0.8150
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Whether you could set the height of the two to something about half and then manipulate the left and bottom positions to make them appear aligned I don't know....it would be an interesting exercise, perhaps; unfortunately, I have other commitments that I can't take that much time away from at the moment to try playing, but that's my bestest suggestion at the moment, anyways.
Well, we could at least try...
pos={hAx.Position}.';
pos{1}(4)= pos{1}(4)/2;pos{2}(4)= pos{1}(4);
set(hAx,{'Position'},pos)
Warning: Unable to set 'Position', 'InnerPosition', 'OuterPosition', or 'PositionConstraint' for objects in a TiledChartLayout
Warning: Unable to set 'Position', 'InnerPosition', 'OuterPosition', or 'PositionConstraint' for objects in a TiledChartLayout
Well, so much for that idea; I kinda' thought it had locked things down...what about subplot()???
figure;
hAx=subplot(1,2,1);
hS = surf(X,Y,Z,'FaceAlpha',0.5);
hAx(2)=subplot(1,2,2);
hS(2) = surf(X,Y,Z,'FaceAlpha',0.5);
pos={hAx.Position}.'
pos = 2x1 cell array
{[0.1300 0.1100 0.3347 0.8150]} {[0.5703 0.1100 0.3347 0.8150]}
pos{1}(4)=pos{1}(4)/2;pos{2}(4)=pos{1}(4); % reduce each height by half
pos{2}(2)=pos{1}(2)+pos{1}(4); % set the bottom of RH to top of LH
set(hAx,{'Position'},pos)
Well, at least you can mess with the positions; whether you can move them around to positions that line up as would want is a biggie...it's the position inside the axes... and you're going to need the LH one to be in front of the RH which probably will occlude it if can manage at all...
Unfortunately for this purpose, if you use a regular plot for the second axis and set the camera angle to match the orientation of the surface plot axes, MATLAB still renders the z axis and the x- and y-axis grid lines show as well as the plot color and there's no way to turn set the background color to only show the xy-plane and to the rear projections of xz and yz.
Maybe @Adam Danz will stumble on to the thread; he's a new(ish) TMW staff member who has done a lot of such shenanigans previously if no other regulars want to give it a go...
One can (at least also superficially) make the 2D surface look as though it is only thing there with a zero height in the projection by
hF=figure;
hF.Color=0.94*hF.Color; % so will show up from default white
hAx=subplot(1,2,1);
hAx.CameraPosition=[-45.6571 -59.5015 86.6025]; % match default orthographic projection
hAx.ZAxis.Visible='off';
hold on
x=[0 1 1 0]; y=[0 0 1 1]; o=ones(size(x)); % patch coordinates to mask verticals
patch(x,o,y,hF.Color,'edgecolor','none')
patch(o,x,y,hF.Color,'edgecolor','none')
[X,Y] = meshgrid(-5:.5:5);
Z = Y.*sin(X) - X.*cos(Y);
hAx(2)=subplot(1,2,2);
hS=surf(X,Y,Z,'FaceAlpha',0.5);
pos={hAx.Position}.';
pos{1}(4)=pos{1}(4)/2;pos{2}(4)=pos{1}(4); % reduce each height by half
pos{2}(2)=pos{1}(2)+pos{1}(4); % set the bottom of RH to top of LH
set(hAx,{'Position'},pos)
As before, still don't know if one can manage to move those pieces around to get them aligned well enough to create the desired illusion or not...the background color patches to hide the other grid lines are probably going to be in the way preventing being able to see the RH axes in its entirety once the LH one is where it needs to be...
All in all, it's still going to be a lot of trial and error...MATLAB simply doesn't have such facilities and while it's an interesting intellectual challenge to see if one can make such plots, it is certainly a way to use up a lot of time that could be generally used in more productive manner...
I do not know what was used to create the figure from the paper; does it provide any hints to the tools used? I also do not know if TecPlot has such as a builtin, I let the license lapse when quit the active consulting gig while still using 32-bit OS and it won't run on this machine now to try with old version...and, that's about all the time I've got that I should spend here at the moment...
Dear @dpb This has already been helpful! I will see to tighten the space betwee plots or else superimpose these plots so as to align them closely. I will fiddle my way around! I may plot my answer in the coming days depending on being successful or not!

Sign in to comment.

 Accepted Answer

This is challenging. The reason it's challenging is because camera properties are set relative to a point in an axes, not relative to a figure. As @dpb points out, when there are multiple axes in a figure, there's no way to rotate a camera to view the tiled arrangments from a certain perspective.
Your only hope that I can imagine to do this in MATLAB is to put the content on the same axes.
Here's a quick and sloppy demo that touches upon the start of a solution. Where it falls short is drawing a 2nd y axis and a 2nd z axis. It's also sensitive to the figure size and other properties so it needs tweaked.
% Generate ridgeline
ridgelineData = nan(300,200);
x = linspace(-1,1,200);
sigma = 0.16; % width of the pulse
gaus = exp(-x.^2/(2*sigma.^2));
for i = 1:height(ridgelineData)
n = rand(size(gaus));
offset = 0.33; % to allow variation near y=0
ridgelineData(i,:) = smoothdata((gaus+offset).*n,'gaussian',16)-offset;
end
xdata = linspace(9,35,width(ridgelineData));
ydata = 1:height(ridgelineData);
vertOffsets = (height(ridgelineData)-1)*5 : -5 : 0;
% Generate the flat 2D data
flatData = ridgelineData;
ax = axes();
view(3)
hold on
for i = 1:height(ridgelineData)
yvec = vertOffsets(i) .* ones(width(ridgelineData),1);
patch(xdata', yvec, ridgelineData(i,:)', [0.066 0.443 0.745],EdgeColor='none')
plot3(xdata',yvec,ridgelineData(i,:),'w-')
end
xlim(ax,"tight")
ylim(ax,"tight")
zlim(ax,"tight")
minX = ax.XLim(1);
minZ = ax.ZLim(1); % this is where the 2D image will go
ax.ZLim(2) = 10; % To mimick the image in the question
% make room for a flat 2D surface on XY next to the existing content
% Xlim is set to tight so xlim can be used to get the extent of the data.
% How wide should the strip be (in x-data units)
stripWidth = 7;
% How wide should the gap be between the strip and the main data (in x-data units)
stripGap = 3;
% Set the new xlim that makes room for the strip.
ax.XLim(1) = ax.XLim(1) - stripWidth - stripGap;
% Plot the flat surface
xExtent = ax.XLim(1) + [0,stripWidth];
yExtent = ax.YLim; % when axes are tight
S = surf(linspace(xExtent(1),xExtent(2),width(flatData)), ...
linspace(yExtent(1),yExtent(2),height(flatData)), ...
zeros(size(flatData))+minZ, ...a
flatData, ...
'EdgeColor', 'none', ...
'Clipping','off'); % Needed so it doesn't disappear when xlim changes
% Cosmetics
ax.Color = 'none';
ax.XLim(1) = minX;
% You may need to shrink the axes if anything is extending beyond the
% figure
ax.OuterPosition = [.05 .05 .9 .9];

3 Comments

This is fantastic! Thank you for your involvement in this feed! I am now a few steps closer to realizing my final plot. Should I not be able to get the axis right, I may consider adding an axis by hand. Thank you! This is perfect!
If you create two axes and then combine them in an image editor outside of MATLAB, here are some tips to get both axes to look right.
  • Set TickDir to out in the 2D axes so the ticks look the same as the 3D axes
  • Use the same yticks and limits for the shared axes (y, I think)
  • Set the same view and, probably, camera properties
  • the plotbox and data aspect ratios should probably match between the two axes
That's clever, Adam! :)
I figured if anybody would, it would be you...

Sign in to comment.

More Answers (0)

Categories

Find more on Graphics Performance in Help Center and File Exchange

Asked:

on 15 Sep 2024

Edited:

on 19 Sep 2024

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!