Skip to content

Commit 181adfd

Browse files
committed
Add basic display of data marks
- Show list of available data marks. - Allow moving x,t graph cursors to data mark positions by (multi-)selecting them in the list. Includes necessary basic infrastructure in TWOMDataFile.
1 parent bb183dc commit 181adfd

File tree

2 files changed

+73
-7
lines changed

2 files changed

+73
-7
lines changed

DataClasses/TWOMDataFile.m

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@
4646
parseClassArgs(varargin, self);
4747

4848
% Load TDMS file structure (no data, only metadata/properties).
49-
[output, self.tdmsMeta] = TDMS_readTDMSFile(filename, 'GET_DATA_OPTION', 'getnone');
49+
[output, self.tdmsMeta] = TDMS_readTDMSFile(filename, ...
50+
'GET_DATA_OPTION', 'getSubset' ...
51+
, 'OBJECTS_GET', struct('groupsKeep', {{'Marks'}}) ...
52+
);
5053
self.tdmsStruct = TDMS_dataToGroupChanStruct_v4(output);
5154

5255
% Is this a valid TWOM data file?
@@ -170,6 +173,30 @@
170173
% << nested functions
171174
end
172175

176+
function [marks] = getMarks(self)
177+
% GETMARKS Returns a list of data marks in the file
178+
%
179+
% OUTPUT:
180+
% marks = struct array with the following fields:
181+
% .number = number of the data mark
182+
% .comment = textual comment on the data mark as entered by
183+
% the user during the measurement
184+
% .t = timestamp (in ms)
185+
186+
marks = struct('number', {}, 'comment', {}, 't', {});
187+
188+
markNumbers = self.tdmsStruct.Marks.Mark__.data;
189+
markTimes = self.tdmsStruct.Marks.Time__ms_.data;
190+
191+
if ~isempty(markNumbers)
192+
for i = 1:length(markNumbers)
193+
marks(end+1).number = markNumbers(i);
194+
marks(end) .comment = self.tdmsStruct.Marks.Props.(sprintf('Mark_%d_comment', markNumbers(i)));
195+
marks(end) .t = markTimes(i);
196+
end
197+
end
198+
end
199+
173200
function [valid] = isValidTWOMDataFile(self)
174201
valid = ~isempty(self.FileFormatVersion) ...
175202
&& isfield(self.tdmsStruct, 'FD_Data');

UI/TWOMDataViewer.m

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,14 @@ function createGui(self)
296296
, 'CellEditCallback',@(h,e) self.onForceChanCellEdit(h,e) ...
297297
);
298298

299+
self.gui.marks = uicontrol(...
300+
'Parent', self.gui.maingrid.rightpanel ...
301+
, 'Style', 'listbox' ...
302+
, 'Min', 0 ...
303+
, 'Max', 2 ... % multi-select
304+
, 'Callback', @(h,e) self.onMarksCallback(h,e) ...
305+
);
306+
299307
self.gui.metadata.table = uitable(...
300308
'Parent', self.gui.maingrid.rightpanel ...
301309
, 'RowName', [] ...
@@ -314,7 +322,7 @@ function createGui(self)
314322
, 'Enable', 'inactive' ...
315323
);
316324

317-
self.gui.maingrid.rightpanel.Sizes = [20 -1 -2 80];
325+
self.gui.maingrid.rightpanel.Sizes = [20 -1 -1 -2 80];
318326

319327
self.gui.maingrid.root.Sizes = [screenSize(3)/6 -1 screenSize(3)/6];
320328
self.gui.maingrid.root.MinimumWidths = [200 200 200];
@@ -360,18 +368,23 @@ function n_updateDirListing()
360368
function fileChanged(self)
361369
if isempty(self.file)
362370
self.gui.window.Name = 'TWOM Data Viewer';
363-
self.gui.metadata.table.Data = {};
364371
self.gui.forcechan.Data = {};
365372
self.gui.forcechan.UserData = {};
373+
self.gui.marks.String = {};
374+
self.gui.metadata.table.Data = {};
366375
else
367376
self.gui.window.Name = sprintf('TWOM Data Viewer - [%s]', self.file.Filename);
368377

369-
% Load metadata
370-
self.gui.metadata.table.Data = self.file.MetaData;
378+
% Load data marks
379+
[self.gui.marks.String, self.gui.marks.UserData] = n_getMarksData();
380+
self.gui.marks.Value = [];
371381

372382
% Load force channel selection list
373383
self.gui.forcechan.Data = [n_getForceChanSelection() n_getForceChanCaptions()];
374384
self.gui.forcechan.UserData = n_getForceChanRefs();
385+
386+
% Load metadata
387+
self.gui.metadata.table.Data = self.file.MetaData;
375388
end
376389

377390
self.resetView();
@@ -413,6 +426,15 @@ function fileChanged(self)
413426
sel{1} = true; % default selection: top item
414427
end
415428
end
429+
function [markStrings, markUserData] = n_getMarksData()
430+
marks = self.file.getMarks();
431+
markStrings = cell(length(marks),1);
432+
markUserData = cell(length(marks),1);
433+
for i = 1:length(marks)
434+
markStrings{i} = sprintf('[%d] %s', marks(i).number, marks(i).comment);
435+
markUserData{i} = marks(i).t;
436+
end
437+
end
416438
% << nested functions
417439
end
418440

@@ -473,9 +495,10 @@ function onCursorDrag(self, h, e)
473495
end
474496
end
475497

476-
function onCursorReleased(self, h, e)
498+
function onCursorReleased(self, ~, ~)
477499
if ~isempty(self.view.data)
478-
self.view.fdSubset = [min(e.Positions) max(e.Positions)];
500+
self.view.fdSubset = [min(self.gui.plotft.cur.Positions) ...
501+
max(self.gui.plotft.cur.Positions)];
479502
self.applyView();
480503
end
481504
end
@@ -551,6 +574,22 @@ function onForceChanCellEdit(self, ~, ~)
551574
end
552575
end
553576

577+
function onMarksCallback(self, ~, ~)
578+
if ~isempty(self.file) && ~isempty(self.gui.marks.Value)
579+
if isscalar(self.gui.marks.Value)
580+
self.gui.plotft.cur.Positions = ...
581+
[self.gui.marks.UserData{self.gui.marks.Value} ...
582+
max(self.gui.plotft.cur.Positions)];
583+
else
584+
self.gui.plotft.cur.Positions = ...
585+
[self.gui.marks.UserData{self.gui.marks.Value(1)} ...
586+
self.gui.marks.UserData{self.gui.marks.Value(2)} ];
587+
end
588+
self.gui.plotdt.cur.Positions = self.gui.plotft.cur.Positions;
589+
self.onCursorReleased();
590+
end
591+
end
592+
554593
function onMetadataCellSelection(self, ~, e)
555594
if isequal(size(e.Indices), [1 2])
556595
self.gui.metadata.details.String = ...

0 commit comments

Comments
 (0)