MATLAB Answers

0

How to use eval(sprintf) without padding?

Asked by Octavian on 14 Dec 2013
Latest activity Edited by per isakson
on 16 Feb 2017
Dear All,
I inherited a code snippet as part of a larger routine, so I have to use it with minor modifications. With it, a text file containing 3D coordinates of different points in space, points organized in clusters, is read into a corresponding .mat double file containing those 3D coordinates. Here is an example of the text file, each of its lines contains point cluster name, point name (same as cluster) and index, and the 3D (disregard the 4th) coordinates:
MO MO9 149.529 157.814 215.614 0
MO MO8 139.855 157.87 215.594 0
MO MO7 133.018 155.614 210.281 0
MO MO6 130.482 151.464 201.607 0
MO MO5 130.692 147.173 192.942 0
MO MO4 131.176 142.157 183.961 0
MO MO3 131.3 136.15 176.05 0
I show only a cluster, but the real files have several. Now, the code snipped generates a matrix of 3D coordinates in order of the point index value, however, it adds 0 coordinates for two inexistent MO1 and MO2 points (the points have not originally been numbered starting with 1, long story why). Here is the .mat contents:
0 0 0
0 0 0
131.300000000000 136.150000000000 176.050000000000
131.176000000000 142.157000000000 183.961000000000
130.692000000000 147.173000000000 192.942000000000
130.482000000000 151.464000000000 201.607000000000
133.018000000000 155.614000000000 210.281000000000
139.855000000000 157.870000000000 215.594000000000
149.529000000000 157.814000000000 215.614000000000
Question: How do I write into the .mat file just the existent points MO3-8, without imaginary points? Here is the code:
fid = fopen(['path to file/file.txt'],'r');
line = fgetl(fid);
PointNames = {};
while line ~= -1
c = textscan(line, '%s %s %f %f %f %f');
pointName = c{1}{1};
pos = [c{3:5}];
pointIdx = str2double(c{2}{1}(length(pointName)+1:end));
PointNames{size(PointNames,2)+1} = pointName;
eval(sprintf('%s(%i,:) = [%f %f %f];', pointName, pointIdx,pos));
line = fgetl(fid);
end
fclose(fid);
I suspect it has to do with '%s(%i,:)', but here I get stuck.
Many thanks, Octavian.

  2 Comments

Please attach file.txt so we can try your code. And for next time read this: http://www.mathworks.com/matlabcentral/answers/13205-tutorial-how-to-format-your-question-with-markup (I fixed your formatting this time for you)
Well taken, here is the file, thank you, Octavian

Sign in to comment.

3 Answers

Answer by Octavian on 15 Dec 2013
 Accepted Answer

Dear Image Analyst & All,
I found a solution, to follow to my initial code posted; these lines would delete those all 0 rows in all mat files corresponding to different clusters.
for name = PointNames
name = name{1};
eval(sprintf('%s = %s(%s(:,1)~=0 |%s(:,2)~=0|%s(:,3)~=0,:);', name,name,name,name,name));
end
Let me know of any suggestions/ comments,
Octavian

  1 Comment

You never said anything about mat files. You only said you have a text file. Moreover, your code above doesn't do anything with any mat files. Plus you're using eval() which is virtually never recommended. Note how I deleted all rows where all numbers were 0 in my previous answer:
% Find the bad rows that are all zeros.
badRows = all(myArray==0, 2)
% Remove those rows:
myArray(badRows) = []
I'm pretty sure that all experienced MATLAB programmers would do it my way rather than your way.
Also, how you're dealing with "name" variable is very non-standard. Where did you learn that it's okay to redefine a loop iterator variable inside the loop? Fortunately with MATLAB it won't have any effect because redefining iterators inside the loop is basically ignored when the loop starts again but it's not like that in every language. For example the following loop will execute 10 times, not once:
for k = 1 : 10
k = 10
end
And finally it seems like you're bucking the recommendation in the FAQ link I gave you about creating variable names in a loop, where it recommends you don't do that . You're doing it anyway despite the recommendation not to. Apparently it's expedient that you use your code (because it works) but soon you should look at this link : http://www.mathworks.com/matlabcentral/answers/8026-best-way-s-to-master-matlab

