generate rectangle annotation in the current figure - matlab

I would like to insert a rectangle into my matlab figure to highlight a specific region:
x = [0 1 2 2 3 4 5 6 7 8 9 10];
y = [0 1 2 4 3 4 5 6 7 8 9 10];
fh = figure(1);
plot(x,y)
xlim([0 10]);
ylim([0 10]);
I can do this by using the annotation function and defining the left bottom width height of the rectangle.
I am wondering, however, can this be done according to the x and y values from the figure in question? For the example shown, for example I would like to draw a rectangle from x = 1.5 y = 1.5 with a height of 3 and a width of two. This is my attempt:
% define location of lbwh in terms of x and y values
l = 1.5;
b = 1.5;
w = 2;
h = 3;
% convert factor of 1
xx = xlim;
l = l./xx(2);
b = b./xx(2);
w = w./xx(2);
h = h./xx(2);
annotation('rectangle','position',[l,b,w,h]);
The problem is that the position I'm providing is in terms of the (0,0) position in the plot and not the bottom left hand of the figure window. how can I correct this?

One way would be to just create a rectangle from line graphs:
plot([l,l,l+w,l+w,l],[b,b+h,b+h,b,b], 'r', 'LineWidth', 2)

Related

How do i zoom in around specific locations in an image?

I have the image:
img = [1 1 1 3 3 3 3 3 3;
1 1 1 3 3 3 3 3 3;
1 1 1 3 3 3 3 3 3;
1 1 2 3 3 3 3 3 3;
1 1 2 2 2 2 2 1 1;
1 2 2 2 2 2 1 1 1;
1 2 2 2 2 1 1 1 1];
Assuming I am interested in seeing finer details around the specific locations with:
Indx = [18; 47];
of coordinates:
rows = [4; 5] and cols = [3; 7]
I understand the “zoom on/off” allows one to zoom interactively by pressing the mouse button. Rather than this manual method however, is there a way to programmatically ask matlab to zoom around - say the 3x3 neighbourhood of these locations (or more)? Whenever ‘imshow’ is called?
Please I need help/advice/suggestions on this. Many thanks in anticipation.
It might be an "overkill", but you can use imwarp function:
imwarp allows zooming with displacement (and more).
Assume:
(center_x, center_y) is your point of interest.
Output image (after zoom) is same as input image size.
Point of interest should be at the center of the image after zoom.
I drawn a cross at the point of interest for testing.
I used 'peppers.png' image for demonstration.
Here is my code sample:
I = imread('peppers.png');
w = size(I, 2); %Image width
h = size(I, 1); %Image height
zoom = 4; %Zoom factor x4
%Point of interest.
center_x = w/2 - 80;
center_y = h/2 - 50;
%Draw center cross for testing (thickness is 2 pixels):
I(center_y-1:center_y, center_x-5:center_x+4, :) = 255;
I(center_y-5:center_y+4, center_x-1:center_x, :) = 255;
figure;imshow(I);
%Compute displacement:
x0 = w/2 - zoom*center_x;
y0 = h/2 - zoom*center_y;
%Build transformation matrix T.
T = [zoom 0 0; ...
0 zoom 0; ...
x0 y0 1];
tform = affine2d(T); %Needed by imwarp
%J = imwarp(I, tform, 'OutputView', imref2d(size(I)), 'Interp', 'nearest'); %Select nearest interpolation.
%Apply transformation (dimensions of J will be the same as I).
J = imwarp(I, tform, 'OutputView', imref2d(size(I)), 'Interp', 'cubic'); %Select cubic interpolation.
figure;imshow(J);
Input image (pay attention to the small cross):
Output image:
There is a piece of code which gives you the pixel location of the point you clicked. You can effectively use this code:
function [loc] = get_image_point (I)
figure('name','Doubleclick to set location');imshow(I);
[c r] = getpts(1);
loc = int32([c r]);
if size(loc)>1
loc = [loc(1,1) loc(1,2)];
end
close all;
end
Having that pixel location, you can create a figure with the specified dimensions, let say you double click pixel position (x,y) in image. Then, you can simply say figure('Position', [0 0 screenWidth screenHeight]), imshow(image(x-x1:x+x1, y-y1:y+y1)). Make sure that x+-x1 and y+-y1 are within the range.

