I am creating a dummy example for my situation. Real problem is way more complicated.
Dummy Example:
I have a struct of size 2 with an entry called 'name' and an array of size 2x1.
So, the Struct called Store looks like:
Store(1).name = 'Apple';
Store(1).Data = [1; 2];
Store(2).name = 'Orange';
Store(2).Data = [24; 57];
I want to print this to excel such that it looks like the following:
Apple 1
Apple 2
Orange 24
Orange 57
I don't even know how to start with the above example. I have used xlswrite in the past but never for mixed type data.
If all your Data fields are of size 2x1, you should be able to the following:
% prepare cell to hold your data
xlData = cell(2*numel(store), 2);
% fill column 1:
xlData(1:2:end-1,1) = {store.name};
xlData(2:2:end,1) = xlData(1:2:end-1);
% fill column 2:
xlData(:,2) = num2cell(vertcat(store.Data));
% write to excel:
xlswrite('yourExcelfile.xlsx', xlData)
Got no Matlab at hand to test, but it should help you get going.
Since xlswrite takes a cell-array, there's no issue with mixed datatypes.
Related
In Matlab (R2021b) I am using some given function, which reads time-dependent values of several variables and returns them in a combined matrix together with a time vector. In the data matrix each column represents one vector of time-dependent values for one variable.
[data,time] = function_reading_data_of_several_values('filename');
For readability of the following code where the variables are further processed, I would like to store these columns in separate vector variables. I am doing it like that:
MomentX = data(1,:);
MomentY = data(2,:);
MomentZ = data(3,:);
ForceX = data(4,:);
ForceY = data(5,:);
ForceZ = data(6,:);
That is working. But is there some simpler (or shorter) way of assigning the column of the matrix to individual vectors? I am asking because in real program I have more than the 6 columns as in the example. Code is getting quite long. I was thinking of something similar to the line below, but that does not work:
[MomentX,MomentY,MomentZ,ForceX,ForceY,ForceZ] = data; %does not work
Do you have any idea? Thanks for help!
Update:
Thanks to the hint here in the group to use tables, a solution could be like this:
...
[data,time] = function_reading_data_of_several_values('filename');
% data in matrix. Each column representing a stime dependent variable
varNames = {'MomentX', 'MomentX',...}; % Names of columns
T=array2table(data','VariableNames',varNames); % Transform to Table
Stress = T.MomentX/W + T.ForceY/A %accesing table columns
...
This seems to work fine and readable to me.
Solution 1: In industrial solutions like dSpace, it is very common to do it in struct arrays:
mydata.X(1).time = [0.01 0.02 0.03 0.04];
mydata.Y(1).name = 'MomentX';
mydata.Y(1).data = [1 2 3 4];
mydata.Y(2).name = 'MomentY';
mydata.Y(2).data = [2 3 4 5];
Solution 2: It is also very common to create tables
See: https://de.mathworks.com/help/matlab/ref/table.html
As already commented, it is probably better to use a table instead of separate variables may not be a good idea. But if you want to, it can be done this way:
A = magic(6): % example 6-column matrix
A_cell = num2cell(A, 1); % separate columns in cells
[MomentX, MomentY, MomentZ, ForceX, ForceY, ForceZ] = A_cell{:};
This is almost the same as your
[MomentX,MomentY,MomentZ,ForceX,ForceY,ForceZ] = data; %does not work
except that the right-hand side needs to be a comma-separated list, which in this case is obtained from a cell array.
I am trying to save some data from MATLAB to excel.
This is very repetitive and I was hoping to use a for loop to significantly reduce the number of lines of code I am using.
To give an example:
APPLES = rand(1,10);
PEARS = rand(1,10);
Horizon = (1:10);
% Writing to excel
xlswrite('Results.xlsx',APPLES,'Apple','B2')
xlswrite('Results.xlsx',Horizon,'Apple','B1')
%Pears
xlswrite('Results.xlsx',PEARS,'Pear','B2')
xlswrite('Results.xlsx',Horizon,'Pear','B1')
The above code will create an excel sheet called Results with two worksheets Apple and Pear with the data I need.
Is it possible to create a for loop to reduce the number of code, as I am actually using 200 fruits, so it starting to take up a lot of space and time to write them by hand?
I have tried to do it by hand which is time-consuming and I have also tried this method which doesn't work:
%test
Apples = rand(1,10);
Pears = rand(1,10);
Horizon = (1:10);
names1 = {'Apples' 'Pears'};
%%
for ii = 1:length(names1)
% Writing to excel
xlswrite('Results22.xlsx',fprintf(names1{ii}),names1{ii},'B2')
xlswrite('Results22.xlsx',Horizon,names1{ii},'B1')
end
The problem is that inside the loop you call the string that represents the name of the variable, instead of the variable itself.
For example, fprintf(names1{ii}) gives the string 'Apples', instead of the variable Apples, that contain the values.
To resolve that, and for good practice of not holding 200 fruits in workspace, you can define the fruits as fields of struct. Then, you can access it with dynamic field name:
fruit_names = {'Apples', 'Pears'};
Horizon = (1:10);
for k=1:length(fruit_names)
fruit.(fruit_names{k}) = rand(1,10);
xlswrite('Results22.xlsx',fruit.(fruit_names{k}),fruit_names{k},'B2')
xlswrite('Results22.xlsx',Horizon,fruit_names{k},'B1')
end
very very new to Matlab and I'm having trouble reading a binary file into a matrix. The problem is I am trying to write the binary file into a two column matrix (which has 100000's of rows) where each column is a different format type.
I want column 1 to be in 'int8' format and column 2 to be a 'float'
This is my attempt so far:
FileID= fopen ('MyBinaryFile.example');
[A,count] = fread(FileID,[nrows, 2],['int8','float'])
This is not working because I get the error message 'Error using fread' 'Invalid Precision'
I will then go on to plot once I have successfully done this.
Probably a very easy solution to someone with matlab experience but I haven't been successful at finding a solution on the internet.
Thanks in advance to anyone who can help.
You should be aware that Matlab cannot hold different data type in a matrix (it can do so in a cell array but this is another topic). So there is no point trying to read your mixed type file in one go in one single matrix ... it is not possible.
Unless you want a cell array, you will have to use 2 different variables for your 2 columns of different type. Once this is established, there are many ways to read such a file.
For the purpose of the example, I had to create a binary file as you described. This is done this way:
%% // write example file
A = int8(-5:5) ; %// a few "int8" data
B = single(linspace(-3,1,11)) ; %// a few "float" (=single) data
fileID = fopen('testmixeddata.bin','w');
for il=1:11
fwrite(fileID,A(il),'int8');
fwrite(fileID,B(il),'single');
end
fclose(fileID);
This create a 2 column binary file, with first column: 11 values of type int8 going from -5 to +5, and second column: 11 values of type float going from -3 to 1.
In each of the solution below, the first column will be read in a variable called C, and the second column in a variable called D.
1) Read all data in one go - convert to proper type after
%% // Read all data in one go - convert to proper type after
fileID = fopen('testmixeddata.bin');
R = fread(fileID,'uint8=>uint8') ; %// read all values, most basic data type (unsigned 8 bit integer)
fclose(fileID);
R = reshape( R , 5 , [] ) ; %// reshape data into a matrix (5 is because 1+4byte=5 byte per column)
temp = R(1,:) ; %// extract data for first column into temporary variable (OPTIONAL)
C = typecast( temp , 'int8' ) ; %// convert into "int8"
temp = R(2:end,:) ; %// extract data for second column
D = typecast( temp(:) , 'single' ) ; %// convert into "single/float"
This is my favourite method. Specially for speed because it minimizes the read/seek operations on disk, and most post calculations are done in memory (much much faster than disk operations).
Note that the temporary variable I used was only for clarity/verbose, you can avoid it altogether if you get your indexing into the raw data right.
The key thing to understand is the use of the typecast function. And the good news is it got even faster since 2014b.
2) Read column by column (using "skipvalue") - 2 pass approach
%% // Read column by column (using "skipvalue") - 2 pass approach
col1size = 1 ; %// size of data in column 1 (in [byte])
col2size = 4 ; %// size of data in column 2 (in [byte])
fileID = fopen('testmixeddata.bin');
C = fread(fileID,'int8=>int8',col2size) ; %// read all "int8" values, skipping all "float"
fseek(fileID,col1size,'bof') ; %// rewind to beginning of column 2 at the top of the file
D = fread(fileID,'single=>single',col1size) ; %// read all "float" values, skipping all "int8"
fclose(fileID);
That works too. It works fine ... but probably much slower than above. Although it may be clearer code to read for someone else ... I find that ugly (and yet I've used this way for several years until I got to use the method above).
3) Read element by element
%% // Read element by element (slow - not recommended)
fileID = fopen('testmixeddata.bin');
C=[];D=[];
while ~feof(fileID)
try
C(end+1) = fread(fileID,1,'int8=>int8') ;
D(end+1) = fread(fileID,1,'single=>single') ;
catch
disp('reached End Of File')
end
end
fclose(fileID);
Talking about ugly code ... that does work too, and if you were writing C code it would be more than ok. But in Matlab ... please avoid ! (well, your choice ultimately)
Merging in one variable
If really you want all of that in one single variable, it could be a structure or a cell array. For a cell array (to keep matrix indexing style), simply use:
%% // Merge into one "cell array"
Data = { C , D } ;
Data =
[11x1 int8] [11x1 single]
I've been at this for 3 hours -- so I need help.
I have a button on MATLAB's GUI GUIDE to load a text file to store 2
columns of data as x and y.
So x = [12, 12, 23];
textfile A is:
12 23
12 32
23 32
The code that is in the GUI GUIDE is under the pushbutton load_file as follows:
filename = uigetfile('*.txt')
loaddata = fullfile(pathname,filename)
load(loaddata)
A = filename(:,1)
B = filename(:,2)
handles.input1 = A;
handles.input2 = B;
axes(handles.axes1)
plot(handles.input1,handles,imput2)
load will load a text file, but it won't assign the contents to anything unless you explicitly specify an output.
%# load xy data from file
xy = load(loaddata,'-ascii')
%# assign columns to A and B, respectively
%# (why not x,y)?
A = xy(:,1)
B = xy(:,2)
The -ascii option of load is not necessary, but guarantees that the file is loaded as text, and will help you remember later that the data is supposed to be a text file.
Firstly, you might want to post your error message to make sure I'm reporting on the right problem, but I can see one problem right off:
the lines:
A = filename(:,1)
B = filename(:,2)
are only retrieving a string naming the file, not the actual data. So first, you have to know the name of the data that is being loaded, then change the load line to:
data = load(loaddata,'-ascii')
and now:
A = data(:,1)
B = data(:,2)
I need to calculate the mean, standard deviation, and other values for a number of variables and I was wondering how to use a loop to my advantage. I have 5 electrodes of data. So to calculate the mean of each I do this:
mean_ch1 = mean(ch1);
mean_ch2 = mean(ch2);
mean_ch3 = mean(ch3);
mean_ch4 = mean(ch4);
mean_ch5 = mean(ch5);
What I want is to be able to condense that code into a line or so. The code I tried does not work:
for i = 1:5
mean_ch(i) = mean(ch(i));
end
I know this code is wrong but it conveys the idea of what I'm trying to accomplish. I want to end up with 5 separate variables that are named by the loop or a cell array with all 5 variables within it allowing for easy recall. I know there must be a way to write this code I'm just not sure how to accomplish it.
You have a few options for how you can do this:
You can put all your channel data into one large matrix first, then compute the mean of the rows or columns using the function MEAN. For example, if each chX variable is an N-by-1 array, you can do the following:
chArray = [ch1 ch2 ch3 ch4 ch5]; %# Make an N-by-5 matrix
meanArray = mean(chArray); %# Take the mean of each column
You can put all your channel data into a cell array first, then compute the mean of each cell using the function CELLFUN:
meanArray = cellfun(#mean,{ch1,ch2,ch3,ch4,ch5});
This would work even if each chX array is a different length from one another.
You can use EVAL to generate the separate variables for each channel mean:
for iChannel = 1:5
varName = ['ch' int2str(iChannel)]; %# Create the name string
eval(['mean_' varName ' = mean(' varName ');']);
end
If it's always exactly 5 channels, you can do
ch = {ch1, ch2, ch3, ch4, ch5}
for j = 1:5
mean_ch(j) = mean(ch{j});
end
A more complicated way would be
for j = 1:nchannels
mean_ch(j) = eval(['mean(ch' num2str(j) ')']);
end
Apart from gnovice's answer. You could use structures and dynamic field names to accomplish your task. First I assume that your channel data variables are all in the format ch* and are the only variables in your MATLAB workspace. The you could do something like the following
%# Move the channel data into a structure with fields ch1, ch2, ....
%# This could be done by saving and reloading the workspace
save('channelData.mat','ch*');
chanData = load('channelData.mat');
%# Next you can then loop through the structure calculating the mean for each channel
flds = fieldnames(chanData); %# get the fieldnames stored in the structure
for i=1:length(flds)
mean_ch(i) = mean(chanData.(flds{i});
end