Sign in to comment.


Answer by Image Analyst
on 14 Dec 2013

  4 Comments

Show 1 older comment
Try this:
folder = pwd; % Current folder.
fullFileName = fullfile(folder, 'file.txt');
% Check if file exists.
if ~exist(fullFileName, 'file')
% File doesn't exist -- didn't find it there. Check the search path for it.
fullFileName = baseFileName; % No path this time.
if ~exist(fullFileName, 'file')
% Still didn't find it. Alert user.
errorMessage = sprintf('Error: %s does not exist in the search path folders.', fullFileName);
uiwait(warndlg(errorMessage));
return;
end
end
% File exists, so open it.
fid = fopen(fullFileName,'r');
thisLine = fgetl(fid);
PointNames = {};
lineNumber = 1;
myArray = zeros(1, 4);
% Scan line by line, building up the array.
while thisLine ~= -1
c = textscan(thisLine, '%s %s %f %f %f %f');
myArray(lineNumber, 1) = c{3};
myArray(lineNumber, 2) = c{4};
myArray(lineNumber, 3) = c{5};
myArray(lineNumber, 4) = c{6};
% Increment the line counter for next time.
lineNumber = lineNumber + 1;
% Retrieve the next line:
thisLine = fgetl(fid);
end
fclose(fid);
% Show in command window:
myArray
Dear Image Analyst
Thank you for your assist. The problem is a bit more complicated, as I mentioned the output coordinate files must list those in the increasing point index order; if I have, say, MO7,9,8,3,5,4,6,7 successively in the .txt file, the output .mat has to list coordinates of points MO3,4,5,6,7,8,9. The code I posted does that, in that for each line read, calling the eval(sprintf) creates a pointIdx (which is the point index) by 3 double array, where all elements except the bottom row are 0. With each iteration/ line reading, the workspace .mat coordinate file is overwritten, this way the results is always a ordered (point-index-wise) array. Besides, the code generates a separate array per cluster, which is required downstream. Please apply my code on another file I attach with 3 point clusters, to be clear as to what the scope of my quest is. Again, all is well, except that the code generates rows of 0 for incomplete point index series (counting not beginning with 1) and I would like to change this, or delete them (automatically) as the next step in the routine, I tried
eval(sprintf('%s = %s(%s(:,1)~=0& %s(:,2)~=0&%s(:,3)~=0,:);', trodeName));
but it does not work. Thank you,
Octavian.
You don't need eval() - please stop using it. Try this code:
folder = pwd; % Current folder.
fullFileName = fullfile(folder, 'file.txt');
% Check if file exists.
if ~exist(fullFileName, 'file')
% File doesn't exist -- didn't find it there. Check the search path for it.
fullFileName = baseFileName; % No path this time.
if ~exist(fullFileName, 'file')
% Still didn't find it. Alert user.
errorMessage = sprintf('Error: %s does not exist in the search path folders.', fullFileName);
uiwait(warndlg(errorMessage));
return;
end
end
% File exists, so open it.
fid = fopen(fullFileName,'r');
thisLine = fgetl(fid);
myArray = zeros(1, 4);
% Scan line by line, building up the array.
while thisLine ~= -1
c = textscan(thisLine, '%s %s %f %f %f %f');
% Get the single digit after MO.
secondString = char(c{2});
theIndex = str2double(secondString(3:end));
myArray(theIndex, 1) = c{3};
myArray(theIndex, 2) = c{4};
myArray(theIndex, 3) = c{5};
myArray(theIndex, 4) = c{6};
% Retrieve the next line:
thisLine = fgetl(fid);
end
fclose(fid);
% Show in command window:
myArray
% Find the bad rows that are all zeros.
badRows = all(myArray==0, 2)
% Remove those rows:
myArray(badRows) = []

Sign in to comment.


Answer by Octavian on 15 Dec 2013

Sorry,
but the above does not save individual .mat arrays for each cluster (SO, MO and OP), nor gets coordinates in the order of the point indexes, please try the above file to see. Also, if this does not become too complicated, please run both codes and see the difference in outputs. Thanks, Octavian

  0 Comments

Sign in to comment.