How to include Annotate extends ... in this MATLAB findpeaks?

I have minimums and maximums in the output now (Fig.1) but I would like to get labels (Fig. 2) for sorted maximums (tallest get 1, ...) and similarly for minimums (lowest gets 1).
I can do the output of Fig. 1 by the following but I cannot integrate those annotations to the function
close all; clear all; clc;
% https://se.mathworks.com/help/signal/ref/findpeaks.html
% http://stackoverflow.com/a/26837689/54964
x = linspace(0,1,1000);
Pos = [1 2 3 5 7 8]/10;
Hgt = [4 4 2 2 2 3];
Wdt = [3 8 4 3 4 6]/100;
for n = 1:length(Pos)
Gauss(n,:) = Hgt(n)*exp(-((x - Pos(n))/Wdt(n)).^2);
end
PeakSig = sum(Gauss) - exp(sum(Gauss))/10;
plot(x, PeakSig);
hold on;
[p l]=findpeaks(PeakSig); %,x); %,'Annotate','extents','WidthReference','halfheight')
plot(x(l), p, 'ko', 'MarkerFaceColor', 'g');
[pn ln]=findpeaks(-PeakSig); %,x); %,'Annotate','extents','WidthReference','halfheight')
plot(x(ln), -pn, 'ko', 'MarkerFaceColor', 'r');
title('Signal Peak Widths')
To just append 'Annotate','extents','WidthReference','halfheight') to [p l]=findpeaks(...) is not working in the application etc the following apparently because the proceeding line plot(x(l), p, 'ko', 'MarkerFaceColor', 'g'); does not understand the extra content made by the one-liner in the corresponding variables
[p l]=findpeaks(PeakSig,'Annotate','extents','WidthReference','halfheight')
[p l]=findpeaks(PeakSig, x, 'Annotate','extents','WidthReference','halfheight')
Fig. 1 Current output without those annotations,
Fig. 2 Expected output but with notes of maximums and minimums
MATLAB: 2016b
OS: Debian 8.5 64 bit
Hardware: Asus Zenbook UX303UA
Here is one way to to this:
x = linspace(0,1,1000);
Pos = [1 2 3 5 7 8]/10;
Hgt = [4 4 2 2 2 3];
Wdt = [3 8 4 3 4 6]/100;
Gauss = zeros(numel(Pos),numel(x));
for n = 1:numel(Pos)
Gauss(n,:) = Hgt(n)*exp(-((x - Pos(n))/Wdt(n)).^2);
end
PeakSig = sum(Gauss) - exp(sum(Gauss))/10;
% get the peaks:
[p,xmax] = findpeaks(PeakSig,x);
maxsrt = sortrows([xmax;p].',-2);
[pn,xmin] = findpeaks(-PeakSig,x);
minsrt = sortrows([xmin;-pn].',2);
% plotting:
blue = [0 0.447 0.741];
plot(x,PeakSig,xmax,p+0.2,'v','MarkerFaceColor',blue,'MarkerEdgeColor',blue);
% you can comment the line above and uncomment the line below, if you
% prefer:
% findpeaks(PeakSig,x,'Annotate','peaks');
text(maxsrt(:,1),maxsrt(:,2)+0.2,num2str((1:numel(p)).'),'FontSize',14,...
'VerticalAlignment','bottom','HorizontalAlignment','center')
ylim([-10 3]);
grid on
hold on
plot(xmin,-pn-0.2,'^','MarkerFaceColor',blue,'MarkerEdgeColor',blue);
hold off
text(minsrt(:,1),minsrt(:,2)-0.2,num2str((1:numel(pn)).'),'FontSize',14,...
'VerticalAlignment','top','HorizontalAlignment','center')
title('Signal Peak Widths')
And here is another way to do this, using gscatter. Instead of calling plot twice (and maybe more if other annotations are needed), you concat all the positions (x-y) and type of annotations to one array (pks bellow), and plot them all at once by thier type (i.e. group) with gscatter:
x = linspace(0,1,1000);
Pos = [1 2 3 5 7 8]/10;
Hgt = [4 4 2 2 2 3];
Wdt = [3 8 4 3 4 6]/100;
Gauss = zeros(numel(Pos),numel(x));
for n = 1:numel(Pos)
Gauss(n,:) = Hgt(n)*exp(-((x - Pos(n))/Wdt(n)).^2);
end
PeakSig = sum(Gauss) - exp(sum(Gauss))/10;
% get the peaks:
[p,xmax] = findpeaks(PeakSig,x);
maxsrt = sortrows([xmax;p].',-2);
[pn,xmin] = findpeaks(-PeakSig,x);
minsrt = sortrows([xmin;-pn].',2);
% plotting:
pks = [[xmin xmax];[-pn-0.2 p+0.2];[zeros(1,numel(pn)) ones(1,numel(p))]].';
blue = [0 0.447 0.741];
ax = axes;
plot(ax,x,PeakSig)
hold on
gscatter(pks(:,1),pks(:,2),pks(:,3),blue,'^v')
hold off
ax.Children(1).MarkerFaceColor = blue;
ax.Children(2).MarkerFaceColor = blue;
text(maxsrt(:,1),maxsrt(:,2)+0.2,num2str((1:numel(p)).'),'FontSize',14,...
'VerticalAlignment','bottom','HorizontalAlignment','center')
text(minsrt(:,1),minsrt(:,2)-0.2,num2str((1:numel(pn)).'),'FontSize',14,...
'VerticalAlignment','top','HorizontalAlignment','center')
ylim([-10 3]);
legend off
grid on
title('Signal Peak Widths')
the result is exactly the same, but this is more short and maybe more elegant.

how to add data labels for bar graph in matlab

For example (code):
x = [3 6 2 9 5 1];
bar(x)
for this I need to add data labels on top of the each bar.
I know that I have to use TEXT keyword, but I'm not getting how to implement it.
Here is a simple solution with text:
x = [3 6 2 9 5 1];
bar(x)
ylim([0 max(x)*1.2])
text(1:numel(x),x+0.5,num2cell(x))
Based off this answer:
data = [3 6 2 9 5 1];
figure; %// Create new figure
hbar = bar(data); %// Create bar plot
%// Get the data for all the bars that were plotted
x = get(hbar,'XData');
y = get(hbar,'YData');
ygap = 0.1; %// Specify vertical gap between the bar and label
ylimits = get(gca,'YLim');
%// The following two lines have minor tweaks from the original answer
set(gca,'YLim',[ylimits(1),ylimits(2)+0.2*max(y)]);
labels = cellstr(num2str(data')) %//'
for i = 1:length(x) %// Loop over each bar
xpos = x(i); %// Set x position for the text label
ypos = y(i) + ygap; %// Set y position, including gap
htext = text(xpos,ypos,labels{i}); %// Add text label
set(htext,'VerticalAlignment','bottom', 'HorizontalAlignment','center')
end
After some attempts I have found the solution. Do the following:
y = Data;
for b = 1 : 10
BarPlot(b) = bar(b, y(b), 'BarWidth', 0.9); % actual plot
set(BarPlot(b), 'FaceColor', 'blue'); %Apply color
barTopper = sprintf('%.1f%s', y(b)*100,'%'); % Place text on top
text(b-0.5, y(b)+0.01, barTopper, 'FontSize', barFontSize); % position the text
hold on;
end
Let me know if it works.

How to colorize individual bar in matlab? [duplicate]

I would like to draw a 3D histogram (with gnuplot or octave) in order to represent my data.
lets say that I have a data file in the following form:
2 3 4
8 4 10
5 6 7
I'd like to draw nine colored bars (the size of the matrix), in the set [1,3]x[1,3], such that the bar's color is proportional to the bar's height. How can I do this?
Below is a function I implemented that acts as a bar3 replacement (partially).
In my version, the bars are rendered by creating a patch graphics object: we build a matrix of vertex coordinates and a list of faces connecting those vertices.
The idea is to first build a single "3d cube" as a template, then replicate it for as many bars as we have. Each bar is shifted and scaled according to its position and height.
The vertices/faces matrices are constructed in a vectorized manner (look ma, no loops!), and the result is a single patch object drawn for all bars, as opposed to multiple patches one per bar (this is more efficient in terms of graphics performance).
The function could have been implemented by specifying coordinates of connected vertices that form polygons, by using the XData, YData, ZData and CData properties instead of the Vertices and Faces properties. In fact this is what bar3 internally does. Such approach usually requires larger data to define the patches (because we cant have shared points across patch faces, although I didn't care much about that in my implementation). Here is a related post where I tried to explain the structure of the data constructed by bar3.
my_bar3.m
function pp = my_bar3(M, width)
% MY_BAR3 3D bar graph.
%
% M - 2D matrix
% width - bar width (1 means no separation between bars)
%
% See also: bar3, hist3
%% construct patch
if nargin < 2, width = 0.8; end
assert(ismatrix(M), 'Matrix expected.')
% size of matrix
[ny,nx] = size(M);
% first we build a "template" column-bar (8 vertices and 6 faces)
% (bar is initially centered at position (1,1) with width=? and height=1)
hw = width / 2; % half width
[X,Y,Z] = ndgrid([1-hw 1+hw], [1-hw 1+hw], [0 1]);
v = [X(:) Y(:) Z(:)];
f = [
1 2 4 3 ; % bottom
5 6 8 7 ; % top
1 2 6 5 ; % front
3 4 8 7 ; % back
1 5 7 3 ; % left
2 6 8 4 % right
];
% replicate vertices of "template" to form nx*ny bars
[offsetX,offsetY] = meshgrid(0:nx-1,0:ny-1);
offset = [offsetX(:) offsetY(:)]; offset(:,3) = 0;
v = bsxfun(#plus, v, permute(offset,[3 2 1]));
v = reshape(permute(v,[2 1 3]), 3,[]).';
% adjust bar heights to be equal to matrix values
v(:,3) = v(:,3) .* kron(M(:), ones(8,1));
% replicate faces of "template" to form nx*ny bars
increments = 0:8:8*(nx*ny-1);
f = bsxfun(#plus, f, permute(increments,[1 3 2]));
f = reshape(permute(f,[2 1 3]), 4,[]).';
%% plot
% prepare plot
if exist('OCTAVE_VERSION','builtin') > 0
% If running Octave, select OpenGL backend, gnuplot wont work
graphics_toolkit('fltk');
hax = gca;
else
hax = newplot();
set(ancestor(hax,'figure'), 'Renderer','opengl')
end
% draw patch specified by faces/vertices
% (we use a solid color for all faces)
p = patch('Faces',f, 'Vertices',v, ...
'FaceColor',[0.75 0.85 0.95], 'EdgeColor','k', 'Parent',hax);
view(hax,3); grid(hax,'on');
set(hax, 'XTick',1:nx, 'YTick',1:ny, 'Box','off', 'YDir','reverse', ...
'PlotBoxAspectRatio',[1 1 (sqrt(5)-1)/2]) % 1/GR (GR: golden ratio)
% return handle to patch object if requested
if nargout > 0
pp = p;
end
end
Here is an example to compare it against the builtin bar3 function in MATLAB:
subplot(121), bar3(magic(7)), axis tight
subplot(122), my_bar3(magic(7)), axis tight
Note that I chose to color all the bars in a single solid color (similar to the output of the hist3 function), while MATLAB emphasizes the columns of the matrix with matching colors.
It is easy to customize the patch though; Here is an example to match bar3 coloring mode by using indexed color mapping (scaled):
M = membrane(1); M = M(1:3:end,1:3:end);
h = my_bar3(M, 1.0);
% 6 faces per bar
fvcd = kron((1:numel(M))', ones(6,1));
set(h, 'FaceVertexCData',fvcd, 'FaceColor','flat', 'CDataMapping','scaled')
colormap hsv; axis tight; view(50,25)
set(h, 'FaceAlpha',0.85) % semi-transparent bars
Or say you wanted to color the bars using gradient according to their heights:
M = 9^2 - spiral(9);
h = my_bar3(M, 0.8);
% use Z-coordinates as vertex colors (indexed color mapping)
v = get(h, 'Vertices');
fvcd = v(:,3);
set(h, 'FaceVertexCData',fvcd, 'FaceColor','interp')
axis tight vis3d; daspect([1 1 10]); view(-40,20)
set(h, 'EdgeColor','k', 'EdgeAlpha',0.1)
Note that in the last example, the "Renderer" property of the figure will affect the appearance of the gradients. In MATLAB, the 'OpenGL' renderer will interpolate colors along the RGB colorspace, whereas the other two renderers ('Painters' and 'ZBuffer') will interpolate across the colors of the current colormap used (so the histogram bars would look like mini colorbars going through the jet palette, as opposed to a gradient from blue at the base to whatever the color is at the defined height as shown above). See this post for more details.
I've tested the function in Octave 3.6.4 and 3.8.1 both running on Windows, and it worked fine. If you run the examples I showed above, you'll find that some of the advanced 3D features are not yet implemented correctly in Octave (this includes transparency, lighting, and such..). Also I've used functions not available in Octave like membrane and spiral to build sample matrices, but those are not essential to the code, just replace them with your own data :)
Solution using only functions available in OCTAVE, tested with octave-online
This solution generates a surface in a similar way to the internals of Matlabs hist3d function.
In brief:
creates a surface with 4 points with the "height" of each
value, which are plotted at each bin edge.
Each is surrounded by zeros, which are also plotted at each bin edge.
The colour is set to be based on the bin values and is applied to
the 4 points and the surrounding zeros. (so that the edges and tops of the 'bars' are coloured to match the "height".)
For data given as a matrix containing bin heights (bin_values in the code):
Code
bin_values=rand(5,4); %some random data
bin_edges_x=[0:size(bin_values,2)];
x=kron(bin_edges_x,ones(1,5));
x=x(4:end-2);
bin_edges_y=[0:size(bin_values,1)];
y=kron(bin_edges_y,ones(1,5));
y=y(4:end-2);
mask_z=[0,0,0,0,0;0,1,1,0,0;0,1,1,0,0;0,0,0,0,0;0,0,0,0,0];
mask_c=ones(5);
z=kron(bin_values,mask_z);
c=kron(bin_values,mask_c);
surf(x,y,z,c)
Output
I don't have access to Octave, butI believe this should do the trick:
Z = [2 3 4
8 4 10
5 6 7];
[H W] = size(Z);
h = zeros( 1, numel(Z) );
ih = 1;
for ix = 1:W
fx = ix-.45;
tx = ix+.45;
for iy = 1:W
fy = iy-.45;
ty = iy+.45;
vert = [ fx fy 0;...
fx ty 0;...
tx fy 0;...
tx ty 0;...
fx fy Z(iy,ix);...
fx ty Z(iy,ix);...
tx fy Z(iy,ix);...
tx ty Z(iy,ix)];
faces = [ 1 3 5;...
5 3 7;...
7 3 4;...
7 8 4;...
5 6 7;...
6 7 8;...
1 2 5;...
5 6 2;...
2 4 8;...
2 6 8];
h(ih) = patch( 'faces', faces, 'vertices', vert, 'FaceVertexCData', Z(iy,ix),...
'FaceColor', 'flat', 'EdgeColor','none' );
ih = ih+1;
end
end
view( 60, 45 );
colorbar;
I think the following should do the trick. I didn't use anything more sophisticated than colormap, surf and patch, which to my knowledge should all work as-is in Octave.
The code:
%# Your data
Z = [2 3 4
8 4 10
5 6 7];
%# the "nominal" bar (adjusted from cylinder())
n = 4;
r = [0.5; 0.5];
m = length(r);
theta = (0:n)/n*2*pi + pi/4;
sintheta = sin(theta); sintheta(end) = sqrt(2)/2;
x0 = r * cos(theta);
y0 = r * sintheta;
z0 = (0:m-1)'/(m-1) * ones(1,n+1);
%# get data for current colormap
map = colormap;
Mz = max(Z(:));
mz = min(Z(:));
% Each "bar" is 1 surf and 1 patch
for ii = 1:size(Z,1)
for jj = 1:size(Z,2)
% Get color (linear interpolation through current colormap)
cI = (Z(ii,jj)-mz)*(size(map,1)-1)/(Mz-mz) + 1;
fC = floor(cI);
cC = ceil(cI);
color = map(fC,:) + (map(cC,:) - map(fC,:)) * (cI-fC);
% Translate and rescale the nominal bar
x = x0+ii;
y = y0+jj;
z = z0*Z(ii,jj);
% Draw the bar
surf(x,y,z, 'Facecolor', color)
patch(x(end,:), y(end,:), z(end,:), color)
end
end
Result:
How I generate the "nominal bar" is based on code from MATLAB's cylinder(). One cool thing about that is you can very easily make much more funky-looking bars:
This was generated by changing
n = 4;
r = [0.5; 0.5];
into
n = 8;
r = [0.5; 0.45; 0.2; 0.1; 0.2; 0.45; 0.5];
Have you looked at this tutorial on bar3?
Adapting it slightly:
Z=[2 3 4
8 4 10
5 6 7]; % input data
figure;
h = bar3(Z); % get handle to graphics
for k=1:numel(h),
z=get(h(k),'ZData'); % old data - need for its NaN pattern
nn = isnan(z);
nz = kron( Z(:,k),ones(6,4) ); % map color to height 6 faces per data point
nz(nn) = NaN; % used saved NaN pattern for transparent faces
set(h(k),'CData', nz); % set the new colors
end
colorbar;
And here's what you get at the end:

How can I fill patch objects using a colormap instead of a solid color?

I need to create a plot like in this image:
I wrote this code:
close all
x = [NaN 1 3 7 9 23 8];
y = [NaN 2 6 7 8 2 1];
z = [NaN 1 4 5 5 4 1];
for n = 1:length(z)-1
x1 = x(n);
x2 = x(n+1);
y1 = y(n);
y2 = y(n+1);
z1 = z(n);
z2 = z(n+1);
p = patch([x1 x2 x2 x1], [y1 y2 y2 y1], [0 0 z2 z1], [0 1 1]);
set(p, 'LineStyle', 'none');
plot3([x1 x2], [y1 y2], [z1 z2], 'b-', 'linewidth', 3);
hold on
end
view(3);
light
And I get this:
This is okay, but every patch face has a solid color, where I would like to have a color gradient based on the Z value, like in the first image where lowest z values are azure and highest z values are white (with a gradient from lowest to highest).
How can I modify my script to get this effect?
There are a number of ways to define your patches, and a number of ways to color them as well. Here's a way to create your coordinate data without a for loop and plot and color your patches with a single call to the function patch:
x = [NaN 1 3 7 9 23 8]; %# Sample x data
y = [NaN 2 6 7 8 2 1]; %# Sample y data
z = [NaN 1 4 5 5 4 1]; %# Sample z data
N = numel(x); %# The number of sample data points
X = [x; x([1 1],[N 1:N-1]); x]; %# X coordinates (one patch per column)
Y = [y; y([1 1],[N 1:N-1]); y]; %# Y coordinates (one patch per column)
Z = [z; z([N 1:N-1]); zeros(2,N)]; %# Z coordinates (one patch per column)
C = round(63.*Z./max(Z(:)))+1; %# Color map index
map = [linspace(0,1,64).' ... %'# Color map (64 values spanning from
ones(64,2)]; %# white to cyan)
figure(); %# Open a new figure
patch(X,Y,Z,C,'FaceColor','interp',... %# Plot the patches
'EdgeColor','none');
colormap(map); %# Update color map
hold on; %# Add to the plot
line(X(1:2,:),Y(1:2,:),Z(1:2,:),... %# Plot the line
'Color','b','LineWidth',2);
view(3); %# Change the view
And this will give you the following plot, with patches colored white at the highest values and fading to cyan at the lowest values:
Explanation of the indexed color mapping...
The variable map above is a 64-by-3 matrix of values between 0 and 1. Each row represents an RGB triplet, thus defining a unique color ranging from cyan in row 1 to white in row 64. This is used as the figure color map. The Face color data in C is a set of row indices into this color map, one for each value in Z. The lowest values in Z are mapped to an index of 1 (cyan in the color map) while the largest values are mapped to an index of 64 (white in the color map).