Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 17 additions & 12 deletions scripts/importTrackMateTracks.m
Original file line number Diff line number Diff line change
Expand Up @@ -81,24 +81,29 @@
%% Load and Test compliance

try
doc = xmlread(file);
catch %#ok<CTCH>
error('Failed to read XML file %s.',file);
doc = matlab.io.xml.dom.Parser().parseFile(file);
catch ME
switch ME.identifier
case 'MATLAB:UndefinedFunction'
error("Your MATLAB is too old (pre-R2021a) to run this script.")
otherwise
error(ME.identifier,'Failed to read XML file %s.',file);
end
end

root = doc.getDocumentElement;

if ~strcmp(root.getTagName, 'Tracks')
if ~strcmp(root.TagName, 'Tracks')
error('MATLAB:importTrackMateTracks:BadXMLFile', ...
'File does not seem to be a proper track file.')
end

%% Get metadata
metadata.spaceUnits = char( root.getAttribute('spaceUnits') );
metadata.timeUnits = char( root.getAttribute('timeUnits') );
metadata.spaceUnits = root.getAttribute('spaceUnits');
metadata.timeUnits = root.getAttribute('timeUnits');
metadata.frameInterval = str2double( root.getAttribute('frameInterval') );
metadata.date = char( root.getAttribute('generationDateTime') );
metadata.source = char( root.getAttribute('from') );
metadata.date = root.getAttribute('generationDateTime');
metadata.source = root.getAttribute('from');


%% Parse
Expand All @@ -109,17 +114,17 @@

for i = 1 : nTracks

trackNode = trackNodes.item(i-1);
trackNode = trackNodes.node(i);
detectionNodes = trackNode.getElementsByTagName('detection');

nSpots = str2double( trackNode.getAttribute('nSpots') );
nSpots = min( nSpots, detectionNodes.getLength() );
nSpots = min( nSpots, detectionNodes.Length );

A = NaN( nSpots, 4); % T, X, Y, Z
A = zeros( nSpots, 4); % T, X, Y, Z

for j = 1 : nSpots

detectionNode = detectionNodes.item(j-1);
detectionNode = detectionNodes.node(j);
t = str2double(detectionNode.getAttribute('t'));
x = str2double(detectionNode.getAttribute('x'));
y = str2double(detectionNode.getAttribute('y'));
Expand Down
265 changes: 172 additions & 93 deletions scripts/trackmateEdges.m
Original file line number Diff line number Diff line change
Expand Up @@ -60,136 +60,215 @@


% __
% Jean-Yves Tinevez - 2016
% Jean-Yves Tinevez & contributors - 2026

%% Import the XPath classes.
import javax.xml.xpath.*

%% Constants definition.

TRACKMATE_ELEMENT = 'TrackMate';
TRACK_ID_ATTRIBUTE = 'TRACK_ID';
TRACK_NAME_ATTRIBUTE = 'name';
SPOT_SOURCE_ID_ATTRIBUTE = 'SPOT_SOURCE_ID';
SPOT_TARGET_ID_ATTRIBUTE = 'SPOT_TARGET_ID';

%% Open file

global isNotFirst xmlDoc %#ok<GVMIS>
if isNotFirst
% Being called by other function
willClear = false;
else
isNotFirst = true;
willClear = true;
end
% We'll call trackmateFeatureDeclarations() to fill in table properties
% no matter what, so let's reuse that one's validation function.
try
xmlDoc = xmlread( filePath );
catch
error('Failed to read XML file %s.',filePath);
[ ~, ef ] = trackmateFeatureDeclarations( filePath );
catch ME
throw(ME)
end
xmlRoot = xmlDoc.getFirstChild();

if ~strcmp(xmlRoot.getTagName, TRACKMATE_ELEMENT)
error('MATLAB:trackMateGraph:BadXMLFile', ...
'File does not seem to be a proper TrackMate file.')
end


%% XPath initialization.
factory = XPathFactory.newInstance;
xPath = factory.newXPath;
rootObj = xmlDoc.getDocumentElement;
modelNodes = rootObj.getElementsByTagName('Model');

