stop matlab line plots from overlapping - matlab

I plot many lines on top of one another, using plot and hold on
however i want one of the lines to be shifted a bit if it falls on another line.
for example in the following case:
plot(1:100); hold on; plot(-100:100,abs(-100:100))
i want it to be clear that there are 2 plots here
i tried to simply increase x values for different plots but this skews the data too much
for z=1:numberofplots
plot((1:size(locations,2))+0.1*z,locations(z,:)','color', altclrz(z,:));
end

You can differentiate the curves in several ways:
-1- Skewing the data
As you said, you could shift the data a bit. I would suggest fixing your axis and then calculating how many units in linewidth is so you get a very tight fit, like this:
lineWidth = 5;
figure(33);
clf;
subplot(1,2,1);
h = plot(myData, 'linewidth', lineWidth);
xlim([1,5]);
ylim([1,5]);
title('Original');
myData = meshgrid(1:5)';
myLimDiff = diff(ylim);
set(gca,'units', 'pixels');
myPos = get(gca, 'position')
myWidthHeight= myPos(3:4)
PixelsPerUnit =myWidthHeight(2)./ myLimDiff;
myDataSkewed = myData + meshgrid(-2:2)*1/PixelsPerUnit(1)*lineWidth;
subplot(1,2,2);
plot(myDataSkewed, 'linewidth', lineWidth);
xlim([1,5]);
ylim([1,5]);
title('Skewed');
Result:
-2- Using solid lines and Dashes
As someone else noted in the comments, you could you a dashed line over a solid line, or some combination of styles.
-3- Using different line thickness
Use different line widths with the thickest on the bottom:
figure(54);
clf
hold all
for ind = 10:-3:1
plot(1:5, 'linewidth', ind);
end
-4- Use separate plots for each line with a twist
Another way to call out each line is to plot each line in a subplot but to plot all the data in gray first. This way you can see where all the lines are with each particular line called out:
figure(55);
clf
data = rand(3);
for ind = 1:3
subplot(1,3,ind);
plot(data, 'linewidth', 4, 'color', [1 1 1]*.75);
hold on
plot(data(:,ind), 'linewidth', 2);
end

Related

Is it possible to separate the legend entry line into two parts in Matlab

I would like to know if it's possible to separate the line from the legend entry into two different types of lines.
Example : imagine that you have 4 curves : solid black, solid red, dashed black, dashed red. The black curves describe the phenomenon black while red ones describe phenomenon red. The solid line determines whether we add no other contribution than the solid one and dashed means we add some dashed contribution to it. In the legend of my plots, I want only two entries : phenomenon black or phenomenon red. But I would like the legend line of each entry to be separated in two : first half is solid and second half is dashed. In the same way, is it possible to do it the other way around (one half is solid black and the other half is solid red and the other curve is half dashed black half dashed red).
For 4 curves this makes not a lot of sense. But I sometimes have to put 6 or 8 curves and the legend is then too big to be able to put it somewhere in the figure...
Currently I use this line to add my legend :
legend({str1,str2},'Interpreter','latex')
but I don't know if it's relevant to say that.
I post a picture to illustrate what I would like (note that it could be the other way around, with two styles for one line instead of two colors) :
it's not exactly what you asked for, but it's another approach:
styles = {'-','--'};
colors = {'r','g','b'};
colorNames = {'red','green','blue'};
styleNames = {'normal','dashed'};
hold on
% plot many lines
for ii = 1:numel(styles)
for jj = 1:numel(colors)
plot((1:10) + jj + ii*numel(colors),'Color',colors{jj},'LineStyle',styles{ii})
end
end
% generate handles for the legend
h = [];
for ii = numel(colors):-1:1
h(numel(styles)+ ii) = plot(0,0,'Color',colors{ii},'LineStyle','-');
end
for ii = numel(styles):-1:1
h(ii) = plot(0,0,'Color','k','LineStyle',styles{ii});
end
hold off
legend(h,[styleNames colorNames]);
There is no in built ability to do this for the Matlab legend. You can achieve something similar by manually drawing lines. This uses the annotation arrow functionality for a figure:
% plot some dummy data (not connected to the manual legend!
x = linspace(-1,1);
clf; hold on; grid on
% Set up linestyles and linecolors here so that they can be (at least
% slightly) linked between the plot and the manual legend.
linestyles = {'-', '--'};
linecolors = {'k', 'r'};
% plots
plot(x,x.^2,'linestyle',linestyles{1},'color',linecolors{1});
plot(x,x.^3,'linestyle',linestyles{1},'color',linecolors{2});
plot(x,x.^4,'linestyle',linestyles{2},'color',linecolors{1});
plot(x,x.^5,'linestyle',linestyles{2},'color',linecolors{2});
% scale the plot within the figure to leave room for legend
plotsize = [0.06, 0.20, 0.9, 0.75];
set(gca,'position', plotsize)
% x and y are original positions for the lines
x = 0.4; y = 0.1;
% dx and dy are length and vertical spacing of lines respectively
dx = 0.1; dy = 0.05;
% The main event: drawing (headless) text arrows, so that one of them can have
% a string properly which is your legend entry label. Use x,y,dx,dy for positioning
annotation('textarrow', [x,x+dx], [y,y], ...
'linestyle', linestyles{1}, 'color', linecolors{1}, 'textcolor', 'k', 'headstyle', 'none', ...
'string', 'Even functions ')
annotation('textarrow', [x+dx + 0.005,x+2*dx + 0.005], [y,y], ...
'linestyle', linestyles{2}, 'color', linecolors{1}, 'textcolor', 'k', 'headstyle', 'none')
annotation('textarrow', [x,x+dx], [y-dy,y-dy], ...
'linestyle', linestyles{1}, 'color', linecolors{2}, 'textcolor', 'k', 'headstyle', 'none', ...
'string', 'Odd functions ')
annotation('textarrow', [x+dx + 0.005,x+2*dx + 0.005], [y-dy,y-dy], ...
'linestyle', linestyles{2}, 'color', linecolors{2}, 'textcolor', 'k', 'headstyle', 'none')
Result:
Note the positioning is done with normalised (between 0 and 1) values, so they stretch with the figure. Dealing in pixels can be easier to visualise if your plot is of a fixed size, this can be done by changing the units argument of the various graphics objects when resizing them (see the docs linked above for annotation arrow).

MATLAB: update surface plot and change location of line objects in while loop

So I am encountering a couple errors and am not sure where they're coming from. I won't post the whole code, but I will do my best to explain (fear I will be accused of plagiarism).
The assignment is to create a window with two plots: a surface plot and a contour plot. The surface plot represents elevation of a portion of the map represented by the contour plot. The portion is indicated by a blue box on the contour plot. I've successfully plotted the surface and contour plots and have identified the first area with a blue box. However, now I need to implement a menu system wherein the user enters 1, 2, 3, or 4 to move the box north, south, east or west.
Here is how I instantiated the plots:
fig = figure(1);
[xGrid, yGrid] = meshgrid(xMeters(xStart:xEnd), yMeters(yStart:yEnd));
%surface plot
elevationBox = ELEV(xStart:xEnd, yStart:yEnd);
surface = subplot(2, 1, 1);
surf(xGrid, yGrid, elevationBox);
axis([0 max(xGrid(:)) 0 max(yGrid(:)) min(elevationBox(:)) max(elevationBox(:))]);
axis tight;
%contour plot
elevation = ELEV;
[xMap, yMap] = meshgrid(xMeters(1:335), yMeters(1:230));
map = subplot(2, 1, 2); contour(xMap, yMap, elevation);
axis([0 max(xMeters(:)) 0 max(yMeters(:))]);
axis fill;
set(fig, 'Position', [500 100 600 700]);
right = line(xRight, xLeft);
left = line(xLeft, yLeft);
top = line(xTop, yTop);
bottom = line(xBottom, yBottom);
So all that works fine. Obviously I didn't include the parts where I defined the data and everything. After this comes a switch statement that changes the values of xLeft, yLeft, etc as well as xStart, xEnd etc.
Here is my attempt to update the plots:
[xGrid, yGrid] = meshgrid(xMeters(xStart:xEnd), yMeters(yStart:yEnd));
elevationBox = ELEV(xStart:xEnd, yStart:yEnd);
subplot(2, 1, 1)
set(surface, 'XData', xGrid, 'YData', yGrid, 'ZData', elevationBox);
drawnow;
I can choose an option and there is no error, but the plot doesn't update and when I quit the program I get this error:
Error using matlab.graphics.axis.Axes/set
There is no XData property on the Axes class.
Error in A9 (line 129)
set(surface, 'XData', xGrid);
The setting is inside the while loop but outside the switch statement. I also had a few lines using set on the line objects but those weren't working either so I thought I'd focus here first. I'm figuring whatever I'm doing wrong applies to both object types but if not let me know.
Thanks!
Rather than grab a handle to the axis (which you call surface), you want the data object. So grab a handle at surf_h = surf(...);.
A little example:
% Generate a random surface grid
n = 10;
[x, y] = meshgrid(1:n, 1:n);
z = rand(n);
% Plot
fig_h = figure(1);
axis_h = subplot(2, 1, 1);
surf_h = surf(x,y,z);
% Modify XData
set(surf_h, 'XData', -x);
drawnow;

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);

waterfall plot using ribbon

I have a series of spectral data which I want to plot in a waterfall style plot.
waterfall itsself is no that usefull, because the thin lines have too many differences in each spectrum, that is is not very usefull
I therefore want to try the ribbon function, which looks promising in the docs
.
But the result is completely different and useless!
figure(2); clf;
ribbon(spectralSeries);
shading flat % otherwise complete dark
axis tight
EDIT:
I created now a manual waterfall plot, which is close to what I wanted:
hold on;
stepsize = 0.35;
for k = length(series):-1:1
color = cmap(k,:);
data = spectralSeries(k,:) + (k-1)*stepsize;
hplot(k) = filledcurve(xaxis, data, 0);
set(hplot(k), 'FaceColor' , color*1.2)
set(hplot(k), 'EdgeColor' , color*0.5)
end
hold off;
axis tight
Nevertheless I am still interested in a solution of the original problem.
EDIT 2:
Here an example using the same data with waterfall, ribbon and my custom code. Only my code is usefull to visualise the data. I would still like to know how to make ribbon and waterfall look like a decent plot...
This code is now used to create some data
xaxis = linspace(-pi/2,3/2*pi, 1000);
variation = [ 0.5 1 5 10];
spectralSeries = abs(sin(xaxis)'*ones(1,4) + sin(xaxis'*variation)*0.25);
Here a result using ribbon
ribbon(spectralSeries);
shading flat % otherwise complete dark
axis tight
And here with waterfall
hplot = waterfall(spectralSeries);
set( hplot, 'LineWidth', 4 );
hidden off;
and for comparison a plot using my own written code, which is similar to a waterfall, but without the depth axis. However it is the only one which looks decent and displays the data curves such that the variations between each curve can be seen.
You can still use waterfall, but set some patch and axes properties to get nicer output. The important thing to notice is that spectralSeries should be transposed.
figure
xaxis = linspace(-pi/2,3/2*pi, 200);
variation = [ 0.5 1 5 10 7 3.5 8];
spectralSeries = abs(sin(xaxis)'*ones(1,7) + sin(xaxis'*variation)*0.25);
h = waterfall(spectralSeries');
cameratoolbar;
%%
set(h, 'FaceColor', 'flat');
set(h, 'FaceAlpha', 0.7);
set(h, 'EdgeColor', 'k');
set(h, 'FaceVertexCData', rand(7,3))
set(gca, 'Color', [1 1 1]*0.85)
set(gca, 'GridLineStyle', 'none');
%%
myaa
The (optional) last statement, myaa, produces an anti-aliased figure; get the script here.

Plotting a subplot on top of another plot in Matlab

I need to plot several plots along a sloped line at different positions.
For example, if I:
plot(0:200,'k');
plotpts = 5:5:200;
I would like to be able to plot a smaller plot at each of my plotpts on top of the original 0:200 line.
I know you can use hold on and plot over top that way, but I need to change my origin each time. Does anyone have any suggestions? I would really like to stay in matlab. Thanks!
Here is a flexible way I usually do it:
plot(1:10, 'k')
plotpts = 2:2:8;
mainbox = get(gca, 'Position');
xlims = get(gca, 'XLim');
ylims = get(gca, 'Ylim');
for i=1:length(plotpts)
originx = mainbox(1) + (plotpts(i) - xlims(1)) * (mainbox(3)) / (xlims(2) - xlims(1));
originy = mainbox(2) + (plotpts(i) - ylims(1)) * (mainbox(4)) / (ylims(2) - ylims(1));
axes('position', [originx originy 0.1 0.1], 'Color', 'none')
% Do some plotting here...
end
It's quite a bit of work, but you probably want to use the axes command. A figure window can host any number of axes, where each axes has it's own position, data, annotations, color etc.
The most difficult thing for the application you describe is that each axis position needs to be defined in the coordinate frame of the underlying figure, which means that some math may be required to create the illusion that the axis is correctly positioned within a parent axes/
For example, if you first create a simple plot
figure(1234); clf;
plot(1:10, rand(1,10),'.k-','linewidth',5);
xlim([1 10]);
ylim([0 1]);
set(gca,'color','y'); %This just helps demonstrate the next steps
You can place another axis directly on top of the first, and then
ha = axes('position',[.2 .3 .1 .1])
plot(linspace(0,2*pi,100), sin(linspace(0,2*pi,100)), 'b-')
xlim([0 2*pi])
You can adjust the the properties of the inset axis to suit your particular needs, for example
set(ha,'color','none'); %A transparent axis
set(ha,'xtick',[],'ytick',[]); %Remove tick labels
title(ha,'This is an inset plot')
Is the command subplot not what you're looking for?