Matlab Legend after FOR loop - matlab

I am creating a file to read in a certain number of .wav files, each of these corresponding to a musical note. I am performing an FFT on each of them and plotting them all on the same figure. However I am having a problem with getting the legend to print correctly, it is separating the names I want to use into individual letters instead of using them as a string. My code is as follows:
clear all
mydir = 'Note Values/';
wavFiles = dir([mydir '*.wav']);
length(wavFiles)
legendText = [];
figure(1);
hold on;
for i = 1:length(wavFiles)
wavFiles(i).name
[y, fs] = wavread([mydir wavFiles(i).name]);
sound(y, fs)
currentSample = y(round(length(y)/2)-2048:round(length(y)/2)+2047);
FFT = abs(fft(currentSample));
Power = FFT.*conj(FFT)/length(FFT);
if (mod(i, 2) == 1)
h = plot(Power, 'Color', 'red');
else
h = plot(Power, 'Color', 'blue');
end
sri = wavFiles(i).name;
sri
legendText = [legendText, sri];
end
length(legendText)
legendText(1)
legend(legendText(:));
hold off;
The sri variable is always a full string, but legendText(1) only prints out A instead of A3.wav. I know it's probably something really obvious but I just can't find it. Thanks
The output on my graph appears as this:

You should use
legendText{i} = sri
to fill the cell with strings and
legend(legendText{:});
at end.