%% Retrieve edge feature list
if nargin < 2 || isempty( featureList )
xPathEdgeFilter = xPath.compile('//Edge');
edgeNode = xPathEdgeFilter.evaluate(xmlDoc, XPathConstants.NODE );
featureList = getEdgeFeatureList( edgeNode );
% //Edge. Why not full path?
edgeList = rootObj.getElementsByTagName( 'Edge' );
if edgeList.Length > 0
attrMap = edgeList.node(1).getAttributes;
nFeatures = attrMap.Length;
featureList = cell(nFeatures, 1);
for k = 1 : nFeatures
featureList{k} = attrMap.item(k-1).Name;
end
else
featureList = {};
end
end

% Add spot source and target, whether they are here or not.
featureList = union( SPOT_TARGET_ID_ATTRIBUTE, featureList, 'stable' );
featureList = union( SPOT_SOURCE_ID_ATTRIBUTE, featureList, 'stable' );
frontOfList = { SPOT_SOURCE_ID_ATTRIBUTE; SPOT_TARGET_ID_ATTRIBUTE };
featureList = union(frontOfList, featureList, 'stable');
nFeatures = numel( featureList );

%% XPath to retrieve filtered track IDs.
% Prepare a map: trackName -> edge table.
trackMap = containers.Map('KeyType', 'char', 'ValueType', 'any');

xPathFTrackFilter = xPath.compile('//Model/FilteredTracks/TrackID');
fTrackNodeList = xPathFTrackFilter.evaluate(xmlDoc, XPathConstants.NODESET);
nFTracks = fTrackNodeList.getLength();

fTrackIDs = NaN( nFTracks, 1);
for i = 1 : nFTracks
fTrackIDs( i ) = str2double( fTrackNodeList.item( i-1 ).getAttribute( TRACK_ID_ATTRIBUTE ) );
% XPath: //Model/FilteredTracks/TrackID/@TrackID
fTracks = zeros(rootObj.getElementsByTagName('TrackID').Length, 1);
iTracks = 0;
for j = 1:modelNodes.Length
node = modelNodes.node(j);
% Model level
fTNode = node.getFirstElementChild;
while ~isempty(fTNode)
if strcmp('FilteredTracks', fTNode.TagName)
% FilteredTracks level
tIDNode = fTNode.getFirstElementChild;
while ~isempty(tIDNode)
if strcmp('TrackID', tIDNode.TagName)
% Found TrackID node
iTracks = iTracks + 1;
fTracks(iTracks) = ...
str2double(tIDNode.getAttribute(TRACK_ID_ATTRIBUTE));
end
tIDNode = tIDNode.getNextElementSibling;
end
end
fTNode = fTNode.getNextElementSibling;
end
end

fTracks(iTracks+1:end) = [];

if isempty(fTracks)
% No selected track, return empty map
if willClear
clear global isNotFirst xmlDoc xmlDocFileName
end
return
end

%% XPath to retrieve filtered track elements.

xPathTrackFilter = xPath.compile('//Model/AllTracks/Track');
trackNodeList = xPathTrackFilter.evaluate(xmlDoc, XPathConstants.NODESET);
nTracks = trackNodeList.getLength();

% Prepare a map: trackName -> edge table.
trackMap = containers.Map('KeyType', 'char', 'ValueType', 'any');

xPathEdgeFilter = xPath.compile('./Edge');
for i = 1 : nTracks

trackNode = trackNodeList.item( i-1 );
trackID = str2double( trackNode.getAttribute( TRACK_ID_ATTRIBUTE ) );
trackName = char( trackNode.getAttribute( TRACK_NAME_ATTRIBUTE ) );

if any( trackID == fTrackIDs )

edgeNodeList = xPathEdgeFilter.evaluate( trackNode, XPathConstants.NODESET );
nEdges = edgeNodeList.getLength();
features = NaN( nEdges, nFeatures );

% Read all edge nodes.
for k = 1 : nEdges
node = edgeNodeList.item( k-1 );
for j = 1 : nFeatures
features( k, j ) = str2double( node.getAttribute( featureList{ j } ) );
end
% Read Tracks table
neTracks = rootObj.getElementsByTagName('Track').Length;
names = cell(neTracks, 1);
tracks = zeros(neTracks, 1);
iTracks = 0;
for j = 1 : modelNodes.Length
node = modelNodes.node(j);
% Model level
aTNode = node.getFirstElementChild;
while ~isempty(aTNode)
if strcmp('AllTracks', aTNode.TagName)
% AllTracks level
tNode = aTNode.getFirstElementChild;
while ~isempty(tNode)
if strcmp('Track', tNode.TagName)
% Track level
iTracks = iTracks + 1;
names{iTracks} = tNode.getAttribute(TRACK_NAME_ATTRIBUTE);
tracks(iTracks) = str2double(tNode.getAttribute(TRACK_ID_ATTRIBUTE));
end

