How can I save the information generate in the script below which include strings and table in the following format to a text file?
Format:
M=5
1 21
2 22
3 23
4 24
5 25
5points
Script:
clc;
clear all;
close all;
ElmentsNum = "EM=5";
x = (1:5)';
y =(21:25)';
t = table(x,y);
M = "5points"
fileID = fopen('E:/Data.txt');
fprintf(fileID,'%s/n',ElmentsNum)
fprintf(fileID,'%.4f',t)
fprintf(fileID,'%s/n',M)
fclose(fileID)
Quite simple, just extract the values of the table, then write them line by line:
extracted_table=table2array(t);
fileID = fopen('Data.txt','w');
fprintf(fileID,'%s\n',ElmentsNum);
for ii=1:size(extracted_table,1)
% fprintf(fileID,'%.4f %.4f\n',extracted_table(ii,:)); % if you want decimal places
fprintf(fileID,'%d %d\n',extracted_table(ii,:)); % if you want integers (as in the example)
end
fprintf(fileID,'%s\n',M);
fclose(fileID);
Related
I made a 865850 by 4464 matrix.
Then I need to save it to a .txt file.
For that, I use fprintf, but I met a hard obstacle....
There are 4464 columns. How can I designate their formatspec?
They are all integers.
Now I know just one way...
fprintf(fid, '%10d %10d.....%10d', Zeros); (4464times..)
Is the only way to save them?
Thank you~!!
clear all; close all;
loop = 1;
Zeros = zeros(15000, 4464);
fileID = fopen('data2.txt','r');
while loop < 4200
Data = fscanf(fileID, '%d %d %d:%d %d\n', [5, 100000]);
Data = Data';
DataA = Data(:,1);
DataB = Data(:,2);
DataC = Data(:,3);
DataD = Data(:,4);
DataE = Data(:,5);
for m=1:100000
r = DataA(m);
c = ((DataB(m)-1)*24*6 + DataC(m)*6 + DataD(m))+1;
Zeros(r,c) = DataE(m);
end
for n=1:4464
Zeros1{n}=Zeros(:, n);
fileID2 = fopen('result.txt','a');
fprintf(fileID2, '%10d %10d\n ', Zeros1{1}, Zeros1{2});
end
fclose(fileID2);
loop = loop + 1;
end
don't use printf with the whole row. Use the CSV export, or iterate over each element of each row and print it isolatedly.
I frequently like to add that for data of this size, textual storage is a bad idea. No one will ever open this in a text editor and think "Oh, this is practical". Everyone will have a bad time carrying around hundreds of megabytes of unnecessary file size. simply use the savemat methods to store the data if you plan to open it in matlab, or use a binary format, for example by just doing fwrite on the data to a file with a sensible binary representation of your numbers.
You could also just use the built-in MATLAB ASCII save format (instead of printf):
>> foo = magic( 4 )
foo =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
>> save( 'foo.txt', '-ascii', 'foo' )
Im trying to plot trajectories on matlab
My data file (try.txt) that has the trajectories looks like this:
NumofTrajectories
TrajID1 #ofPoints x y x y....
TrajID2 #ofPoints x y x y....
example:
7
0 23 898.6 673.0 859.1 669.9 813.7 667.8 776.8 664.0 739.8 662.1 699.9 654.7 664.5 649.6 625.3 645.5 588.2 640.6 552.3 634.2 516.6 628.2 477.2 624.3 442.1 613.6 406.7 603.4 369.5 599.8 332.7 594.1 297.4 585.2 258.6 583.7 224.1 573.1 191.2 556.8 152.7 554.0 115.1 546.0 79.6 535.8
1 8 481.4 624.9 445.9 596.3 374.5 573.9 354.2 541.0 334.2 508.9 327.6 474.1 324.6 437.5 324.2 390.3
2 24 151.6 570.8 188.3 556.5 225.1 547.7 257.9 529.4 292.9 509.8 326.8 496.8 356.2 476.0 391.2 463.3 423.7 447.9 455.7 431.8 489.2 416.0 524.3 405.3 560.0 395.9 595.8 385.6 632.8 376.1 671.5 372.0 706.9 361.8 742.3 347.3 778.0 334.5 820.5 336.5 856.5 325.0 894.5 309.5 946.1 309.9 990.5 287.0
3 3 594.2 580.4 566.6 544.3 544.9 509.4
4 5 281.8 661.9 266.8 623.4 246.2 576.4 229.7 541.0 220.9 498.4
5 2 563.6 511.3 532.5 479.7
6 5 571.9 617.7 525.6 576.4 481.0 551.9 456.8 524.2 419.7 474.0
I'm trying to plot this on matlab
my code is as follows:
clc;
clear;
%read the input
importfile('try.txt')
%See how many trajectorys there are convert to number
nTraj=str2num(cell2mat(textdata));
%loop over the trajectories
for i = 1:nTraj
disp(data(i,1));
%print the current trajectory number of points
disp(data(i,2));
%get the x-y coordinates of each trajectory
current_traj=data(i,2);
for j=1:current_traj
points=data(i,3:j*2+2);
end
%print the x-y coordinates of each trajectory
%disp(points);
%seperate the x-y coordinates of each trajectory
x=points(1:2:length(points)-1)
y=points(2:2:length(points))
xlabel('latitude');
ylabel('longitude');
plot(x,y,'r');
grid on ;
hold on;
end
And function importfile:
function importfile(fileToRead1)
%IMPORTFILE(FILETOREAD1)
% Imports data from the specified file
% FILETOREAD1: file to read
DELIMITER = ' ';
HEADERLINES = 1;
% Import the file
newData1 = importdata(fileToRead1, DELIMITER, HEADERLINES);
% Create new variables in the base workspace from those fields.
vars = fieldnames(newData1);
for i = 1:length(vars)
assignin('base', vars{i}, newData1.(vars{i}));
end
The code sometimes works and usually gives me an error say:
Index exceeds matrix dimensions.
Error in ==> plotTrajectory at 23
points=data(i,3:j*2+2);
Can someone explain the error and tell me how to fix it?
The trajectories in try.txt have different lengths. importdata will use the first line to determine the length of your data. If another line is the longest, this line will be split over several lines of your imported matrix. At least this is what debugging shows. I would suggest you use another method to read your file. For me dlmread works:
%read the input
data = dlmread('try.txt', ' ');
% remove header
data = data(2:end,:);
%See how many trajectorys there are convert to number
nTraj=size(data,1);
You can replace your first lines with this code and remove your importfilefunction.
I have a big problem to Acquire a block of data structured in a particular way.
Here's how the data are to be acquired (is a txt):
V|0|0|0|t|0|1|1|4|11|T4|H13||||||||||||
P|40|0.01|10|1|1|0|40|1|1|1||1|*||0|0|0
*|A1|A1|A7|A16|F|F|F|F|F|F|||||||||||||
*|codserv|area|codice|nome|tnom|tmin|tmax|pc|qc|susc|||||||
*|||||kV|kV|kV|MW|MVAR|S||||||||||||
N|I|1|N01|N01|132|125.4|138.6|0|0||||||||
N|I|1|N02|N02|20|19|21|0|0|||||||||||||
N|I|1|N03|N03|20|19|21|1.013532234|0.49087611||||||||
N|I|1|N04|N04|20|19|21|0.390791617|0.189269056||||||||
N|I|1|N05|N05|20|19|21|0.180634542|0.121387171||||||||
N|I|1|N06|N06|20|19|21|0.709472564|0.343613323||||||||
N|I|1|N07|N07|20|19|21|0.103495727|0.069549543||||||||
N|I|1|N08|N08|20|19|21|0.351712456|0.170342158||||||||
N|I|1|N09|N09|20|19|21|0.097697904|0.06565339||||||||
N|I|1|N10|N10|20|19|21|0.162165157|0.078540184||||||||
The algorithm should:
skip the first 3 rows
skip fifth row
The fourth row
*|codserv|area|codice|nome|tnom|tmin|tmax|pc|qc|susc|||||||
save each string in a vector empty
codeserv=[]
area=[]
codice=[]
nome=[]
tnom=[]
tmin=[]
tmax=[]
pc=[]
qc=[]
susc=[]
Fill vectors with data and strings in the rows following the fourth
codeserv=[N N N N N N N N N N ....]
area=[I I I I I I I ....]
codice=[1 1 1 1 1 1 ...]
nome=[N01 N02 N03 N04 N05 ]
tnom=[N01 N02 N03 N04 N05]
tmin=[132 20 20.....]
tmax=[125.4 19 19 19 ....]
pc=[138.6 21 21 21....]
qc=[0 0 1.013532234 ....]
susc=[0 0 0.49087611]
take a look at textscan
do you have any control over the format of the textfile?
EDIT
here's a rather hackish way to achieve the result
function readtest()
fid = fopen('test.txt');
%skip 3 lines, save 4th, skip 5th
for i = 1:4
names = fgetl(fid);
end
fgetl(fid);
% separate out names
names = textscan(names,'%s','delimiter','|');
% read the data
data = textscan(fid,'%s %s %d %s %s %d %d %f %f %f %[| ]','delimiter','|');
fclose(fid);
for i = 1:size(data,2)-1
values = ( data{i}(1:end));
if(iscell(values))
values = cell2mat(values);
end
name = names{1}{i+1};
% very basic error checking
if(~strcmp(name, ''))
%save the value in the calling work space
assignin('caller', name, values)
end
end
Any reason for Matlab? If you're in academia, you might have access to LabVIEW, which could be easier to learn for something like this. You'll want to use the Read from Text File VI, then parse the string. Of course, you'll have to make use of the "|" characters to separate the data (use the Match Pattern VI). You might eventually want to restructure the way data are stored to the text file too - use text keys rather than |. Something like:
codserv N area | codice 1 nome N01 tnom 20 etc...
Sorry for not providing an answer with some Matlab source but I would consider LabVIEW if it's an option.
I'm trying to load the following ascii file into MATLAB using load()
% some comment
1 0xc661
2 0xd661
3 0xe661
(This is actually a simplified file. The actual file I'm trying to load contains an undefined number of columns and an undefined number of comment lines at the beginning, which is why the load function was attractive)
For some strange reason, I obtain the following:
K>> data = load('testMixed.txt')
data =
1 50785
2 58977
3 58977
I've observed that the problem occurs anytime there's a "d" in the hexadecimal number.
Direct hex2dec conversion works properly:
K>> hex2dec('d661')
ans =
54881
importdata seems to have the same conversion issue, and so does the ImportWizard:
K>> importdata('testMixed.txt')
ans =
1 50785
2 58977
3 58977
Is that a bug, am I using the load function in some prohibited way, or is there something obvious I'm overlooking?
Are there workarounds around the problem, save from reimplementing the file parsing on my own?
Edited my input file to better reflect my actual file format. I had a bit oversimplified in my original question.
"GOLF" ANSWER:
This starts with the answer from mtrw and shortens it further:
fid = fopen('testMixed.txt','rt');
data = textscan(fid,'%s','Delimiter','\n','MultipleDelimsAsOne','1',...
'CommentStyle','%');
fclose(fid);
data = strcat(data{1},{' '});
data = sscanf([data{:}],'%i',[sum(isspace(data{1})) inf]).';
PREVIOUS ANSWER:
My first thought was to use TEXTSCAN, since it has an option that allows you to ignore certain lines as comments when they start with a given character (like %). However, TEXTSCAN doesn't appear to handle numbers in hexadecimal format well. Here's another option:
fid = fopen('testMixed.txt','r'); % Open file
% First, read all the comment lines (lines that start with '%'):
comments = {};
position = 0;
nextLine = fgetl(fid); % Read the first line
while strcmp(nextLine(1),'%')
comments = [comments; {nextLine}]; % Collect the comments
position = ftell(fid); % Get the file pointer position
nextLine = fgetl(fid); % Read the next line
end
fseek(fid,position,-1); % Rewind to beginning of last line read
% Read numerical data:
nCol = sum(isspace(nextLine))+1; % Get the number of columns
data = fscanf(fid,'%i',[nCol inf]).'; % Note '%i' works for all integer formats
fclose(fid); % Close file
This will work for an arbitrary number of comments at the beginning of the file. The computation to get the number of columns was inspired by Jacob's answer.
New:
This is the best I could come up with. It should work for any number of comment lines and columns. You'll have to do the rest yourself if there are strings, etc.
% Define the characters representing the start of the commented line
% and the delimiter
COMMENT_START = '%%';
DELIMITER = ' ';
% Open the file
fid = fopen('testMixed.txt');
% Read each line till we reach the data
l = COMMENT_START;
while(l(1)==COMMENT_START)
l = fgetl(fid);
end
% Compute the number of columns
cols = sum(l==DELIMITER)+1;
% Split the first line
split_l = regexp(l,' ','split');
% Read all the data
A = textscan(fid,'%s');
% Compute the number of rows
rows = numel(A{:})/cols;
% Close the file
fclose(fid);
% Assemble all the data into a matrix of cell strings
DATA = [split_l ; reshape(A{:},[cols rows])']; %' adding this to make it pretty in SO
% Recognize each column and process accordingly
% by analyzing each element in the first row
numeric_data = zeros(size(DATA));
for i=1:cols
str = DATA(1,i);
% If there is no '0x' present
if isempty(findstr(str{1},'0x')) == true
% This is a number
numeric_data(:,i) = str2num(char(DATA(:,i)));
else
% This is a hexadecimal number
col = char(DATA(:,i));
numeric_data(:,i) = hex2dec(col(:,3:end));
end
end
% Display the data
format short g;
disp(numeric_data)
This works for data like this:
% Comment 1
% Comment 2
1.2 0xc661 10 0xa661
2 0xd661 20 0xb661
3 0xe661 30 0xc661
Output:
1.2 50785 10 42593
2 54881 20 46689
3 58977 30 50785
OLD:
Yeah, I don't think LOAD is the way to go. You could try:
a = char(importdata('testHexa.txt'));
a = hex2dec(a(:,3:end));
This is based on both gnovice's and Jacob's answers, and is a "best of breed"
For files like:
% this is my comment
% this is my other comment
1 0xc661 123
2 0xd661 456
% surprise comment
3 0xe661 789
4 0xb661 1234567
(where the number of columns within the file MUST be the same, but not known ahead of time, and all comments denoted by a '%' character), the following code is fast and easy to read:
f = fopen('hexdata.txt', 'rt');
A = textscan(f, '%s', 'Delimiter', '\n', 'MultipleDelimsAsOne', '1', 'CollectOutput', '1', 'CommentStyle', '%');
fclose(f);
A = A{1};
data = sscanf(A{1}, '%i')';
data = repmat(data, length(A), 1);
for ctr = 2:length(A)
data(ctr,:) = sscanf(A{ctr}, '%i')';
end
I have a textfile with the following structure:
1999-01-04
1,100.00
1,060.00
1,092.50
0
6,225
1,336,605
37
1999-01-05
1,122.50
1,087.50
1,122.50
0
3,250
712,175
14
...
The file contains repeated sets of eight values (a date followed by seven numbers, each on their own line).
I want to read it into MATLAB and get the values into different vectors. I've tried to accomplish this with several different methods, but none have worked - all output some sort of error.
In case it's important, I'm doing this on a Mac.
EDIT: This is a shorter version of the code I previously had in my answer...
If you'd like to read your data file directly, without having to preprocess it first as dstibbe suggested, the following should work:
fid = fopen('datafile.txt','rt');
data = textscan(fid,'%s %s %s %s %s %s %s %s','Delimiter','\n');
fclose(fid);
data = [datenum(data{1}) cellfun(#str2double,[data{2:end}])]';
The above code places each set of 8 values into an 8-by-N matrix, with N being the number of 8 line sets in the data file. The date is converted to a serial date number so that it can be included with the other double-precision values in the matrix. The following functions (used in the above code) may be of interest: TEXTSCAN, DATENUM, CELLFUN, STR2DOUBLE.
I propose yet another solution. This one is the shortest in MATLAB code. First using sed, we format the file as a CSV file (comma seperated, with each record on one line):
cat a.dat | sed -e 's/,//g ; s/[ \t]*$/,/g' -e '0~8 s/^\(.*\),$/\1\n/' |
sed -e :a -e '/,$/N; s/,\n/,/; ta' -e '/^$/d' > file.csv
Explanation: First we get rid of the thousands comma seperator, and trim spaces at the end of each line adding a comma. But then we remove that ending comma for each 8th line. Finally we join the lines and remove empty ones.
The output will look like this:
1999-01-04,1100.00,1060.00,1092.50,0,6225,1336605,37
1999-01-05,1122.50,1087.50,1122.50,0,3250,712175,14
Next in MATLAB, we simply use textscan to read each line, with the first field as a string (to be converted to num), and the rest as numbers:
fid = fopen('file.csv', 'rt');
a = textscan(fid, '%s %f %f %f %f %f %f %f', 'Delimiter',',', 'CollectOutput',1);
fclose(fid);
M = [datenum(a{1}) a{2}]
and the resulting matrix M is:
730124 1100 1060 1092.5 0 6225 1336605 37
730125 1122.5 1087.5 1122.5 0 3250 712175 14
Use a script to modify your text file into something that Matlab can read.
eg. make it a matrix:
M = [
1999-01-04
1,100.00
1,060.00
1,092.50
0
6,225
1,336,605; <-- notice the ';'
37
1999-01-05
1,122.50
1,087.50
1,122.50
0
3,250; <-- notice the ';'
712,175
14
...
]
import this into matlab and read the various vectors from the matrix.
Note: my matlab is a bit rusty. Might containt errors.
It isn't entirely clear what form you want the data to be in once you've read it. The code below puts it all in one matrix, with each row representing a group of 8 rows in your text file. You may wish use different variables for different columns, or (if you have access to the Statistics toolbox), use a dataset array.
% Read file as text
text = fileread('c:/data.txt');
% Split by line
x = regexp(text, '\n', 'split');
% Remove commas from numbers
x = regexprep(x, ',', '')
% Number of items per object
n = 8;
% Get dates
index = 1:length(x);
dates = datenum(x(rem(index, n) == 1));
% Get other numbers
nums = str2double(x(rem(index, n) ~= 1));
nums = reshape(nums, (n-1), length(nums)/(n-1))';
% Combine dates and numbers
thedata = [dates nums];
You could also look into the function textscan for alternative ways of solving the problem.
Similar to Richie's. Using str2double to convert the file strings to doubles. This implementation processes line by line instead of breaking the file up with a regular expression. The output is a cell array of individual vectors.
function vectors = readdata(filename)
fid=fopen(filename);
tline = fgetl(fid);
counter = 0;
vectors = cell(7,1);
while ischar(tline)
disp(tline)
if counter > 0
vectors{counter} = [vectors{counter} str2double(tline)];
end
counter = counter + 1
if counter > 7
counter = 0;
end
tline = fgetl(fid);
end
fclose(fid);
This has regular expression checking to make sure your data is formatted well.
fid = fopen('data.txt','rt');
%these will be your 8 value arrays
val1 = [];
val2 = [];
val3 = [];
val4 = [];
val5 = [];
val6 = [];
val7 = [];
val8 = [];
linenum = 0; % line number in file
valnum = 0; % number of value (1-8)
while 1
line = fgetl(fid);
linenum = linenum+1;
if valnum == 8
valnum = 1;
else
valnum = valnum+1;
end
%-- if reached end of file, end
if isempty(line) | line == -1
fclose(fid);
break;
end
switch valnum
case 1
pat = '(?\d{4})-(?\d{2})-(?\d{2})'; % val1 (e.g. 1999-01-04)
case 2
pat = '(?\d*[,]*\d*[,]*\d*[.]\d{2})'; % val2 (e.g. 1,100.00) [valid up to 1billion-1]
case 3
pat = '(?\d*[,]*\d*[,]*\d*[.]\d{2})'; % val3 (e.g. 1,060.00) [valid up to 1billion-1]
case 4
pat = '(?\d*[,]*\d*[,]*\d*[.]\d{2})'; % val4 (e.g. 1,092.50) [valid up to 1billion-1]
case 5
pat = '(?\d+)'; % val5 (e.g. 0)
case 6
pat = '(?\d*[,]*\d*[,]*\d+)'; % val6 (e.g. 6,225) [valid up to 1billion-1]
case 7
pat = '(?\d*[,]*\d*[,]*\d+)'; % val7 (e.g. 1,336,605) [valid up to 1billion-1]
case 8
pat = '(?\d+)'; % val8 (e.g. 37)
otherwise
error('bad linenum')
end
l = regexp(line,pat,'names'); % l is for line
if length(l) == 1 % match
if valnum == 1
serialtime = datenum(str2num(l.yr),str2num(l.mo),str2num(l.dy)); % convert to matlab serial date
val1 = [val1;serialtime];
else
this_val = strrep(l.val,',',''); % strip out comma and convert to number
eval(['val',num2str(valnum),' = [val',num2str(valnum),';',this_val,'];']) % save this value into appropriate array
end
else
warning(['line number ',num2str(linenum),' skipped! [didnt pass regexp]: ',line]);
end
end