Four identical subplots with different view angle - matlab

I have made the following 3D plot:
figure
subplot(2,1,1)
hold on
plot3(X_LE, Y_LE,Z, 'red', 'linewidth', 2)
plot3(X_TE, Y_LE,Z, 'red', 'linewidth', 2)
plot3(X_LE, -Y_LE,Z, 'red', 'linewidth', 2)
plot3(X_TE, -Y_LE,Z, 'red', 'linewidth', 2)
plot3([X_LE(end) X_TE(end)],[Y_LE(end) Y_LE(end)],[0 0], 'red', 'linewidth', 2)
plot3([X_LE(end) X_TE(end)],[-Y_LE(end) -Y_LE(end)],[0 0], 'red', 'linewidth', 2)
grid on
axis equal
xlabel('x/b','Interpreter','latex')
ylabel('y/b','Interpreter','latex')
view(-45, 23);
However, I would like to create a 2x2 subplot where in each one of the 4 subplots the view angle will be different.
Instead of copying the whole code 4 times and just changing the view angle, is there some elegant way to do it?
Example of the output im trying to get:

You could make use of the copyobj function.
copyobj will allow you to replicate any graphic object you already defined. So the principle is to create your first subplot, then simply copy it 3 times and adjust the position and view of each new copy.
To use this feature (and for many other reasons), it is good to save the handle of the graphic objects you create. This is usually done by assigning the return value of a graphic instruction to a variable. Ex:
hp = plot(x,y) ;
Would keep the handle of the plot object in the variable hp, so you can always use this handle to modify the line properties.
For your specific case it would go like that:
%% Quick mock up of a 3D triangle (you did not give any sample data)
x = [0 ; 2 ; 1 ; 0 ] ;
y = [3 ; 1 ; 5 ; 3 ] ;
z = [2 ; -1 ; 4 ; 2 ] ;
%% use dummy subplots, just to save their position on a figure
hf = figure ;
for k=1:4
hs = subplot(2,2,k) ;
axpos{k,1} = hs.OuterPosition ;
end
clf(hf) ; % clear all subplots, keep only "axpos" and the empty figure
%% Generate the first subplot
%% (use your own code for that, but don't forget to retrieve the handles of the figure and the axes)
figure(hf) ;
% hs(1) = subplot(2,2,1) ; % use the line below instead. It is equivalent
% and it also set the 'hold on' mode for the axe
hs(1) = axes('parent',hf, 'OuterPosition',axpos{1},'NextPlot','add') ;
hp = plot3(x,y,z,'red', 'linewidth', 2) ;
grid on
axis equal
xlabel('x/b','Interpreter','latex')
ylabel('y/b','Interpreter','latex')
view(-45, 23);
%% Now use "copyobj" to copy the full axes object with the content and labels
for k=2:4
hs(k) = copyobj( hs(1) , hf ) ; % create a copy of the full subplot
set( hs(k) , 'OuterPosition',axpos{k} ) % reposition it so it doesn't overlap the original
end
Then all you have to do is to change the view of each subplot according to your needs.
This can be done by using the subplot handle as the first argument of the view instruction. For ex:
%% adjust the view of each subplot
view( hs(2) , 25,40)
view( hs(3) , -25,32)
view( hs(4) , 37,92)
Note: If you know the view you want beforehand, you could also place the values in an array at the beginning, and set each axes view directly in the loop where you adjust their position.

Yes, an elegant solution would be creating a function from your code, like this.
function [y] = changeViewAngle(pos, azimuth, elevation)
X_LE = -1:0.01:1;
X_TE = -1:0.01:1;
Y_LE = -1:0.01:1;
Z = -1:0.01:1;
subplot(2,2,pos)
hold on
plot3(X_LE, Y_LE,Z, 'red', 'linewidth', 2)
plot3(X_TE, Y_LE,Z, 'red', 'linewidth', 2)
plot3(X_LE, -Y_LE,Z, 'red', 'linewidth', 2)
plot3(X_TE, -Y_LE,Z, 'red', 'linewidth', 2)
plot3([X_LE(end) X_TE(end)],[Y_LE(end) Y_LE(end)],[0 0], 'red', 'linewidth', 2)
plot3([X_LE(end) X_TE(end)],[-Y_LE(end) -Y_LE(end)],[0 0], 'red', 'linewidth', 2)
grid on
axis equal
xlabel('x/b','Interpreter','latex')
ylabel('y/b','Interpreter','latex')
view(azimuth, elevation)
end
and then saving it as a file with the same name, i.e. changeViewAngle.m
Now create another script, main.m , which looks as below,
figure(2);
clear;
clc;
clf;
changeViewAngle(1, -45, 23)
changeViewAngle(2, 45, -23)
changeViewAngle(3, 25, 90)
changeViewAngle(4, 35, 75)
Note: Remember to change the directory to where you saved your both files. It would be convenient if you saved them both the same folder. Otherwise, MATLAB might complain that it cannot find the function.
Of course, you will also have to change the values for Z, X_LE, X_TE and Y_LE, according to the plot you want to make. I did not have those values, so I used some dummy values in this function. But I guess you understand how to plot 4 subplots with 4 different viewing angles, as that was the main point of your question.

Related

matlab adding single legend for multiple data

figure(1);
hold on;
na=4;
circle_X = [0 0 5 5]';
circle_Y = [0 3 0 3]';
for a = 1:na
r=0.3;
N=100;
theta=linspace(0, 2*pi, N);
cx=r*cos(theta)+circle_X(a);
cy=r*sin(theta)+circle_Y(a);
plot3(cx , cy, 300*ones(N), 'r', 'linewidth', 2,'DisplayName',sprintf('circle'));
end
legend('show');
I want to draw 4 circles and add a single legend 'circle' indicating 4 circles all at once, without using "legend('circle')".
For now the legend looks like this
how should I change the code?
First, you don't need plot3, you can achieve the same figure with plot, and probably the long legend is because of that.
just change the line of plot to that:
plot(cx , cy, 'r', 'linewidth', 2,'DisplayName','circle');
Now, the legend will have 4 entries because you draw four objects. If you want a single entry you have some ways:
add the legend inside the loop, after an if statement. For example,
if a==1 ,
legend('show');
end
get handles for your plots, and legend just one of them. It can be done directly from legend, but then you will need to specify the string:
for....
h(a)=plot...
end
legend(h(1),'circle')
get handles like in part 2, and if you don't want specify the string 'circle', you can use the undocumented hasbehavior:
for...
h(a)=plot...
end
hasbehavior(h(2),'legend',false);
hasbehavior(h(3),'legend',false);
hasbehavior(h(4),'legend',false);
l=legend('show');

Making a legend when some of the data sets could be empty

For my project I have six sets of data to put on a scatter plot, like so:
plot(ax, ay, '.r', bx, by, '.b', cx, cy, '.m', dx, dy, '.c', ex, ey, '.y', fx, fy, '.k');
Sometimes these sets of data will be empty, so bx and by might have nothing in them, therefore getting skipped over.
Is there any way to build a legend that will match the right label to the right color piece of data? In other words, data in the [cx, cy] would always match the label 'c' on the legend next to a magenta dot, even when there is no 'b'. My current legend is as follows:
legend('a', 'b', 'c', 'd', 'e', 'f', -1);
Thanks!
You can get the results you want if you first replace any sets containing empty data with NaN values. For example:
x = [];
y = [];
if isempty(x) || isempty(y)
x = nan;
y = nan;
end
plot(1:10, rand(1,10), 'r', x, y, 'g', 1:10, rand(1,10), 'b');
legend('r', 'g', 'b');
Leaving x and y as empty would give a warning when creating the legend and result in an incorrect legend. When passing empty vectors ([]) to the plot command, it simply doesn't create a line object for that data. When passing a NaN value, it creates but doesn't render a line object, so it still exists and can have a legend entry generated for it.
To complete #gnovice answer with the advantage proposed in #Guto answer, if the order of the lines matters, you can still use NaN, and set their order after it:
x = 1:10;
% plot and get the handle to the lines:
p = plot(x,x,'--g',nan,nan,'r',x,x,'b','linewidth',2);
% set the order of the lines from front to back:
set(p(1).Parent,'Children',p(1).Parent.Children([3 2 1]))
% add the legend:
legend('data 1', 'data 2', 'data 3');
In the above example we bring the green line on top of the blue one:
One other possibility that does not use the x=NaN; is to use a 'dummy plot' out of the boundaries.
The drawback of this process is that you need to select the boundaries manually and if you made any changes in the main plots, you need to manually change the dummy plot as well. Bad idea for use in automated plots. Also If the legend is deleted and called again (either in the insert menu or by legend off; legend show)
The advantage is that you can plot it in a different order from the legend. This can be important when plotting multiple line types and thickness that overlay in some regions. In the figure below, for instance, if you plot the green first, it will disappear in the region x<5 under the blue line.
An example of code:
x_e = [];
y_e = [];
figure()
hold on
plot(100,100, '--g', 100,100, 'r', 100,100, 'b'); %dummy plot
x=1:10;
y=[1 3 3 3 3 4 5 6 9 10]/10;
y2=[1 3 3 3 3 7 6 6 4 3]/10;
plot(x,y2, 'b',x_e, y_e, 'r',x, y, '--g','linewidth',2);
set(gca,'box','on',... %box just to be prettier
'Xlim',[1 10], 'Ylim',[0 1]) % relevant set up!
legend('data 1', 'data 2', 'data 3');
and it give this graph:

Matlab different linewith of marker and errorbar

I would like to set different linewidth for marker and for error bar. Is there a set call for that or maybe a custom functon? The documentation only says that markersize affects the error bar width as weel.
here's a fraction of my code:
s = subplot(1,5,r);
if any(imDATA(r,1,1))
errorbar(imDATA(r,19:26,1), imDATA(r,3:10,1), imDATA(r,27:34,1),'-'k','MarkerSize',e,'LineWidth',w)
hold on;
Thanks!
errorbar returns a handle to the created objects, you can change those if you want later on. The handle is a group containing both the errorbars as the plot of the data (eg connecting line).
Inspect this handle with get and you'll see that you can change them individually:
x = 0:pi/3:pi;
y = sin(x);
h=errorbar(x,y,e,'rx:')
hchildren = get(h,'children');
set(hchildren(1), 'LineWidth', 1, 'Color', 'b')
set(hchildren(2), 'LineWidth', 3, 'Color', 'g');

Matlab: same colormap for hist, plot and mesh

I have datasets for 5 different frequencies in a matrix and I want to illustrate them using plot, hist and mesh. However, each plot type is using different colormaps (see picture), so I need a legend for every plot.
Is there a way to set the same colormap for all plot types, or specify one for each of them? Another thing thats strange: I can set the colormap for hist using the figure tools for example, but not for the normal plot. For the mesh I have to use a hold on loop, so I guess setting the color here is different from defining a colormap?
Edit:
Here is a minimal example. Its still not working, see comments in the code below.
clear all;
close all;
clc;
% make up some data with the original format
freqLen = 5;
data = zeros(10, 3, 3, freqLen);
data(:, :, :, 1) = rand(10, 3, 3);
data(:, :, :, 2) = rand(10, 3, 3)+1;
data(:, :, :, 3) = rand(10, 3, 3)+2;
data(:, :, :, 4) = rand(10, 3, 3)+3;
data(:, :, :, 5) = rand(10, 3, 3)+4;
% reshape data so we get a vector for each frequency
dataF = reshape(data, [10*3*3, freqLen]);
% prepare colors for plot, try to get 5 colors over the range of colormap
% but I get wrong colors using both methods below!
%cols = colormap(jet);
%cols = cols(1:round(length(cols)/length(freqGHz)):end, :);
cols = jet(freqLen);
% plot samples in 3D
figure('Position', [0 0 1000 1000]);
subplot(211);
hold on;
for iF = 1:freqLen
dataThisF = dataF(:, iF);
data3D = reshape(dataThisF, [10*3, 3]);
mesh(data3D);
% try to give each "holded" mesh a different color. Not working!
% after the loop, all meshes have the last color
set(get(gca, 'child'), 'FaceColor', 'w', 'EdgeColor', cols(iF, :));
end
view(60, 20);
% plot samples
subplot(223);
hold on;
for iF = 1:freqLen
% the loop is not avoidable
% because matlab maps the colors wrong when plotting as a matrix
% at least its not using the colormap colors
plot(dataF(:, iF), 'Color', cols(iF, :));
end
% plot histogram
subplot(224);
% actually the only one which is working as intended, horray!
hist(dataF, 50);
How can I give a holded mesh a single color, different from the others? How can I map the correct jet colormap when plotting a matrix using simple line plot, or at least get 5 colors from the jet colormap (jet(5) give 5 different colors, but not from start to end)?
What you are talking about is mainly the ColorOrder property (and not the colormap of the figure).
The link for the colororder given just above will explain you how to force Matlab to use a given set of colors for all the plots. It works perfectly fine for plot. You wouldn't need a loop, just define the DefaultColororder property of the figure before the plots then plot all your series in one single call, Matlab will assign the color of each plot according to the order you defined earlier.
For mesh and hist it is not that simple unfortunately, so you will have to run a loop to specify the color or each graphic object. To modify a graphic object property (like the color) after it has been created, you have to use the set method, or even the direct dot notation if you're using a Matlab version >= 2014b. For both methods you needs to have the handle of the graphic object, so usually the easiest when you know you'll need that is to retrieve the graphic object handle at the time of creation*.
*instead of dirty hack like get(gca, 'child'). This is quite prone to errors and as a matter of fact was wrong in your case. Your code wouldn't color properly because you were not getting the right graphic handle this way.
The code below plots all your graphs, retrieve the handle of each graphic object, then assign the colors in the final loop.
%// Get a few colors
cols = jet(freqLen);
% plot samples in 3D
figure('Position', [0 0 1000 1000]);
set( gcf , 'DefaultAxesColorOrder',cols) %// set the line color order for this figure
subplot(2,1,1,'NextPlot','add'); %// 'NextPlot','add' == "hold on" ;
for iF = 1:freqLen
dataThisF = dataF(:, iF);
data3D = reshape(dataThisF, [10*3, 3]);
h.mesh(iF) = mesh(data3D) ; %// plot MESH and retrieve handles
%// You can set the color here direct, or in the last final "coloring" loop
%// set( h.mesh(iF) , 'FaceColor', 'w', 'EdgeColor', cols(iF, :));
end
view(60, 20);
%// plot samples
subplot(223);
h.plots = plot(dataF); %// plot LINES and retrieve handles
%// plot histogram
subplot(224);
[counts,centers] = hist(dataF, 50 ) ; %// get the counts values for each series
h.hist = bar(centers,counts) ; %// plot HISTOGRAM and retrieve handles
%// now color every series with the same color
for iF = 1:freqLen
thisColor = cols(iF, :) ;
set( h.mesh(iF) , 'EdgeColor' , thisColor , 'FaceColor', 'w' );
set( h.hist(iF) , 'EdgeColor' , thisColor , 'FaceColor' , thisColor )
%// this is actually redundant, the colors of the plots were already right from the
%// beginning thanks to the "DefaultColorOrder" property we specified earlier
set( h.plots(iF) , 'Color' , thisColor )
end
Will land you the following figure:
UPDATE: The original question asked
Is there a way to set the same colormap for all plot types, or specify one for each of them?
this answer, answers that question with colormap taken to mean colormap in MATLAB literally.
You can set the colormap for a figure using colormap. You could use one of the many built in colormaps or specify your own.
An example using mesh and the builtin hsv colormap could be
figure;
mesh(data);
colormap(hsv);
This would apply a colormap based on
to your figure. You can also create your own colormap like
map = [1, 0, 0,
1, 1, 1,
0, 1, 0,
0, 0, 0];
colormap(map);
which would create a colormap with the colours Red, White, Blue and Black.
The MATLAB documentation contains extensive information on the use of colormap.

In MATLAB, how does one clear the last thing plotted to a figure?

In MATLAB, I plot many different vectors to a figure. Now, what I would like to do is simply undo the last vector that I plotted to that figure, without clearing everything else. How can this be accomplished? Can it be accomplished?
Thanks
Edit:
figure(1); clf(1);
N = 100;
x = randn(1,N);
y = randn(1,N);
z = sin(1:N);
plot(x); hold on;
plot(y,'r');
plot(z,'k');
Now here, I would like to remove the plot z, which was the last plot I made.
If you know before plotting that you want to remove it again later, you can save the handle returned by plot and delete it afterwards.
figure;
h1 = plot([0 1 2], [3 4 5]);
delete(h1);
Try
items = get(gca, 'Children');
delete(items(end));
(or maybe delete(items(1)))
The answer that #groovingandi gives is the best way to generally do it. You can also use FINDALL to find the handle based on the properties of the object:
h = findall(gca, 'type', 'line', 'color', 'k');
delete(h);
This searches the current axes for all line objects (plot produces line objects) that are colored black.
To do this on, say, figure 9, you need to find the axes for figure 9. Figure handles are simply the figure number, so:
ax = findall(9, 'axes');
h = findall(ax, 'type', 'line', 'color', 'k');
delete(h);