From a4e7c04d95561c2931b72522423112b5feaa623f Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Thu, 22 Aug 2024 16:48:54 +0200 Subject: [PATCH 01/12] Add .trim() to remove leading and trailing whitespace before number parsing * In some datasets, number format exceptions may occur if leading trailing whitespaces are not trimmed before parsing the number value --- .../org/mastodon/mamut/io/csv/CSVImporter.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java b/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java index 63cdfd0..a45c638 100644 --- a/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java +++ b/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java @@ -298,15 +298,15 @@ public boolean process() try { - pos[ 0 ] = Double.parseDouble( record[ xcol ] ) + xOrigin; - pos[ 1 ] = Double.parseDouble( record[ ycol ] ) + yOrigin; - pos[ 2 ] = Double.parseDouble( record[ zcol ] ) + zOrigin; - final int t = Integer.parseInt( record[ framecol ] ); + pos[ 0 ] = Double.parseDouble( record[ xcol ].trim() ) + xOrigin; + pos[ 1 ] = Double.parseDouble( record[ ycol ].trim() ) + yOrigin; + pos[ 2 ] = Double.parseDouble( record[ zcol ].trim() ) + zOrigin; + final int t = Integer.parseInt( record[ framecol ].trim() ); final Spot spot = graph.addVertex( vref ).init( t, pos, radius ); if ( null != idcol ) { - final int id = Integer.parseInt( record[ idcol ] ); + final int id = Integer.parseInt( record[ idcol ].trim() ); originalIdFeature.set( spot, id ); if ( null == labelcol ) spot.setLabel( "" + id ); @@ -314,12 +314,12 @@ public boolean process() if ( null != labelcol ) { - spot.setLabel( record[ labelcol ] ); + spot.setLabel( record[ labelcol ].trim() ); } double q = 1.; if ( null != qualitycol ) { - q = Double.parseDouble( record[ qualitycol ] ); + q = Double.parseDouble( record[ qualitycol ].trim() ); qualityFeature.set( spot, q ); } } From 707951305c44e3776c885d744d5efe87a3616948 Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Thu, 22 Aug 2024 16:53:21 +0200 Subject: [PATCH 02/12] Let CSVImporter extend ModelImporter * By doing so startImport() can be called before the import of potentially huge amount of spots starts * startImport() pauses some listeners so that undo/redo functionality does not cause problems during mass import * finishImport resumes these listeners --- src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java b/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java index a45c638..9adeed7 100644 --- a/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java +++ b/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java @@ -49,6 +49,7 @@ import org.mastodon.feature.Multiplicity; import org.mastodon.feature.io.FeatureSerializer; import org.mastodon.io.FileIdToObjectMap; +import org.mastodon.mamut.io.importer.ModelImporter; import org.mastodon.mamut.model.Model; import org.mastodon.mamut.model.ModelGraph; import org.mastodon.mamut.model.Spot; @@ -64,7 +65,7 @@ import net.imglib2.algorithm.Algorithm; -public class CSVImporter implements Algorithm +public class CSVImporter extends ModelImporter implements Algorithm { public static final String PLUGIN_VERSION = VersionUtils.getVersion( CSVImporter.class ); @@ -115,6 +116,7 @@ private CSVImporter( final double yOrigin, final double zOrigin ) { + super( model ); this.model = model; this.filePath = filePath; this.separator = separator; @@ -287,6 +289,7 @@ public boolean process() lock.lock(); final Spot vref = graph.vertexRef(); final double[] pos = new double[ 3 ]; + startImport(); try { @@ -335,6 +338,7 @@ public boolean process() { lock.unlock(); graph.releaseRef( vref ); + finishImport(); } } catch ( final FileNotFoundException e ) From e6e3e1092a5e6b07505e4dd9471c2b4148ef0f66 Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Thu, 22 Aug 2024 16:56:54 +0200 Subject: [PATCH 03/12] Add the possibility to specify a "mother_id" in the CSV importer * A column mother id would allow to import links between subsequent spots during the CSV import --- .../mastodon/mamut/io/csv/CSVImporter.java | 36 +++++++++++++++++++ .../io/csv/plugin/ui/CSVImporterPanel.java | 21 ++++++++++- .../plugin/ui/CSVImporterUIController.java | 8 +++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java b/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java index 9adeed7..f6f2b9b 100644 --- a/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java +++ b/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java @@ -38,7 +38,9 @@ import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; import org.mastodon.RefPool; +import org.mastodon.collection.IntRefMap; import org.mastodon.collection.RefCollection; +import org.mastodon.collection.ref.IntRefHashMap; import org.mastodon.feature.Dimension; import org.mastodon.feature.Feature; import org.mastodon.feature.FeatureModel; @@ -50,6 +52,7 @@ import org.mastodon.feature.io.FeatureSerializer; import org.mastodon.io.FileIdToObjectMap; import org.mastodon.mamut.io.importer.ModelImporter; +import org.mastodon.mamut.model.Link; import org.mastodon.mamut.model.Model; import org.mastodon.mamut.model.ModelGraph; import org.mastodon.mamut.model.Spot; @@ -86,6 +89,8 @@ public class CSVImporter extends ModelImporter implements Algorithm private final String idColumnName; + private final String motherIdColumnName; + private final String labelColumnName; private final double radius; @@ -111,6 +116,7 @@ private CSVImporter( final String frameColumnName, final String qualityColumName, final String idColumnName, + final String motherIdColumnName, final String labelColumnName, final double xOrigin, final double yOrigin, @@ -127,6 +133,7 @@ private CSVImporter( this.frameColumnName = frameColumnName; this.qualityColumnName = qualityColumName; this.idColumnName = idColumnName; + this.motherIdColumnName = motherIdColumnName; this.labelColumnName = labelColumnName; this.xOrigin = xOrigin; this.yOrigin = yOrigin; @@ -277,10 +284,16 @@ public boolean process() ? null : OriginalIdFeature.getOrRegister( model.getFeatureModel(), graph.vertices().getRefPool() ); + Integer motherIdcol = null; + if ( null != motherIdColumnName && !motherIdColumnName.isEmpty() ) + motherIdcol = headerMap.get( motherIdColumnName ); + Integer labelcol = null; if ( null != labelColumnName && !labelColumnName.isEmpty() ) labelcol = headerMap.get( labelColumnName ); + IntRefMap< Spot > spotMap = new IntRefHashMap<>( model.getGraph().vertices().getRefPool(), -1 ); + /* * Iterate over the rest of lines. */ @@ -288,6 +301,8 @@ public boolean process() final WriteLock lock = graph.getLock().writeLock(); lock.lock(); final Spot vref = graph.vertexRef(); + final Spot motherVertexRef = graph.vertexRef(); + final Link edgeRef = graph.edgeRef(); final double[] pos = new double[ 3 ]; startImport(); @@ -311,6 +326,8 @@ public boolean process() { final int id = Integer.parseInt( record[ idcol ].trim() ); originalIdFeature.set( spot, id ); + if ( null != motherIdcol ) + spotMap.put( id, spot ); if ( null == labelcol ) spot.setLabel( "" + id ); } @@ -325,6 +342,14 @@ public boolean process() q = Double.parseDouble( record[ qualitycol ].trim() ); qualityFeature.set( spot, q ); } + + if ( null != motherIdcol ) + { + final int motherId = Integer.parseInt( record[ motherIdcol ].trim() ); + final Spot mother = spotMap.get( motherId, motherVertexRef ); + if ( mother != null ) + model.getGraph().addEdge( mother, spot, edgeRef ).init(); + } } catch ( final NumberFormatException nfe ) { @@ -338,6 +363,8 @@ public boolean process() { lock.unlock(); graph.releaseRef( vref ); + graph.releaseRef( motherVertexRef ); + graph.releaseRef( edgeRef ); finishImport(); } } @@ -453,6 +480,8 @@ public static class Builder private String idColumnName; + private String motherIdColumnName; + private String labelColumnName; private double xOrigin = 0.; @@ -517,6 +546,12 @@ public Builder idColumnName( final String idColumnName ) return this; } + public Builder motherIdColumnName( final String motherIdColumnName ) + { + this.motherIdColumnName = motherIdColumnName; + return this; + } + public Builder labelColumnName( final String labelColumnName ) { this.labelColumnName = labelColumnName; @@ -613,6 +648,7 @@ public CSVImporter get() frameColumnName, qualityColumnName, idColumnName, + motherIdColumnName, labelColumnName, xOrigin, yOrigin, diff --git a/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java b/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java index f3a071a..574b693 100644 --- a/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java +++ b/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java @@ -73,6 +73,8 @@ public class CSVImporterPanel extends JPanel final JComboBox< String > comboBoxIDCol; + final JComboBox< String > comboBoxMotherIdCol; + final JComboBox< String > comboBoxTrackCol; final JCheckBox chckbxImportTracks; @@ -310,12 +312,29 @@ public CSVImporterPanel() gbc_comboBoxID.gridy = 13; panelControl.add( comboBoxIDCol, gbc_comboBoxID ); + final JLabel lblMotherIdColumn = new JLabel( "Mother ID column:" ); + final GridBagConstraints gbc_lblMotherIdColumn = new GridBagConstraints(); + gbc_lblMotherIdColumn.anchor = GridBagConstraints.EAST; + gbc_lblMotherIdColumn.insets = new Insets( 5, 5, 5, 5 ); + gbc_lblMotherIdColumn.gridx = 0; + gbc_lblMotherIdColumn.gridy = 14; + panelControl.add( lblMotherIdColumn, gbc_lblMotherIdColumn ); + + comboBoxMotherIdCol = new JComboBox<>(); + final GridBagConstraints gbc_comboBoxMotherID = new GridBagConstraints(); + gbc_comboBoxMotherID.insets = new Insets( 5, 5, 5, 0 ); + gbc_comboBoxMotherID.gridwidth = 4; + gbc_comboBoxMotherID.fill = GridBagConstraints.HORIZONTAL; + gbc_comboBoxMotherID.gridx = 1; + gbc_comboBoxMotherID.gridy = 14; + panelControl.add( comboBoxMotherIdCol, gbc_comboBoxMotherID ); + final JPanel panelButtonExport = new JPanel(); final GridBagConstraints gbc_panelButtonExport = new GridBagConstraints(); gbc_panelButtonExport.anchor = GridBagConstraints.EAST; gbc_panelButtonExport.gridwidth = 5; gbc_panelButtonExport.gridx = 0; - gbc_panelButtonExport.gridy = 14; + gbc_panelButtonExport.gridy = 15; panelControl.add( panelButtonExport, gbc_panelButtonExport ); final FlowLayout flowLayout = ( FlowLayout ) panelButtonExport.getLayout(); flowLayout.setAlignment( FlowLayout.RIGHT ); diff --git a/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterUIController.java b/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterUIController.java index b36f814..812ce1d 100644 --- a/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterUIController.java +++ b/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterUIController.java @@ -114,6 +114,7 @@ public void run() .frameColumnName( ( String ) view.comboBoxFrameCol.getSelectedItem() ) .qualityColumnName( ( String ) view.comboBoxQualityCol.getSelectedItem() ) .idColumnName( ( String ) view.comboBoxIDCol.getSelectedItem() ) + .motherIdColumnName( ( String ) view.comboBoxMotherIdCol.getSelectedItem() ) .get(); if ( !importer.checkInput() || !importer.process() ) @@ -289,8 +290,10 @@ private boolean readHeaders() view.comboBoxQualityCol.setModel( new DefaultComboBoxModel<>( nonMandatory ) ); view.comboBoxNameCol.setModel( new DefaultComboBoxModel<>( nonMandatory ) ); view.comboBoxIDCol.setModel( new DefaultComboBoxModel<>( nonMandatory ) ); + view.comboBoxMotherIdCol.setModel( new DefaultComboBoxModel<>( nonMandatory ) ); int idcol = headers.indexOf( NONE_COLUMN ); + int motheridcol = headers.indexOf( NONE_COLUMN ); int qualitycol = headers.indexOf( NONE_COLUMN ); int namecol = headers.indexOf( NONE_COLUMN ); for ( int i = 0; i < nonMandatory.length; i++ ) @@ -306,9 +309,13 @@ private boolean readHeaders() if ( current.toLowerCase().startsWith( "q" ) ) qualitycol = i; + + if ( current.toLowerCase().startsWith( "mother" ) ) + motheridcol = i; } view.comboBoxIDCol.setSelectedIndex( idcol ); + view.comboBoxMotherIdCol.setSelectedIndex( motheridcol ); view.comboBoxQualityCol.setSelectedIndex( qualitycol ); view.comboBoxNameCol.setSelectedIndex( namecol ); } @@ -331,6 +338,7 @@ private void clearComboBoxes() comboBoxes.add( view.comboBoxQualityCol ); comboBoxes.add( view.comboBoxNameCol ); comboBoxes.add( view.comboBoxIDCol ); + comboBoxes.add( view.comboBoxMotherIdCol ); comboBoxes.add( view.comboBoxTrackCol ); for ( final JComboBox< String > cb : comboBoxes ) cb.setModel( new DefaultComboBoxModel<>() ); From d9fe2e98f15535bcdd4b93f1a354dd7abb791c38 Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Thu, 22 Aug 2024 16:57:28 +0200 Subject: [PATCH 04/12] Add class to StartImageJ with Mastodon Pasteur Plugins included --- .../java/org/mastodon/mamut/StartImageJ.java | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/test/java/org/mastodon/mamut/StartImageJ.java diff --git a/src/test/java/org/mastodon/mamut/StartImageJ.java b/src/test/java/org/mastodon/mamut/StartImageJ.java new file mode 100644 index 0000000..bd458e0 --- /dev/null +++ b/src/test/java/org/mastodon/mamut/StartImageJ.java @@ -0,0 +1,54 @@ +/*- + * #%L + * mastodon-deep-lineage + * %% + * Copyright (C) 2022 - 2024 Stefan Hahmann + * %% + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * #L% + */ +package org.mastodon.mamut; + +import org.scijava.Context; +import org.scijava.ui.UIService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.invoke.MethodHandles; + +/** + * Shows the ImageJ main window, with Mastodon installed. + * + * @author Stefan Hahmann + */ +public class StartImageJ +{ + private static final Logger logger = LoggerFactory.getLogger( MethodHandles.lookup().lookupClass() ); + + public static void main( String... args ) + { + logger.info( "Starting ImageJ..." ); + Context context = new Context(); + UIService uiService = context.service( UIService.class ); + uiService.showUI(); + } +} From 0e28beda752aab644f3780d4cda6d86e66b9eef1 Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Fri, 23 Aug 2024 11:37:33 +0200 Subject: [PATCH 05/12] Open CSVReader in try-with-statement * By this the Autocloseable feature of the CSVReader is used --- .../java/org/mastodon/mamut/io/csv/CSVImporter.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java b/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java index f6f2b9b..51fe994 100644 --- a/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java +++ b/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java @@ -205,11 +205,10 @@ public boolean process() .withSeparator( separator ) .withIgnoreQuotations( true ) .build(); - try + try (final CSVReader reader = new CSVReaderBuilder( new FileReader( filePath ) ) + .withCSVParser( parser ) + .build()) { - final CSVReader reader = new CSVReaderBuilder( new FileReader( filePath ) ) - .withCSVParser( parser ) - .build(); final Iterator< String[] > it = reader.iterator(); /* @@ -374,6 +373,12 @@ public boolean process() e.printStackTrace(); return false; } + catch ( final IOException e ) + { + errorMessage = "Error reading file " + filePath; + e.printStackTrace(); + return false; + } /* * Return. From 93814906c3b6dfec3ab4b4c2e8d1d971d6608fd4 Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Fri, 23 Aug 2024 11:40:01 +0200 Subject: [PATCH 06/12] Add possibility to read tags from a tag column and create a tag set from it --- .../mastodon/mamut/io/csv/CSVImporter.java | 75 ++++++++++++++++++- .../io/csv/plugin/ui/CSVImporterPanel.java | 21 +++++- .../plugin/ui/CSVImporterUIController.java | 8 ++ 3 files changed, 102 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java b/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java index 51fe994..d5d83a4 100644 --- a/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java +++ b/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java @@ -33,10 +33,15 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; +import java.util.stream.Collectors; +import org.apache.commons.lang3.tuple.Pair; import org.mastodon.RefPool; import org.mastodon.collection.IntRefMap; import org.mastodon.collection.RefCollection; @@ -56,8 +61,11 @@ import org.mastodon.mamut.model.Model; import org.mastodon.mamut.model.ModelGraph; import org.mastodon.mamut.model.Spot; +import org.mastodon.model.tag.TagSetStructure; import org.mastodon.properties.IntPropertyMap; import org.mastodon.tracking.mamut.detection.DetectionQualityFeature; +import org.mastodon.ui.coloring.GlasbeyLut; +import org.mastodon.util.TagSetUtils; import org.scijava.plugin.Plugin; import org.scijava.util.VersionUtils; @@ -93,6 +101,8 @@ public class CSVImporter extends ModelImporter implements Algorithm private final String labelColumnName; + private final String tagColumnName; + private final double radius; private final double xOrigin; @@ -118,6 +128,7 @@ private CSVImporter( final String idColumnName, final String motherIdColumnName, final String labelColumnName, + final String tagColumnName, final double xOrigin, final double yOrigin, final double zOrigin ) @@ -135,6 +146,7 @@ private CSVImporter( this.idColumnName = idColumnName; this.motherIdColumnName = motherIdColumnName; this.labelColumnName = labelColumnName; + this.tagColumnName = tagColumnName; this.xOrigin = xOrigin; this.yOrigin = yOrigin; this.zOrigin = zOrigin; @@ -291,6 +303,14 @@ public boolean process() if ( null != labelColumnName && !labelColumnName.isEmpty() ) labelcol = headerMap.get( labelColumnName ); + Integer tagcol = null; + if ( null != tagColumnName && !tagColumnName.isEmpty() ) + tagcol = headerMap.get( tagColumnName ); + + TagSetStructure.TagSet importedTagSet = null; + if ( null != tagcol ) + importedTagSet = parseTagsFromFile( parser, tagcol ); + IntRefMap< Spot > spotMap = new IntRefHashMap<>( model.getGraph().vertices().getRefPool(), -1 ); /* @@ -304,6 +324,8 @@ public boolean process() final Link edgeRef = graph.edgeRef(); final double[] pos = new double[ 3 ]; startImport(); + if ( null != tagcol ) + model.getTagSetModel().pauseListeners(); try { @@ -333,8 +355,10 @@ public boolean process() if ( null != labelcol ) { - spot.setLabel( record[ labelcol ].trim() ); + String label = record[ labelcol ].trim(); + spot.setLabel( label ); } + double q = 1.; if ( null != qualitycol ) { @@ -349,6 +373,14 @@ public boolean process() if ( mother != null ) model.getGraph().addEdge( mother, spot, edgeRef ).init(); } + + if ( null != tagcol ) + { + String label = record[ tagcol ].trim(); + TagSetStructure.Tag tag = TagSetUtils.findTag( importedTagSet, label ); + TagSetUtils.tagSpot( model, importedTagSet, tag, spot ); + TagSetUtils.tagLinks( model, importedTagSet, tag, spot.incomingEdges() ); + } } catch ( final NumberFormatException nfe ) { @@ -364,6 +396,8 @@ public boolean process() graph.releaseRef( vref ); graph.releaseRef( motherVertexRef ); graph.releaseRef( edgeRef ); + if ( null != tagcol ) + model.getTagSetModel().resumeListeners(); finishImport(); } } @@ -387,6 +421,36 @@ public boolean process() return true; } + private TagSetStructure.TagSet parseTagsFromFile( final CSVParser parser, int labelcol ) + { + try (final CSVReader readerTags = new CSVReaderBuilder( new FileReader( filePath ) ) + .withCSVParser( parser ) + .build()) + { + Iterator< String[] > csvIterator = readerTags.iterator(); + + Set< String > tags = new HashSet<>(); + csvIterator.next(); + while ( csvIterator.hasNext() ) + { + final String[] line = csvIterator.next(); + String tag = line[ labelcol ].trim(); + tags.add( tag ); + } + GlasbeyLut glasbeyLut = new GlasbeyLut(); + List< Pair< String, Integer > > tagsAndColors = + tags.stream().map( tag -> Pair.of( tag, glasbeyLut.next() ) ).collect( Collectors.toList() ); + + return TagSetUtils.addNewTagSetToModel( model, "Imported Tags", tagsAndColors ); + } + catch ( final IOException e ) + { + errorMessage = "Error reading file " + filePath; + e.printStackTrace(); + return null; + } + } + @Override public String getErrorMessage() { @@ -489,6 +553,8 @@ public static class Builder private String labelColumnName; + private String tagColumnName; + private double xOrigin = 0.; private double yOrigin = 0.; @@ -563,6 +629,12 @@ public Builder labelColumnName( final String labelColumnName ) return this; } + public Builder tagColumnName( final String tagColumnName ) + { + this.tagColumnName = tagColumnName; + return this; + } + public Builder xOrigin( final double xOrigin ) { this.xOrigin = xOrigin; @@ -655,6 +727,7 @@ public CSVImporter get() idColumnName, motherIdColumnName, labelColumnName, + tagColumnName, xOrigin, yOrigin, zOrigin ); diff --git a/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java b/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java index 574b693..224da5a 100644 --- a/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java +++ b/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java @@ -75,6 +75,8 @@ public class CSVImporterPanel extends JPanel final JComboBox< String > comboBoxMotherIdCol; + final JComboBox< String > comboBoxTagCol; + final JComboBox< String > comboBoxTrackCol; final JCheckBox chckbxImportTracks; @@ -329,12 +331,29 @@ public CSVImporterPanel() gbc_comboBoxMotherID.gridy = 14; panelControl.add( comboBoxMotherIdCol, gbc_comboBoxMotherID ); + final JLabel lblTagColumn = new JLabel( "Tag column:" ); + final GridBagConstraints gbc_lblTagColumn = new GridBagConstraints(); + gbc_lblTagColumn.anchor = GridBagConstraints.EAST; + gbc_lblTagColumn.insets = new Insets( 5, 5, 5, 5 ); + gbc_lblTagColumn.gridx = 0; + gbc_lblTagColumn.gridy = 15; + panelControl.add( lblTagColumn, gbc_lblTagColumn ); + + comboBoxTagCol = new JComboBox<>(); + final GridBagConstraints gbc_comboBoxTag = new GridBagConstraints(); + gbc_comboBoxTag.insets = new Insets( 5, 5, 5, 0 ); + gbc_comboBoxTag.gridwidth = 4; + gbc_comboBoxTag.fill = GridBagConstraints.HORIZONTAL; + gbc_comboBoxTag.gridx = 1; + gbc_comboBoxTag.gridy = 15; + panelControl.add( comboBoxTagCol, gbc_comboBoxTag ); + final JPanel panelButtonExport = new JPanel(); final GridBagConstraints gbc_panelButtonExport = new GridBagConstraints(); gbc_panelButtonExport.anchor = GridBagConstraints.EAST; gbc_panelButtonExport.gridwidth = 5; gbc_panelButtonExport.gridx = 0; - gbc_panelButtonExport.gridy = 15; + gbc_panelButtonExport.gridy = 16; panelControl.add( panelButtonExport, gbc_panelButtonExport ); final FlowLayout flowLayout = ( FlowLayout ) panelButtonExport.getLayout(); flowLayout.setAlignment( FlowLayout.RIGHT ); diff --git a/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterUIController.java b/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterUIController.java index 812ce1d..cc4b1be 100644 --- a/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterUIController.java +++ b/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterUIController.java @@ -115,6 +115,7 @@ public void run() .qualityColumnName( ( String ) view.comboBoxQualityCol.getSelectedItem() ) .idColumnName( ( String ) view.comboBoxIDCol.getSelectedItem() ) .motherIdColumnName( ( String ) view.comboBoxMotherIdCol.getSelectedItem() ) + .tagColumnName( ( String ) view.comboBoxTagCol.getSelectedItem() ) .get(); if ( !importer.checkInput() || !importer.process() ) @@ -291,9 +292,11 @@ private boolean readHeaders() view.comboBoxNameCol.setModel( new DefaultComboBoxModel<>( nonMandatory ) ); view.comboBoxIDCol.setModel( new DefaultComboBoxModel<>( nonMandatory ) ); view.comboBoxMotherIdCol.setModel( new DefaultComboBoxModel<>( nonMandatory ) ); + view.comboBoxTagCol.setModel( new DefaultComboBoxModel<>( nonMandatory ) ); int idcol = headers.indexOf( NONE_COLUMN ); int motheridcol = headers.indexOf( NONE_COLUMN ); + int tagcol = headers.indexOf( NONE_COLUMN ); int qualitycol = headers.indexOf( NONE_COLUMN ); int namecol = headers.indexOf( NONE_COLUMN ); for ( int i = 0; i < nonMandatory.length; i++ ) @@ -312,10 +315,14 @@ private boolean readHeaders() if ( current.toLowerCase().startsWith( "mother" ) ) motheridcol = i; + + if ( current.toLowerCase().startsWith( "tag" ) ) + tagcol = i; } view.comboBoxIDCol.setSelectedIndex( idcol ); view.comboBoxMotherIdCol.setSelectedIndex( motheridcol ); + view.comboBoxTagCol.setSelectedIndex( tagcol ); view.comboBoxQualityCol.setSelectedIndex( qualitycol ); view.comboBoxNameCol.setSelectedIndex( namecol ); } @@ -339,6 +346,7 @@ private void clearComboBoxes() comboBoxes.add( view.comboBoxNameCol ); comboBoxes.add( view.comboBoxIDCol ); comboBoxes.add( view.comboBoxMotherIdCol ); + comboBoxes.add( view.comboBoxTagCol ); comboBoxes.add( view.comboBoxTrackCol ); for ( final JComboBox< String > cb : comboBoxes ) cb.setModel( new DefaultComboBoxModel<>() ); From d73d04564d6f42f10f65a761d1bc619839c80393 Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Fri, 23 Aug 2024 11:54:30 +0200 Subject: [PATCH 07/12] Add some separators and intermediate headlines for mandatory and optional sections --- .../io/csv/plugin/ui/CSVImporterPanel.java | 84 +++++++++++++------ 1 file changed, 60 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java b/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java index 224da5a..2a40900 100644 --- a/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java +++ b/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java @@ -148,12 +148,21 @@ public CSVImporterPanel() gbc_separator.gridy = 4; panelControl.add( separator, gbc_separator ); + final JLabel lblMandatory = new JLabel( "Mandatory" ); + lblMandatory.setFont( new Font( Font.SANS_SERIF, Font.ITALIC, 12 ) ); + final GridBagConstraints gbc_lblRadiusMandatory = new GridBagConstraints(); + gbc_lblRadiusMandatory.anchor = GridBagConstraints.EAST; + gbc_lblRadiusMandatory.insets = new Insets( 0, 0, 5, 50 ); + gbc_lblRadiusMandatory.gridx = 0; + gbc_lblRadiusMandatory.gridy = 5; + panelControl.add( lblMandatory, gbc_lblRadiusMandatory ); + final JLabel lblRadius = new JLabel( "Radius:" ); final GridBagConstraints gbc_lblRadius = new GridBagConstraints(); gbc_lblRadius.anchor = GridBagConstraints.EAST; gbc_lblRadius.insets = new Insets( 0, 0, 5, 5 ); gbc_lblRadius.gridx = 0; - gbc_lblRadius.gridy = 5; + gbc_lblRadius.gridy = 6; panelControl.add( lblRadius, gbc_lblRadius ); ftfRadius = new JFormattedTextField( NumberFormat.getNumberInstance() ); @@ -163,7 +172,7 @@ public CSVImporterPanel() gbc_ftfRadius.insets = new Insets( 5, 5, 5, 5 ); gbc_ftfRadius.fill = GridBagConstraints.HORIZONTAL; gbc_ftfRadius.gridx = 1; - gbc_ftfRadius.gridy = 5; + gbc_ftfRadius.gridy = 6; panelControl.add( ftfRadius, gbc_ftfRadius ); labelRadiusUnit = new JLabel(); @@ -171,7 +180,7 @@ public CSVImporterPanel() gbc_labelRadiusUnitl.anchor = GridBagConstraints.WEST; gbc_labelRadiusUnitl.insets = new Insets( 0, 0, 5, 5 ); gbc_labelRadiusUnitl.gridx = 3; - gbc_labelRadiusUnitl.gridy = 5; + gbc_labelRadiusUnitl.gridy = 6; panelControl.add( labelRadiusUnit, gbc_labelRadiusUnitl ); final JLabel lblXColumn = new JLabel( "X column:" ); @@ -179,7 +188,7 @@ public CSVImporterPanel() gbc_lblXColumn.anchor = GridBagConstraints.EAST; gbc_lblXColumn.insets = new Insets( 5, 5, 5, 5 ); gbc_lblXColumn.gridx = 0; - gbc_lblXColumn.gridy = 6; + gbc_lblXColumn.gridy = 7; panelControl.add( lblXColumn, gbc_lblXColumn ); comboBoxXCol = new JComboBox<>(); @@ -188,7 +197,7 @@ public CSVImporterPanel() gbc_comboBoxX.insets = new Insets( 5, 5, 5, 0 ); gbc_comboBoxX.fill = GridBagConstraints.HORIZONTAL; gbc_comboBoxX.gridx = 1; - gbc_comboBoxX.gridy = 6; + gbc_comboBoxX.gridy = 7; panelControl.add( comboBoxXCol, gbc_comboBoxX ); final JLabel lblYColumn = new JLabel( "Y column:" ); @@ -196,7 +205,7 @@ public CSVImporterPanel() gbc_lblYColumn.anchor = GridBagConstraints.EAST; gbc_lblYColumn.insets = new Insets( 5, 5, 5, 5 ); gbc_lblYColumn.gridx = 0; - gbc_lblYColumn.gridy = 7; + gbc_lblYColumn.gridy = 8; panelControl.add( lblYColumn, gbc_lblYColumn ); comboBoxYCol = new JComboBox<>(); @@ -205,7 +214,7 @@ public CSVImporterPanel() gbc_comboBoxY.insets = new Insets( 5, 5, 5, 0 ); gbc_comboBoxY.fill = GridBagConstraints.HORIZONTAL; gbc_comboBoxY.gridx = 1; - gbc_comboBoxY.gridy = 7; + gbc_comboBoxY.gridy = 8; panelControl.add( comboBoxYCol, gbc_comboBoxY ); final JLabel lblZColumn = new JLabel( "Z column:" ); @@ -213,7 +222,7 @@ public CSVImporterPanel() gbc_lblZColumn.anchor = GridBagConstraints.EAST; gbc_lblZColumn.insets = new Insets( 5, 5, 5, 5 ); gbc_lblZColumn.gridx = 0; - gbc_lblZColumn.gridy = 8; + gbc_lblZColumn.gridy = 9; panelControl.add( lblZColumn, gbc_lblZColumn ); comboBoxZCol = new JComboBox<>(); @@ -222,7 +231,7 @@ public CSVImporterPanel() gbc_comboBoxZ.insets = new Insets( 5, 5, 5, 0 ); gbc_comboBoxZ.fill = GridBagConstraints.HORIZONTAL; gbc_comboBoxZ.gridx = 1; - gbc_comboBoxZ.gridy = 8; + gbc_comboBoxZ.gridy = 9; panelControl.add( comboBoxZCol, gbc_comboBoxZ ); final JLabel lblFrameColumn = new JLabel( "Frame column:" ); @@ -230,7 +239,7 @@ public CSVImporterPanel() gbc_lblFrameColumn.anchor = GridBagConstraints.EAST; gbc_lblFrameColumn.insets = new Insets( 5, 5, 5, 5 ); gbc_lblFrameColumn.gridx = 0; - gbc_lblFrameColumn.gridy = 9; + gbc_lblFrameColumn.gridy = 10; panelControl.add( lblFrameColumn, gbc_lblFrameColumn ); comboBoxFrameCol = new JComboBox<>(); @@ -239,15 +248,33 @@ public CSVImporterPanel() gbc_comboBoxFrame.insets = new Insets( 5, 5, 5, 0 ); gbc_comboBoxFrame.fill = GridBagConstraints.HORIZONTAL; gbc_comboBoxFrame.gridx = 1; - gbc_comboBoxFrame.gridy = 9; + gbc_comboBoxFrame.gridy = 10; panelControl.add( comboBoxFrameCol, gbc_comboBoxFrame ); + final JSeparator separatorOptional = new JSeparator(); + final GridBagConstraints gbc_separatorOptional = new GridBagConstraints(); + gbc_separatorOptional.fill = GridBagConstraints.BOTH; + gbc_separatorOptional.gridwidth = 5; + gbc_separatorOptional.insets = new Insets( 5, 5, 5, 5 ); + gbc_separatorOptional.gridx = 0; + gbc_separatorOptional.gridy = 11; + panelControl.add( separatorOptional, gbc_separatorOptional ); + + final JLabel lblOptional = new JLabel( "Optional" ); + lblOptional.setFont( new Font( Font.SANS_SERIF, Font.ITALIC, 12 ) ); + final GridBagConstraints gbc_lblRadiusOptional = new GridBagConstraints(); + gbc_lblRadiusOptional.anchor = GridBagConstraints.EAST; + gbc_lblRadiusOptional.insets = new Insets( 0, 0, 5, 50 ); + gbc_lblRadiusOptional.gridx = 0; + gbc_lblRadiusOptional.gridy = 12; + panelControl.add( lblOptional, gbc_lblRadiusOptional ); + final JLabel lblTrackColumn = new JLabel( "Track column:" ); final GridBagConstraints gbc_lblTrackColumn = new GridBagConstraints(); gbc_lblTrackColumn.anchor = GridBagConstraints.EAST; gbc_lblTrackColumn.insets = new Insets( 5, 5, 5, 5 ); gbc_lblTrackColumn.gridx = 0; - gbc_lblTrackColumn.gridy = 10; + gbc_lblTrackColumn.gridy = 13; panelControl.add( lblTrackColumn, gbc_lblTrackColumn ); lblTrackColumn.setVisible( false ); // TODO @@ -257,7 +284,7 @@ public CSVImporterPanel() gbc_comboBoxTrackCol.insets = new Insets( 5, 5, 5, 0 ); gbc_comboBoxTrackCol.fill = GridBagConstraints.HORIZONTAL; gbc_comboBoxTrackCol.gridx = 1; - gbc_comboBoxTrackCol.gridy = 10; + gbc_comboBoxTrackCol.gridy = 13; panelControl.add( comboBoxTrackCol, gbc_comboBoxTrackCol ); chckbxImportTracks.addActionListener( ( e ) -> comboBoxTrackCol.setEnabled( chckbxImportTracks.isSelected() ) ); comboBoxTrackCol.setEnabled( chckbxImportTracks.isSelected() ); @@ -268,7 +295,7 @@ public CSVImporterPanel() gbc_lblQualityColumn.anchor = GridBagConstraints.EAST; gbc_lblQualityColumn.insets = new Insets( 5, 5, 5, 5 ); gbc_lblQualityColumn.gridx = 0; - gbc_lblQualityColumn.gridy = 11; + gbc_lblQualityColumn.gridy = 14; panelControl.add( lblQualityColumn, gbc_lblQualityColumn ); comboBoxQualityCol = new JComboBox<>(); @@ -277,7 +304,7 @@ public CSVImporterPanel() gbc_comboBoxQuality.insets = new Insets( 5, 5, 5, 0 ); gbc_comboBoxQuality.fill = GridBagConstraints.HORIZONTAL; gbc_comboBoxQuality.gridx = 1; - gbc_comboBoxQuality.gridy = 11; + gbc_comboBoxQuality.gridy = 14; panelControl.add( comboBoxQualityCol, gbc_comboBoxQuality ); final JLabel lblNameColumn = new JLabel( "Name column:" ); @@ -285,7 +312,7 @@ public CSVImporterPanel() gbc_lblNameColumn.anchor = GridBagConstraints.EAST; gbc_lblNameColumn.insets = new Insets( 5, 5, 5, 5 ); gbc_lblNameColumn.gridx = 0; - gbc_lblNameColumn.gridy = 12; + gbc_lblNameColumn.gridy = 15; panelControl.add( lblNameColumn, gbc_lblNameColumn ); comboBoxNameCol = new JComboBox<>(); @@ -294,7 +321,7 @@ public CSVImporterPanel() gbc_comboBoxName.insets = new Insets( 5, 5, 5, 0 ); gbc_comboBoxName.fill = GridBagConstraints.HORIZONTAL; gbc_comboBoxName.gridx = 1; - gbc_comboBoxName.gridy = 12; + gbc_comboBoxName.gridy = 15; panelControl.add( comboBoxNameCol, gbc_comboBoxName ); final JLabel lblIdColumn = new JLabel( "ID column:" ); @@ -302,7 +329,7 @@ public CSVImporterPanel() gbc_lblIdColumn.anchor = GridBagConstraints.EAST; gbc_lblIdColumn.insets = new Insets( 5, 5, 5, 5 ); gbc_lblIdColumn.gridx = 0; - gbc_lblIdColumn.gridy = 13; + gbc_lblIdColumn.gridy = 16; panelControl.add( lblIdColumn, gbc_lblIdColumn ); comboBoxIDCol = new JComboBox<>(); @@ -311,7 +338,7 @@ public CSVImporterPanel() gbc_comboBoxID.gridwidth = 4; gbc_comboBoxID.fill = GridBagConstraints.HORIZONTAL; gbc_comboBoxID.gridx = 1; - gbc_comboBoxID.gridy = 13; + gbc_comboBoxID.gridy = 16; panelControl.add( comboBoxIDCol, gbc_comboBoxID ); final JLabel lblMotherIdColumn = new JLabel( "Mother ID column:" ); @@ -319,7 +346,7 @@ public CSVImporterPanel() gbc_lblMotherIdColumn.anchor = GridBagConstraints.EAST; gbc_lblMotherIdColumn.insets = new Insets( 5, 5, 5, 5 ); gbc_lblMotherIdColumn.gridx = 0; - gbc_lblMotherIdColumn.gridy = 14; + gbc_lblMotherIdColumn.gridy = 17; panelControl.add( lblMotherIdColumn, gbc_lblMotherIdColumn ); comboBoxMotherIdCol = new JComboBox<>(); @@ -328,7 +355,7 @@ public CSVImporterPanel() gbc_comboBoxMotherID.gridwidth = 4; gbc_comboBoxMotherID.fill = GridBagConstraints.HORIZONTAL; gbc_comboBoxMotherID.gridx = 1; - gbc_comboBoxMotherID.gridy = 14; + gbc_comboBoxMotherID.gridy = 17; panelControl.add( comboBoxMotherIdCol, gbc_comboBoxMotherID ); final JLabel lblTagColumn = new JLabel( "Tag column:" ); @@ -336,7 +363,7 @@ public CSVImporterPanel() gbc_lblTagColumn.anchor = GridBagConstraints.EAST; gbc_lblTagColumn.insets = new Insets( 5, 5, 5, 5 ); gbc_lblTagColumn.gridx = 0; - gbc_lblTagColumn.gridy = 15; + gbc_lblTagColumn.gridy = 18; panelControl.add( lblTagColumn, gbc_lblTagColumn ); comboBoxTagCol = new JComboBox<>(); @@ -345,15 +372,24 @@ public CSVImporterPanel() gbc_comboBoxTag.gridwidth = 4; gbc_comboBoxTag.fill = GridBagConstraints.HORIZONTAL; gbc_comboBoxTag.gridx = 1; - gbc_comboBoxTag.gridy = 15; + gbc_comboBoxTag.gridy = 18; panelControl.add( comboBoxTagCol, gbc_comboBoxTag ); + final JSeparator separatorButton = new JSeparator(); + final GridBagConstraints gbc_separatorButton = new GridBagConstraints(); + gbc_separatorButton.fill = GridBagConstraints.BOTH; + gbc_separatorButton.gridwidth = 5; + gbc_separatorButton.insets = new Insets( 5, 5, 5, 5 ); + gbc_separatorButton.gridx = 0; + gbc_separatorButton.gridy = 19; + panelControl.add( separatorButton, gbc_separatorButton ); + final JPanel panelButtonExport = new JPanel(); final GridBagConstraints gbc_panelButtonExport = new GridBagConstraints(); gbc_panelButtonExport.anchor = GridBagConstraints.EAST; gbc_panelButtonExport.gridwidth = 5; gbc_panelButtonExport.gridx = 0; - gbc_panelButtonExport.gridy = 16; + gbc_panelButtonExport.gridy = 20; panelControl.add( panelButtonExport, gbc_panelButtonExport ); final FlowLayout flowLayout = ( FlowLayout ) panelButtonExport.getLayout(); flowLayout.setAlignment( FlowLayout.RIGHT ); From e3a559b9eb22ced6de17415d2242f944654ad10e Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Fri, 23 Aug 2024 16:44:16 +0200 Subject: [PATCH 08/12] Add radius column selection to CSV importer * If a radius column is specified the default radius would be overwritten with a radius found in this column --- .../mastodon/mamut/io/csv/CSVImporter.java | 23 ++++++++++- .../io/csv/plugin/ui/CSVImporterPanel.java | 39 ++++++++++++++----- .../plugin/ui/CSVImporterUIController.java | 8 ++++ 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java b/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java index d5d83a4..b994097 100644 --- a/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java +++ b/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java @@ -95,6 +95,8 @@ public class CSVImporter extends ModelImporter implements Algorithm private final String qualityColumnName; + private final String radiusColumnName; + private final String idColumnName; private final String motherIdColumnName; @@ -125,6 +127,7 @@ private CSVImporter( final String zColumnName, final String frameColumnName, final String qualityColumName, + final String radiusColumnName, final String idColumnName, final String motherIdColumnName, final String labelColumnName, @@ -143,6 +146,7 @@ private CSVImporter( this.zColumnName = zColumnName; this.frameColumnName = frameColumnName; this.qualityColumnName = qualityColumName; + this.radiusColumnName = radiusColumnName; this.idColumnName = idColumnName; this.motherIdColumnName = motherIdColumnName; this.labelColumnName = labelColumnName; @@ -287,6 +291,10 @@ public boolean process() ? null : DetectionQualityFeature.getOrRegister( model.getFeatureModel(), graph.vertices().getRefPool() ); + Integer radiuscol = null; + if ( null != radiusColumnName && !radiusColumnName.isEmpty() ) + radiuscol = headerMap.get( radiusColumnName ); + Integer idcol = null; if ( null != idColumnName && !idColumnName.isEmpty() ) idcol = headerMap.get( idColumnName ); @@ -342,7 +350,11 @@ public boolean process() pos[ 2 ] = Double.parseDouble( record[ zcol ].trim() ) + zOrigin; final int t = Integer.parseInt( record[ framecol ].trim() ); - final Spot spot = graph.addVertex( vref ).init( t, pos, radius ); + double r = radius; + if ( null != radiuscol ) + r = Double.parseDouble( record[ radiuscol ].trim() ); + + final Spot spot = graph.addVertex( vref ).init( t, pos, r ); if ( null != idcol ) { final int id = Integer.parseInt( record[ idcol ].trim() ); @@ -547,6 +559,8 @@ public static class Builder private String qualityColumnName; + private String radiusColumnName; + private String idColumnName; private String motherIdColumnName; @@ -611,6 +625,12 @@ public Builder qualityColumnName( final String qualityColumnName ) return this; } + public Builder radiusColumnName( final String radiusColumnName ) + { + this.radiusColumnName = radiusColumnName; + return this; + } + public Builder idColumnName( final String idColumnName ) { this.idColumnName = idColumnName; @@ -724,6 +744,7 @@ public CSVImporter get() zColumnName, frameColumnName, qualityColumnName, + radiusColumnName, idColumnName, motherIdColumnName, labelColumnName, diff --git a/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java b/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java index 2a40900..94958a3 100644 --- a/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java +++ b/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java @@ -69,6 +69,8 @@ public class CSVImporterPanel extends JPanel final JComboBox< String > comboBoxQualityCol; + final JComboBox< String > comboBoxRadiusCol; + final JComboBox< String > comboBoxNameCol; final JComboBox< String > comboBoxIDCol; @@ -307,12 +309,29 @@ public CSVImporterPanel() gbc_comboBoxQuality.gridy = 14; panelControl.add( comboBoxQualityCol, gbc_comboBoxQuality ); + final JLabel lblRadiusColumn = new JLabel( "Radius column:" ); + final GridBagConstraints gbc_lblRadiusColumn = new GridBagConstraints(); + gbc_lblRadiusColumn.anchor = GridBagConstraints.EAST; + gbc_lblRadiusColumn.insets = new Insets( 5, 5, 5, 5 ); + gbc_lblRadiusColumn.gridx = 0; + gbc_lblRadiusColumn.gridy = 15; + panelControl.add( lblRadiusColumn, gbc_lblRadiusColumn ); + + comboBoxRadiusCol = new JComboBox<>(); + final GridBagConstraints gbc_comboBoxRadius = new GridBagConstraints(); + gbc_comboBoxRadius.gridwidth = 4; + gbc_comboBoxRadius.insets = new Insets( 5, 5, 5, 0 ); + gbc_comboBoxRadius.fill = GridBagConstraints.HORIZONTAL; + gbc_comboBoxRadius.gridx = 1; + gbc_comboBoxRadius.gridy = 15; + panelControl.add( comboBoxRadiusCol, gbc_comboBoxRadius ); + final JLabel lblNameColumn = new JLabel( "Name column:" ); final GridBagConstraints gbc_lblNameColumn = new GridBagConstraints(); gbc_lblNameColumn.anchor = GridBagConstraints.EAST; gbc_lblNameColumn.insets = new Insets( 5, 5, 5, 5 ); gbc_lblNameColumn.gridx = 0; - gbc_lblNameColumn.gridy = 15; + gbc_lblNameColumn.gridy = 16; panelControl.add( lblNameColumn, gbc_lblNameColumn ); comboBoxNameCol = new JComboBox<>(); @@ -321,7 +340,7 @@ public CSVImporterPanel() gbc_comboBoxName.insets = new Insets( 5, 5, 5, 0 ); gbc_comboBoxName.fill = GridBagConstraints.HORIZONTAL; gbc_comboBoxName.gridx = 1; - gbc_comboBoxName.gridy = 15; + gbc_comboBoxName.gridy = 16; panelControl.add( comboBoxNameCol, gbc_comboBoxName ); final JLabel lblIdColumn = new JLabel( "ID column:" ); @@ -329,7 +348,7 @@ public CSVImporterPanel() gbc_lblIdColumn.anchor = GridBagConstraints.EAST; gbc_lblIdColumn.insets = new Insets( 5, 5, 5, 5 ); gbc_lblIdColumn.gridx = 0; - gbc_lblIdColumn.gridy = 16; + gbc_lblIdColumn.gridy = 17; panelControl.add( lblIdColumn, gbc_lblIdColumn ); comboBoxIDCol = new JComboBox<>(); @@ -338,7 +357,7 @@ public CSVImporterPanel() gbc_comboBoxID.gridwidth = 4; gbc_comboBoxID.fill = GridBagConstraints.HORIZONTAL; gbc_comboBoxID.gridx = 1; - gbc_comboBoxID.gridy = 16; + gbc_comboBoxID.gridy = 17; panelControl.add( comboBoxIDCol, gbc_comboBoxID ); final JLabel lblMotherIdColumn = new JLabel( "Mother ID column:" ); @@ -346,7 +365,7 @@ public CSVImporterPanel() gbc_lblMotherIdColumn.anchor = GridBagConstraints.EAST; gbc_lblMotherIdColumn.insets = new Insets( 5, 5, 5, 5 ); gbc_lblMotherIdColumn.gridx = 0; - gbc_lblMotherIdColumn.gridy = 17; + gbc_lblMotherIdColumn.gridy = 18; panelControl.add( lblMotherIdColumn, gbc_lblMotherIdColumn ); comboBoxMotherIdCol = new JComboBox<>(); @@ -355,7 +374,7 @@ public CSVImporterPanel() gbc_comboBoxMotherID.gridwidth = 4; gbc_comboBoxMotherID.fill = GridBagConstraints.HORIZONTAL; gbc_comboBoxMotherID.gridx = 1; - gbc_comboBoxMotherID.gridy = 17; + gbc_comboBoxMotherID.gridy = 18; panelControl.add( comboBoxMotherIdCol, gbc_comboBoxMotherID ); final JLabel lblTagColumn = new JLabel( "Tag column:" ); @@ -363,7 +382,7 @@ public CSVImporterPanel() gbc_lblTagColumn.anchor = GridBagConstraints.EAST; gbc_lblTagColumn.insets = new Insets( 5, 5, 5, 5 ); gbc_lblTagColumn.gridx = 0; - gbc_lblTagColumn.gridy = 18; + gbc_lblTagColumn.gridy = 19; panelControl.add( lblTagColumn, gbc_lblTagColumn ); comboBoxTagCol = new JComboBox<>(); @@ -372,7 +391,7 @@ public CSVImporterPanel() gbc_comboBoxTag.gridwidth = 4; gbc_comboBoxTag.fill = GridBagConstraints.HORIZONTAL; gbc_comboBoxTag.gridx = 1; - gbc_comboBoxTag.gridy = 18; + gbc_comboBoxTag.gridy = 19; panelControl.add( comboBoxTagCol, gbc_comboBoxTag ); final JSeparator separatorButton = new JSeparator(); @@ -381,7 +400,7 @@ public CSVImporterPanel() gbc_separatorButton.gridwidth = 5; gbc_separatorButton.insets = new Insets( 5, 5, 5, 5 ); gbc_separatorButton.gridx = 0; - gbc_separatorButton.gridy = 19; + gbc_separatorButton.gridy = 20; panelControl.add( separatorButton, gbc_separatorButton ); final JPanel panelButtonExport = new JPanel(); @@ -389,7 +408,7 @@ public CSVImporterPanel() gbc_panelButtonExport.anchor = GridBagConstraints.EAST; gbc_panelButtonExport.gridwidth = 5; gbc_panelButtonExport.gridx = 0; - gbc_panelButtonExport.gridy = 20; + gbc_panelButtonExport.gridy = 21; panelControl.add( panelButtonExport, gbc_panelButtonExport ); final FlowLayout flowLayout = ( FlowLayout ) panelButtonExport.getLayout(); flowLayout.setAlignment( FlowLayout.RIGHT ); diff --git a/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterUIController.java b/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterUIController.java index cc4b1be..f06a9f6 100644 --- a/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterUIController.java +++ b/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterUIController.java @@ -113,6 +113,7 @@ public void run() .labelColumnName( ( String ) view.comboBoxNameCol.getSelectedItem() ) .frameColumnName( ( String ) view.comboBoxFrameCol.getSelectedItem() ) .qualityColumnName( ( String ) view.comboBoxQualityCol.getSelectedItem() ) + .radiusColumnName( ( String ) view.comboBoxRadiusCol.getSelectedItem() ) .idColumnName( ( String ) view.comboBoxIDCol.getSelectedItem() ) .motherIdColumnName( ( String ) view.comboBoxMotherIdCol.getSelectedItem() ) .tagColumnName( ( String ) view.comboBoxTagCol.getSelectedItem() ) @@ -289,6 +290,7 @@ private boolean readHeaders() headers.add( NONE_COLUMN ); final String[] nonMandatory = headers.toArray( new String[] {} ); view.comboBoxQualityCol.setModel( new DefaultComboBoxModel<>( nonMandatory ) ); + view.comboBoxRadiusCol.setModel( new DefaultComboBoxModel<>( nonMandatory ) ); view.comboBoxNameCol.setModel( new DefaultComboBoxModel<>( nonMandatory ) ); view.comboBoxIDCol.setModel( new DefaultComboBoxModel<>( nonMandatory ) ); view.comboBoxMotherIdCol.setModel( new DefaultComboBoxModel<>( nonMandatory ) ); @@ -298,6 +300,7 @@ private boolean readHeaders() int motheridcol = headers.indexOf( NONE_COLUMN ); int tagcol = headers.indexOf( NONE_COLUMN ); int qualitycol = headers.indexOf( NONE_COLUMN ); + int radiuscol = headers.indexOf( NONE_COLUMN ); int namecol = headers.indexOf( NONE_COLUMN ); for ( int i = 0; i < nonMandatory.length; i++ ) { @@ -313,6 +316,9 @@ private boolean readHeaders() if ( current.toLowerCase().startsWith( "q" ) ) qualitycol = i; + if ( current.toLowerCase().startsWith( "r" ) || current.toLowerCase().startsWith( "radius" ) ) + radiuscol = i; + if ( current.toLowerCase().startsWith( "mother" ) ) motheridcol = i; @@ -324,6 +330,7 @@ private boolean readHeaders() view.comboBoxMotherIdCol.setSelectedIndex( motheridcol ); view.comboBoxTagCol.setSelectedIndex( tagcol ); view.comboBoxQualityCol.setSelectedIndex( qualitycol ); + view.comboBoxRadiusCol.setSelectedIndex( radiuscol ); view.comboBoxNameCol.setSelectedIndex( namecol ); } catch ( final FileNotFoundException e ) @@ -343,6 +350,7 @@ private void clearComboBoxes() comboBoxes.add( view.comboBoxZCol ); comboBoxes.add( view.comboBoxFrameCol ); comboBoxes.add( view.comboBoxQualityCol ); + comboBoxes.add( view.comboBoxRadiusCol ); comboBoxes.add( view.comboBoxNameCol ); comboBoxes.add( view.comboBoxIDCol ); comboBoxes.add( view.comboBoxMotherIdCol ); From 2a160446294c4a36507d103da540d60561dea0a6 Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Fri, 23 Aug 2024 16:45:36 +0200 Subject: [PATCH 09/12] For consistency rename Name column to Label column * e.g. in the table the name of a spot is called "label" --- .../org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java b/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java index 94958a3..45de685 100644 --- a/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java +++ b/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java @@ -326,7 +326,7 @@ public CSVImporterPanel() gbc_comboBoxRadius.gridy = 15; panelControl.add( comboBoxRadiusCol, gbc_comboBoxRadius ); - final JLabel lblNameColumn = new JLabel( "Name column:" ); + final JLabel lblNameColumn = new JLabel( "Label column:" ); final GridBagConstraints gbc_lblNameColumn = new GridBagConstraints(); gbc_lblNameColumn.anchor = GridBagConstraints.EAST; gbc_lblNameColumn.insets = new Insets( 5, 5, 5, 5 ); From fedc5d28039c08f2d58f87614c046f05e1e12f5c Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Fri, 23 Aug 2024 16:46:11 +0200 Subject: [PATCH 10/12] Add unit test that tests importing links, radius and tags --- .../mamut/io/csv/CSVImporterTest.java | 66 +++++++++++++++++++ .../io/csv/TestCSVImportTagMotherIdRadius.csv | 6 ++ 2 files changed, 72 insertions(+) create mode 100644 src/test/resources/org/mastodon/mamut/io/csv/TestCSVImportTagMotherIdRadius.csv diff --git a/src/test/java/org/mastodon/mamut/io/csv/CSVImporterTest.java b/src/test/java/org/mastodon/mamut/io/csv/CSVImporterTest.java index 55e357f..2c227af 100644 --- a/src/test/java/org/mastodon/mamut/io/csv/CSVImporterTest.java +++ b/src/test/java/org/mastodon/mamut/io/csv/CSVImporterTest.java @@ -28,14 +28,23 @@ */ package org.mastodon.mamut.io.csv; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import java.io.IOException; import java.net.URL; +import java.util.Iterator; +import java.util.List; import org.junit.Test; import org.mastodon.mamut.model.Model; +import org.mastodon.mamut.model.ModelGraph; +import org.mastodon.mamut.model.Spot; +import org.mastodon.model.tag.ObjTagMap; +import org.mastodon.model.tag.ObjTags; +import org.mastodon.model.tag.TagSetStructure; import org.mastodon.tracking.mamut.detection.DetectionQualityFeature; import mpicbg.spim.data.SpimDataException; @@ -81,4 +90,61 @@ public void test() throws IOException, SpimDataException assertEquals( "Imported incorrect value for quality.", expectedQ[ id ], quality.value( s ), 1e-3 ); } ); } + + @Test + public void testImportWithRadiusTagsLinks() + { + final URL urlCSV = CSVImporterTest.class.getResource( "TestCSVImportTagMotherIdRadius.csv" ); + assertNotNull( urlCSV ); + + final Model model = new Model(); + + final String csvFilePath = urlCSV.getPath(); + final CSVImporter importer = CSVImporter.create() + .model( model ) + .csvFilePath( csvFilePath ) + .radius( 3. ) + .xColumnName( "POSITION_X" ) + .yColumnName( "POSITION_Y" ) + .zColumnName( "POSITION_Z" ) + .frameColumnName( "FRAME" ) + .idColumnName( "ID" ) + .tagColumnName( "TAG" ) + .motherIdColumnName( "MOTHER_ID" ) + .radiusColumnName( "RADIUS" ) + .get(); + if ( !importer.checkInput() || !importer.process() ) + fail( importer.getErrorMessage() ); + + ModelGraph graph = model.getGraph(); + assertEquals( "Incorrect number of spots imported.", 5, graph.vertices().size() ); + assertEquals( "Incorrect number of links imported.", 2, graph.edges().size() ); + + Iterator< Spot > it = graph.vertices().iterator(); + it.next(); + it.next(); + it.next(); + it.next(); + Spot spot4 = it.next(); + List< TagSetStructure.TagSet > tagSets = model.getTagSetModel().getTagSetStructure().getTagSets(); + TagSetStructure.TagSet tagSet = tagSets.get( 0 ); + TagSetStructure.Tag tag1 = tagSet.getTags().get( 0 ); + TagSetStructure.Tag tag2 = tagSet.getTags().get( 1 ); + ObjTags< Spot > vertexTags = model.getTagSetModel().getVertexTags(); + ObjTagMap< Spot, TagSetStructure.Tag > spotToTagMap = vertexTags.tags( tagSet ); + + assertEquals( "4", spot4.getLabel() ); + assertEquals( 1, spot4.incomingEdges().size() ); + assertEquals( 0, spot4.outgoingEdges().size() ); + assertEquals( 4d, spot4.getBoundingSphereRadiusSquared(), 0d ); + assertArrayEquals( new double[] { 36d, 12d, 9d }, spot4.positionAsDoubleArray(), 0d ); + assertEquals( 2, spot4.getTimepoint() ); + assertEquals( 1, tagSets.size() ); + assertEquals( "Imported Tags", tagSet.getName() ); + assertEquals( 2, tagSet.getTags().size() ); + assertEquals( "tag1", tag1.label() ); + assertEquals( "tag2", tag2.label() ); + TagSetStructure.Tag actualTag = spotToTagMap.get( spot4 ); + assertEquals( tag2.label(), actualTag.label() ); + } } diff --git a/src/test/resources/org/mastodon/mamut/io/csv/TestCSVImportTagMotherIdRadius.csv b/src/test/resources/org/mastodon/mamut/io/csv/TestCSVImportTagMotherIdRadius.csv new file mode 100644 index 0000000..9e6bed3 --- /dev/null +++ b/src/test/resources/org/mastodon/mamut/io/csv/TestCSVImportTagMotherIdRadius.csv @@ -0,0 +1,6 @@ +ID;QUALITY;POSITION_X;POSITION_Y;POSITION_Z;FRAME;RADIUS;MEDIAN_INTENSITY;TAG;MOTHER_ID +0; 50.943; 11.000; 11.000; 5.000; 0; 5.73; 51; tag1; -1 +1; 206.877; 30.000; 31.000; 6.000; 0; 4.; 119; tag1; -1 +2; 130.664; 36.000; 12.000; 7.000; 0; 2; 197; tag2; -1 +3; 206.877; 30.000; 31.000; 8.000; 1; 4.; 119; tag2; 2 +4; 130.664; 36.000; 12.000; 9.000; 2; 2; 197; tag2; 3 From 9fa98b130fd48630095e70eeeee923af0364bc9d Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Mon, 26 Aug 2024 14:55:54 +0200 Subject: [PATCH 11/12] Rename mother id to parent id --- .../mastodon/mamut/io/csv/CSVImporter.java | 36 +++++++++---------- .../io/csv/plugin/ui/CSVImporterPanel.java | 34 +++++++++--------- .../plugin/ui/CSVImporterUIController.java | 8 ++--- .../mamut/io/csv/CSVImporterTest.java | 4 +-- ...csv => TestCSVImportTagParentIdRadius.csv} | 2 +- 5 files changed, 42 insertions(+), 42 deletions(-) rename src/test/resources/org/mastodon/mamut/io/csv/{TestCSVImportTagMotherIdRadius.csv => TestCSVImportTagParentIdRadius.csv} (93%) diff --git a/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java b/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java index b994097..916f265 100644 --- a/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java +++ b/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java @@ -99,7 +99,7 @@ public class CSVImporter extends ModelImporter implements Algorithm private final String idColumnName; - private final String motherIdColumnName; + private final String parentIdColumnName; private final String labelColumnName; @@ -129,7 +129,7 @@ private CSVImporter( final String qualityColumName, final String radiusColumnName, final String idColumnName, - final String motherIdColumnName, + final String parentIdColumnName, final String labelColumnName, final String tagColumnName, final double xOrigin, @@ -148,7 +148,7 @@ private CSVImporter( this.qualityColumnName = qualityColumName; this.radiusColumnName = radiusColumnName; this.idColumnName = idColumnName; - this.motherIdColumnName = motherIdColumnName; + this.parentIdColumnName = parentIdColumnName; this.labelColumnName = labelColumnName; this.tagColumnName = tagColumnName; this.xOrigin = xOrigin; @@ -303,9 +303,9 @@ public boolean process() ? null : OriginalIdFeature.getOrRegister( model.getFeatureModel(), graph.vertices().getRefPool() ); - Integer motherIdcol = null; - if ( null != motherIdColumnName && !motherIdColumnName.isEmpty() ) - motherIdcol = headerMap.get( motherIdColumnName ); + Integer parentIdcol = null; + if ( null != parentIdColumnName && !parentIdColumnName.isEmpty() ) + parentIdcol = headerMap.get( parentIdColumnName ); Integer labelcol = null; if ( null != labelColumnName && !labelColumnName.isEmpty() ) @@ -328,7 +328,7 @@ public boolean process() final WriteLock lock = graph.getLock().writeLock(); lock.lock(); final Spot vref = graph.vertexRef(); - final Spot motherVertexRef = graph.vertexRef(); + final Spot parentVertexRef = graph.vertexRef(); final Link edgeRef = graph.edgeRef(); final double[] pos = new double[ 3 ]; startImport(); @@ -359,7 +359,7 @@ public boolean process() { final int id = Integer.parseInt( record[ idcol ].trim() ); originalIdFeature.set( spot, id ); - if ( null != motherIdcol ) + if ( null != parentIdcol ) spotMap.put( id, spot ); if ( null == labelcol ) spot.setLabel( "" + id ); @@ -378,12 +378,12 @@ public boolean process() qualityFeature.set( spot, q ); } - if ( null != motherIdcol ) + if ( null != parentIdcol ) { - final int motherId = Integer.parseInt( record[ motherIdcol ].trim() ); - final Spot mother = spotMap.get( motherId, motherVertexRef ); - if ( mother != null ) - model.getGraph().addEdge( mother, spot, edgeRef ).init(); + final int parentId = Integer.parseInt( record[ parentIdcol ].trim() ); + final Spot parent = spotMap.get( parentId, motherVertexRef ); + if ( parent != null ) + model.getGraph().addEdge( parent, spot, edgeRef ).init(); } if ( null != tagcol ) @@ -406,7 +406,7 @@ public boolean process() { lock.unlock(); graph.releaseRef( vref ); - graph.releaseRef( motherVertexRef ); + graph.releaseRef( parentVertexRef ); graph.releaseRef( edgeRef ); if ( null != tagcol ) model.getTagSetModel().resumeListeners(); @@ -563,7 +563,7 @@ public static class Builder private String idColumnName; - private String motherIdColumnName; + private String parentIdColumnName; private String labelColumnName; @@ -637,9 +637,9 @@ public Builder idColumnName( final String idColumnName ) return this; } - public Builder motherIdColumnName( final String motherIdColumnName ) + public Builder parentIdColumnName( final String parentIdColumnName ) { - this.motherIdColumnName = motherIdColumnName; + this.parentIdColumnName = parentIdColumnName; return this; } @@ -746,7 +746,7 @@ public CSVImporter get() qualityColumnName, radiusColumnName, idColumnName, - motherIdColumnName, + parentIdColumnName, labelColumnName, tagColumnName, xOrigin, diff --git a/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java b/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java index 45de685..6e0c6ee 100644 --- a/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java +++ b/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterPanel.java @@ -75,7 +75,7 @@ public class CSVImporterPanel extends JPanel final JComboBox< String > comboBoxIDCol; - final JComboBox< String > comboBoxMotherIdCol; + final JComboBox< String > comboBoxParentIdCol; final JComboBox< String > comboBoxTagCol; @@ -360,22 +360,22 @@ public CSVImporterPanel() gbc_comboBoxID.gridy = 17; panelControl.add( comboBoxIDCol, gbc_comboBoxID ); - final JLabel lblMotherIdColumn = new JLabel( "Mother ID column:" ); - final GridBagConstraints gbc_lblMotherIdColumn = new GridBagConstraints(); - gbc_lblMotherIdColumn.anchor = GridBagConstraints.EAST; - gbc_lblMotherIdColumn.insets = new Insets( 5, 5, 5, 5 ); - gbc_lblMotherIdColumn.gridx = 0; - gbc_lblMotherIdColumn.gridy = 18; - panelControl.add( lblMotherIdColumn, gbc_lblMotherIdColumn ); - - comboBoxMotherIdCol = new JComboBox<>(); - final GridBagConstraints gbc_comboBoxMotherID = new GridBagConstraints(); - gbc_comboBoxMotherID.insets = new Insets( 5, 5, 5, 0 ); - gbc_comboBoxMotherID.gridwidth = 4; - gbc_comboBoxMotherID.fill = GridBagConstraints.HORIZONTAL; - gbc_comboBoxMotherID.gridx = 1; - gbc_comboBoxMotherID.gridy = 18; - panelControl.add( comboBoxMotherIdCol, gbc_comboBoxMotherID ); + final JLabel lblParentIdColumn = new JLabel( "Parent ID column:" ); + final GridBagConstraints gbc_lblParentIdColumn = new GridBagConstraints(); + gbc_lblParentIdColumn.anchor = GridBagConstraints.EAST; + gbc_lblParentIdColumn.insets = new Insets( 5, 5, 5, 5 ); + gbc_lblParentIdColumn.gridx = 0; + gbc_lblParentIdColumn.gridy = 18; + panelControl.add( lblParentIdColumn, gbc_lblParentIdColumn ); + + comboBoxParentIdCol = new JComboBox<>(); + final GridBagConstraints gbc_comboBoxParentID = new GridBagConstraints(); + gbc_comboBoxParentID.insets = new Insets( 5, 5, 5, 0 ); + gbc_comboBoxParentID.gridwidth = 4; + gbc_comboBoxParentID.fill = GridBagConstraints.HORIZONTAL; + gbc_comboBoxParentID.gridx = 1; + gbc_comboBoxParentID.gridy = 18; + panelControl.add( comboBoxParentIdCol, gbc_comboBoxParentID ); final JLabel lblTagColumn = new JLabel( "Tag column:" ); final GridBagConstraints gbc_lblTagColumn = new GridBagConstraints(); diff --git a/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterUIController.java b/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterUIController.java index f06a9f6..b58a4eb 100644 --- a/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterUIController.java +++ b/src/main/java/org/mastodon/mamut/io/csv/plugin/ui/CSVImporterUIController.java @@ -115,7 +115,7 @@ public void run() .qualityColumnName( ( String ) view.comboBoxQualityCol.getSelectedItem() ) .radiusColumnName( ( String ) view.comboBoxRadiusCol.getSelectedItem() ) .idColumnName( ( String ) view.comboBoxIDCol.getSelectedItem() ) - .motherIdColumnName( ( String ) view.comboBoxMotherIdCol.getSelectedItem() ) + .parentIdColumnName( ( String ) view.comboBoxParentIdCol.getSelectedItem() ) .tagColumnName( ( String ) view.comboBoxTagCol.getSelectedItem() ) .get(); @@ -293,7 +293,7 @@ private boolean readHeaders() view.comboBoxRadiusCol.setModel( new DefaultComboBoxModel<>( nonMandatory ) ); view.comboBoxNameCol.setModel( new DefaultComboBoxModel<>( nonMandatory ) ); view.comboBoxIDCol.setModel( new DefaultComboBoxModel<>( nonMandatory ) ); - view.comboBoxMotherIdCol.setModel( new DefaultComboBoxModel<>( nonMandatory ) ); + view.comboBoxParentIdCol.setModel( new DefaultComboBoxModel<>( nonMandatory ) ); view.comboBoxTagCol.setModel( new DefaultComboBoxModel<>( nonMandatory ) ); int idcol = headers.indexOf( NONE_COLUMN ); @@ -327,7 +327,7 @@ private boolean readHeaders() } view.comboBoxIDCol.setSelectedIndex( idcol ); - view.comboBoxMotherIdCol.setSelectedIndex( motheridcol ); + view.comboBoxParentIdCol.setSelectedIndex( motheridcol ); view.comboBoxTagCol.setSelectedIndex( tagcol ); view.comboBoxQualityCol.setSelectedIndex( qualitycol ); view.comboBoxRadiusCol.setSelectedIndex( radiuscol ); @@ -353,7 +353,7 @@ private void clearComboBoxes() comboBoxes.add( view.comboBoxRadiusCol ); comboBoxes.add( view.comboBoxNameCol ); comboBoxes.add( view.comboBoxIDCol ); - comboBoxes.add( view.comboBoxMotherIdCol ); + comboBoxes.add( view.comboBoxParentIdCol ); comboBoxes.add( view.comboBoxTagCol ); comboBoxes.add( view.comboBoxTrackCol ); for ( final JComboBox< String > cb : comboBoxes ) diff --git a/src/test/java/org/mastodon/mamut/io/csv/CSVImporterTest.java b/src/test/java/org/mastodon/mamut/io/csv/CSVImporterTest.java index 2c227af..c446134 100644 --- a/src/test/java/org/mastodon/mamut/io/csv/CSVImporterTest.java +++ b/src/test/java/org/mastodon/mamut/io/csv/CSVImporterTest.java @@ -94,7 +94,7 @@ public void test() throws IOException, SpimDataException @Test public void testImportWithRadiusTagsLinks() { - final URL urlCSV = CSVImporterTest.class.getResource( "TestCSVImportTagMotherIdRadius.csv" ); + final URL urlCSV = CSVImporterTest.class.getResource( "TestCSVImportTagParentIdRadius.csv" ); assertNotNull( urlCSV ); final Model model = new Model(); @@ -110,7 +110,7 @@ public void testImportWithRadiusTagsLinks() .frameColumnName( "FRAME" ) .idColumnName( "ID" ) .tagColumnName( "TAG" ) - .motherIdColumnName( "MOTHER_ID" ) + .parentIdColumnName( "PARENT_ID" ) .radiusColumnName( "RADIUS" ) .get(); if ( !importer.checkInput() || !importer.process() ) diff --git a/src/test/resources/org/mastodon/mamut/io/csv/TestCSVImportTagMotherIdRadius.csv b/src/test/resources/org/mastodon/mamut/io/csv/TestCSVImportTagParentIdRadius.csv similarity index 93% rename from src/test/resources/org/mastodon/mamut/io/csv/TestCSVImportTagMotherIdRadius.csv rename to src/test/resources/org/mastodon/mamut/io/csv/TestCSVImportTagParentIdRadius.csv index 9e6bed3..2fa20c4 100644 --- a/src/test/resources/org/mastodon/mamut/io/csv/TestCSVImportTagMotherIdRadius.csv +++ b/src/test/resources/org/mastodon/mamut/io/csv/TestCSVImportTagParentIdRadius.csv @@ -1,4 +1,4 @@ -ID;QUALITY;POSITION_X;POSITION_Y;POSITION_Z;FRAME;RADIUS;MEDIAN_INTENSITY;TAG;MOTHER_ID +ID;QUALITY;POSITION_X;POSITION_Y;POSITION_Z;FRAME;RADIUS;MEDIAN_INTENSITY;TAG;PARENT_ID 0; 50.943; 11.000; 11.000; 5.000; 0; 5.73; 51; tag1; -1 1; 206.877; 30.000; 31.000; 6.000; 0; 4.; 119; tag1; -1 2; 130.664; 36.000; 12.000; 7.000; 0; 2; 197; tag2; -1 From b4165ca45cd8d26a65c518c673620f61dc8fe91e Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Mon, 26 Aug 2024 17:31:18 +0200 Subject: [PATCH 12/12] Create links in another parsing through the file step * The reason for this change is that the initial assumption that spots would be sorted by the time frame did not hold true for some test data sets * In a test data set, it happened that the child spot was in the file before the parent spot so that the parent spot could not be found --- .../mastodon/mamut/io/csv/CSVImporter.java | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java b/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java index 916f265..04e41ac 100644 --- a/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java +++ b/src/main/java/org/mastodon/mamut/io/csv/CSVImporter.java @@ -378,14 +378,6 @@ public boolean process() qualityFeature.set( spot, q ); } - if ( null != parentIdcol ) - { - final int parentId = Integer.parseInt( record[ parentIdcol ].trim() ); - final Spot parent = spotMap.get( parentId, motherVertexRef ); - if ( parent != null ) - model.getGraph().addEdge( parent, spot, edgeRef ).init(); - } - if ( null != tagcol ) { String label = record[ tagcol ].trim(); @@ -401,6 +393,8 @@ public boolean process() continue; } } + if ( null != parentIdcol ) + parseLinksFromFile( parser, spotMap, idcol, vref, parentIdcol, parentVertexRef, edgeRef ); } finally { @@ -433,6 +427,33 @@ public boolean process() return true; } + private void parseLinksFromFile( final CSVParser parser, final IntRefMap< Spot > spotMap, final int idCol, final Spot spotRef, + final int parentIdcol, final Spot parentSpotRef, final Link edgeRef ) + { + try (final CSVReader readerTags = new CSVReaderBuilder( new FileReader( filePath ) ) + .withCSVParser( parser ) + .build()) + { + Iterator< String[] > csvIterator = readerTags.iterator(); + csvIterator.next(); + while ( csvIterator.hasNext() ) + { + final String[] line = csvIterator.next(); + final int spotId = Integer.parseInt( line[ idCol ].trim() ); + final Spot spot = spotMap.get( spotId, spotRef ); + final int parentId = Integer.parseInt( line[ parentIdcol ].trim() ); + final Spot parent = spotMap.get( parentId, parentSpotRef ); + if ( parent != null && spot != null ) + model.getGraph().addEdge( parent, spot, edgeRef ).init(); + } + } + catch ( final IOException e ) + { + errorMessage = "Error reading file " + filePath; + e.printStackTrace(); + } + } + private TagSetStructure.TagSet parseTagsFromFile( final CSVParser parser, int labelcol ) { try (final CSVReader readerTags = new CSVReaderBuilder( new FileReader( filePath ) )