package gdsc.smlm.ij.settings;
import gdsc.core.clustering.optics.SampleMode;
/*-----------------------------------------------------------------------------
* GDSC SMLM Software
*
* Copyright (C) 2016 Alex Herbert
* Genome Damage and Stability Centre
* University of Sussex, UK
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*---------------------------------------------------------------------------*/
/**
* Contain the settings for the clustering algorithm
*
* @author Alex Herbert
*/
public class OPTICSSettings implements Cloneable
{
/**
* Options for displaying the clustering image
*/
public enum ImageMode
{
//@formatter:off
CLUSTER_ID {
@Override
public String getName() { return "Cluster Id"; };
@Override
public float getValue(float value, int clusterId, int order) { return clusterId; }
@Override
public boolean isMapped() { return true; }
@Override
public boolean isRequiresClusters() { return true; }
},
CLUSTER_DEPTH {
@Override
public String getName() { return "Cluster Depth"; };
@Override
public float getValue(float value, int clusterId, int order) { return clusterId; }
@Override
public boolean isMapped() { return true; }
@Override
public boolean isRequiresClusters() { return true; }
},
CLUSTER_ORDER {
@Override
public String getName() { return "Cluster Order"; };
@Override
public float getValue(float value, int clusterId, int order) { return order; }
@Override
public boolean isMapped() { return true; }
@Override
public boolean isRequiresClusters() { return true; }
},
VALUE {
@Override
public String getName() { return "Value"; };
@Override
public boolean canBeWeighted() { return true; }
@Override
public float getValue(float value, int clusterId, int order) { return value; }
},
COUNT {
@Override
public String getName() { return "Count"; };
@Override
public boolean canBeWeighted() { return true; }
@Override
public float getValue(float value, int clusterId, int order) { return 1f; }
},
LOOP {
@Override
public String getName() { return "Local Outlier Probability (LoOP)"; };
@Override
public float getValue(float value, int clusterId, int order) { return order; }
@Override
public boolean isMapped() { return true; }
},
NONE {
@Override
public String getName() { return "None"; };
@Override
public float getValue(float value, int clusterId, int order) { return 0; }
};
//@formatter:on
/**
* Gets the name.
*
* @return the name
*/
abstract public String getName();
/**
* Return the value to draw.
*
* @param value
* The value of the cluster point
* @param clusterId
* The cluster Id of the cluster point
* @param order
* the order of the cluster point
* @return The value
*/
abstract public float getValue(float value, int clusterId, int order);
/**
* Return true if the value can be weighted amongst neighbour pixels int the output image
*
* @return true, if successful
*/
public boolean canBeWeighted()
{
return false;
}
/**
* Return true if the value should be mapped to the 1-255 range for the output image
*
* @return true, if is mapped
*/
public boolean isMapped()
{
return false;
}
@Override
public String toString()
{
return getName();
}
/**
* Checks if the mode requires clusters.
*
* @return true, if requires clusters
*/
public boolean isRequiresClusters()
{
return false;
}
}
/**
* Options for plotting the OPTICS algorithm
*/
public enum OPTICSMode
{
//@formatter:off
FAST_OPTICS {
@Override
public String getName() { return "FastOPTICS"; };
},
OPTICS {
@Override
public String getName() { return "OPTICS"; };
};
//@formatter:on
/**
* Gets the name.
*
* @return the name
*/
abstract public String getName();
@Override
public String toString()
{
return getName();
}
}
/**
* Options for plotting the OPTICS results
*/
public enum ClusteringMode
{
//@formatter:off
XI {
@Override
public String getName() { return "Xi"; };
},
DBSCAN {
@Override
public String getName() { return "pseudo-DBSCAN"; };
};
//@formatter:on
/**
* Gets the name.
*
* @return the name
*/
abstract public String getName();
@Override
public String toString()
{
return getName();
}
}
/**
* Options for plotting the OPTICS results
*/
public enum PlotMode
{
//@formatter:off
ON {
@Override
public String getName() { return "On"; };
},
HIGHLIGHTED {
@Override
public String getName() { return "Highlighted"; };
@Override
public boolean isHighlightProfile() { return true; }
},
COLOURED_BY_ID {
@Override
public String getName() { return "Coloured by Id"; };
@Override
public boolean isColourProfileById() { return true; }
},
COLOURED_BY_DEPTH {
@Override
public String getName() { return "Coloured by depth"; };
@Override
public boolean isColourProfileByDepth() { return true; }
},
COLOURED_BY_ORDER {
@Override
public String getName() { return "Coloured by order"; };
@Override
public boolean isColourProfileByOrder() { return true; }
},
WITH_CLUSTERS {
@Override
public String getName() { return "With clusters"; };
@Override
public boolean isDrawClusters() { return true; }
},
HIGHLIGHTED_WITH_CLUSTERS {
@Override
public String getName() { return "Highlighted with clusters"; };
@Override
public boolean isHighlightProfile() { return true; }
@Override
public boolean isDrawClusters() { return true; }
},
COLOURED_BY_ID_WITH_CLUSTERS {
@Override
public String getName() { return "Coloured by Id with clusters"; };
@Override
public boolean isColourProfileById() { return true; }
@Override
public boolean isDrawClusters() { return true; }
},
COLOURED_BY_DEPTH_WITH_CLUSTERS {
@Override
public String getName() { return "Coloured by depth with clusters"; };
@Override
public boolean isColourProfileByDepth() { return true; }
@Override
public boolean isDrawClusters() { return true; }
},
COLOURED_BY_ORDER_WITH_CLUSTERS {
@Override
public String getName() { return "Coloured by order with clusters"; };
@Override
public boolean isColourProfileByOrder() { return true; }
@Override
public boolean isDrawClusters() { return true; }
},
OFF {
@Override
public String getName() { return "Off"; };
};
//@formatter:on
/**
* Gets the name.
*
* @return the name
*/
abstract public String getName();
/**
* @return True if the profile should be highlighted for top-cluster regions
*/
public boolean isHighlightProfile()
{
return false;
}
/**
* @return True if the profile should be coloured using the OPTICS results
*/
public boolean isColourProfile()
{
return isColourProfileByDepth() || isColourProfileById() || isColourProfileByOrder();
}
/**
* @return True if the profile should be coloured using the cluster Id
*/
public boolean isColourProfileById()
{
return false;
}
/**
* @return True if the profile should be coloured using the cluster depth
*/
public boolean isColourProfileByDepth()
{
return false;
}
/**
* @return True if the profile should be coloured using the cluster order
*/
public boolean isColourProfileByOrder()
{
return false;
}
/**
* @return If clusters should be drawn on the plot
*/
public boolean isDrawClusters()
{
return false;
}
/**
* @return True if the clusters are needed
*/
public boolean requiresClusters()
{
return isDrawClusters() || isHighlightProfile() || isColourProfile();
}
@Override
public String toString()
{
return getName();
}
}
/**
* Options for plotting the OPTICS results
*/
public enum OutlineMode
{
//@formatter:off
COLOURED_BY_CLUSTER {
@Override
public String getName() { return "Coloured by cluster"; };
},
COLOURED_BY_DEPTH {
@Override
public String getName() { return "Coloured by depth"; };
@Override
public boolean isColourByDepth() { return true; }
},
OFF {
@Override
public String getName() { return "Off"; };
@Override
public boolean isOutline() { return false; }
};
//@formatter:on
/**
* Gets the name.
*
* @return the name
*/
abstract public String getName();
/**
* @return True if the outline should be displayed
*/
public boolean isOutline()
{
return true;
}
/**
* @return True if the outline should be coloured using the cluster depth
*/
public boolean isColourByDepth()
{
return false;
}
@Override
public String toString()
{
return getName();
}
}
/**
* Options for plotting the OPTICS results
*/
public enum SpanningTreeMode
{
//@formatter:off
COLOURED_BY_CLUSTER {
@Override
public String getName() { return "Coloured by cluster"; };
},
COLOURED_BY_DEPTH {
@Override
public String getName() { return "Coloured by depth"; };
},
COLOURED_BY_ORDER {
@Override
public String getName() { return "Coloured by order"; };
},
COLOURED_BY_LOOP {
@Override
public String getName() { return "Coloured by LoOP"; };
},
OFF {
@Override
public String getName() { return "Off"; };
@Override
public boolean isSpanningTree() { return false; }
};
//@formatter:on
/**
* Gets the name.
*
* @return the name
*/
abstract public String getName();
/**
* @return True if the spanning tree should be displayed
*/
public boolean isSpanningTree()
{
return true;
}
@Override
public String toString()
{
return getName();
}
}
// Affect creating the OPTICS manager
/**
* The input results dataset to use
*/
public String inputOption = "";
// Affect running OPTICS
/**
* The OPTICS algorithm to use.
*/
private OPTICSMode opticsMode = OPTICSMode.FAST_OPTICS;
/** The number of splits to compute (if below 1 it will be auto-computed using the size of the data) */
public int numberOfSplitSets = 0;
/**
* Set to true to use random vectors for the projections. The default is to uniformly create vectors on the
* semi-circle interval.
*/
public boolean useRandomVectors = false;
/**
* Set to true to save all sets that are approximately min split size. The default is to only save sets smaller than
* min split size.
*/
public boolean saveApproximateSets = false;
/** The sample mode. */
private SampleMode sampleMode = SampleMode.RANDOM;
/**
* The generating distance, i.e. the distance to search for neighbours of a point. Set to zero to auto-calibrate
* using the expected density of uniformly spread random points.
*/
public double generatingDistance = 0;
/**
* The minimum number of neighbours to define a core point.
* <p>
* Note that the minimum cardinality (i.e. count of the number of neighbours) in the paper discussing Generalised
* DBSCAN is recommended to be 2 x dimensions, so 4 for a 2D dataset.
*/
public int minPoints = 4;
// OPTICS clustering
/**
* The clustering mode to use on the OPTICS results.
*/
private ClusteringMode clusteringMode = ClusteringMode.XI;
// Affect running OPTICS Xi
/**
* The steepness parameter for the OPTICS hierarchical clustering algorithm using the reachability profile.
*/
public double xi = 0.03;
/**
* Set to true to only show the top-level clusters, i.e. child clusters will be merged into their parents.
*/
public boolean topLevel = false;
/**
* The upper limit for reachability. The first and last reachable points within a cluster must have a
* reachability equal or below the upper limit. This prevents creating clusters with points associated above the
* upper limit.
*/
public double upperLimit = 0;
/**
* The lower limit for reachability. The first and last reachable points within a cluster must have a reachability
* equal or above the lower limit. This prevents creating clusters that are only associated below the lower limit.
*/
public double lowerLimit = 0;
// Affect DBSCAN clustering
/**
* The number of samples to take for the k-distance plot. This should be 1-10% of the data.
*/
public int samples = 100;
/**
* The fraction of the data to sample for the k-distance plot. Recommended to be 1-10%.
*/
public double sampleFraction = 0.05;
/**
* The fraction of noise in the k-distance plot. The clustering distance is set as the next distance after noise has
* been ignored.
*/
public double fractionNoise = 0.05;
/**
* The clustering distance for DBSCAN.
*/
public double clusteringDistance = 0;
/**
* Set to true to only include core point in clusters. Note: Non-core points can be assigned arbitrarily to clusters
* if they are on the border of two clusters due to the arbitrary processing order of input points.
*/
public boolean core = false;
// Affect display of results
/**
* The magnification scale of the output image
*/
public double imageScale = 2;
/**
* The output image mode
*/
private ImageMode imageMode = ImageMode.VALUE;
/**
* Set to true to weight the image data over nearest neighbour pixels
*/
public boolean weighted = true;
/**
* Set to true to equalise the image histogram (allowing viewing high dynamic range data)
*/
public boolean equalised = true;
/**
* The plot mode for the reachability distance profile
*/
private PlotMode plotMode = PlotMode.COLOURED_BY_DEPTH_WITH_CLUSTERS;
/**
* The outline mode for the reachability distance profile
*/
private OutlineMode outlineMode = OutlineMode.COLOURED_BY_CLUSTER;
/**
* The spanningTree mode for the reachability distance profile
*/
private SpanningTreeMode spanningTreeMode = SpanningTreeMode.OFF;
/**
* The number of standard deviations to consider for density computation using Local Outlier Probability (LoOP).
* Note that scores are monotonic with respect to Lambda so this value just effects the local contrast of outlier
* scores, not the actual ranking of outliers.
*/
public double lambda = 3;
public OPTICSMode getOPTICSMode()
{
if (opticsMode == null)
setOPTICSMode(0);
return opticsMode;
}
public int getOPTICSModeOridinal()
{
if (opticsMode == null)
return 0;
return opticsMode.ordinal();
}
public void setOPTICSMode(OPTICSMode mode)
{
opticsMode = mode;
}
public void setOPTICSMode(int mode)
{
OPTICSMode[] values = OPTICSMode.values();
if (mode < 0 || mode >= values.length)
mode = 0;
this.opticsMode = values[mode];
}
public ImageMode getImageMode()
{
if (imageMode == null)
setImageMode(0);
return imageMode;
}
public int getImageModeOridinal()
{
if (imageMode == null)
return 0;
return imageMode.ordinal();
}
public void setImageMode(ImageMode mode)
{
imageMode = mode;
}
public void setImageMode(int mode)
{
ImageMode[] values = ImageMode.values();
if (mode < 0 || mode >= values.length)
mode = 0;
this.imageMode = values[mode];
}
public SampleMode getSampleMode()
{
if (sampleMode == null)
setSampleMode(0);
return sampleMode;
}
public int getSampleModeOridinal()
{
if (sampleMode == null)
return 0;
return sampleMode.ordinal();
}
public void setSampleMode(SampleMode mode)
{
sampleMode = mode;
}
public void setSampleMode(int mode)
{
SampleMode[] values = SampleMode.values();
if (mode < 0 || mode >= values.length)
mode = 0;
this.sampleMode = values[mode];
}
public ClusteringMode getClusteringMode()
{
if (clusteringMode == null)
setClusteringMode(0);
return clusteringMode;
}
public int getClusteringModeOridinal()
{
if (clusteringMode == null)
return 0;
return clusteringMode.ordinal();
}
public void setClusteringMode(ClusteringMode mode)
{
clusteringMode = mode;
}
public void setClusteringMode(int mode)
{
ClusteringMode[] values = ClusteringMode.values();
if (mode < 0 || mode >= values.length)
mode = 0;
this.clusteringMode = values[mode];
}
public PlotMode getPlotMode()
{
if (plotMode == null)
setPlotMode(0);
return plotMode;
}
public int getPlotModeOridinal()
{
if (plotMode == null)
return 0;
return plotMode.ordinal();
}
public void setPlotMode(PlotMode mode)
{
plotMode = mode;
}
public void setPlotMode(int mode)
{
PlotMode[] values = PlotMode.values();
if (mode < 0 || mode >= values.length)
mode = 0;
this.plotMode = values[mode];
}
public OutlineMode getOutlineMode()
{
if (outlineMode == null)
setOutlineMode(0);
return outlineMode;
}
public int getOutlineModeOridinal()
{
if (outlineMode == null)
return 0;
return outlineMode.ordinal();
}
public void setOutlineMode(OutlineMode mode)
{
outlineMode = mode;
}
public void setOutlineMode(int mode)
{
OutlineMode[] values = OutlineMode.values();
if (mode < 0 || mode >= values.length)
mode = 0;
this.outlineMode = values[mode];
}
public SpanningTreeMode getSpanningTreeMode()
{
if (spanningTreeMode == null)
setSpanningTreeMode(0);
return spanningTreeMode;
}
public int getSpanningTreeModeOridinal()
{
if (spanningTreeMode == null)
return 0;
return spanningTreeMode.ordinal();
}
public void setSpanningTreeMode(SpanningTreeMode mode)
{
spanningTreeMode = mode;
}
public void setSpanningTreeMode(int mode)
{
SpanningTreeMode[] values = SpanningTreeMode.values();
if (mode < 0 || mode >= values.length)
mode = 0;
this.spanningTreeMode = values[mode];
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#clone()
*/
@Override
public OPTICSSettings clone()
{
try
{
return (OPTICSSettings) super.clone();
}
catch (CloneNotSupportedException ex)
{
return null;
}
}
}