1 %> @brief IRootLab TXT loader/saver
3 %> This file type is recommended
if you want to edit the dataset in e.g. Excel, it is capable of storing all the properties of the dataset.
5 %> See Figure 1
for example.
7 %> @image html dataformat_iroot.png
8 %> <center>Figure 1 - Example of IRootLab TXT file open in a spreadsheet editing program.</center>
10 properties(SetAccess=
protected)
11 %> This affects saving: whether to save the classes
as strings.
13 flag_stringclasses = 0;
16 function data = load(o)
20 mask = repmat('%q', 1, no_cols);
22 fid = fopen(o.filename);
25 fieldsfound = struct('name', {},
'flag_cell', {},
'idxs', {},
'flag_classes', {});
26 flag_stringclasses = 0; % Whether classes are specified
as strings or numbers
29 if flag_exp_table % expecting table
30 % reads everything, i.e., row fields
31 cc = textscan(fid, newmask,
'Delimiter', deli,
'CollectOutput', 0);
33 for i = 1:length(fieldsfound)
34 fn = fieldsfound(i).name;
35 idxs = fieldsfound(i).idxs;
36 if fieldsfound(i).flag_classes
37 if any(cellfun(@(x) isempty(str2num(x)), cc{idxs},
'UniformOutput', 1))
38 % Classes are expressed
as strings
39 flag_stringclasses = 1; %#ok<*PROP>
43 no_obs = numel(clalpha);
44 data.classes(no_obs, 1) = -1; % pre-allocates
46 data.classes(i) = find(strcmp(data.classlabels, clalpha{i}))-1;
49 % Classes are expressed as numbers
50 data.(fn) = cellfun(@str2num, cc{idxs}, 'UniformOutput
', 1);
52 elseif fieldsfound(i).flag_cell
55 data.(fn) = cell2mat(cc(idxs));
61 cc = textscan(fid, mask, 1, 'Delimiter
', deli, 'CollectOutput
', 1);
69 % goes through header to find which columns contain what
72 fn_now = '@#$!*%@!
'; % Current field name
74 s = strip_quotes(cc{i});
76 b = strcmp(s, data.rowfieldnames);
78 j = find(b); j = j(1);
79 num_fields = num_fields+1;
80 fieldsfound(num_fields).name = s;
81 flag_cell = data.flags_cell(j);
82 fieldsfound(num_fields).flag_cell = flag_cell;
83 fieldsfound(num_fields).flag_classes = strcmp(s, 'classes
');
86 irerror(sprintf('Unknown field:
"%s"', s));
89 fieldsfound(num_fields).idxs(end+1) = i;
90 newmask = [newmask, '%
', iif(strcmp(s, 'classes
') || flag_cell, 'q
', 'f
')]; %#ok<AGROW>
95 s = strip_quotes(cc{1});
96 if strcmp(s, 'classlabels
')
98 data.classlabels = eval(strip_quotes(cc{2}));
100 irerror(['Error trying to parse the
"classlabels" property!
', 10, 10, 'Original error:
', 10, ME.message]);
103 elseif strcmp(s, 'fea_x
')
104 % discards empty elements at the end of the cell
105 for i = length(cc):-1:1
111 data.fea_x = str2double(cc);
112 elseif strcmp(s, 'table
')
114 elseif strcmp(s, 'direction
')
115 data.direction = strip_quotes(cc{2});
116 elseif strcmp(s, 'height
')
117 data.height = str2num(strip_quotes(cc{2})); %#ok<*ST2NM>
118 elseif strcmp(s, 'title
')
119 data.title = str2num(strip_quotes(cc{2})); %#ok<*ST2NM>
127 if ~flag_stringclasses
128 % Makes sure claslabels is correct
129 ncc = max(data.classes)+1;
130 if ncc > numel(data.classlabels)
131 irverbose('WARNING: Number of classlabels lower than number of classes
', 2);
132 nl = data.get_no_levels();
133 suffix = repmat('|1
', 1, nl-1);
134 for i = numel(data.classlabels)+1:ncc
135 % data.classlabels{i} = ['Class
', int2str(i-1), suffix];
136 data.classlabels{i} = [int2str(i-1), suffix];
140 data = data.eliminate_unused_classlabels();
143 data.assert_not_nan();
144 data.filename = o.filename;
145 data.filetype = 'txt_irootlab
';
146 data = data.make_groupnumbers();
150 %------------------------------------------------------------------
152 function o = save(o, data)
154 h = fopen(o.filename, 'w
');
156 irerror(sprintf('Could not create file
''%s
''!
', o.filename));
163 flag_table = 1; % Whether any of the data.rowfieldnames is in use, otherwise table part of file won't be saved
165 % goes through possible fields to find which ones are being used, and to determine number of columns
for CSV
167 for i = 1:length(data.rowfieldnames)
168 if ~isempty(data.(data.rowfieldnames{i}))
169 fieldidxs(end+1) = i;
170 fieldcols(end+1) = size(data.(data.rowfieldnames{i}), 2);
171 no_cols = no_cols+fieldcols(end);
172 no_fields = no_fields+1;
177 no_cols = length(data.fea_x)+1;
184 newl = sprintf(
'\n');
187 fwrite(h, [
'title' tab data.title repmat(tab, 1, no_cols-2) newl]);
188 if ~o.flag_stringclasses
189 fwrite(h, [
'classlabels' tab
cell2str(data.classlabels) repmat(tab, 1, no_cols-2) newl]);
191 temp = sprintf([
'%g' tab], data.fea_x);
192 fwrite(h, [
'fea_x' tab temp(1:end-1) repmat(tab, 1, no_cols-data.nf-1) newl]);
193 fwrite(h, [
'height' tab int2str(data.height) repmat(tab, 1, no_cols-2) newl]);
194 fwrite(h, [
'direction' tab data.direction repmat(tab, 1, no_cols-2) newl]);
195 fwrite(h, [
'table' repmat(tab, 1, no_cols-1) newl]);
200 buflen = 1024; % writes every MB to disk
201 buffer = repmat(
' ', 1, buflen);
206 s = repmat([data.rowfieldnames{fieldidxs(i)} tab], 1, fieldcols(i));
207 buffer(ptr:ptr+length(s)-1) = s;
210 ptr = ptr-1;% last tab won
't count
217 if o.flag_stringclasses
218 labels = classes2labels(data.classes, data.classlabels);
224 rowlen = 0; % average row length
233 fn = data.rowfieldnames{fieldidxs(i)};
234 if strcmp(fn, 'classes
') && o.flag_stringclasses
235 s = sprintf('%s\t
', labels{rowptr});
237 if data.flags_cell(fieldidxs(i))
238 s = sprintf('%s\t
', data.(fn){rowptr, :});
240 s = sprintf('%g\t
', data.(fn)(rowptr, :));
243 buffer(ptr:ptr+length(s)-1) = s;
246 ptr = ptr-1;% last tab won't count
251 rowlen = (rowlen*(rowptr-1)+(ptr-ptr_save))/rowptr;
254 % tolerance of rowlen not to blow buffer
255 if ptr+2*rowlen > buflen
256 fwrite(h, buffer(1:ptr-1));
265 fwrite(h, buffer(1:ptr-1));
271 irverbose(sprintf(
'Just saved file "%s"', o.filename), 2);
function irverbose(in s, in level)
IRootLab TXT that saves classes column as labels, not numbers.
Dataset loader/saver common class.
Analysis Session (AS) base class.
function unique_appear(in classlabels)
function get_no_cols_deli(in filename)
function irootlab_version()
IRootLab TXT loader/saver.