I need read values of a txt file with MATLAB, the file is here:
-0.933475 0.358642
-1 6.12323e-17
but I have some troubles with this value 6.12323e-17, in matlab when I read it, the vale is 0.0000
here is the MATLAB code:
close all; clear;
arquivo = fopen('fftOut.txt');
formatSpec = '%f %f';
sizeA = [2 inf];
X = fscanf(arquivo,formatSpec, sizeA);
X'
fclose(arquivo);
and the output is
-0.9335 0.3586
-1.0000 0.0000
How can I handle it 0.0000?
Thanks in advance
You are using %f which is fixed point. Use %e for exponential notation. Check out mathwork’s web site: http://www.mathworks.com/help/matlab/matlab_prog/formatting-strings.html?refresh=true
It's not 0, when matlab prints a matrix, it uses the same notation for all elements, so the printed value is truncated but the stored one isn't.
Try printing just the imaginary part of the second number.
Related
I have a function that takes data and imports that data into a text file. The issue that I am having is with formatting. I want to be able to set the width of the columns based on the widest array of characters in that column. So, in the code below I have labels and then data. My idea would be to take the length of each individually and find the largest value. Say the second column labels has 15 chars and that is longer than any data array, then I want to set the width of that column to 15 + 3 (white spaces) making it 18. If column 3 had a max of 8 chars for a member of data, then I would like to set the width to 11. I have found plenty of literature on fixed width, and I found that I could do '-*s', *width, colLabels; but I am having difficulty figuring out how to implement that.
Below is my code and it doesn't fail but it takes forever and then won't open because there is not enough memory. I have really tried to work through this to no avail.
Thanks in advance and if there is any other information I can provide, then let me know.
for col = 1:length(this.colLabels) % iterate through columns
colLen = length(this.colLabels{col}); % find the longest string in labels
v = max(this.data(:,col)); % find the longest double in data
n = num2str(v, '%.4f'); % precision of 4 after decimal place
dataLen = length(n);
% find max width for column and add white space
if colLen > dataLen
colWidth = colLen + 3;
else
colWidth = dataLen + 3;
end
% print it
fprintf(fid, '%-*s', this.colWidth, this.colLabels{col}); % write col position i
fprintf(fid, '\n');
fprintf(fid, '%-*s', this.colWidth, this.colUnits{col});% write unit position i
fprintf(fid, '\n');
fprintf(fid, '%-*s', this.colWidth, this.data(:,col)); % write all rows of data in column i
end
There are few places where you are making mistakes:
The size of number is not necessarily related to its size when printed. Consider 1.1234 and 1000, one of these is a larger string and the other is a larger number. This may or may not matter for your data ...
Two, it is best to use the correct format strings when printing to string. %s is for strings, not numbers.
Perhaps most importantly, text appears on multiple lines because of the newline character which ends one line and starts another. This means you essentially have to write one row at a time, not one column at a time.
I tend to prefer creating the text in memory then writing to a file. The following isn't the cleanest implementation but it works.
this.colLabels = {'test' 'cheese' 'variable' 'really long string'};
this.colUnits = {'ml' 'cm' 'C' 'kg'};
n_columns = length(this.colLabels);
%Fake data
this.data = reshape(1:n_columns*5,5,n_columns);
this.data(1) = 1.2345678;
this.data(5) = 1000; %larger number but smaller string
%Format as desired ...
string_data = arrayfun(#(x) sprintf('%g',x),this.data,'un',0);
string_data = [this.colLabels; this.colUnits; string_data];
%Add on newlines ...
%In newer versions you can use newline instead of char(10)
string_data(:,end+1) = {char(10)};
string_lengths = cellfun('length',string_data);
max_col_widths = max(string_lengths,[],1);
%In newer versions you can use singleton expansion, but beware
n_spaces_add = bsxfun(#minus,max_col_widths,string_lengths);
%left justify filling with spaces
final_strings = cellfun(#(x,y) [x blanks(y)],string_data,num2cell(n_spaces_add),'un',0);
%Optional delimiter between columns
%Don't add delimiter for last column or for newline column
final_strings(:,1:end-2) = cellfun(#(x) [x ', '],final_strings(:,1:end-2),'un',0);
%Let's skip last newline
final_strings{end,end} = '';
%transpose for next line so that (:) goes by row first, not column
%Normally (:) linearizes by column first
final_strings = final_strings';
%concatenate all cells together
entire_string = [final_strings{:}];
%Write this to disk fprintf(fid,'%s',entire_string);
The data in the text file is stored one line after the other, so you cannot write column by column. You need first to determine the width of the columns and write the label/unit header, then write all the data. All we need to have is a proper format string for fprintf: fixed width format and fprintf is extremely useful for exporting column delimited data.
The first part of the code is ok in order to determine the width of the columns (assuming the data only has positive samples). You only need to store it in an array.
nCol=length(this.colLabels);
colWidth = zeros(1,nCol);
for col = 1:nCol
colLen = length(this.colLabels{col}); % find the longest string in labels
v = max(this.data(:,col)); % find the longest double in data
n = num2str(v, '%.4f'); % precision of 4 after decimal place
dataLen = length(n);
% find max width for column and add white space
colWidth(col)=max(colLen,dataLen);
end
Now, we need to build format string for the labels and data, to use with sprintf. The format string will look like '%6s %8s %10s\n' for the header and '%6.4f %8.4f %10.4f\n' for the data.
fmtHeader=sprintf('%%%ds ',colWidth);
fmtData=sprintf('%%%d.4f ',colWidth);
%Trim the triple space at the end and add the newline
fmtHeader=[fmtHeader(1:end-3) '\n'];
fmtData =[fmtData(1:end-3) '\n'];
We use the fact that, when sprintf is given an array as input, it will iterate through all the values to produce a long string. We can use the same trick to write the data, but singe we write line by line and Matlab stores data in column major order, a transpose is necessary.
fid=fopen('myFile.txt');
fprintf(fid,fmtHeader,this.colLabels{:});
fprintf(fid,fmtHeader,this.colUnits{:});
fprintf(fid,fmtData,transpose(this.data));
fclose(fid);
For the headers, the cell can be converted to a comma separated list with {:}. This is the same as writing fprintf(fid,fmtHeader,this.colLabels{1},this.colLabels{2},...)
Using the same test data from #Jimbo 's answer and fid=1; to output the fprintf to the screen the code gives:
test cheese variable really long string
ml cm C kg
1.2346 6.0000 11.0000 16.0000
2.0000 7.0000 12.0000 17.0000
3.0000 8.0000 13.0000 18.0000
4.0000 9.0000 14.0000 19.0000
1000.0000 10.0000 15.0000 20.0000
Finally, the most compact version of the code is:
fid=1; %print to screen for test purpose
colWidth =max( cellfun(#length,this.colLabels(:)') , max(1+floor(log10(max(this.data,[],1))) , 1) + 5); %log10 to count digits, +5 for the dot and decimal digits ; works for data >=0 only
fprintf(fid,[sprintf('%%%ds ',colWidth(1:end-1)) sprintf('%%%ds\n',colWidth(end))],this.colLabels{:},this.colUnits{:}); %print header
fprintf(fid,[sprintf('%%%d.4f ',colWidth(1:end-1)) sprintf('%%%d.4f\n',colWidth(end))],this.data'); %print data
I've been trying to obtain a variable from a text file which I read in within the Matlab workspace.
The file contains the following:
---------------------------------------------------------------
Surface Forces (referred to Sref,Cref,Bref about Xref,Yref,Zref)
Standard axis orientation, X fwd, Z down
Sref = 35.00 Cref = 2.4325 Bref = 14.5000
Xref = 18.5306 Yref = 0.0000 Zref = -0.7092
n Area CL CD Cm CY Cn Cl CDi CDv
1 35.263 0.6972 0.0138 4.8547 0.0040 0.0069 -0.2817 0.0138 0.0000 F27 WING
Surface Forces (referred to Ssurf, Cave about root LE on hinge axis)
n Ssurf Cave cl cd cdv cm_LE
1 35.263 2.432 0.6920 0.0137 0.0000 0.0000 F27 WING
---------------------------------------------------------------
I need the value below CL, in this case its 0.6972. I've tried using fopen and importdata without succes. The importdata just puts the whole file in a cell array with 9 rows and 1 column containing all strings. From there I dont't know how to proceed further.
With the fopen, I've tried to read the file line by line and to check whether he finds the CL string. He does find it but the value its gives is [].
Can anyone give me a tip? Thank you.
Use fgetl() to extract lines you don't need, then use fscanf() to read a line of data into a vector ('dataline'). Then you can access the individual elements of the vector.
Example based on your file:
Open and read file, discarding first 7 lines, including blank lines:
fid = fopen(filename, 'r')
for i = 1:7
oneline = fgetl(fid);
end
read 8th line of file; store in a vector of floats
dataline = fscanf(fid, ['%f' ])
assign third value of vector to 'CL'
CL = dataline(3)
fclose(fid)
CL
ans =
0.6972
If you have the luxury of having one of the newer versions of Matlab, then the following will work.
B = readtable('test.dat'),'Delimiter','\t');
c = regexp(B{9,:}, ' ','split');
CL_vec = c{1,1};
CL_cell = CL_vec(13);
Wing_CL = str2num(CL_cell{1,1});
I am trying to export data from Matlab in format that would be understood by another application... For that I need to change the NaN, Inf and -Inf strings (that Matlab prints by default for such values) to //m, //inf+ and //Inf-.
In general I DO KNOW how to accomplish this. I am asking how (and whether it is possible) to exploit one particular thing in Matlab. The actual question is located in the last paragraph.
There are two approaches that I have attempted (code bellow).
Use sprintf() on data and strrep() the output. This is done in line-by-line fashion in order to save memory. This solution takes almost 10 times more time than simple fprintf(). The advantage is that it has low memory overhead.
Same as option 1., but the translation is done on the whole data at once. This solution is way faster, but vulnerable to out of memory exception. My problem with this approach is that I do not want to unnecessarily duplicate the data.
Code:
rows = 50000
cols = 40
data = rand(rows, cols); % generate random matrix
data([1 3 8]) = NaN; % insert some NaN values
data([5 6 14]) = Inf; % insert some Inf values
data([4 2 12]) = -Inf; % insert some -Inf values
fid = fopen('data.txt', 'w'); %output file
%% 0) Write data using default fprintf
format = repmat('%g ', 1, cols);
tic
fprintf(fid, [format '\n'], data');
toc
%% 1) Using strrep, writing line by line
fprintf(fid, '\n');
tic
for i = 1:rows
fprintf(fid, '%s\n', strrep(strrep(strrep(sprintf(format, data(i, :)), 'NaN', '//m'), '-Inf', '//inf-'), 'Inf', '//inf+'));
end
toc
%% 2) Using strrep, writing all at once
fprintf(fid, '\n');
format = [format '\n'];
tic
fprintf(fid, '%s\n', strrep(strrep(strrep(sprintf(format, data'), 'NaN', '//m'), '-Inf', '//inf-'), 'Inf', '//inf+'));
toc
Output:
Elapsed time is 1.651089 seconds. % Regular fprintf()
Elapsed time is 11.529552 seconds. % Option 1
Elapsed time is 2.305582 seconds. % Option 2
Now to the question...
I am not satisfied with the memory overhead and time lost using my solutions in comparison with simple fprintf().
My rationale is that the 'NaN', 'Inf' and '-Inf' strings are simple data saved in some variable inside the *printf() or *2str() implementation. Is there any way to change their value at runtime?
For example in C# I would change the System.Globalization.CultureInfo.NumberFormat.NaNSymbol, etc. as explaind here.
In the limited case mentioned in comments that a number of (unknown, changing per data set) columns may be entirely NaN (or Inf, etc), but that there are not unwanted NaN values otherwise, another possibility is to check the first row of data, assemble a format string which writes the \\m strings directly, and use that while telling fprintf to ignore the columns that contain NaN or other unwanted values.
y = ~isnan(data(1,:)); % find all non-NaN
format = sprintf('%d ',y); % print a 1/0 string
format = strrep(format,'1','%g');
format = strrep(format,'0','//m');
fid = fopen('data.txt', 'w');
fprintf(fid, [format '\n'], data(:,y)'); %pass only the non-NaN data
fclose(fid);
By my check with two columns of NaN this fprintf is pretty much the same as your "regular" fprintf and quicker than the loop - not taking into account the initialisation step of producing format. It would be fiddlier to set it up to automatically produce the format string if you also have to take +/- Inf into account, but certainly possible. There is probably a cleaner way of producing format as well.
How it works:
You can pass in a subset of your data, and you can also insert any text you like into a format string, so if every row has the same desired "text" in the same spot (in this case NaN columns and our desired replacement for "NaN"), we can put the text we want in that spot and then just not pass those parts of the data to fprintf in the first place. A simpler example for trying out on the command line:
x = magic(5);
x(:,3)=NaN
sprintf('%d %d ihatethrees %d %d \n',x(:,[1,2,4,5])');
I am trying to read data into Matlab consisting of rows of numbers and texts however I only want to read the numerical values and skip the text (whenever it occurs). I have been using textscan but to read the numbers in but when it reaches a column with text the functions terminates.
This is my first post so I am not familiar with how to post my data and code here so I have attached a bit of the data below:
0.37364 1.318 0.1090E-02 0.4885E-03 0.236E-02 0.527E-02
0.39237 1.372 0.1214E-02 0.5470E-03 0.211E-02 0.546E-02
0.41129 1.580 0.1612E-02 0.6992E-03 0.142E-02 0.588E-02
CF SET TO 0.000002 AT X= 0.430 ON SURFACE 1 (1=U/S, 2=L/S)
0.43038 3.070 0.4482E-02 0.1160E-02 0.200E-05 0.905E-02
HBAR MAX LIMIT REACHED
So I want Matlab to read the columns with the numerical data and skip the ones containing the text.
I appreciate your help and thank you in advance!!!
Hamza
Solution
result = [];
fid=fopen('data.txt');
while 1
tline = fgetl(fid);
if ~ischar(tline), break, end
celldata = textscan(tline,'%f %f %f %f %f %f');
matdata = cell2mat(celldata);
% match fails for text lines, textscan returns empty cells
result = [result ; matdata];
end
fclose(fid);
Result
result =
0.3736 1.3180 0.0011 0.0005 0.0024 0.0053
0.3924 1.3720 0.0012 0.0005 0.0021 0.0055
0.4113 1.5800 0.0016 0.0007 0.0014 0.0059
0.4304 3.0700 0.0045 0.0012 0.0000 0.0091
data.txt
0.37364 1.318 0.1090E-02 0.4885E-03 0.236E-02 0.527E-02
0.39237 1.372 0.1214E-02 0.5470E-03 0.211E-02 0.546E-02
0.41129 1.580 0.1612E-02 0.6992E-03 0.142E-02 0.588E-02
CF SET TO 0.000002 AT X= 0.430 ON SURFACE 1 (1=U/S, 2=L/S)
0.43038 3.070 0.4482E-02 0.1160E-02 0.200E-05 0.905E-02
HBAR MAX LIMIT REACHED
I came up with the following work-around:
m=1;
for k=1:10; % create for loop ranging from start to finish of data
ful = sscanf(S{k,1},'%f'); % scan each line for a floating point number
le=size(ful); % gives size of the scanned values
if le(1) > 0 % Only read if there is a value of > 0 ( for non-floating i.e. string, the value = 0)
for t=1:le(1)
data1(m,t)=ful(t); % store the value in matrix
end
m=m+1;
end
end
This seems to do the trick!
I have a question regarding the importing of .txt files. The file is in the format below, the problem is that matlab does not seem to recognize the "new line" character indicators following every "$", so matlab just sees the 5th line as a continuous stream of data
Data Matlab sees:
01-24-2013 [6:01:53]
Kp (0070.0000)
Ki (0200.0000)
Kd (0009.0000)
$,0045,0044,0000.05,0011.53,0005.64,$,0045,0048,0000.04,0011.55,0005.66,$....etc
01-24-2013 [7:01:48]
Data Wordpad sees:
01-24-2013 [6:01:53]
Kp (0070.0000)
Ki (0200.0000)
Kd (0009.0000)
$,0045,0044,0000.05,0011.53,0005.64,
$,0045,0048,0000.04,0011.55,0005.66,
$, ....
I have no problem importing the format seen by "wordpad (re-saved with)" using "csvread" and skipping column 1, but for the raw .txt file "Data Matlab sees", I cant find a way to tell Matlab how to read. Ideally, I would like to tell Matlab to skip to Row-5, then start reading data and creating a new line in the matrix [nx5] every time it encounters a "$". Is there a way to detect the "$" and reformat the data into a usable matrix form?
Thanks!
I don't know how you managed to read this data as one line, but suppose you did and you want to split it. You can use the almighty regexp to for that:
C = regexp(str, '\$,', 'split');
Then turn the strings into numbers and convert everything into a matrix:
C = cellfun(#str2num, C, 'Uniform', false);
A = vertcat(C{:});
Regarding the second part of the question:
Ideally, I would like to tell Matlab to skip to Row-5, then start reading data...
You can make textread do that by using the 'headerlines' option:
C = textread('file.txt', '%s', 1, 'headerlines', 4, 'delimiter', '\n')
str = C{1};
and then use the code that employs regexp to split the string str.
Note that this will only work if MATLAB indeed "sees" the 5th line like you described. If not, you'll simply get only the first row in your matrix.
Example
str = '$,0045,0044,0000.05,0011.53,0005.64,$,0045,0048,0000.04,0011.55,0005.66';
C = cellfun(#str2num, regexp(str, '\$,', 'split'), 'Uniform', false);
A = vertcat(C{:})
This results in:
A =
45.0000 44.0000 0.0500 11.5300 5.6400
45.0000 48.0000 0.0400 11.5500 5.6600