Reading data from ASCII file
390 views (last 30 days)
Show older comments
Pratyush Manocha
on 17 May 2020
Commented: Pratyush Manocha
on 19 May 2020
Hi,
I have an ASCII file with data corresponding to several runs of a simulation. I want to plot all the runs in the same plot for comparison purposes and know that I have to import the data as a matrix to begin with any other processing. However, I have been facing problems with importing the data. I have attached the file here for reference purposes.
This was my take on solving this problem:
1. Using textscan
fidi = fopen('data.txt');
D=textscan(fidi, '%u %u');
E = cell2mat(D);
However, this returned empty cells as is shown by the following command:
whos E
Name Size Bytes Class Attributes
E 0x2 0 uint32
2. Using textread
fid = 'data.txt';
B = textread(fid, '%f %f');
This returned the following errors:
Error using dataread
Number of outputs must match the number of unskipped input fields.
Error in textread (line 171)
[varargout{1:nlhs}]=dataread('file',varargin{:}); %#ok<REMFF1>
Then I changed the code to this:
[B,C]=textread(fid, '%f %f');
Which in turn returned the following errors:
Error using dataread
Trouble reading floating point number from file (row 1, field 1) ==> vds Id(M1)\n
Error in textread (line 171)
[varargout{1:nlhs}]=dataread('file',varargin{:}); %#ok<REMFF1>
3. Using spcread
B=spcread(fid);
This gave the following error:
Undefined function or variable 'spcread'.
4. Using importdata
I had limited success with this, but this was as far as I could go...
A=importdata(fid);
This gave me a 1x1 struct file with a 101x2 double comprising of the first 101 lines of the text file and a 2x1 cell with the first two header lines.
I then removed all the header files which did import the entire data, albeit without all headers and would require splitting into multiple matrices to be able to plot all of the runs in one graph (because if I recall correctly, plot function doesn't support dot indexing for variables of the form A.data) like so (output taken from a commercial spice simulator):
![](https://www.mathworks.com/matlabcentral/answers/uploaded_files/293568/image.png)
Could someone help me import the data properly so that I can move to plotting the curves?
0 Comments
Accepted Answer
Stephen23
on 18 May 2020
Edited: Stephen23
on 18 May 2020
Importing the entire file data as character, converting to string, spltting that string into multiple little strings, and then finally converting those many little strings to numeric is convoluted, an inefficient use of memory (because on each of those conversions you duplicate the data in MATLAB memory), and involves multiple data type conversions (also inefficient).
The most efficient way to import the data is to get the importing routine to directly convert the data to numeric, for example very simply using textscan (no data duplication required):
opt = {'CollectOutput',true};
hdr = {};
out = {};
[fid,msg] = fopen('data.txt','rt');
assert(fid>=3,msg) % ensure the file opened correctly.
fgetl(fid); % read and ignore the very first line.
while ~feof(fid)
hdr{end+1} = fgetl(fid);
out(end+1) = textscan(fid,'%f%f',opt{:});
end
fclose(fid);
Giving all eleven groups of data:
>> size(out)
ans =
1 11
Take a quick look at the imported data:
>> out{1}
ans =
0 0
0.1 1.3168e-10
0.2 1.3725e-10
0.3 1.4305e-10
0.4 1.4907e-10
0.5 1.5532e-10
0.6 1.6183e-10
... lots more lines here
9.6 5.8922e-09
9.7 6.1318e-09
9.8 6.3811e-09
9.9 6.6406e-09
10 6.9106e-09
>> out{11}
ans =
0 0
0.1 0.00020176
0.2 0.00038716
0.3 0.00055754
0.4 0.00071407
0.5 0.00085781
0.6 0.00098973
0.7 0.0011107
0.8 0.0012214
0.9 0.0013227
1 0.0014152
1.1 0.0014994
... lots more lines here
9.2 0.0027014
9.3 0.0027099
9.4 0.0027185
9.5 0.002727
9.6 0.0027355
9.7 0.002744
9.8 0.0027525
9.9 0.0027611
10 0.0027696
Converting the intermediate header data to numeric is trickier because some of them include SI prefixes (e.g. '500m' for 0.5) but one easy approach is to download my FEX submission sip2num and do something like this:
>> mat = cell2mat(cellfun(@sip2num,strrep(hdr(:),'Inf',''),'uni',0))
mat =
0 1 11
0.5 2 11
1 3 11
1.5 4 11
2 5 11
2.5 6 11
3 7 11
3.5 8 11
4 9 11
4.5 10 11
5 11 11
5 Comments
J. Alex Lee
on 18 May 2020
This answer indeed looks better. I didn't realize textscan can be used this way...it fails out gracefully by just not continuing and keeping file pointer where it is.
More Answers (1)
J. Alex Lee
on 17 May 2020
It would have been helpful to know these things in advance (you hinted at the first, but say it explicitly)
- Data contains multiple header rows for multiple sets of data
- Each data set is exactly 101 data points long
Without having known the 2nd detail, here's a script that will split your data - maybe there's more elegant ways (certainly much better ones knowing the exact length of all data sets)
fc = string(fileread('data.txt'));
flines = split(fc,newline);
% remove empty lines
flines(flines=="") = [];
HeaderMask = contains(flines,"Step");
HeaderIdx = find(HeaderMask);
% pad the indices with "ghost" line after last line
HeaderIdx(end+1) = length(flines)+1;
NSets = length(HeaderIdx) - 1;
hdrs = flines(HeaderMask)
for i = NSets:-1:1
tmp = flines(HeaderIdx(i)+1:HeaderIdx(i+1)-1);
tmp = str2double(split(tmp,char(9)));
data{i,1} = tmp;
hdrs(i,1) = flines(HeaderIdx(i));
end
8 Comments
J. Alex Lee
on 18 May 2020
In this case, in my inefficient process of reading in the text data into a string, Matlab showed the tab character as a right-arrow in the command line. But as Stephen's answer indicates, I guess you don't necessarily need to know that since textscan can figure it out.
You could also copy-paste the character and do
double(' ')
See Also
Categories
Find more on Text Data Preparation in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!