Matlab: how to set logarithmic scale on the coutour plot - matlab

I have some data that I want to display as contour plot with logarithmic scale of the values (the matrix Z) and labelled countours. This is how I do it:
[C, h1] = contourf(X, Y, log(Z));
clabel(C,h1);
Here is my result:
My question is: how can I get the right labels on the contours? I don't want a color bar as described here.
Edit: Here is my example:
X = 1:1:20;
Y = X;
Z = zeros(size(Y));
for i = 1:size(Y,2);
Z(i, :) = 10^i;
end
[C, h1] = contourf(X, Y, Z);
clabel(C,h1);
My true data looks like this:
I can set any countour lines labels I want, but they won't be visible since my data is exponential (And by the way, the labels that are visible in this plot, are the true ones, the ones I want to get on the next plot).
Now, since my data in exponential, I have to use the logarithmic scale on the displayed values (the matrix Z) to show the data properly. Here is how I do it (maybe there is another, better way, I don't know, I haven't found anything else):
[C, h1] = contourf(X, Y, log(Z));
clabel(C,h1);
Here is how my picture looks like:
And it looks well now - you can see how my data varies. However, the labels are wrong. I can now set them to any vector you like:
0:5:45 - and I'll get exactly what I have now.
10^[0:5:45] (these labels I'd like to have). But now my plotted data rang is (0, 45) (because I calculated the logarithm of it). So, most of the labels won't be shown (they exceed data range) and the one that will, will be misplaced.
Ideally, I'd like to be able to something like this:
[C, h1] = contourf(X, Y, Z, 'ZScale', 'Log');
clabel(C,h1);
and get the picture at the bottom with labels 10, 10^5, 10^10, etc.
Summing up, I need to do one of the following:
Find a way to set the logarithmic scale programmatically and let matlab worry about the isolines.
Be able to manually change the label on the isolines without moving them (new_label = 10^old_label).

A little 'Hack' that will work, although it will not be possible to keep the labels as nice as they are with a call to clabel(C,h1) :
The first step consists in calculating the values of the contour lines. You say you want them to be placed at 1,10,... and so on so you just need to find the first power of 10 bigger than the maximum of your data :
nextpow10Z=ceil(log10(max(Z(:))));
Now call contourf with the vector of contour line values :
[C,h1]=contourf(X,Y,log10(Z),1:nextpow10Z);
Now instead of calling clabel(C,h1);, we need to use another syntax of clabel that will allow us to loop trough the texts (The downgrade is that they'll be less pretty) :
tl=clabel(C);
Now if you go see the description of tl, you'll see that it's a Data object, containing Text and Line elements.
The next step consists in selecting all the elements of Type Text contained in tl :
TextElements=findobj(tl,'Type','Text');
Finally, The last step will be to loop over these and replace the numbers N with 1EN :
for i=1:length(TextElements)
TextElements(i).String=strcat('1E',TextElements(i).String);
end
And voila!

Related

Matlab Plot Legend Locating on Each Curve

I have a Matlab plot that contains relatively high amount of different data and hence if i use standard legend representation, i could not figure out which legend color belongs to which curve.
So, is there any way to put legends on each curve? Lets say "BUS7" text should be located on the purple curve (undermost one).
Thanks.
I am trying to do something like this:
The text(x, y, txt) function allows you to add text at a given location on the plot. link.
Looking at your example, it seems that you want to have all the labels on the left-hand side. So, one way to do it would be like this, where I have generated my own dummy data:
leg = {'First Curve', 'Second Curve', 'Third Curve'};
figure;
x = linspace(1,10,100);
for ii = 1:3
y = x + ii*10;
plot(x, y);
hold on
text(x(1), y(1)+2.5, leg{ii});
end
Regretfully, this does not do anything clever with where the label is placed - it is merely placed slightly above the first point of the curve. You can clearly easily move it along the curve, but if you have many curves, like in your case, the labels will likely overlap and you will need to tinker a bit to avoid this.

How to set x and y values when using bar3 in Matlab?

Quick version
How can I control the x- and y-values for a 3-d bar plot in Matlab?
Details
Say we have an 10 x 20 data matrix and we plot it using bar3, and we want to set the x- and y-values. For instance:
foodat = rand(10,20);
xVals = [5:14];
yVals = [-3:16];
bar3(xVals, foodat);
xlabel('x'); ylabel('y');
Is there a way to feed it the yVals as well? Otherwise the y axes always defaults to [1:N].
Note I don't just want to change the labels using XTickLabel and YTickLabel. I need to change the actual values on the axes, because I am plotting multiple things in the same figure. It isn't enough to just change how the (wrong) axis ticks are labeled. So this is different from issues like this:
How can I adjust 3-D bar grouping and y-axis labeling in MATLAB?
Other things I have tried
When I try changing the xvals with:
set(gca,'XTick', xVals)
set(gca,'YTick', yVals)
The values are taken in, but actually show up on the wrong axes, so it seems x and y axes are switched using bar3. Plus, it is too late anyway as the bar graph was already plotted with the wrong x- and y-values, so we would end up giving ticks to empty values.
Note added
Matlab tech support just emailed me to let me know about the user contributed function scatterbar3, which does what I want, in a different way than the accepted answer:
http://www.mathworks.com/matlabcentral/fileexchange/1420-scatterbar3
I found a way of doing it. Ill give you a piece of code, then you'll need to "tidy up" , mainly the axis limits and the Xticks, as bar3 does set up the Xticks inside, so if you want others you'll need to set them manually yourself.
So the trick here is to get the Xdata from the bar3 handle. The thing here is that it seems that there is a handle for each row of the data, so you need to iterate for each of them. Here is the code with the current output:
foodat = rand(20,10);
xVals = [5:14];
yVals = [-3:16];
% The values of Y are OK if called like this.
subplot(121)
bar3(yVals, foodat);
subplot(122)
h=bar3(yVals, foodat);
Xdat=get(h,'XData');
axis tight
% Widdth of barplots is 0.8
for ii=1:length(Xdat)
Xdat{ii}=Xdat{ii}+(min(xVals(:))-1)*ones(size(Xdat{ii}));
set(h(ii),'XData',Xdat{ii});
end
axis([(min(xVals(:))-0.5) (max(xVals(:))+0.5) min(yVals(:))-0.5, max(yVals(:))+0.5])
Note: Y looks different but is not.
As you can see now the X values are the ones you wanted. If you'd want other size than 1 for the intervals between them you'd need to change the code, but you can guess how probably!

horizontally shift starting point for stem() in MatLab

I have a sequence with data and an offset. I'm asked to plot a stem() graph of the data, starting at the offset. I have figured out the data part (the easy part) and how to change the window to include the offset, but when I plot the graph, it shows the offset with a value of zero and zeros until 1 where the sequence.data will start and plot points.
methods
function s = sequence(data, offset)
s.data = data;
s.offset = offset;
end
function stem(x)
% STEM Display a Matlab sequence, x, using a stem plot.
stem(x.offset,x.data);
axis([x.offset x.offset+length(x.data) 'auto' 'auto']);
end
I need to figure out how to "move" my x.data to my x.offset and start stem plotting there.
I don't understand why you simply can't add an x offset while keeping the y data the same?
For instance, given your example in your comments above:
x = 0:4;
y = 1:5;
This is what the original graph looks like, as well as shifting the graph to the left by 3 (-3):
stem(x,y,'b');
hold on;
stem(x-3,y,'r');
This is what I get:
The blue data is the original, while the red is the shifted instance to the left by 3. As you can see, the y data is the same, but the x points move to the left by 3. What your code is actually doing is that it does not shift the actual data. You are only changing the display range of your stem plot. As such, you should really be doing this:
methods
function s = sequence(data, offset)
s.data = data;
s.offset = offset;
end
function stem(x)
% STEM Display a Matlab sequence, x, using a stem plot.
%// First define sequence from [0,N-1]
vals = 0:numel(x.data)-1;
%// Now use the above and manually shift the x coordinate
stem(vals+x.offset,x.data);
end
I'm going to assume that your data on the x-axis starts counting at 0, and so we will declare a sequence from 0 up to N-1 where N is the total number of elements that you have. Once we declare this sequence, when it's time to draw the stem plot, we simply add an offset to this sequence and use this as the x data. The y data should stay the same.
However, I would argue that creating a custom class for implementing this addition to stem is less readable than what I originally did above. If this is a requirement for whatever you're developing, then certainly go ahead and do it this way, but I don't really think it's necessary.

Making an accurate colorbar for a simple plot

I am trying to make a simple plot (for this example doing a plot of y=x^2 will suffice) where I want to set the colors of the points based on their magnitude given some colormap.
Following along my simple example say I had:
x = 1:10;
y = x.^2;
Use gscatter(x,y,jet(10)); legend hide; colorbar which produces a plot with the points colored but the colorbar does not agree with the colored values. (Can't post picture as this is my first post). Using a caxis([1,100]) command gives the right range but the colors are still off.
So I have two questions:
(1) How can I fix the colors to fit to a colorbar given a range? In my real data, I am looking at values that range from -50 to 50 in some instances and have many more data points.
(2) I want to create a different plot with the same points (but on different axes) and I want the colors of each point on this new plot to have the same colors as their counterparts in the previous plot. How can I, programmatically, extract the color from each point so I can plot it on two different sets of axes?
I would just move the points into a matrix and do an imagesc() command but they aren't spaced as integers or equally so simple scaling wouldn't work either.
Thanks for any help!
Regarding you first question, you need to interpolate the y values into a linear index to the colormap. Something like:
x = 1:10;
y = x.^4;
csize = 128;
cmap = jet(csize);
ind = interp1(linspace(min(y),max(y),csize),1:csize,y,'nearest');
scatter(x,y,14,cmap(ind,:),'filled')
colorbar
caxis([min(y) max(y)])
Using interp1 in this case is an overkill; you could calculate it directly. However, I think in this way it is clearer.
I think it also answers your 2nd question, since you have the index of the color of each data point, so you can use it again in the same way.

Matlab: Detect peaks above a certain height on bar graph and label just above peak height

I am trying to add labels to a bar chart with many bars. The complicating factor is that I am doing this in a loop (for hundreds of bar-charts) and want to have Matlab do the labeling automatically. Essentially, I only want to label peaks with a height above a certain threshold. One thing which should hopefully make this easier is that I simply want to label the bar with it's x-value.
Here's an illustration of how I want the label placed:
If you still have access to the original data, and assuming you want to label each point that's above the threshold, you should be able to do this by:
loop over each (x, y) in data array for the chart
if y is bigger than the threshold
then call text(x, y, num2str(x))
If you want to label peaks that have consecutive values all above the threshold (like around maybe 115 on your image?) with a single label, you can add some slightly more complicated logic to group those peaks together...if that's what you want, we can help you figure that out.
As mentioned by #Dougal, the text function is what you want. However, there is no need to loop:
%# generate some data
y = poissrnd(5,20,1);
x = 1:20;
%# find where the data is above the threshold
bigIdx = y>6;
%# create a bar plot
bar(x,y)
%# add the text. The alignment setting ensures that the text
%# is directly above the bar. I add 1 here as an y-offset,
%# the ideal value may depend on your data
text(x(bigIdx),y(bigIdx)+1,num2str(x(bigIdx)),'horizontalAlignment','center')
%# you may need to make sure that the y-limit is high enough
%# so that the text is visible
ylim([0 max(y)+2])