How can I plot multiple Matlab files onto one boxplot?

Hi guys, I am currently doing an assignment where I have been tasked to filter frequency data for 4 different frequencies and compute FFT’s on them. I have filtered them and computed the FFTs but now I need to create a boxplot with the ffts of all 4 frequencies on one plot to compare. The FFT results are saved as Matlab files. The variable name for the first FFT results Matlab file is fft_results, the second is fft_results2 then fft_results3 and finally fft_results4. The FFT Matlab files are saved as fft_7_results, fft_8_results, fft_9_results and fft_10_results. Any help would be appreciated.

7 Commenti

Are you running into difficulty loading the MATLAB files (by which I assume you mean .mat files) or creating the boxplots?
I’ve loaded the files and created the box plot, and the code runs however the plot is empty. The axis are there and numbered and labelled, however the actual box plots are not there.
Please share the code and files. You can upload files using the paperclip button.
folderPath = 'BoxPlot/';
fileList = dir(fullfile(folderPath, 'fft*.mat'));
fft_results_all = cell(1, numel(fileList));
for i = 1:numel(fileList)
data = load(fullfile(folderPath, fileList(i).name));
switch i
case 1
fft_results_all{i} = data.fft_results;
case 2
fft_results_all{i} = data.fft_results2;
case 3
fft_results_all{i} = data.fft_results3;
case 4
fft_results_all{i} = data.fft_results4;
otherwise
error('Unexpected number of files.');
end
end
figure;
boxplot(fft_results_all, 'Notch', 'on', 'Labels', {'7 Hz', '8 Hz', '9 Hz', '10 Hz'});
xlabel('Frequency (Hz)');
ylabel('FFT Amplitude');
title('Comparison of FFT Results for Different Frequencies');
This is the code I have used that produces the boxplot with the axis but not the actual plots
I have attached the matlab data files. Thank you.
Sorry for any confusion caused, but I just realised I need to find the amplitude and location of the peaks for each frequency and plot this.
A box plot of the amplitudes and locations of the peaks of each FFT result? I'm not sure what that would look like. Do you have an example? Either a sketch or a link to an image?
Upon further inspection I realised the boxplot is solely meant to be the amplitude of the FFT results for 7 Hz, 8 Hz, 9 Hz, 10 Hz. I have attached an example of how it should look.

Accedi per commentare.

 Risposta accettata

