Skip to content

Commit

Permalink
Introduce new class ExternalProjects
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanhahmann committed Jul 22, 2024
1 parent ee9476a commit 9a1e8d3
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 106 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@
*/
package org.mastodon.mamut.classification;

import mpicbg.spim.data.SpimDataException;
import org.apache.commons.lang3.tuple.Pair;
import org.mastodon.collection.RefSet;
import org.mastodon.graph.algorithm.traversal.DepthFirstIterator;
import org.mastodon.mamut.ProjectModel;
import org.mastodon.mamut.classification.config.ClusteringMethod;
import org.mastodon.mamut.classification.config.SimilarityMeasure;
import org.mastodon.mamut.classification.multiproject.ExternalProjects;
import org.mastodon.mamut.classification.util.Classification;
import org.mastodon.mamut.classification.config.CropCriteria;
import org.mastodon.mamut.classification.ui.DendrogramView;
Expand All @@ -60,12 +60,9 @@
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
Expand All @@ -90,8 +87,6 @@ public class ClassifyLineagesController

private final PrefService prefs;

private final MastodonProjectService projectService;

private SimilarityMeasure similarityMeasure = SimilarityMeasure.NORMALIZED_ZHANG_DIFFERENCE;

private ClusteringMethod clusteringMethod = ClusteringMethod.AVERAGE_LINKAGE;
Expand All @@ -106,12 +101,10 @@ public class ClassifyLineagesController

private int minCellDivisions;

private final Map< File, ProjectSession > externalProjects;

private final Map< File, String > failingExternalProjects;

private boolean showDendrogram;

private final ExternalProjects externalProjects;

private boolean addTagSetToExternalProjects;

private boolean running = false;
Expand All @@ -137,9 +130,7 @@ public ClassifyLineagesController( final ProjectModel referenceProjectModel, fin
this.referenceProjectModel = referenceProjectModel;
this.referenceModel = referenceProjectModel.getModel();
this.prefs = prefs;
this.projectService = projectService;
this.externalProjects = new HashMap<>();
this.failingExternalProjects = new HashMap<>();
this.externalProjects = new ExternalProjects( projectService );
}

/**
Expand Down Expand Up @@ -197,10 +188,10 @@ private Classification< BranchSpotTree > classifyUsingExternalProjects( final Li
for ( int i = 1; i < roots.size(); i++ )
{
averageClassification = classifyLineageTrees( roots.get( i ), distances );
for ( ProjectSession projectSession : externalProjects.values() )
for ( Map.Entry< File, ProjectSession > externalProject : externalProjects.getProjects().entrySet() )
{
ProjectModel projectModel = projectSession.getProjectModel();
File file = projectSession.getFile();
ProjectModel projectModel = externalProject.getValue().getProjectModel();
File file = externalProject.getKey();
branchSpotProvider = branchSpotTree -> projectModel.getModel().getBranchGraph().vertices().stream()
.filter( ( branchSpot -> branchSpot.getFirstLabel().equals( branchSpotTree.getName() ) ) )
.findFirst().orElse( null );
Expand Down Expand Up @@ -233,9 +224,9 @@ private Pair< List< List< BranchSpotTree > >, double[][] > getRootsAndDistanceMa

keepCommonRootsAndSort( roots, commonRootNames );
treeMatrix.add( roots );
for ( ProjectSession projectSession : externalProjects.values() )
for ( ProjectModel projectModel : externalProjects.getProjectModels() )
{
List< BranchSpotTree > externalRoots = getRoots( projectSession.getProjectModel() );
List< BranchSpotTree > externalRoots = getRoots( projectModel );
keepCommonRootsAndSort( externalRoots, commonRootNames );
treeMatrix.add( externalRoots );
}
Expand All @@ -245,9 +236,9 @@ private Pair< List< List< BranchSpotTree > >, double[][] > getRootsAndDistanceMa
private List< String > findCommonRootNames()
{
Set< String > commonRootNames = extractRootNamesFromProjectModel( referenceProjectModel );
for ( ProjectSession projectSession : externalProjects.values() )
for ( ProjectModel projectModel : externalProjects.getProjectModels() )
{
Set< String > rootNames = extractRootNamesFromProjectModel( projectSession.getProjectModel() );
Set< String > rootNames = extractRootNamesFromProjectModel( projectModel );
commonRootNames.retainAll( rootNames );
}
List< String > commonRootNamesList = new ArrayList<>( commonRootNames );
Expand Down Expand Up @@ -430,68 +421,7 @@ public void setShowDendrogram( final boolean showDendrogram )
public void setExternalProjects( final File[] projects, final boolean addTagSetToExternalProjects )
{
this.addTagSetToExternalProjects = addTagSetToExternalProjects;
List< File > projectsList = projects == null ? Collections.emptyList() : Arrays.asList( projects );
removeProjects( projectsList );
cleanUpFailingProjects( projectsList );
addProjects( projects );
}

/**
* Remove files from the externalProjects map that are not in the projects list
*/
private void removeProjects( final List< File > projectsList )
{
Iterator< Map.Entry< File, ProjectSession > > iterator = externalProjects.entrySet().iterator();
while ( iterator.hasNext() )
{
Map.Entry< File, ProjectSession > entry = iterator.next();
File file = entry.getKey();
if ( !projectsList.contains( file ) )
{
ProjectSession projectSession = entry.getValue();
projectSession.close();
iterator.remove();
}
}
}

