How to label plot having peaks in matlab - matlab

I'm trying to label my XRD data which have peaks, and I want to label it from my array of data:
peak label
ab
ac
ad
cb
bb
ba
See picture below
I also want those labels to be vertically aligned on the top of the peaks.
I tried the findpeaks function but it doesn't work.

Try this (but you need to have a Signal Processing Toobox):
x = [1 2 3 4 5 6 7 8 9]
y = [1 4 2 7 3 9 5 10 2]
[peak, peakId] = findpeaks(y); %find peaks in your serie
figure(1)
plot(x, y)
lbalph=('a':'z').'
lb=strcat(Alphabet(1),lbalph(1:length(peak))) %Create a label matrix
lb = num2cell(lb,2) % Convert to cell array
lbid = 1:length(lb)
text(x(peakId), peak, lb(lbid),'Rotation',90) % label the peak with your lb matrix
As you have the index peaks, you can labeled as you want.

Related

Merging sorted pairs

I have two (or more but if solved for two, it's solved for any number) 2-by-N matrices which represent points with an x (the first row) and y (the second row) coordinates. The points are always sorted in the increasing x coordinate. What I want to do is I want to merge these two matrices into one 3-by-N matrix so that if two points (one from each matrix) have the same x coordinate, they would form one column in the new matrix, the first row being the x coordinate and the second and third row being the two y coordinates. However, if there is a point in one matrix that has x coordinate different than all other points in the second matrix, I still want to have full 3-element column that is placed such that the x coordinates are still sorted and the missing value from the other matrix is replaced by the nearest value with lower x coordinate (or NaN if there is none).
Better to explain by example.
First matrix:
1 3 5 7 % x coordinate
1 2 3 4 % y coordinate
Second matrix:
2 3 4 7 8 % x coordinate
5 6 7 8 9 % y coordinate
Desired result:
1 2 3 4 5 7 8 % x coordinate
1 1 2 2 3 4 4 % y coordinate from first matrix
NaN 5 6 7 7 8 9 % y coordinate from second matrix
My question is, how can I do it effectively in matlab/octave and numpy? (Effectively because I can always do it "manually" with loops but that doesn't seem right.)
You can do it with interp1 and the keyword 'previous' for strategy (you can also choose 'nearest' if you do not care if it is larger or smaller) and 'extrap' for allowing extrapolation.
Define the matrices
a=[...
1 3 5 7;...
1 2 3 4];
b=[...
2 3 4 7 8;...
5 6 7 8 9];
Then find the interpolation points
x = unique([a(1,:),b(1,:)]);
And interpolate
[x ; interp1(a(1,:),a(2,:),x,'previous','extrap') ; interp1(b(1,:),b(2,:),x,'previous','extrap') ]
Timeit results:
I tested the algorithms on
n = 1e6;
a = cumsum(randi(3,2,n),2);
b = cumsum(randi(2,2,n),2);
and got:
Wolfie: 1.7473 s
Flawr: 0.4927 s
Mine: 0.2757 s
This verions uses set operations:
a=[...
1 3 5 7;...
1 2 3 4];
b=[...
2 3 4 7 8;...
5 6 7 8 9];
% compute union of x coordinates
c = union(a(1,:),b(1,:));
% find indices of x of a and b coordinates in c
[~,~,ia] = intersect(a(1,:),c);
[~,~,ib] = intersect(b(1,:),c);
% create output matrix
d = NaN(3,numel(c));
d(1,:) = c;
d(2,ia) = a(2,:);
d(3,ib) = b(2,:);
% fill NaNs
m = isnan(d);
m(:,1) = false;
i = find(m(:,[2:end,1])); %if you have multiple consecutive nans you have to repeat these two steps
d(m) = d(i);
disp(d);
Try it online!
Your example:
a = [1 3 5 7; 1 2 3 4];
b = [2 3 4 7 8; 5 6 7 8 9];
% Get the combined (unique, sorted) `x` coordinates
output(1,:) = unique([a(1,:), b(1,:)]);
% Initialise y values to NaN
output(2:3, :) = NaN;
% Add x coords from `a` and `b`
output(2, ismember(output(1,:),a(1,:))) = a(2,:);
output(3, ismember(output(1,:),b(1,:))) = b(2,:);
% Replace NaNs in columns `2:end` with the previous value.
% A simple loop has the advantage of capturing multiple consecutive NaNs.
for ii = 2:size(output,2)
colNaN = isnan(output(:, ii));
output(colNaN, ii) = output(colNaN, ii-1);
end
If you have more than 2 matrices (as suggested in your question) then I'd advise
Store them in a cell array, and loop over them to do the calls to ismember, instead of having one code line per matrix hardcoded.
The NaN replacement loop is already vectorised for any number of rows.
This is the generic solution for any number of matrices, demonstrated with a and b:
mats = {a, b};
cmats = horzcat(mats);
output(1, :) = unique(cmats(1,:));
output(2:numel(mats)+1, :) = NaN;
for ii = 1:size(mats)
output(ii+1, ismember(output(1,:), mats{ii}(1,:))) = mats{ii}(2,:);
end
for ii = 2:size(output,2)
colNaN = isnan(output(:,ii));
output(colNaN, ii) = output(colNaN, ii-1);
end

MATLAB: How to add custom ticks and labels to an imagesc plot?

I have made a matrix containing 13 different vectors with ~300K+ rows. I have visualized the matrix by transposing it and using the imagesc function to see the distribution of colors. All vectors have been resampled, processed and normalized between 0 & 1 individually.
The imagesc plot gives me this result (fig 1):
But, when I use the axis functionality to add x & y limits, I get this:
How do I maintain the imagesc plot while being able to add custom ticks and labels to the X & y axis? The x axis represents time, while the y axis will get its own labels with sensor names.
You redefine limits from 0 to 30 on the x-axis while the initial xlimits goes up to 3e5. Same issue with the y-axis
Here's how to redefine the Y-axis to put sensor names:
C = [0 2 4 6 9 ; 8 10 12 44 14; 16 48 10 32 23];
image(C)
% Get axis handle
ax = gca;
% Set where ticks will be
ax.YTick = [1 2 3];
% Set TickLabels;
ax.YTickLabel = {'S1','S2','S3'};
Figure out the ax.YTick where you want the labels to appear.
If you want the x-axis to go from 0 to 30, divide the x component of all vectors by 1e4 before plotting. Alternatively, you can add the line:
ax.XTickLabel = ax.XTick/1e4;

Matlab bar plot in specific time points of each measured values

I want to plot vertical lines corresponding to values obtained at specific time points.
Example:
a = [0 5 7 9 ] at 0 seconds,
b = [0.5 6 6.5 11] at 2 seconds,
c = [0 4 2 10] at 4 seconds
Each time point will be a vertical line between the maximum and minimum of the vectors. I also need to mark the start and end points of a, b and c, for instance a should have a circle (or star etc.) at 0 and 9.
Here is an example output:
You can use line with end markers.
% Your data
a = [0 5 7 9 ];
b = [0.5 6 6.5 11];
c = [0 4 2 10];
% Combine to get min/max values
data = [a; b; c].';
mins = min(data);
maxs = max(data);
% Plot using line, nice flexible method which plots vertical lines at points 2:2:n
line(repmat(2*(0:numel(mins)-1), 2, 1), [mins; maxs], 'color', 'k', 'marker', 'o')
Output:
If you want different markers on each end, or different colours, please see this answer which gives more detailed examples.

Impulse response function in matlab

There are examples for summation of a vector but not for matrix in Matlab. So please help solve the following:
How to write impulse response function in matlab?
I want program in Matlab for the equation:
hij(t) = ∑_(k=1)to n (φik*φjk*e-xwk*sin(wdk(t))/(M*wdk))
h is impulse response function
φ is mode shape
x is constant
wk is kth mode nat frequency
wdk is kth mode damped frequency
M is mass matrix.
Summing on a matrix, in general, looks like this:
>> A = randi(5,[3,6]) % Creating a random [3 x 6] integer matrix
A =
3 4 4 1 2 4
3 4 4 3 3 2
4 2 1 5 2 3
>> sum(A) % Sums on rows (dim=1 is default) so you get a [1 x 6] vector
ans =
10 10 9 9 7 9
>> sum(A,2) % Sums on columns (dim=2) so you get a [3 x 1] vector
ans =
18
19
17
And similarly if you had a 3D matrix V, then you could do sum(V,3) to sum on the slices.
If you want more specific help, please note the dimensions of each input (phi_i, phi_j, M, w, and wd)

Getting all pixel coordinates of a vector inside a image

I have an intensity/greyscale image, and I have chosen a pixel inside this image. I want to send vectors starting from this pixel in all directions/angles, and I want to sum all the intensities of the pixels touching one vector, for all vectors.
After this step I would like to plot a histogram with the intensities on one axis and the angle on the other axis. I think I can do this last step on my own, but I don't know how to create these vectors inside my greyscale image and how to get the coordinates of the pixels a vector touches.
I previously did this in C++, which required a lot of code. I am sure this can be done with less effort in MATLAB, but I am quite new to MATLAB, so any help would be appreciated, since I haven't found anything helpful in the documentation.
It might not be the best way to solve it, but you can do it using a bit of algebra, heres how...
We know the Point-Slope formula of a line passing through point (a,b) with angle theta is:
y = tan(theta) * (x-a) + b
Therefore a simple idea is to compute the intersection of this line with y=const for all const, and read the intensity values at the intersection. You would repeat this for all angles...
A sample code to illustrate the concept:
%% input
point = [128 128]; % pixel location
I = imread('cameraman.tif'); % sample grayscale image
%% calculations
[r c] = size(I);
angles = linspace(0, 2*pi, 4) + rand;
angles(end) = [];
clr = lines( length(angles) ); % get some colors
figure(1), imshow(I), hold on
figure(2), hold on
for i=1:length(angles)
% line equation
f = #(x) tan(angles(i))*(x-point(1)) + point(2);
% get intensities along line
x = 1:c;
y = round(f(x));
idx = ( y<1 | y>r ); % indices of outside intersections
vals = diag(I(x(~idx), y(~idx)));
figure(1), plot(x, y, 'Color', clr(i,:)) % plot line
figure(2), plot(vals, 'Color', clr(i,:)) % plot profile
end
hold off
This example will be similar to Amro's, but it is a slightly different implementation that should work for an arbitrary coordinate system assigned to the image...
Let's assume that you have matrices of regularly-spaced x and y coordinates that are the same size as your image, such that the coordinates of pixel (i,j) are given by (x(i,j),y(i,j)). As an example, I'll create a sample 5-by-5 set of integer coordinates using MESHGRID:
>> [xGrid,yGrid] = meshgrid(1:5)
xGrid =
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
yGrid =
1 1 1 1 1
2 2 2 2 2
3 3 3 3 3
4 4 4 4 4
5 5 5 5 5
Next we can define a line y = m*(x - a) + b passing through the coordinate system by selecting some values for the constants and computing y using the x coordinates of the grid:
>> a = 0;
>> b = 1;
>> m = rand
m =
0.5469
>> y = m.*(xGrid(1,:)-a)+b
y =
1.5469 2.0938 2.6406 3.1875 3.7344
Finally, we find the y points in the grid that differ from the points computed above by less than the grid size:
>> index = abs(yGrid-repmat(y,size(yGrid,1),1)) <= yGrid(2,1)-yGrid(1,1)
index =
1 0 0 0 0
1 1 1 0 0
0 1 1 1 1
0 0 0 1 1
0 0 0 0 0
and use this index matrix to get the x and y coordinates for the pixels crossed by the line:
>> xCrossed = xGrid(index);
>> yCrossed = yGrid(index);