Skip to content

Commit 876c975

Browse files
committed
Avoid duplicated attributes when export to MaMuT a file imported from MaMuT.
During an export to MaMuT, the position of the spots are encoded in the feature 'POSITION_X' etc, so that MaMuT can retrieve the spots at the right position. A problem might occur if the data in Mastodon have been imported from a MaMuT (or TrackMate) file. In that case the exporter will try to write two attribute with the same name: the POSITION_X from the actual spot position and the POSITION_X that was imported. This is happening for all the builtin features we need for the MaMuT export. To avoid this, we rename the imported features with 'IMPORTED_...'. And if we have imported features already named 'IMPORTED_...' (if the user re-reimport a MaMuT exported file from a MaMut imported file), we skip them. Fix #364
1 parent 97719f6 commit 876c975

1 file changed

Lines changed: 90 additions & 13 deletions

File tree

src/main/java/org/mastodon/mamut/io/importer/trackmate/MamutExporter.java

Lines changed: 90 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -424,9 +424,9 @@ private Element[] trackCollectionToXml()
424424
public void processVertexLate( final Spot vertex, final DepthFirstSearch< Spot, Link > search )
425425
{
426426
/*
427-
* 1 root = 1 track, unless a track has several roots. Add
428-
* the iterated vertex to the list of root to skip if
429-
* needed.
427+
* 1 root = 1 track, unless a track has several
428+
* roots. Add the iterated vertex to the list of
429+
* root to skip if needed.
430430
*/
431431
if ( vertex.incomingEdges().isEmpty() )
432432
toSkip.add( vertex );
@@ -520,6 +520,15 @@ private Element spotCollectionToXml()
520520
return spotCollectionElement;
521521
}
522522

523+
/**
524+
* Collection of link feature names that we want to export in the mamut
525+
* file, but computed from the link data currently set in Mastodon. We used
526+
* this collection to avoid exporting a feature with identical name in the
527+
* case a feature imported as the same name.
528+
*/
529+
private final static Set< String > IMPORTED_LINK_BUILTIN_FEATURES = new HashSet<>( Arrays.asList(
530+
EDGE_SOURCE_ATTRIBUTE, EDGE_TARGET_ATTRIBUTE ) );
531+
523532
private Element edgeToXml( final Link edge, final int sourceSpotID, final int targetSpotID )
524533
{
525534
final Collection< Attribute > attributes = new ArrayList<>();
@@ -529,9 +538,38 @@ private Element edgeToXml( final Link edge, final int sourceSpotID, final int ta
529538
attributes.add( new Attribute( EDGE_TARGET_ATTRIBUTE, Integer.toString( targetSpotID ) ) );
530539

531540
// Link features.
532-
linkFeatureProjections.forEach( p -> attributes.add( new Attribute(
533-
p.attributeName,
534-
Double.toString( p.projection.value( edge ) ) ) ) );
541+
for ( final ExportFeatureProjection< Link > p : linkFeatureProjections )
542+
{
543+
final String attName;
544+
final String origName = p.attributeName;
545+
/*
546+
* If the model to export was imported from a TrackMate or a MaMuT
547+
* file, it will already contain features with the same name that
548+
* the builtin feature we added just above. Which will cause an
549+
* error.
550+
*
551+
* To avoid this, rename these imported features.
552+
*/
553+
if ( IMPORTED_LINK_BUILTIN_FEATURES.contains( origName ) )
554+
{
555+
final String importedAttName = "IMPORTED_" + origName;
556+
attName = importedAttName;
557+
}
558+
else if ( origName.startsWith( "IMPORTED_" ) )
559+
{
560+
// We skip features that have been re-imported.
561+
continue;
562+
}
563+
else
564+
{
565+
// All good.
566+
attName = origName;
567+
}
568+
569+
attributes.add( new Attribute(
570+
attName,
571+
Double.toString( p.projection.value( edge ) ) ) );
572+
}
535573

536574
final Element edgeElement = new Element( EDGE_TAG );
537575
edgeElement.setAttributes( attributes );
@@ -556,9 +594,20 @@ private Element trackToXml( final Spot root )
556594
return trackElement;
557595
}
558596

597+
/**
598+
* Collection of spot feature names that we want to export in the mamut
599+
* file, but computed from the actual position, etc, currently set in
600+
* Mastodon. We used this collection to avoid exporting a feature with
601+
* identical name in the case a feature imported as the same name.
602+
*/
603+
private final static Set< String > IMPORTED_SPOT_BUILTIN_FEATURES = new HashSet<>( Arrays.asList( ID_FEATURE_NAME, LABEL_FEATURE_NAME, POSITION_X_FEATURE_NAME,
604+
POSITION_Y_FEATURE_NAME, POSITION_Z_FEATURE_NAME, FRAME_FEATURE_NAME,
605+
POSITION_T_FEATURE_NAME, QUALITY_FEATURE_NAME, VISIBILITY_FEATURE_NAME,
606+
RADIUS_FEATURE_NAME ) );
607+
559608
private Element spotToXml( final Spot spot )
560609
{
561-
final Collection< Attribute > attributes = new ArrayList<>();
610+
final List< Attribute > attributes = new ArrayList<>();
562611

563612
// Id.
564613
attributes.add( new Attribute( ID_FEATURE_NAME, Integer.toString( spot.getInternalPoolIndex() ) ) );
@@ -583,10 +632,38 @@ private Element spotToXml( final Spot spot )
583632
final double meanRadius = Arrays.stream( eig.getRealEigenvalues() ).map( Math::sqrt ).average().getAsDouble();
584633
attributes.add( new Attribute( RADIUS_FEATURE_NAME, Double.toString( meanRadius ) ) );
585634

586-
// Spot features.
587-
spotFeatureProjections.forEach( p -> attributes.add( new Attribute(
588-
p.attributeName,
589-
Double.toString( p.projection.value( spot ) ) ) ) );
635+
for (final ExportFeatureProjection< Spot > p : spotFeatureProjections )
636+
{
637+
final String attName;
638+
final String origName = p.attributeName;
639+
/*
640+
* If the model to export was imported from a TrackMate or a MaMuT
641+
* file, it will already contain features with the same name that
642+
* the builtin feature we added just above. Which will cause an
643+
* error.
644+
*
645+
* To avoid this, rename these imported features.
646+
*/
647+
if ( IMPORTED_SPOT_BUILTIN_FEATURES.contains( origName ) )
648+
{
649+
final String importedAttName = "IMPORTED_" + origName;
650+
attName = importedAttName;
651+
}
652+
else if ( origName.startsWith( "IMPORTED_" ) )
653+
{
654+
// We skip features that have been re-imported.
655+
continue;
656+
}
657+
else
658+
{
659+
// All good.
660+
attName = origName;
661+
}
662+
663+
attributes.add( new Attribute(
664+
attName,
665+
Double.toString( p.projection.value( spot ) ) ) );
666+
}
590667

591668
final Element spotElement = new Element( SPOT_ELEMENT_TAG );
592669
spotElement.setAttributes( attributes );
@@ -652,8 +729,8 @@ private static Document getSAXParsedDocument( final String fileName )
652729
}
653730

654731
/**
655-
* Tries to recover the TrackMate dimension from the unit string and the spatial and
656-
* time units.
732+
* Tries to recover the TrackMate dimension from the unit string and the
733+
* spatial and time units.
657734
*
658735
* @param units
659736
* the unit string.

0 commit comments

Comments
 (0)