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.
Related
I am trying to create a plot in Octave (using v4.4.1 on Windows) using plotyy and putting the legend outside the plot (because the data covers all the usable space inside the graph). The following MVCE should reproduce the issue fairly well:
% Generate some random data to reproduce the issue
data = rand(1000,10);
data(:,1:8) = data(:,1:8)-0.5;
data(:,9:10) = data(:,9:10)+30;
timedate = linspace(737310,737313,size(data,1));
data_labels={'1';'2';'3';'4';'5';'6';'7';'8';'9';'10'};
% Plot the data
figure('Name','MVCE','Position',[300 200 1000 600])
[ax,h1,h2] = plotyy(timedate,data(:,1:8),timedate,data(:,9:10));
set(h2,'Visible','on');
datetick(ax(1),'x','HH:MM:SS')
datetick(ax(2),'x','HH:MM:SS')
ylim(ax(1),[-1 1])
ylim(ax(2),[20 50])
xlabel('Date & time')
ylabel(ax(1),'Something')
ylabel(ax(2),'Something else')
title('plotyy graph with legend problem')
[hl,hlo] = legend([h1;h2],data_labels,'location','eastoutside');
grid on
This the output of the code using the gnuplot graphics toolkit:
As you can see, the legend does not go outside the plot, and the second y axis is not visible (it looks like part of the plot is actually truncated).
I have tried using the qt and fltk graphics toolkits, which give issues of their own:
With qt graphics toolkit
With fltk graphics toolkit
Can anoybody suggest a fix or at least workaround? Does the same issue also happen in MATLAB or is it Octave-specific?
EDIT
Using the suggestion in Tasos' answer, I managed to almost make it work with gnuplot:
% Plot the data
figure('Name','MVCE','Position',[300 200 1000 600])
[ax,h1,h2] = plotyy(timedate,data(:,1:8),timedate,data(:,9:10));
set(h2,'Visible','on');
datetick(ax(1),'x','HH:MM:SS')
datetick(ax(2),'x','HH:MM:SS')
ylim(ax(1),[-1 1])
ylim(ax(2),[20 50])
ax1Pos = get(ax(1), 'position');
ax2Pos = get(ax(2), 'position');
ax1Pos(3) = ax1Pos(3) * 0.73;
ax2Pos(3) = ax2Pos(3) * 0.73;
set(ax(1), 'position', ax2Pos);
set(ax(2), 'position', ax2Pos);
xlabel('Date & time')
ylabel(ax(1),'Something')
ylabel(ax(2),'Something else')
title('plotyy graph with legend problem')
[hl,hlo] = legend([h1;h2],data_labels,'location','eastoutside');
pos = get(hl,'Position');
pos(1) = 0.9;
set(hl,'Position',pos)
grid on
Which produces:
Apart from the fact that the legend overlays with the second y axis label (which it doesn't on my screen, only when printing to jpg), the problem is that Octave appears to plot two legends on top of each other for some reason: one with the first set of data attached to the first set of axes, and one with the complete set of data, for both axes right on top of the first legend. This is obviously wrong, and trying to set the Visible property of hl to off deletes both legends, not just the one.
UPDATED: deals with both legend placement and OpenGL precision affecting graph.
Regarding the problem of the legend not appearing exactly in the position you want it to, you can manually adjust the position of all axes involved in a figure, to place them exactly where you want.
Regarding the problem of OpenGL being unable to deal with the precision involved when adding small numbers to a large number, plot the graph with only the small numbers involved, and then simply adjust the xticklabels to correspond to the numbers you desire.
Full code below:
% Generate some random data to reproduce the issue
data = rand(1000,10);
data(:,1:8) = data(:,1:8)-0.5;
data(:,9:10) = data(:,9:10)+30;
t_offset = 737310;
timedate = linspace(0,3,size(data,1));
data_labels={'1';'2';'3';'4';'5';'6';'7';'8';'9';'10'};
% Plot the data
figure('Name','MVCE','Position',[300 200 1000 600])
[ax,h1,h2] = plotyy(timedate,data(:,1:8),timedate,data(:,9:10));
set(h2,'Visible','on');
ylim(ax(1),[-1 1])
ylim(ax(2),[20 50])
ylabel(ax(1),'Something')
ylabel(ax(2),'Something else')
title('plotyy graph with legend problem')
[hl,hlo] = legend([h1;h2],data_labels,'location','eastoutside');
set(hl, 'position', get(hl, 'position') .* [0.975, 1, 0.975, 1] )
grid on
ax1Pos = get(ax(1), 'position'); ax2Pos = get(ax(2), 'position');
ax1Pos(3) = ax1Pos(3) * 0.95; ax2Pos(3) = ax2Pos(3) * 0.95;
set(ax(1), 'position', ax2Pos); set(ax(2), 'position', ax2Pos);
XTicks = get(ax(1), 'xtick');
set(ax(1), 'xticklabel', datestr(XTicks + t_offset, 'HH:MM:SS'))
xlabel('Date & time')
set(ax(2), 'xtick', []);
Output:
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;
I have some points in a 'jet' colormap. The points have a coefficient that can go from 0 to 1, but usually they dont cover all the range, e.g 0.75-0.9.
When I plot those points I colour them so 0.75 is the lesser colour in the colormap and 0.9 is the maximum color in the colormap, so all the colormap is shown. What I want to do is show that in the colorbar also. When I plot the colorbar the labels on it go to 64, but I want them from 0.75 to 0.9. How can I do that?
EDIT
I don't think the code itself helps a lot but here it goes, just in case. In the colors variable I convert the ZNCC to the range of the colormap.
EDIT2
I found the reason why caxis is not working for me. Here is the code:
%this is why it doesnt work
im=imread('someimageyouwanttotest_inRGB.png')
imshow(im)
points=[1, 2;1 , 2 ;0.3,0.7]
ZNCC=points(3,:)
cmap=colormap('jet');
colors=cmap(round( ((1-min(ZNCC))+ZNCC-1).*(size(cmap,1)-1)/max((1-min(ZNCC))+ZNCC-1))+1,: );
hold on
for i=1:length(ZNCC)
plot(points(1,i),points(2,i),'.','Color',colors(i,:));
end
colorbar()
hold off
I think that is your code displays all your colours correctly then rather just set up the colour bar first on no image:
points=[1, 2;1 , 2 ;0.3,0.7]
ZNCC=points(3,:)
cmap=colormap('jet');
caxis([min(ZNCC) max(ZNCC)]);
colorbar();
hold on
%this is why it doesnt work
im=imread('someimageyouwanttotest_inRGB.png')
imshow(im)
colors=cmap(round( ((1-min(ZNCC))+ZNCC-1).*(size(cmap,1)-1)/max((1-min(ZNCC))+ZNCC-1))+1,: );
for i=1:length(ZNCC)
plot(points(1,i),points(2,i),'.','Color',colors(i,:));
end
hold off
I can't test it as I don't have imshow :/
If caxis is not working for you, you could store the return from colorbar - it is a handle to the colorbar object. Then you can set its properties, like 'YTick' and 'YLim'. The full list of properties you can set is the same as the Axes Properties (because the colorbar is just an axes object, after all).
Here is an example:
% Generate some random data
z = rand(10);
[x, y] = meshgrid(1:size(z, 1));
% Plot colour map
pcolor(x, y, z);
shading interp; % Comment out to disable colour interpolation
colormap jet;
% Setup colorbar
c = colorbar();
set(c, 'YTick', [0.75 0.875 1]); % In this example, just use three ticks for illustation
ylim(c, [0.75 1]);
It is only necessary to do this once, after you've finished plotting.
Edit: If you need the limits and ticks automatically from the data, then you can do something like
% Find the limits
lims = [min(z(:)) max(z(:))];
% Function for rounding to specified decimal places
dprnd = #(x, dps)round(x*(10.^dps))./(10.^dps);
% Generate ticks
nTicks = 5;
nDps = 2;
ticks = dprnd(linspace(lims(1), lims(2), nTicks), nDps);
set(c, 'YTick', ticks);
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
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?