summaryrefslogtreecommitdiff
path: root/src/de/lmu/ifi/dbs/elki/visualization/visualizers/parallel/cluster/ClusterOutlineVisualization.java
diff options
context:
space:
mode:
authorAndrej Shadura <andrewsh@debian.org>2019-03-09 22:30:40 +0000
committerAndrej Shadura <andrewsh@debian.org>2019-03-09 22:30:40 +0000
commit337087b668d3a54f3afee3a9adb597a32e9f7e94 (patch)
treed860094269622472f8079d497ac7af02dbb4e038 /src/de/lmu/ifi/dbs/elki/visualization/visualizers/parallel/cluster/ClusterOutlineVisualization.java
parent14a486343aef55f97f54082d6b542dedebf6f3ba (diff)
Import Upstream version 0.6.5~20141030
Diffstat (limited to 'src/de/lmu/ifi/dbs/elki/visualization/visualizers/parallel/cluster/ClusterOutlineVisualization.java')
-rw-r--r--src/de/lmu/ifi/dbs/elki/visualization/visualizers/parallel/cluster/ClusterOutlineVisualization.java175
1 files changed, 112 insertions, 63 deletions
diff --git a/src/de/lmu/ifi/dbs/elki/visualization/visualizers/parallel/cluster/ClusterOutlineVisualization.java b/src/de/lmu/ifi/dbs/elki/visualization/visualizers/parallel/cluster/ClusterOutlineVisualization.java
index 10aa6309..b155005e 100644
--- a/src/de/lmu/ifi/dbs/elki/visualization/visualizers/parallel/cluster/ClusterOutlineVisualization.java
+++ b/src/de/lmu/ifi/dbs/elki/visualization/visualizers/parallel/cluster/ClusterOutlineVisualization.java
@@ -40,18 +40,26 @@ import de.lmu.ifi.dbs.elki.math.DoubleMinMax;
import de.lmu.ifi.dbs.elki.result.HierarchicalResult;
import de.lmu.ifi.dbs.elki.result.Result;
import de.lmu.ifi.dbs.elki.result.ResultUtil;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.Flag;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClass;
import de.lmu.ifi.dbs.elki.visualization.projector.ParallelPlotProjector;
+import de.lmu.ifi.dbs.elki.visualization.style.ClusterStylingPolicy;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
+import de.lmu.ifi.dbs.elki.visualization.style.StyleResult;
+import de.lmu.ifi.dbs.elki.visualization.style.StylingPolicy;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGPath;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
import de.lmu.ifi.dbs.elki.visualization.visualizers.AbstractVisFactory;
import de.lmu.ifi.dbs.elki.visualization.visualizers.Visualization;
import de.lmu.ifi.dbs.elki.visualization.visualizers.parallel.AbstractParallelVisualization;
+import de.lmu.ifi.dbs.elki.visualization.visualizers.scatterplot.cluster.ClusterHullVisualization;
/**
* Generates a SVG-Element that visualizes the area covered by a cluster.
@@ -66,45 +74,41 @@ public class ClusterOutlineVisualization extends AbstractVisFactory {
/**
* A short name characterizing this Visualizer.
*/
- public static final String NAME = "Parallel Cluster Outline";
+ private static final String NAME = "Cluster Hull (Parallel Coordinates)";
/**
- * Currently unused option to enable/disable rounding
+ * Settings
*/
- public static final OptionID ROUNDED_ID = new OptionID("parallel.clusteroutline.rounded", "Draw lines rounded");
+ Parameterizer settings;
/**
- * Currently, always enabled.
- */
- private boolean rounded = true;
-
- /**
- * Constructor, adhering to
- * {@link de.lmu.ifi.dbs.elki.utilities.optionhandling.Parameterizable}
+ * Constructor.
+ *
+ * @param settings Settings
*/
- public ClusterOutlineVisualization() {
+ public ClusterOutlineVisualization(Parameterizer settings) {
super();
+ this.settings = settings;
}
@Override
public Visualization makeVisualization(VisualizationTask task) {
- return new Instance(task, rounded);
+ return new Instance(task);
}
@Override
public void processNewResult(HierarchicalResult baseResult, Result result) {
- // Find clusterings we can visualize:
- Collection<Clustering<?>> clusterings = ResultUtil.filterResults(result, Clustering.class);
- for(Clustering<?> c : clusterings) {
- if(c.getAllClusters().size() > 0) {
- Collection<ParallelPlotProjector<?>> ps = ResultUtil.filterResults(baseResult, ParallelPlotProjector.class);
- for(ParallelPlotProjector<?> p : ps) {
- final VisualizationTask task = new VisualizationTask(NAME, c, p.getRelation(), this);
- task.level = VisualizationTask.LEVEL_DATA - 1;
- task.initDefaultVisibility(false);
- baseResult.getHierarchy().add(c, task);
- baseResult.getHierarchy().add(p, task);
- }
+ // We attach ourselves to the style library, not the clustering, so there is
+ // only one hull.
+ Collection<StyleResult> styleres = ResultUtil.filterResults(result, StyleResult.class);
+ for(StyleResult s : styleres) {
+ Collection<ParallelPlotProjector<?>> ps = ResultUtil.filterResults(baseResult, ParallelPlotProjector.class);
+ for(ParallelPlotProjector<?> p : ps) {
+ final VisualizationTask task = new VisualizationTask(NAME, s, p.getRelation(), this);
+ task.level = VisualizationTask.LEVEL_DATA - 1;
+ task.initDefaultVisibility(false);
+ baseResult.getHierarchy().add(s, task);
+ baseResult.getHierarchy().add(p, task);
}
}
}
@@ -121,7 +125,7 @@ public class ClusterOutlineVisualization extends AbstractVisFactory {
* @author Robert Rödler
* @author Erich Schubert
*/
- public class Instance extends AbstractParallelVisualization<NumberVector<?>> implements DataStoreListener {
+ public class Instance extends AbstractParallelVisualization<NumberVector> implements DataStoreListener {
/**
* Generic tags to indicate the type of element. Used in IDs, CSS-Classes
* etc.
@@ -131,22 +135,16 @@ public class ClusterOutlineVisualization extends AbstractVisFactory {
/**
* The result we visualize
*/
- private Clustering<Model> clustering;
-
- /**
- * Flag for using rounded shapes
- */
- boolean rounded = true;
+ private StyleResult style;
/**
* Constructor.
*
* @param task VisualizationTask
*/
- public Instance(VisualizationTask task, boolean rounded) {
+ public Instance(VisualizationTask task) {
super(task);
- this.clustering = task.getResult();
- this.rounded = rounded;
+ this.style = task.getResult();
context.addDataStoreListener(this);
context.addResultListener(this);
incrementalRedraw();
@@ -161,17 +159,27 @@ public class ClusterOutlineVisualization extends AbstractVisFactory {
@Override
protected void redraw() {
- addCSSClasses(svgp);
+ final StylingPolicy spol = style.getStylingPolicy();
+ if(!(spol instanceof ClusterStylingPolicy)) {
+ return;
+ }
+ final ClusterStylingPolicy cpol = (ClusterStylingPolicy) spol;
+ @SuppressWarnings("unchecked")
+ Clustering<Model> clustering = (Clustering<Model>) cpol.getClustering();
+
int dim = proj.getVisibleDimensions();
DoubleMinMax[] mms = DoubleMinMax.newArray(dim);
DoubleMinMax[] midmm = DoubleMinMax.newArray(dim - 1);
+ // Heuristic value for transparency:
+ double baseopacity = .5;
+
Iterator<Cluster<Model>> ci = clustering.getAllClusters().iterator();
for(int cnum = 0; cnum < clustering.getAllClusters().size(); cnum++) {
Cluster<?> clus = ci.next();
final DBIDs ids = clus.getIDs();
- if (ids.size() < 1) {
+ if(ids.size() < 1) {
continue;
}
for(int i = 0; i < dim; i++) {
@@ -194,7 +202,7 @@ public class ClusterOutlineVisualization extends AbstractVisFactory {
}
SVGPath path = new SVGPath();
- if(!rounded) {
+ if(!settings.bend) {
// Straight lines
for(int i = 0; i < dim; i++) {
path.drawTo(getVisibleAxisX(i), mms[i].getMax());
@@ -208,7 +216,6 @@ public class ClusterOutlineVisualization extends AbstractVisFactory {
}
path.drawTo(getVisibleAxisX(i), mms[i].getMin());
}
- path.close();
}
else {
// Maxima
@@ -221,10 +228,19 @@ public class ClusterOutlineVisualization extends AbstractVisFactory {
for(int i = dim - 1; i > 0; i--) {
path.quadTo(getVisibleAxisX(i - .5), midmm[i - 1].getMin(), getVisibleAxisX(i - 1), mms[i - 1].getMin());
}
- path.close();
}
+ path.close();
+
+ // TODO: improve the visualization by adjusting the opacity by the
+ // cluster extends on each axis (maybe use a horizontal gradient?)
+ double weight = 0.;
+ for(int i = 0; i < dim; i++) {
+ weight += mms[i].getDiff();
+ }
+ weight = (weight > 0.) ? (dim * StyleLibrary.SCALE) / weight : 1.;
Element intervals = path.makeElement(svgp);
+ addCSSClasses(svgp, cpol.getStyleForCluster(clus), baseopacity * weight * ids.size() / relation.size());
SVGUtil.addCSSClass(intervals, CLUSTERAREA + cnum);
layer.appendChild(intervals);
}
@@ -234,33 +250,66 @@ public class ClusterOutlineVisualization extends AbstractVisFactory {
* Adds the required CSS-Classes
*
* @param svgp SVG-Plot
+ * @param clusterID Cluster ID to style
+ * @param opac Opacity
*/
- private void addCSSClasses(SVGPlot svgp) {
- if(!svgp.getCSSClassManager().contains(CLUSTERAREA)) {
- final StyleLibrary style = context.getStyleResult().getStyleLibrary();
- ColorLibrary colors = style.getColorSet(StyleLibrary.PLOT);
- int clusterID = 0;
-
- for(@SuppressWarnings("unused")
- Cluster<?> cluster : clustering.getAllClusters()) {
- CSSClass cls = new CSSClass(this, CLUSTERAREA + clusterID);
- // cls.setStatement(SVGConstants.CSS_STROKE_WIDTH_PROPERTY,
- // context.getStyleLibrary().getLineWidth(StyleLibrary.PLOT) / 2.0);
- cls.setStatement(SVGConstants.CSS_OPACITY_PROPERTY, 0.5);
- final String color;
- if(clustering.getAllClusters().size() == 1) {
- color = SVGConstants.CSS_BLACK_VALUE;
- }
- else {
- color = colors.getColor(clusterID);
- }
- // cls.setStatement(SVGConstants.CSS_STROKE_PROPERTY, color);
- cls.setStatement(SVGConstants.CSS_FILL_PROPERTY, color);
+ private void addCSSClasses(SVGPlot svgp, int clusterID, double opac) {
+ final StyleLibrary style = context.getStyleResult().getStyleLibrary();
+ ColorLibrary colors = style.getColorSet(StyleLibrary.PLOT);
- svgp.addCSSClassOrLogError(cls);
- clusterID++;
- }
+ CSSClass cls = new CSSClass(this, CLUSTERAREA + clusterID);
+ final String color = colors.getColor(clusterID);
+
+ // cls.setStatement(SVGConstants.CSS_STROKE_WIDTH_PROPERTY,
+ // context.getStyleLibrary().getLineWidth(StyleLibrary.PLOT) / 2.0);
+ // cls.setStatement(SVGConstants.CSS_STROKE_PROPERTY, color);
+ cls.setStatement(SVGConstants.CSS_FILL_PROPERTY, color);
+ cls.setStatement(SVGConstants.CSS_FILL_OPACITY_PROPERTY, opac);
+
+ svgp.addCSSClassOrLogError(cls);
+ }
+ }
+
+ /**
+ * Parameterization class.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ public static class Parameterizer extends AbstractParameterizer {
+ /**
+ * Option string to draw straight lines for hull.
+ */
+ public static final OptionID STRAIGHT_ID = new OptionID("parallel.clusteroutline.straight", "Draw straight lines");
+
+ /**
+ * Alpha value
+ */
+ double alpha = Double.POSITIVE_INFINITY;
+
+ /**
+ * Use bend curves
+ */
+ private boolean bend = true;
+
+ @Override
+ protected void makeOptions(Parameterization config) {
+ super.makeOptions(config);
+ DoubleParameter alphaP = new DoubleParameter(ClusterHullVisualization.Parameterizer.ALPHA_ID, Double.POSITIVE_INFINITY);
+ if(config.grab(alphaP)) {
+ alpha = alphaP.doubleValue();
}
+
+ Flag bendP = new Flag(STRAIGHT_ID);
+ if(config.grab(bendP)) {
+ bend = bendP.isFalse();
+ }
+ }
+
+ @Override
+ protected ClusterOutlineVisualization makeInstance() {
+ return new ClusterOutlineVisualization(this);
}
}
} \ No newline at end of file