One problem is that you are assuming the list of files returned by dir is in a particular order (7, 8, 9, 10), but in fact the order is 10, 7, 8, 9. So you'd get an error trying to access a field that doesn't exist on the first mat-file you load. To get around that and have the files in sorted order, you can download and use the File Exchange submission natsortfiles.
Also, since each mat-file has only one variable, you can store it in fft_results_all, regardless of its name (so you don't have to check for a particular variable name for a particular mat file).
If you have the Signal Processing Toolbox, you can use findpeaks to get the peaks and their locations for each FFT result. Here's an example, and you can mess with the parameters findpeaks uses to get the result you want.
I really don't know what the boxplot you have in mind should look like for this. Note that the peak locations are not used in the boxplot, only their amplitudes.
folderPath = '.'; % here in Answers the files are in the current directory
fileList = natsortfiles(dir(fullfile(folderPath, 'fft*.mat')));
N = numel(fileList);
fft_results_all = cell(1,N);
for i = 1:N
data = load(fullfile(folderPath, fileList(i).name));
% store the first (and only) variable in each mat-file:
fn = fieldnames(data);
fft_results_all{i} = data.(fn{1})(1:end/2); % use only the 1st half of the data, because of symmetry
end
% plot the data and the peaks
figure
pks = cell(1,N);
locs = cell(1,N);
for ii = 1:N
subplot(2,2,ii)
semilogy(fft_results_all{ii})
hold on
[pks{ii},locs{ii}] = findpeaks(fft_results_all{ii},'MinPeakHeight',100);
semilogy(locs{ii},pks{ii},'.r')
title(fileList(ii).name,'Interpreter','none')
end
pks
pks = 1x4 cell array
{28x1 double} {21x1 double} {23x1 double} {28x1 double}
% append NaNs to each pks as necessary to make them the same length for
% plotting in boxplot
pks_plot = pks;
n = cellfun(@numel,pks_plot);
n_max = max(n);
for ii = 1:N
P = n_max-n(ii);
pks_plot{ii} = [pks_plot{ii}; NaN(P,1)];
end
figure;
boxplot([pks_plot{:}], 'Notch', 'on', 'Labels', {'7 Hz', '8 Hz', '9 Hz', '10 Hz'});
xlabel('Frequency (Hz)');
ylabel('FFT Amplitude');
title('Comparison of FFT Results for Different Frequencies');

10 Commenti

Thank you, that boxplot is exactly how I want it to look. When I run your code I am met with an error code Error using vertcat
Dimensions of arrays being concatenated are not consistent.
Error in SignalCode (line 31)
pks_plot{ii} = [pks_plot{ii}; NaN(P,1)];
Any ideas on what could be happening?
Also, I updated the fft_results files for each frequency as now they contain the Amplitude instead of just the FFT data, which is what I actually need to plot, however I have many outliers.
You're welcome!
Where are the updated mat files? The ones from your previous comment appear to be the same as before.
As for that error, double-check that you copied the code correctly and are not transposing the data or the pks vectors somewhere. To make it work whether pks_plot is a row or column vector, you can use:
pks_plot{ii} = [pks_plot{ii}(:); NaN(P,1)];
So the boxplot should be a plot of all amplitudes, not only peak amplitudes? OK:
folderPath = '.'; % here in Answers the files are in the current directory
fileList = natsortfiles(dir(fullfile(folderPath, 'fft*.mat')));
N = numel(fileList);
fft_results_all = cell(1,N);
for i = 1:N
data = load(fullfile(folderPath, fileList(i).name));
% store the first (and only) variable in each mat-file:
fn = fieldnames(data);
fft_results_all{i} = data.(fn{1})(1:end/2); % use only the 1st half of the data, because of symmetry
end
figure;
boxplot([fft_results_all{:}], 'Notch', 'on', 'Labels', {'7 Hz', '8 Hz', '9 Hz', '10 Hz'});
xlabel('Frequency (Hz)');
ylabel('FFT Amplitude');
title('Comparison of FFT Results for Different Frequencies');
set(gca(),'YScale','log')
But again, if your variables are now row vectors instead of column vectors, you'll need to do
boxplot(vertcat(fft_results_all{:}).', 'Notch', 'on', 'Labels', {'7 Hz', '8 Hz', '9 Hz', '10 Hz'});
still assuming that they are all the same size as each other.
I should probably explain better. For each of the 7, 8, 9 and 10 frequencies, we have 5 sets of frequency Matlab data for each. So for 7 Hz we have 7_1, 7_2, 7_3, 7_4, 7_5. And I used a text file with the names of all the Matlab files for each frequency, filtered them and computed the FFT on them, and after I get the amplitude of the fft results using the max function. So the array for the amplitude contains data for each Matlab file for the frequency. And then this is what I need to plot.
Voss
Voss il 9 Apr 2024
Modificato: Voss il 9 Apr 2024
So each mat file that I have actually contains data from 5 separate files, and you want to process each one individually? If something like that, I would need the original 20 files, right?
Techically yes, but I dont want to process them individually, the FFT I computed has processed them all. So I have 5 different matlab files for ,for example, 7 Hz data. I put all the matlab files within one folder with the matlab script. Then using the notepad app I created a text file with the names of the matlab data files and included this within the same folder. Then I imported the text file into the lab script and the txt file is what I filtered and computed the FFT on. I have also attached the updated fft_results files which contain the amplitude for each frequency, which is what i want to boxplot. And thank you for all the help.
OK. I've got a row vector of 19200 elements in each of these new mat files.
folderPath = '.'; % here in Answers the files are in the current directory
fileList = natsortfiles(dir(fullfile(folderPath, 'fft*.mat')));
N = numel(fileList);
fft_results_all = cell(1,N);
for i = 1:N
data = load(fullfile(folderPath, fileList(i).name));
% store the first (and only) variable in each mat-file:
fn = fieldnames(data);
fft_results_all{i} = data.(fn{1});
end
fft_results_all
fft_results_all = 1x4 cell array
{1x19200 double} {1x19200 double} {1x19200 double} {1x19200 double}
M = vertcat(fft_results_all{:}).';
I can plot them each on a semi-log plot:
figure
semilogy(M)
legend({'7','8','9','10'})
I can make boxplots out of them:
figure;
boxplot(M, 'Notch', 'on', 'Labels', {'7 Hz', '8 Hz', '9 Hz', '10 Hz'});
xlabel('Frequency (Hz)');
ylabel('FFT Amplitude');
title('Comparison of FFT Results for Different Frequencies');
What else should be done with them?
Actually, that final boxplot you sent me is exactly what I needed, and when I tried it myself that is also exactly what I got. I was wondering, do you have any idea why there could be so many outliers, as I filtered the data for each frequency. But again thank you for all the help you have provided me.
You're welcome!
Regarding the outliers, you can see from the semilogy plot that most of the samples have amplitude around 1, but there are a handful (maybe 300 or so in each vector) that are much higher than that, between 100 and 10000, occurring around sample #300-400 and #3500-3600. That almost all amplitudes are around 1 makes the boxplots flat, and those peaks of high amplitude are the outliers in the boxplot plot.
Thank you for clarifying this, and again thank you for all the help and advice!
You're welcome!

Accedi per commentare.

Più risposte (0)

Categorie

Richiesto:

il 9 Apr 2024

Commentato:

il 10 Apr 2024

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by