I don't have MATLAB by me, so I'm not able to test it, but as I recall, you should use { instead of [ :
legendText = {legendText, sri};

Related

How to add standrad deviation and moving average

What I want to is:
I got folder with 32 txt files and 1 excle file, each file contain some data in two columns: time, level.
I already managed to pull the data from the folder and open each file in Matlab and get the data from it. What I need to do is create plot for each data file.
each of the 32 plots should have:
Change in average over time
Standard deviation
With both of this things I am straggling can't make it work.
also I need to make another plot this time the plot should have the average over each minute from all the 32 files.
here is my code until now:
clc,clear;
myDir = 'my path';
dirInfo = dir([myDir,'*.txt']);
filenames = {dirInfo.name};
N = numel(filenames);
data=cell(N,1);
for i=1:N
fid = fopen([myDir,filenames{i}] );
data{i} = textscan(fid,'%f %f','headerlines',2);
fclose(fid);
temp1=data{i,1};
time=temp1{1};
level=temp1{2};
Average(i)=mean(level(1:find(time>60)));
AverageVec=ones(length(time),1).*Average(i);
Standard=std(level);
figure(i);
plot(time,level);
xlim([0 60]);
hold on
plot(time, AverageVec);
hold on
plot(time, Standard);
legend('Level','Average','Standard Deviation')
end
the main problam with this code is that i get only average over all the 60 sec not moving average, and the standard deviation returns nothing.
few things you need to know:
*temp1 is 1x2 cell
*time and level are 22973x1 double.
Apperently you need an alternative to movmean and movstd since they where introduced in 2016a. I combined the suggestion from #bla with two loops that correct for the edge effects.
function [movmean,movstd] = moving_ms(vec,k)
if mod(k,2)==0,k=k+1;end
L = length(vec);
movmean=conv(vec,ones(k,1)./k,'same');
% correct edges
n=(k-1)/2;
movmean(1) = mean(vec(1:n+1));
N=n;
for ct = 2:n
movmean(ct) = movmean(ct-1) + (vec(ct+n) - movmean(ct-1))/N;
N=N+1;
end
movmean(L) = mean(vec((L-n):L));
N=n;
for ct = (L-1):-1:(L-n)
movmean(ct) = movmean(ct+1) + (vec(ct-n) - movmean(ct+1))/N;
N=N+1;
end
%mov variance
movstd = nan(size(vec));
for ct = 1:n
movstd(ct) = sum((vec(1:n+ct)-movmean(ct)).^2);
movstd(ct) = movstd(ct)/(n+ct-1);
end
for ct = n+1:(L-n)
movstd(ct) = sum((vec((ct-n):(ct+n))-movmean(ct)).^2);
movstd(ct) = movstd(ct)/(k-1);
end
for ct = (L-n):L
movstd(ct) = sum((vec((ct-n):L)-movmean(ct)).^2);
movstd(ct) = movstd(ct)/(L-ct+n);
end
movstd=sqrt(movstd);
Someone with matlab >=2016a can compare them using:
v=rand(1,1E3);m1 = movmean(v,101);s1=movstd(v,101);
[m2,s2] = moving_ms(v,101);
x=1:1E3;figure(1);clf;
subplot(1,2,1);plot(x,m1,x,m2);
subplot(1,2,2);plot(x,s1,x,s2);
It should show a single red line since the blue line is overlapped.

Using MATLAB to stack several 2D plots generated from .csv into a 3D plot

I have code to generate a 2D plot from data stored in several .csv files:
clearvars;
files = dir('*.csv');
name = 'E_1';
set(groot, 'DefaultLegendInterpreter', 'none')
set(gca,'FontSize',20)
hold on;
for file = files'
csv = xlsread(file.name);
[n,s,r] = xlsread(file.name);
des_cols = {'Stress','Ext.1(Strain)'};
colhdrs = s(2,:);
[~,ia] = intersect(colhdrs, des_cols);
colnrs = flipud(ia);
file.name = n(:, colnrs);
file.name = file.name(1:end-500,:);
plot(file.name(:,2),file.name(:,1),'DisplayName',s{1,1});
end
ylabel({'Stress (MPa)'});
xlabel({'Strain (%)'});
title({name});
legend('show');
What I would like to do is modify the code in order to concatenate 2D plots made from the .csv data into a 3D plot where one of the axis is the index of the .csv in files kind of like the picture at the top of this post. I got the idea of using plot3 from that post but I'm not sure how to get it to work.
From what I understood I need to create 3 new matrices xMat, yMat, zMat. The columns of each matrix contain the data from the csv file and the yMat contains columns that are just the index of the csv but I'm not entirely sure where to go from here.
Thanks for any help!
You could call plot3 in the loop like something like the following. Basically change the Y-values to Z-Values. Then increment Y by one for each iteration of the loop.
figure;
a = axes;
grid on;
hold(a,'on');
x = 0:.1:4*pi;
for ii = 1:10
plot3(a,x,ones(size(x))*ii,sin(x));
end
view(40,40)
Modifying your code would look something like the following. Note that since I don't have your CSVs I can't test any of this.
clearvars;
files = dir('*.csv');
name = 'E_1';
set(groot, 'DefaultLegendInterpreter', 'none')
set(gca,'FontSize',20)
a = gca;
hold on;
ii = 1;
for file = files'
csv = xlsread(file.name);
[n,s,r] = xlsread(file.name);
des_cols = {'Stress','Ext.1(Strain)'};
colhdrs = s(2,:);
[~,ia] = intersect(colhdrs, des_cols);
colnrs = flipud(ia);
file.name = n(:, colnrs);
file.name = file.name(1:end-500,:);
plot3(a,file.name(:,2),ones(size(file.name(:,2))).*ii,file.name(:,1),'DisplayName',s{1,1});
ii = ii+1;
end
view(40,40);
ylabel({'Stress (MPa)'});
xlabel({'Strain (%)'});
title({name});
legend('show');

How to separate circles and lines in a binary image?

I got a problem and I'm supposed to separate circles and lines in the following image:
the thing is that I've just made some codes and it's working in a way that only separates them as different objects and the final separated objects are not the same as input ones! I post this question as it might be helpful for someone and if there's anybody that can make a better code to separate objects more clearly and maybe as accurate as the input ones.
I appreciate any comments in advance ...
The code is as follows:
clear; close all; clc; warning off
im = imread('input\circle_and_lines.jpg');
level = graythresh(im);
imBin = im2bw(im,level);
figure; imshow(imBin);
%% Separating circles
se1 = strel('disk',6);
imCircles = imopen(imBin,se1);
figure; imshow(imCircles);
[~,numCC] = bwlabel(imCircles,8);
imwrite(imCircles,'output\ex04_circle.png');
%% Separating lines
linDeg0 = imopen(imBin,strel('line',60,0)); figure; imshow(linDeg0);
linDeg10 = imopen(imBin,strel('line',60,10)); figure; imshow(linDeg10);
linDeg20 = imopen(imBin,strel('line',60,20)); figure; imshow(linDeg20);
linDeg75 = imopen(imBin,strel('line',60,75)); linDeg75 = imclose(linDeg75,strel('line',60,75)); figure; imshow(linDeg75);
linDeg95 = imopen(imBin,strel('line',40,95)); linDeg95 = imdilate(linDeg95,strel('disk',1)); figure; imshow(linDeg95);
linDeg135 = imopen(imBin,strel('line',60,135)); linDeg135 = imdilate(linDeg135,strel('disk',1)); figure; imshow(linDeg135);
linDeg170 = imopen(imBin,strel('line',60,170)); figure; imshow(linDeg170);
imLines = linDeg0 | linDeg10 | linDeg20 | linDeg75 | linDeg95 | linDeg135 | linDeg170;
figure; imshow(imLines);
imwrite(imLines,'output\ex04_line.png');
The final results are as follows:
% load image
I = imread('circles_and_lines.jpg');
% Separate the Circles
S1 = strel('disk',6,0);
circles = imopen(I, S1);
figure, imshow(circles);
title('Circles only');
lines = imopen(I,strel('line',60,1));
% Separate the Lines
for c = 1:1:200
lines = lines + imopen(I,strel('line',60,c));
end
figure, imshow(lines);
title('Lines only');
basically a slightly better version of your solution since the for loop scans and separates with more detail the lines

Matlab GUI for array of spots

I need to create a GUI in Matlab. It requires me to identify the spots for two images, and calculate the distance between them.
I have obtained the code for finding and encircling a single spot. It is as follows:
function [meanx,meany] = centroid(pic)
[x,y,z] = size(pic);
if(z==1)
;
else
pic = rgb2gray(pic);
end
% N=2;
% image = interp2(double(pic),N,'spline');
image = sort(sort(pic,1),2);
image =reshape(image,1,numel(image));
i=0;
while(i<3)
if(image(end)==image(end-1))
image(end)=[];
else
image(end)=[];
i=i+1;
end
end
threshold = image(end);
pic2 =(pic>=threshold);
pic=(pic-threshold).*uint8(pic2);
% % image=(pic-threshold+1).*uint8(image); %minus threshold
[rows,cols] = size(pic);
x = ones(rows,1)*[1:cols];
y = [1:rows]'*ones(1,cols);
area = sum(sum(pic));
if area ~= 0
meanx = sum(sum(double(pic).*x))/area;
meany = sum(sum(double(pic).*y))/area;
else
meanx = cols/2;
meany = rows/2;
end
However, I need it to work for multiple spots as shown below :
http://imgur.com/oEe0mRV,UAnbH5y#0
http://imgur.com/oEe0mRV,UAnbH5y#1
So far, I have come up with this, but it only circles separate spots and not all together.
PLEASE HELP - I need to encircle at least 10X10 spots and store their values, and do this for two images as shown above, and find the distance between them!
img1 = imread('r0.bmp');
centroidmat=zeros(10,10,2);
for numx=1:2
for numy=1:2
single_spot=img1((numx*220+780):((numx+1)*220+780),(numy*220+1272):((numy+1)*220+1272),:);
figure
imshow(single_spot);
figure
[cx,cy] = centroid(single_spot);
centroidmat(numx,numy,1)=cx;
centroidmat(numx,numy,2)=cy;
imshow(single_spot);
hold on;
plot(cx,cy,'og')
end
end
Please HELP GUYS! Any help is appreciated!
Would this work ? -
centroidmat=zeros(10,10,2);
for numx=1:2
for numy=1:2
single_spot=img1((numx*220+780):((numx+1)*220+780),(numy*220+1272):((numy+1)*220+1272),:);
[cx,cy] = centroid(single_spot);
centroidmat(numx,numy,1)=cx;
centroidmat(numx,numy,2)=cy;
figure,
imshow(single_spot);
hold on;
plot(cx,cy,'og')
end
end
I have only removed the redundant figure and imshow(single_spot); at the start of the loop, as they appear again later on inside the same loop.

Most efficient way of drawing grouped boxplot matlab

I have 3 vectors: Y=rand(1000,1), X=Y-rand(1000,1) and ACTid=randi(6,1000,1).
I'd like to create boxplots by groups of Y and X corresponding to their group value 1:6 (from ACTid).
This is rather ad-hoc and looks nasty
for ii=
dummyY(ii)={Y(ACTid==ii)};
dummyX(ii)={X(ACTid==ii)}
end
Now I have the data in a cell but can't work out how to group it in a boxplot. Any thoughts?
I've found aboxplot function that looks like this but I don't want that, I'd like the builtin boxplot function because i'm converting it to matlab2tikz and this one doesn't do it well.
EDIT
Thanks to Oleg: we now have a grouped boxplot... but the labels are all skew-whiff.
xylabel = repmat({'Bleh','Blah'},1000,1); % need a legend instead, but doesn't appear possible
boxplot([Y(:,end); cfu], {repmat(ACTid,2,1), xylabel(:)} ,'factorgap',10,'color','rk')
set(gca,'xtick',1.5:3.2:50)
set(gca,'xticklabel',{'Direct care','Housekeeping','Mealtimes','Medication','Miscellaneous','Personal care'})
>> ylabel('Raw CFU counts (Y)')
How to add a legend?
I had the same problem with grouping data in a box plot. A further constraint of mine was that different groups have different amounts of data points. Based on a tutorial I found, this seems to be a nice solution I wanted to share with you:
x = [1,2,3,4,5,1,2,3,4,6];
group = [1,1,2,2,2,3,3,3,4,4];
positions = [1 1.25 2 2.25];
boxplot(x,group, 'positions', positions);
set(gca,'xtick',[mean(positions(1:2)) mean(positions(3:4)) ])
set(gca,'xticklabel',{'Direct care','Housekeeping'})
color = ['c', 'y', 'c', 'y'];
h = findobj(gca,'Tag','Box');
for j=1:length(h)
patch(get(h(j),'XData'),get(h(j),'YData'),color(j),'FaceAlpha',.5);
end
c = get(gca, 'Children');
hleg1 = legend(c(1:2), 'Feature1', 'Feature2' );
Here is a link to the tutorial.
A two-line approach (although if you want to retain two-line xlables and center those in the first line, it's gonna be hackish):
Y = rand(1000,1);
X = Y-rand(1000,1);
ACTid = randi(6,1000,1);
xylabel = repmat('xy',1000,1);
boxplot([X; Y], {repmat(ACTid,2,1), xylabel(:)} ,'factorgap',10)
The result:
EDIT
To center labels...
% Retrieve handles to text labels
h = allchild(findall(gca,'type','hggroup'));
% Delete x, y labels
throw = findobj(h,'string','x','-or','string','y');
h = setdiff(h,throw);
delete(throw);
% Center labels
mylbl = {'this','is','a','pain','in...','guess!'};
hlbl = findall(h,'type','text');
pos = cell2mat(get(hlbl,'pos'));
% New centered position for first intra-group label
newPos = num2cell([mean(reshape(pos(:,1),2,[]))' pos(1:2:end,2:end)],2);
set(hlbl(1:2:end),{'pos'},newPos,{'string'},mylbl')
% delete second intra-group label
delete(hlbl(2:2:end))
Exporting as .png will cause problems...