/**
* Remove files from the failingExternalProjects map that are not in the projects list
*/
private void cleanUpFailingProjects( final List< File > projectsList )
{
for ( Map.Entry< File, String > entry : failingExternalProjects.entrySet() )
{
File file = entry.getKey();
if ( !projectsList.contains( file ) )
failingExternalProjects.remove( file );
}
}

/**
* Add files from projects to the map if they are not already present
*/
private void addProjects( final File[] projects )
{
if ( projects == null )
return;
for ( File file : projects )
{
if ( !externalProjects.containsKey( file ) )
{
try
{
externalProjects.put( file, projectService.createSession( file ) );
failingExternalProjects.remove( file );
}
catch ( SpimDataException | IOException | RuntimeException e )
{
failingExternalProjects.put( file,
"Could not read project from file " + file.getAbsolutePath() + ".<br>Error: " + e.getMessage() );
logger.warn( "Could not read project from file {}. Error: {}", file.getAbsolutePath(), e.getMessage() );
}
}
}
externalProjects.setProjects( projects );
}

public List< String > getFeedback()
Expand All @@ -514,7 +444,7 @@ public List< String > getFeedback()
}
if ( cropCriterion.equals( CropCriteria.NUMBER_OF_SPOTS ) )
feedback.addAll( checkNumberOfSpots() );
feedback.addAll( failingExternalProjects.values() );
feedback.addAll( externalProjects.getFailingProjectMessages() );
return feedback;
}