% Create table.
edgeTable = table();
for j = 1 : nFeatures
edgeTable.( featureList{ j } ) = features( :, j );
tNode = tNode.getNextElementSibling;
end

end
aTNode = aTNode.getNextElementSibling;
end
end
names(iTracks+1:neTracks) = [];
tracks(iTracks+1:neTracks) = [];

% Find the selected Track IDs and cache the result.
whichSel = ismember( tracks, fTracks);

% Prepare metadata once
if ~isempty(whichSel)
nVNames = numel( featureList );
vDescriptions = cell( nVNames, 1);
vUnits = cell( nVNames, 1);

for l = 1 : nVNames
vn = featureList{ l };
vDescriptions{ l } = ef( vn ).name;
vUnits{ l } = ef( vn ).units;
end
else
% None of the selected tracks were found, return empty map.
if willClear
clear global isNotFirst xmlDoc xmlDocFileName
end
return
end

% Current track No.
iTracks = 0;

% XPath: (//Model/AllTracks/Track)/Edge
for j = 1 : modelNodes.Length
node = modelNodes.node(j);
% Model level
aTNode = node.getFirstElementChild;
while ~isempty(aTNode)
if strcmp('AllTracks', aTNode.TagName)
% AllTracks level
tNode = aTNode.getFirstElementChild;
while ~isempty(tNode)
if strcmp('Track', tNode.TagName)
% Track level
iTracks = iTracks + 1;
if whichSel(iTracks)
% Create table.
edgeTable = walkAndMakeTable(tNode);
% Set table metadata.
edgeTable.Properties.DimensionNames = { 'Edge', 'Feature' };

vNames = edgeTable.Properties.VariableNames;
nVNames = numel( vNames );
vDescriptions = cell( nVNames, 1);
vUnits = cell( nVNames, 1);

[ ~, ef ] = trackmateFeatureDeclarations( filePath );
for l = 1 : nVNames
vn = vNames{ l };
vDescriptions{ l } = ef( vn ).name;
vUnits{ l } = ef( vn ).units;
edgeTable.Properties.DimensionNames = { 'Edge', 'Feature' };
edgeTable.Properties.VariableDescriptions = vDescriptions;
edgeTable.Properties.VariableUnits = vUnits;

trackMap( names{iTracks} ) = edgeTable;
end
end
tNode = tNode.getNextElementSibling;
end
edgeTable.Properties.VariableDescriptions = vDescriptions;
edgeTable.Properties.VariableUnits = vUnits;

trackMap( trackName ) = edgeTable;

end
aTNode = aTNode.getNextElementSibling;
end
end

if willClear
clear global isNotFirst xmlDoc xmlDocFileName
end

%% Subfunction.

function featureList = getEdgeFeatureList(node)

attribute_map = node.getAttributes;
n_attributes = attribute_map.getLength;

featureList = cell(n_attributes, 1);
index = 1;
for ii = 1 : n_attributes

namel = node.getAttributes.item(ii-1).getName;
featureList{index} = char(namel);
index = index + 1;

function edgeTable = walkAndMakeTable(trackNode)
% Assuming every child element is an <Edge>...
neEdges = trackNode.getChildElementCount;
holders = cell(1, nFeatures);
for i = 1 : nFeatures
holders{i} = zeros(neEdges, 1);
end
nEdges = 0;
edgeNode = trackNode.getFirstElementChild;
while ~isempty(edgeNode)
if strcmp('Edge', edgeNode.TagName)
nEdges = nEdges+1;
for i = 1 : nFeatures
holders{i}(nEdges) = str2double(edgeNode.getAttribute(featureList{i}));
end
end
edgeNode = edgeNode.getNextElementSibling;
end

% And trim the end if that turns out to be false
if nEdges < neEdges
for i = 1 : nFeatures
holders{i}(nEdges+1:end) = [];
end
end

edgeTable = table(holders{:}, 'VariableNames', featureList);
end

end
Loading