I have an excel file with what I would like to become variables in column 1 and values in column 2:
Plot.Shift 20
Plot.MarkerSize 6
Plot.MarkerColor black
Plot.MarkerFaceColor black
Plot.FontSize 22
I read the file with
s=readcell('PlotOptions.xlsx','Sheet','PlotOptions');
I would like to have new variable, Plot in the MATLAB code such as:
>> Plot.Shift % Set it to 20
>> Plot.MarkerSize % Set to 6
Using cell2struct:
s=readcell('PlotOptions.xlsx','Sheet','PlotOptions');
field_names=regexp(s(:,1),'(?<=\.)[A-Za-z]+$','match','once');
Plot = cell2struct(s,field_names);
Plot(1) = [];
Plot is a struct with the desired fields:
>> Plot.Shift
20
>> Plot.MarkerFaceSize
6
...
Consider using cell2struct to convert your heterogeneous data from into a struct array.
From the documentation, sturcts allow you to refer to each item through the requested dot notation while maintaining support for heterogeneous data types.
structArray = cell2struct(cellArray, fields, dim)
Related
I use a function which may return outputs more than 3 or 4 which makes it hard to assign those numbers / matrices to user defined variables one by one. Here is the example:
k = fix(log2(length(s)))
[c,l] = wavedec(s,k,'db1');
[cd1,cd2,cd3, ... , cdk] = detcoef(c,l,1:k);
k is 22 in this example. How can I get those outputs by not writing all cd's from 1 to 22?
Don't create those dynamic variables. Just use:
D = detcoef(c,l,1:k);
This will create a cell array having the same contents as of cd1, cd2, ..., cdk at its 1st, 2nd, ..., kth index respectively. Access them using D{1}, D{2},..., D{k} respectively.
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]
Suppose I have different rows loaded from a .mat file (using load filename.mat) containing float numbers following the same naming convention, e.g:
file_3try = [ 2.4, 5.2, 7.8 ]
file_4try = [ 8.7, 2.5, 4,2 ]
file_5try = [ 11.2, 9.11 ]
to plot all of these in one plot using automation (I have many more rows than in the example above) I created a cell containing the names of the arrays by using:
name{l} = sprintf('%s%02i%s','file_',num,'try');
inside a for loop with num the numbers in the names and l a counter starting from 1.
But when I try to plot the arrays using for example:
plot(name{1})
I get the error:
Error using plot
Invalid first data argument
Is there a way to solve this, or am I going about this wrong?
There is something built in to solve this
data = load ( 'filename' ); % load data and store in struct
fnames = fieldnames ( data );
for ii=1:length(fnames)
plot ( axHandle, data.(fnames{ii}) );
end
axHandle is a handle to the axes you want to plot on. Its not required but it is good practice to use it. If its not provided then the plot command will plot on the current axes, e.g. gca.
So as mentioned already you need to use eval.
Assuming the file_**X**try rows are different lengths then you could just place all of them in a cell rather than creating a cell of the variable names. So instead of assigning to separate variables the way you are doing you could assign to a cell, so:
file_try{i} = [.....];
You can then cycle through file_try and plot each entry:
for i = 1:length(file_try)
plot(file_try{i});
end
If the rows are not different lengths then stick them in a matrix and plot it.
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.
This question already has answers here:
Using a colon for indexing in matrices of unknown dimensions
(2 answers)
Closed 9 years ago.
Suppose I want do something similar to
image(1:end-1,2:end,:)
which here is taking part of colored image
but with unknown number of dimensions, i.e. which will work automatically like
image(1:end-1,2:end)
for 2 dimensions
image(1:end-1,2:end,:)
for 3 and
image(1:end-1,2:end,:,:)
for 4 and so on.
If you always want to take all of the 3rd dim and up, you can use
>> image(1:end-1,2:end,:,:,:)
even for 2D array.
Alternatively, you can use subsref for a less ad-hoc/hacky approach:
>> [S.subs{1:ndims(image)}] = deal(':');
>> S.subs{1} = '1:end-1';
>> S.subs{2} = '2:end';
>> S.type = '()';
>> subsref(image, S )
I would have two ideas for this case.
1st way:
You could reshape your image before, e.g.
% transform image to 3d format
% do not forget to transform all used entities to this 3d-format as well
sizeIm = size(image);
image3 = reshape(image,[sizeIm(1:2),prod(sizeIm(3:end)])
% work on image3
image3(1:end-1,2:end,:) = ...;
% transform back:
image = reshape(image3,sizeIm);
2nd way:
Could be a solution to use eval and repmat, e.g.
eval(['image(1:end-1,2:end',repmat(',:',[1,length(size(image))-2]) ')'])
Depends a little bit on what you are using it for (setting, getting, ...).
Suppose you have an array A:
A = rand(2,3,2,5,7);
Then, you can fill with ':', the remaining dimensions of your selection:
nd = ndims(A);
subs = repmat({':'},1,nd-2);
A(1:end-1,2:end, subs{:})
I have there a little idea. You can formulate a function, that analyse the dimension of your Matrix with size(size(Matrix),2). Then you are able to construct a string, that contain your desired command with a little for loop and after this you execute this string with eval.
A=rand(3,3,3,3,3,3,3,3,3,3) %<--- change here dimension
dim=size(size(A),2)
addstr='';
if dim>2
for i=1:dim-2
addstr=[addstr ',:'];
end
end
command=['A(1:2,1:2' addstr ')']
eval(command)