Iterate through a lot of Structs - matlab

my Problem is the following:
I have about 300 Struct files given.
They are set up like this:
DSC_0001 has about 250 other struct files in it:
-> like this: DSC_0001.marker_1
And this one has 10 Numbers in it.
Like that:
DSC_0001.marker_1.flow_angle = 90
and now I want to iterate through all the Struct files
Something like that:
for i = 1:300
for j = 1:250
flow_angle = DSC_**i**.marker_**j**
end
end
Is there a way to do this?
I have the feeling that it could be really easy but I just can't find the solution...
I hope my question is clear enough...
Thanks for your help!

If possible don't use eval.
It depends on how your data is stored, but one possiblity is that it is in a .mat file. In that case it can be loaded using
DSC_structs = load('My_DSC_struct_file.mat');
and then you can access the values like so:
for i = 1:300
for j = 1:250
flow_angle(i,j) = DSC_structs.(['DSC_' sprintf('%04d',i)]).(['marker_' sprintf('%d',j)]);
end
end
Why avoid the eval function
Edit: You say that each struct is in a different file. That's a bit messier. I would probably do something like this to load them:
DSC_structs = cell(1,300);
for i = 1:300
%Note: I'm guess at your file names here
DSC_structs{i} = load(['DSC_' sprintf('%04d',i) '.mat'];
end
and then access the values as
DSC_structs{i}.(['DSC_' sprintf('%04d',i)]).(['marker_' sprintf('%d',j)]);

I guess this is a use case for the dreaded eval function:
for i = 1:300
for j = 1:250
eval (['flow_angle = DSC_', sprintf('%04d',i), '.marker_', num2str(j)]);
end
end
BUT NB there are 2 problems with my code above
You haven't told us where you want to store your angle, so my code doesn't :/ but you'd want something like this if you just want to store them in a matrix: eval (['flow_angle(', num2str(i), ',', num2str(j), ') = DSC_', sprintf('%04d',i), '.marker_', num2str(j)])
eval is a horrible way of doing things but you're forced to because someone saved your data in a horrible. Sort yourself out now for the future by re-saving your data in a smarter way! so something like:
.
for i = 1:300
eval ( ['DSC(', num2str(i), ') = DSC_', sprintf('%04d',i)]);
end
%// then save DCS!
And now your can iterate through this matrix of structs rather than having a 300 structs polluting your workspace and forcing you to use eval

Related

How to load a sequence of image files using a for loop in MATLAB?

I am beginner in MATLAB. I would like to load 200 image files (size 192x192) in a specific folder by using a for loop.
The image names are '1.png', '2.png', '3.png' and so on.
My code is as below.
list = dir('C:/preds/*.png');
N = size(list,1);
sum_image = zeros(192,192,200);
for i = 1:N
sum_image(:,:,i) = imread('C:/preds/i.png');
end
Which part should I change ?
I would probably do it like the code below:
You are currently getting the list of filenames then not really doing much with it. Iterating over the list is safer otherwise if there is a missing number you could have issues. Also, the sort maybe unnecessary depending if you image numbering is zero-padded so they come out in the correct order ... but better safe than sorry. One other small change initializing the array to size N instead of hard-coding 200. This will make it more flexible.
searchDir = 'C:\preds\';
list = dir([searchDir '*.png']);
nameList = {list.name}; %Get array of names
imNum = str2double(strrep(nameList,'.png','')); %Get image number
[~,idx] = sort(imNum); %sort it
nameList = nameList(idx);
N = numel(nameList);
sum_image = zeros(192,192,N);
for i=1:N
sum_image(:,:,i) = imread(fullfile(searchDir,nameList{i}));
end
I would suggest changing the line within the loop to the following:
sum_image(:,:,i) = imread(['C:/preds/', num2str(i), '.png']);
MATLAB treats the i in your string as a character and not the variable i. The above line of code builds your string piece by piece.
If this isn't a homework problem, the right answer to this question is don't write this as a for loop. Use an imageDatastore:
https://www.mathworks.com/help/matlab/ref/imagedatastore.html
ds = imageDatastore('C:/preds/');
sumImageCellArray = readall(ds);
sumImage = cat(3,sumImageCellArray{:});

Dynamic switch in Matlab MAT file

I have a Matlab mat file, which has the following variables:
variable0
variable1
variable2
variable3
Is it possible to dynamically index them and modify, something like this:
function setVariable(obj, variableNum, data)
obj.matFile.(variable0+variableNum) = data;
end
So, if someone passes 0 variable 0 is modified and if someone passes 3 then variable three. I know this code doesn't work, this is just some example of what I tried. My current solution is to use a switch statement. This is not so good as in the C++ code, I am using indexing like above. I would like the C++ and Matlab to be as close as possible.
ANSWER
I did it this way and it is working:
eval(sprintf('obj.matfile_variable%d = data;', variableNum));
function setVariable(obj, variableNum, data)
% check if variableNum is numeric
if isnumeric(variableNum)
variableNum = num2str(variableNum);
varName = strcat('variable',variableNum);
else
varName = strcat('variable',variableNum);
end
obj.matFile.(varName) = data;
end
This should do the trick.
What about using
obj.matFile(variableNum).data = data;

MATLAB Changing the name of a matrix with each iteration

I was just wondering if there is a clean way to store a matrix after each iteration with a different name? I would like to be able to store each matrix (uMatrix) under a different name depending on which simulation I am on eg Sim1, Sim2, .... etc. SO that Sim1 = uMatrix after first run through, then Sim2 = uMatrix after 2nd run through. SO that each time I can store a different uMatrix for each different Simulation.
Any help would be much appreciated, and sorry if this turns out to be a silly question. Also any pointers on whether this code can be cleaned up would be great too
Code I am using below
d = 2;
kij = [1,1];
uMatrix = [];
RLABEL=[];
SimNum = 2;
for i =1:SimNum
Sim = ['Sim',num2str(i)] %Simulation number
for j=1:d
RLABEL = [RLABEL 'Row','',num2str(j) ' '];
Px = rand;
var = (5/12)*d*sum(kij);
invLam = sqrt(var);
u(j) = ((log(1-Px))*-invLam)+kij(1,j);
uMatrix(j,1) = j;
uMatrix(j,2) = u(j);
uMatrix(j,3) = kij(1,j);
uMatrix(j,4) = Px;
uMatrix(j,5) = invLam;
uMatrix(j,6) = var;
end
printmat(uMatrix,'Results',RLABEL,'SECTION u kij P(Tij<u) 1/Lambda Var')
end
There are really too many options. To go describe both putting data into, and getting data our of a few of these methods:
Encode in variable names
I really, really dislike this approach, but it seems to be what you are specifically asking for. To save uMatrix as a variable Sim5 (after the 5th run), add the following to your code at the end of the loop:
eval([Sim ' = uMatrix;']); %Where the variable "Sim" contains a string like 'Sim5'
To access the data
listOfStoredDataNames = who('Sim*')
someStoredDataItem = eval(listOfStoredDataNames {1}) %Ugghh
%or of you know the name already
someStoredDataItem = Sim1;
Now, please don't do this. Let me try and convince you that there are better ways.
Use a structure
To do the same thing, using a structure called (for example) simResults
simResults.(Sim) = uMatrix;
or even better
simResults.(genvarname(Sim)) = uMatrix;
To access the data
listOfStoredDataNames = fieldnames(simResults)
someStoredDataItem = simResults.(listOfStoredDataNames{1})
%or of you know the name already
someStoredDataItem = simResults.Sim1
This avoids the always problematic eval statement, and more importantly makes additional code much easier to write. For example you can easily pass all simResults into a function for further processing.
Use a Map
To use a map to do the same storage, first initialize the map
simResults = containers.Map('keyType','char','valueType','any');
Then at each iteration add the values to the map
simResults(Sim) = uMatrix;
To access the data
listOfStoredDataNames = simResults.keys
someStoredDataItem = simResults(listOfStoredDataNames{1})
%or of you know the name already
someStoredDataItem = simResults('Sim1')
Maps are a little more flexible in the strings which can be used for names, and are probably a better solution if you are comfortable.
Use a cell array
For simple, no nonsense storage of the results
simResults{i} = uMatrix;
To access the data
listOfStoredDataNames = {}; %Names are Not available using this method
someStoredDataItem = simResults{1}
Or, using a slight level of nonesense
simResults{i,1} = Sim; %Store the name in column 1
simResults{i,2} = uMatrix; %Store the result in column 2
To access the data
listOfStoredDataNames = simResults(:,1)
someStoredDataItem = simResults{1,2}
Just to add to the detailed answer given by #Pursuit, there is one further method I am fond of:
Use an array of structures
Each item in the array is a structure which stores the results and any additional information:
simResults(i).name = Sim; % store the name of the run
simResults(i).uMatrix = uMatrix; % store the results
simResults(i).time = toc; % store the time taken to do this run
etc. Each element in the array will need to have the same fields. You can use quick operations to extract all the elements from the array, for example to see the timings of each run at a glance you can do:
[simResults.time]
You can also use arrayfun to to a process on each element in the array:
anon_evaluation_func = #(x)( evaluate_uMatrix( x.uMatrix ) );
results = arrayfun( anon_evaluation_func, simResults );
or in a more simple syntax,
for i = 1:length(simResults)
simResults(i).result = evaluate_uMatrix( simResults(i).uMatrix );
end
I would try to use a map which stores a <name, matrix>.
the possible way to do it would be to use http://www.mathworks.com/help/matlab/map-containers.html

creating variables from structures in matlab

I have the following example which expresses the type of problem that I'm trying to solve:
clear all
textdata = {'DateTime','St','uSt','Ln','W'};
data = rand(365,4);
Final = struct('data',data,'textdata',{textdata})
clear textdata data
From this, Final.data contains values which correspond to the headings in Final.textdata excluding the first ('DateTime') thus Final.data(:,1) corresponds to the heading 'St'... and so on. What I'm trying to do is to create a variable in the workspace for each of these vectors. So, I would have a variable for St, uSt, Ln, and W in the workspace with the corresponding values given in Final.data.
How could this be done?
Will this solve your problem:
for ii=2:length( textdata )
assignin('base',Final.textdata{ii},Final.data(:,ii-1));
end
Let me know if I misunderstood.
The direct answer to your question is to use the assignin function, like so (edit: just like macduff suggested 10 minutes ago):
%Starting with a Final structure containing the data, like this
Final.textdata = {'DateTime','St','uSt','Ln','W'};
Final.data = rand(365,4);
for ix = 1:4
assignin('base',Final.textdata{ix+1}, Final.data(:,ix));
end
However, I strongly discourage using dynamic variable names to encode data like this. Code that starts this way usually ends up as spaghetti code full of long string concatenations and eval statements. Better is to use a structure, like this
for ix = 1:4
dataValues(Final.textdata{ix+1}) = Final.data(:,ix);
end
Or, to get the same result in a single line:
dataValues = cell2struct(num2cell(Final.data,1), Final.textdata(2:end),2)

matlab code source

how to write a program in matlab that reads a certain number of images let's say 20 for example which are saved in a given directory (C:) such that later i can use them. suppose that the images are saved by numbers. later, i am gonna use them.
I'd have the code look something like this. Assuming cell array im holds your images.
Write out:
IMG_DIR = 'C:\';
filename_root = 'image';
IMG_EXT = '.jpg';
NUM_IMAGES = 20;
for i = 1:NUM_IMAGES
imwrite(im{i}, [IMG_DIR filename_root num2str(i) IMG_EXT]);
end
Read in:
for i = 1:NUM_IMAGES
im{i} = imread([IMG_DIR filename_root num2str(i) IMG_EXT]);
end
If you don't know how many there are, you can also use ls command (works differently in Windows vs. Linux).
If you don't know, in advance, which files will be in there, but you know that they have the string in them, 'rawImage' (like 'rawImage001.jpg' etc.) you can do something like
a = dir('c:\temp');
requiredBaseFileName = 'rawImage'; % you want them to contain the substring 'rawImage'
for i = 1:length(a),
fileName = a(i).name;
if(isempty(strfind(fileName,'.jpg')) & isempty(strfind(fileName,'.png')))
continue;
end
if(isempty(strfind(fileName,requiredBaseFileName)))
continue;
end
% do your processing here
end