Skip to content

Commit

Permalink
Add t-SNE computation for spot and branch features
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanhahmann committed Nov 14, 2024
1 parent 1b0101a commit 0375d7c
Show file tree
Hide file tree
Showing 9 changed files with 657 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*-
* #%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.feature.branch.dimensionalityreduction.tsne;

import java.util.List;

import org.mastodon.feature.Feature;
import org.mastodon.feature.FeatureProjectionKey;
import org.mastodon.feature.FeatureProjectionSpec;
import org.mastodon.feature.FeatureSpec;
import org.mastodon.feature.Multiplicity;
import org.mastodon.mamut.feature.dimensionalityreduction.tsne.feature.AbstractTSneFeature;
import org.mastodon.mamut.model.branch.BranchSpot;
import org.mastodon.properties.DoublePropertyMap;
import org.scijava.plugin.Plugin;

/**
* Represents a t-SNE feature for BranchSpots in the Mastodon project.
* <br>
* This feature is used to store the t-SNE outputs for BranchSpots.
* <br>
* The t-SNE outputs are stored in a list of {@link DoublePropertyMap}s. The size of the list is equal to the number of dimensions of the t-SNE output.
*/
public class BranchTSneFeature extends AbstractTSneFeature< BranchSpot >
{
public static final String KEY = "Branch t-SNE outputs";

private final BranchSpotTSneFeatureSpec adaptedSpec;

public static final BranchSpotTSneFeatureSpec GENERIC_SPEC = new BranchSpotTSneFeatureSpec();

public BranchTSneFeature( final List< DoublePropertyMap< BranchSpot > > outputMaps )
{
super( outputMaps );
FeatureProjectionSpec[] projectionSpecs =
projectionMap.keySet().stream().map( FeatureProjectionKey::getSpec ).toArray( FeatureProjectionSpec[]::new );
this.adaptedSpec = new BranchSpotTSneFeatureSpec( projectionSpecs );
}

@Plugin( type = FeatureSpec.class )
public static class BranchSpotTSneFeatureSpec extends FeatureSpec< BranchTSneFeature, BranchSpot >
{
public BranchSpotTSneFeatureSpec()
{
super( KEY, HELP_STRING, BranchTSneFeature.class, BranchSpot.class, Multiplicity.SINGLE );
}

public BranchSpotTSneFeatureSpec( final FeatureProjectionSpec... projectionSpecs )
{
super( KEY, HELP_STRING, BranchTSneFeature.class, BranchSpot.class, Multiplicity.SINGLE, projectionSpecs );
}
}

@Override
public FeatureSpec< ? extends Feature< BranchSpot >, BranchSpot > getSpec()
{
return adaptedSpec;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*-
* #%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.feature.branch.dimensionalityreduction.tsne;

import java.util.Collection;
import java.util.List;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.mastodon.RefPool;
import org.mastodon.mamut.feature.dimensionalityreduction.tsne.feature.AbstractTSneFeature;
import org.mastodon.mamut.feature.dimensionalityreduction.tsne.feature.AbstractTSneFeatureComputer;
import org.mastodon.mamut.model.Model;
import org.mastodon.mamut.model.branch.BranchLink;
import org.mastodon.mamut.model.branch.BranchSpot;
import org.mastodon.mamut.model.branch.ModelBranchGraph;
import org.mastodon.properties.DoublePropertyMap;
import org.scijava.Context;

public class BranchTSneFeatureComputer extends AbstractTSneFeatureComputer< BranchSpot, BranchLink, ModelBranchGraph >
{

public BranchTSneFeatureComputer( final Model model, final Context context )
{
super( model, context );
}

@Override
protected AbstractTSneFeature< BranchSpot > createFeatureInstance( final List< DoublePropertyMap< BranchSpot > > umapOutputMaps )
{
return new BranchTSneFeature( umapOutputMaps );
}

@Override
protected RefPool< BranchSpot > getRefPool()
{
return model.getBranchGraph().vertices().getRefPool();
}

@Override
protected ReentrantReadWriteLock getLock( final ModelBranchGraph branchGraph )
{
return branchGraph.getLock();
}

@Override
protected Collection< BranchSpot > getVertices()
{
return model.getBranchGraph().vertices();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*-
* #%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.feature.branch.dimensionalityreduction.tsne;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import org.mastodon.feature.FeatureSpec;
import org.mastodon.feature.io.FeatureSerializer;
import org.mastodon.io.FileIdToObjectMap;
import org.mastodon.io.ObjectToFileIdMap;
import org.mastodon.mamut.feature.branch.BranchFeatureSerializer;
import org.mastodon.mamut.feature.branch.dimensionalityreduction.BranchOutputSerializerTools;
import org.mastodon.mamut.model.ModelGraph;
import org.mastodon.mamut.model.Spot;
import org.mastodon.mamut.model.branch.BranchSpot;
import org.mastodon.mamut.model.branch.ModelBranchGraph;
import org.scijava.plugin.Plugin;

/**
* De-/serializes {@link BranchTSneFeature}
*/
@Plugin( type = FeatureSerializer.class )
public class BranchTSneFeatureSerializer implements BranchFeatureSerializer< BranchTSneFeature, BranchSpot, Spot >
{
@Override
public FeatureSpec< BranchTSneFeature, BranchSpot > getFeatureSpec()
{
return BranchTSneFeature.GENERIC_SPEC;
}

@Override
public void serialize( final BranchTSneFeature feature, final ObjectToFileIdMap< Spot > idmap, final ObjectOutputStream oos,
final ModelBranchGraph branchGraph, final ModelGraph graph ) throws IOException
{
BranchOutputSerializerTools.serialize( feature, idmap, oos, branchGraph, graph );
}

@Override
public BranchTSneFeature deserialize( final FileIdToObjectMap< Spot > idmap, final ObjectInputStream ois,
final ModelBranchGraph branchGraph, final ModelGraph graph ) throws ClassNotFoundException, IOException
{
return BranchOutputSerializerTools.deserialize( idmap, ois, branchGraph, graph, BranchTSneFeature::new );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,14 @@
import org.mastodon.graph.Edge;
import org.mastodon.graph.ReadOnlyGraph;
import org.mastodon.graph.Vertex;
import org.mastodon.mamut.feature.branch.dimensionalityreduction.tsne.BranchTSneFeatureComputer;
import org.mastodon.mamut.feature.branch.dimensionalityreduction.umap.BranchUmapFeatureComputer;
import org.mastodon.mamut.feature.dimensionalityreduction.tsne.TSneSettings;
import org.mastodon.mamut.feature.dimensionalityreduction.tsne.feature.AbstractTSneFeatureComputer;
import org.mastodon.mamut.feature.dimensionalityreduction.umap.UmapSettings;
import org.mastodon.mamut.feature.dimensionalityreduction.umap.feature.AbstractUmapFeatureComputer;
import org.mastodon.mamut.feature.dimensionalityreduction.util.InputDimension;
import org.mastodon.mamut.feature.spot.dimensionalityreduction.tsne.SpotTSneFeatureComputer;
import org.mastodon.mamut.feature.spot.dimensionalityreduction.umap.SpotUmapFeatureComputer;
import org.mastodon.mamut.model.Link;
import org.mastodon.mamut.model.Model;
Expand Down Expand Up @@ -177,10 +180,23 @@ public void setAlgorithm( final DimensionalityReductionAlgorithm algorithm )
throw new IllegalArgumentException( "Number of output dimensions (" + commonSettings.getNumberOfOutputDimensions()
+ ") must be smaller than the number of input features (" + inputDimensions.size() + ")." );
G graph = getGraph( isModelGraph );
AbstractUmapFeatureComputer< V, E, G > umapFeatureComputer =
isModelGraph ? Cast.unchecked( new SpotUmapFeatureComputer( model, context ) )
: Cast.unchecked( new BranchUmapFeatureComputer( model, context ) );
umapFeatureComputer.computeFeature( commonSettings, umapSettings, inputDimensions, graph );
switch ( algorithm )
{
case UMAP:
AbstractUmapFeatureComputer< V, E, G > umapFeatureComputer =
isModelGraph ? Cast.unchecked( new SpotUmapFeatureComputer( model, context ) )
: Cast.unchecked( new BranchUmapFeatureComputer( model, context ) );
umapFeatureComputer.computeFeature( commonSettings, umapSettings, inputDimensions, graph );
break;
case TSNE:
AbstractTSneFeatureComputer< V, E, G > tSneFeatureComputer =
isModelGraph ? Cast.unchecked( new SpotTSneFeatureComputer( model, context ) )
: Cast.unchecked( new BranchTSneFeatureComputer( model, context ) );
tSneFeatureComputer.computeFeature( commonSettings, tSneSettings, inputDimensions, graph );
break;
default:
throw new IllegalArgumentException( "Unknown algorithm: " + algorithm );
}
}

private < V extends Vertex< E >, E extends Edge< V >, G extends ReadOnlyGraph< V, ? > > G getGraph( boolean isSpotGraph )
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*-
* #%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.feature.dimensionalityreduction.tsne.feature;

import java.util.List;

import org.mastodon.graph.Vertex;
import org.mastodon.mamut.feature.dimensionalityreduction.AbstractOutputFeature;
import org.mastodon.properties.DoublePropertyMap;

/**
* This generic feature is used to store the t-SNE outputs.
* <br>
* The t-SNE outputs are stored in a list of {@link DoublePropertyMap}s. The size of the list is equal to the number of dimensions of the t-SNE output.
*/
public abstract class AbstractTSneFeature< V extends Vertex< ? > > extends AbstractOutputFeature< V >
{
private static final String PROJECTION_NAME_TEMPLATE = "tSNE%d";

protected static final String HELP_STRING =
"Computes the t-SNE according to the selected input dimensions, number of target dimensions, the perplexity value and maximum number of iterations.";

protected AbstractTSneFeature( final List< DoublePropertyMap< V > > umapOutputMaps )
{
super( umapOutputMaps );
}

@Override
protected String getProjectionNameTemplate()
{
return PROJECTION_NAME_TEMPLATE;
}
}
Loading

0 comments on commit 0375d7c

Please sign in to comment.