Related
A = [239920.240412166 1.31193313030682;
243577.444235102 1.38185205485119;
241899.250050298 1.51264147493485;
244659.326936560 1.50845243215867;
239862.361809342 1.50810833389632;
238395.616682194 1.37125000688350;
244558.389789124 1.27212093329482;
244290.890880318 1.35116080948488;
240303.711239396 1.36064181572699;
237464.430450140 1.48857869573721;
244415.381196104 1.51252425335623;
239855.328594799 1.29178640586301;
239304.806448742 1.31075813783171;
244827.243024016 1.32080934043223;
241465.885648910 1.53667019314427;
241139.254464482 1.40424079027764;
242300.037630214 1.27160249886092;
243330.396959248 1.61411410292679;
237530.389940994 1.21846939260826];
B = [0.6 0.18; 0.15 0.46]; % green circles
for i=1:2
plot(A(:,1),A(:,2),'r*');
hold on
plot(B(i,1),B(i,2), '-ko',...
'LineWidth',1,...
'MarkerFaceColor',[.49 1 .63],...
'MarkerSize',9);
end
When I ploted A and B, I got this:
B(1,1) = 0.6, but it appears in 0 (X-axis). Same with B(2,1) = 0.15
How to correct this?
A logarithmic scale on the xaxis will help with the view
set(gca, 'XScale', 'log')
However, it will lead to the fact, that now the values of A appear to populate one vertical line.
If you cannot live with this, you may want to try a broken x-axis. MATLAB doesn't support this with build-in functions, but there is a solution in the MATLAB file exchange
https://de.mathworks.com/matlabcentral/fileexchange/3683-breakxaxis
Btw: There is no need for the loop in your code. In fact you plot A twice on top of each other. Just
% Plot A and B without loop
plot(A(:,1), A(:,2),'r*')
hold on
plot(B(:,1), B(:,2), '-ko', 'LineWidth', 1, ...
'MarkerFaceColor', [.49 1 .63], 'MarkerSize',9)
% Set x axis to logarithmic scale
set(gca, 'XScale', 'log')
is sufficient to display your plot
Your x-axis goes from 0 to 250000. On that range, 0.6 and 0.15 are practically 0.
If you want you can use logarithmic scale in x-axis using semilogx
I have created an example scatter plot with five points in MATLAB as follows:
x = linspace(0,pi,5);
y = cos(x);
scatter(x,y);
In my case, the y-value of each point shall be in a predefined range defined as follows:
y_limits = {[0.9 1.1], [0.6 0.8], [-0.1 0.1], [-0.8 -0.6], [-1.1 -0.9]};
So for example, the y value of point 1 at x = 0 shall be in the range [0.9 1.1].
I would somehow like to draw five vertical boundaries nicely in the same plot perhaps by means of
five vertical lines with endpoints at the respective two limits
five filled vertical areas between the respective two limits
something else that may be more appropriate
I would like to get some suggestions or sample code of people who are more experienced than me in such kind of graphical representations.
You can do this in one line by using the errorbar function
% Your example variables
x = linspace(0,pi,5)';
y = cos(x);
y_limits = [0.9, 1.1; 0.6, 0.8; -0.1, 0.1; -0.8, -0.6; -1.1, -0.9];
% Plot
errorbar(x, y, y - y_limits(:,1), y_limits(:,2) - y, 'x');
% Format: (x, y, negative error, positive error, point style)
Result:
Edit, you can set the line properties of the plot as you call errorbar. For example, you could use larger, blue circle markers with thicker, red error bars
using:
errorbar(x, y, y - y_limits(:,1), y_limits(:,2) - y, 'o', 'MarkerSize', 2, 'MarkerFaceColor', 'b', 'MarkerEdgeColor', 'b', 'Color', 'r', 'LineWidth', 1);
Note for these images I'm using grid on to add the grid. Second result:
Creating a lines is done with the line command.
for i = 1:length(x)
line([x(i) x(i)], [y_limits{i}]);
end
Filled areas can be done with patch or fill. Some reordering of the limits is necessary so that the order given follows a path around the area to be filled. One nice trick is to use the alpha command on those filled areas to create transparency.
hold on
y_corners = reshape([y_limits{:}], 2, length(x)).'; %make an array
y_corners = [y_corners(:,1); flipud(y_corners(:,2))]; %corners follow a path around the shape
fill([x fliplr(x)], y_corners, 'blue');
alpha(0.5);
I want to visualize the peaks of a function, and I want to have markers for it appear above the line they are associated with.
I fabricated a minimum example where I already have the peaks, the question is just how to visualize the markers correctly:
y = [0.1 0.3 10.0 1.0 0.5 0.1 24.0 0.6 0.1 0.2]
x = (1:length(y))
plot(x,y);
hold on;
peaks = [3 7];
plot(x(peaks), y(peaks), 'v', 'MarkerSize', 24);
print('-dpng', 'example.png', '-S640,480');
So, as a result, the markers appear centered on the line like this:
The result that I want could be achieved by carefully tuning a parameter OFFSET like this:
plot(x(peaks), y(peaks)+OFFSET, 'v', 'MarkerSize', 24);
As shown in the following figure, for this exact example OFFSET=2.56 works for the exported png, but with the interactive plot and exporting vector graphics, it's wrong again.
Can anyone recommend a way to get this result without having to manually doing trial/error?
Currently I am using Octave with gnuplot to export to latex+tikz, and it would be good if the solution would work there.
In my actual (more complicated) use case I am plotting multiple lines after each other into the same figure, and the y limits change, so the offsets can not just be calculated easily, as the markersize doesn't change with the y limits.
Edit: Additionally I am using a semilogx plot, so drawing lines inside the diagram in the x/y-Axis scales would look distorted.
One way to do this is with annotations, but there are some drawbacks (see below).
Annotations enable you to place various graphic objects into your figure. One very annoying thing about them is that they work in so-called normalized coordinates,
which span the whole figure window (not just the plot area) and go from [0,0] to [1,1], forcing you to convert to these coordinates first. I wrote a simple function to do this, provided your plot scale is linear (if you want logarithmic, you will have to modify this function):
## Convert from data coordinates to normalized figure coordinates.
function [xf yf] = figcoords(xa, ya)
axp = get(gca, "position");
lf = axp(1);
bf = axp(2);
rf = lf + axp(3);
tf = bf + axp(4);
xl = xlim();
yl = ylim();
la = xl(1);
ra = xl(2);
ba = yl(1);
ta = yl(2);
xf = lf + (xa-la).*(rf-lf)./(ra-la);
yf = bf + (ya-ba).*(tf-bf)./(ta-ba);
endfunction
With this out of your way, you can proceed to annotating the plot using the annotation function:
y = [0.1 0.3 10.0 1.0 0.5 0.1 24.0 0.6 0.1 0.2];
x = (1:length(y));
peaks = [3 7];
## Plot the data as you would normally
plot(x,y);
## Plot peak markers (no `hold on` needed)
[xp yp] = figcoords(peaks, y(peaks)); # Transform to figure coordinates
for coords = [xp; yp]
xpi = coords(1);
ypi = coords(2);
annotation("arrow", [xpi xpi], [ypi+eps ypi]);
endfor
Plot with annotated peaks
Here, we actually draw little arrows pointing from top onto the peaks.
As their height is very small, we only see the arrowheads.
The arguments to the annotation function are the x and y coordinates
of the endpoints of the arrow. Note that we added a small number (eps)
to the y-value of the starting point to make the arrow point downward.
If you want, you can tweak the appearance of the markers to make them more visually appealing:
y = [0.1 0.3 10.0 1.0 0.5 0.1 24.0 0.6 0.1 0.2];
x = (1:length(y));
peaks = [3 7];
coloridx = get(gca, "ColorOrderIndex")
peakcolor = get(gca, "ColorOrder")(coloridx,:); # Save current plot colour
plot(x,y);
## Plot peak markers
[xp yp] = figcoords(peaks, y(peaks));
for coords = [xp; yp]
xpi = coords(1);
ypi = coords(2);
annotation("arrow", [xpi xpi], [ypi+eps ypi], "headstyle", "plain",...
"color", peakcolor);
endfor
Plot with annotated peaks in the same color
Drawbacks
While this approach works fine regardless of the size of the markers or your plot, there are some drawbacks:
First, the annotations are fixed relative to the figure window, not the plot.
This is fine when you display the plot for the first time, but once you zoom
or pan, the alignment is lost: The markes stay in place while the plot moves.
If you don't need an interactive plot (eg, you just want to export it to image),
just be sure to set the plot limits before adding the annotations and you should
be fine.
Second, this method is very slow compared to plotting the points using the
plot function. On my computer, for example, when drawing a simple example with
seven annotated peaks, it takes about a second before the markers appear.
Plotting a signal with thousands of peaks is near impossible.
Concerning the Matlab part, you could draw the peak markers yourself. Somewhere along these lines (extending your example):
y = [0.1 0.3 10.0 1.0 0.5 0.1 24.0 0.6 0.1 0.2]
x = (1:length(y))
figure, plot(x,y);
leglengthx=0.2;
leglengthy=0.5;
hold on;
peaks = [3 7];
peaks_max=[10 24];
for ii=1:2
line([peaks(ii) peaks(ii)+leglengthx],[peaks_max(ii) peaks_max(ii)+leglengthy]);
line([peaks(ii) peaks(ii)-leglengthx],[peaks_max(ii) peaks_max(ii)+leglengthy]);
line([peaks(ii)-leglengthx peaks(ii)+leglengthx],[peaks_max(ii)+leglengthy peaks_max(ii)+leglengthy]);
end
plot(x(peaks), y(peaks), 'v', 'MarkerSize', 24);
I have added the maxima of the peaks, which should not be an issue to automatically extract and two variables that control the triangle size of the marker. And then its just drawing three lines for every peak.
I don't know how this will translate to Octave.
What about drawing the little triangles?
y = [0.1 0.3 10.0 1.0 0.5 0.1 24.0 0.6 0.1 0.2];
x = (1:length(y));
peaks = [3 7];
plot(x,y);
hold on; line([peaks(1) peaks(1)+0.2], [y(x==peaks(1)) y(x==peaks(1))+1], 'color','b')
hold on; line([peaks(1) peaks(1)-0.2], [y(x==peaks(1)) y(x==peaks(1))+1], 'color','b')
hold on; line([peaks(1)+0.2 peaks(1)-0.2], [y(x==peaks(1))+1 y(x==peaks(1))+1], 'color','b')
hold on; line([peaks(2) peaks(2)+0.2], [y(x==peaks(2)) y(x==peaks(2))+1], 'color','b')
hold on; line([peaks(2) peaks(2)-0.2], [y(x==peaks(2)) y(x==peaks(2))+1], 'color','b')
hold on; line([peaks(2)+0.2 peaks(2)-0.2], [y(x==peaks(2))+1 y(x==peaks(2))+1], 'color','b')
There can be a problem if the y-values of the peaks exists in other locations on the vector. If so, you can specify first or other matching specs for the find function.
Environment: Windows 7 64 bit, Matlab 2014a
Objective:
To draw a heatmap of errors for two parameters to be optimized.
To put proper tick marks and tick values
Draw the grid lines in the correct place
Problem: Arranging the X and Y tick positions and values. When the last ("end") value of the vectors in x and y axes are the same, the code I use puts the ticks and values properly. However, when the end values are different it does not, and produces something really weird.
Below I have included the code which I have modified so that you can run it without the need of adding anything. Of course in my case the error vector are the error values, not random numbers. To see the problem of "end value" use the second b vector.
fontsize = 20
k = [2^-5, 2^-3, 2^-1, 2^0, 2^1, 2^3, 2^5, 2^7, 2^9, 2^11, 2^13, 2^15]
b = [2^-5, 2^-3, 2^-1, 2^0, 2^1, 2^3, 2^5, 2^7, 2^8, 2^9, 2^10, 2^11, 2^13, 2^15]
% b = [2^-5, 2^-3, 2^-1, 2^0, 2^1, 2^3, 2^5, 2^7, 2^8, 2^9, 2^10, 2^11, 2^13, 2^19]
errorVector = randi(20, 1, length(b)*length(k))'
figure
% Create a matrix from error vector (size of error vector is [length(k)*length(b),1])
B = reshape(errorVector, [length(b), length(k)])
B = flipud(B)
% imagesc(x,y,C)
imagesc(b, k, B)
title('Heatmap Parameters Percent Error', 'FontSize', fontsize);
% Set colorbar limits
caxis([0 15])
colorbar;
ax1 = gca;
xTickLabel = (k)'
xTick = linspace(k(1), k(end), numel(xTickLabel))';
set(ax1, 'XTick', xTick, 'XTickLabel', xTickLabel)
xlabel('k parameter', 'FontSize', fontsize)
yTickLabel = (b)'
yTick = linspace(b(1), b(end), numel(yTickLabel))';
set(ax1, 'YTick', yTick, 'YTickLabel', flipud(yTickLabel(:)))
ylabel('b parameter', 'FontSize', fontsize)
set(ax1,'FontSize', fontsize)
Here, change any of the end values of b or k vectors, and the program will output a graph where the X and Y ticks are totally wrong.
Also, I would like to draw grid lines. When I use "grid on" it draws grid lines right on the tick marks which is not correct in the case of heatmap. Because tick marks will be in the center of the columns -or rows- but the grid lines should be at the boundaries between the columns -or rows.
By the way if you know a better way to plot a heatmap in Matlab, please do tell.
Please help me solve this problem. Any help is appreciated,
Ilyas
First of all - you don't need to flipud the B matrix - by default imagesc plots the y-data inversed, but you can fix this with the following statement:
set(gca,'ydir','normal');
This also means you don't have to mess around with flipping the tick-labels. You can get the labels right by doing the following:
% replace the imagesc call with:
imagesc(B);
set(gca,'ydir','normal');
% formatting stuff
...
% replace the set commands with:
set(ax1, 'XTick', 1:length(k), 'XTickLabel', k)
set(ax1, 'YTick', 1:length(b), 'YTickLabel', b)
By default, if you don't provide x and y data to the imagesc command, it will number them linearly (1,2,3...). Basically what we've done here is make sure that it has ticks for each of the elements of b and k, and then set the labels to the values of the respective vectors.
Unfortunately, I'm not sure if there is a way to get the grid spacing right with imagesc or not. You could try using pcolor instead, which has it's own set of issues, but allows you to get grid lines (of sorts) between the elements. It also allows you to use an interpolated shading mode, which will make your plot look more like a typical heat map.
To use pcolor instead, you just have to replace imagesc:
% imagesc(B);
% set(gca,'ydir','normal');
pcolor(B);
% this uses a smoother shading method, for a more 'heatmap' like output
% shading interp
Everything else should work as intended, I believe.
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);