Expand Down Expand Up @@ -544,8 +474,7 @@ private List< String > checkNumberOfSpots()
{
List< String > feedback = new ArrayList<>();
Set< ProjectModel > allModels = new HashSet<>( Collections.singletonList( referenceProjectModel ) );
for ( ProjectSession projectSession : externalProjects.values() )
allModels.add( projectSession.getProjectModel() );
allModels.addAll( externalProjects.getProjectModels() );
for ( ProjectModel projectModel : allModels )
{
Model model = projectModel.getModel();
Expand Down Expand Up @@ -576,7 +505,6 @@ private List< String > checkNumberOfSpots()

public void close()
{
for ( ProjectSession projectSession : externalProjects.values() )
projectSession.close();
externalProjects.close();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package org.mastodon.mamut.classification.multiproject;

import mpicbg.spim.data.SpimDataException;
import org.mastodon.mamut.ProjectModel;
import org.mastodon.mamut.util.MastodonProjectService;
import org.mastodon.mamut.util.ProjectSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* A collection of external projects.
* <br>
* This class manages a collection of external projects. It holds a mapping of project files to project sessions and a mapping of projects that failed to be loaded and the reason why they failed to load.
*/
public class ExternalProjects implements AutoCloseable
{
private static final Logger logger = LoggerFactory.getLogger( MethodHandles.lookup().lookupClass() );

private final MastodonProjectService projectService;

private final Map< File, ProjectSession > projectSessions;

private final Map< File, String > failingProjects;

public ExternalProjects( final MastodonProjectService projectService )
{
this.projectService = projectService;
this.projectSessions = new HashMap<>();
this.failingProjects = new HashMap<>();
}

/**
* Gets all project models of the external projects
* @return the project models
*/
public Collection< ProjectModel > getProjectModels()
{
return projectSessions.values().stream().map( ProjectSession::getProjectModel ).collect( Collectors.toList() );
}

/**
* Gets a mapping of external project files to their project sessions
* @return the mapping
*/
public Map< File, ProjectSession > getProjects()
{
return projectSessions;
}

/**
* Get the number of external projects
* @return the number of external projects
*/
public int size()
{
return projectSessions.size();
}

/**
* Check if the external projects is empty
* @return {@code true} if the external projects is empty, {@code false} otherwise
*/
public boolean isEmpty()
{
return projectSessions.isEmpty();
}

/**
* Get a Collection failing projects and the reason why they failed to load.
* @return the failing projects
*/
public Collection< String > getFailingProjectMessages()
{
return failingProjects.values();
}

/**
* Set the external projects
* @param projects the external projects
*/
public void setProjects( final File[] projects )
{
List< File > projectsList = projects == null ? Collections.emptyList() : Arrays.asList( projects );
removeProjects( projectsList );
cleanUpFailingProjects( projectsList );
addProjects( projects );
logger.debug( "Set {} projects. Active project sessions: {}.", projectsList.size(), projectService.activeSessions() );
}

/**
* Remove files from the externalProjects map that are not in the projects list
*/
private void removeProjects( final List< File > projectsList )
{
Iterator< Map.Entry< File, ProjectSession > > iterator = projectSessions.entrySet().iterator();
while ( iterator.hasNext() )
{
Map.Entry< File, ProjectSession > entry = iterator.next();
File file = entry.getKey();
if ( !projectsList.contains( file ) )
{
ProjectSession projectSession = entry.getValue();
projectSession.close();
iterator.remove();
}
}
}

/**
* Remove files from the failingExternalProjects map that are not in the projects list
*/
private void cleanUpFailingProjects( final List< File > projectsList )
{
for ( Map.Entry< File, String > entry : failingProjects.entrySet() )
{
File file = entry.getKey();
if ( !projectsList.contains( file ) )
failingProjects.remove( file );
}
}

/**
* Add files from projects to the map if they are not already present
*/
private void addProjects( final File[] files )
{
if ( files == null )
return;
for ( File file : files )
{
if ( !projectSessions.containsKey( file ) )
{
try
{
projectSessions.put( file, projectService.createSession( file ) );
failingProjects.remove( file );
}
catch ( SpimDataException | IOException | RuntimeException e )
{
failingProjects.put( file,
"Could not read project from file " + file.getAbsolutePath() + ".<br>Error: " + e.getMessage() );
logger.warn( "Could not read project from file {}. Error: {}", file.getAbsolutePath(), e.getMessage() );
}
}
}
}

@Override
public void close()
{
for ( ProjectSession projectSession : projectSessions.values() )
projectSession.close();
logger.debug( "Remaining active project sessions: {}.", projectService.activeSessions() );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public ProjectSession createSession( final File file ) throws SpimDataException,
if ( projectModels.containsKey( file ) )
{
ProjectModel projectModel = projectModels.get( file );
ProjectSession projectSession = new ProjectSession( file, projectModel, this );
ProjectSession projectSession = new ProjectSession( projectModel, this );
sessions.get( projectModel ).add( projectSession );
return projectSession;
}
Expand All @@ -78,7 +78,7 @@ public ProjectSession createSession( final File file ) throws SpimDataException,
ProjectModel projectModel =
ProjectLoader.open( file.getAbsolutePath(), getContext(), false, true );
logger.debug( "Loaded project from file: {} in {} ms", file.getAbsolutePath(), System.currentTimeMillis() - start );
ProjectSession projectSession = new ProjectSession( file, projectModel, this );
ProjectSession projectSession = new ProjectSession( projectModel, this );
projectModels.put( file, projectModel );
List< ProjectSession > projectSessionList = new ArrayList<>();
projectSessionList.add( projectSession );
Expand Down
Loading

0 comments on commit 9a1e8d3

Please sign in to comment.