summaryrefslogtreecommitdiff
path: root/src/de/lmu/ifi/dbs/elki/visualization/visualizers/vis2d/TooltipScoreVisualization.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/de/lmu/ifi/dbs/elki/visualization/visualizers/vis2d/TooltipScoreVisualization.java')
-rw-r--r--src/de/lmu/ifi/dbs/elki/visualization/visualizers/vis2d/TooltipScoreVisualization.java230
1 files changed, 230 insertions, 0 deletions
diff --git a/src/de/lmu/ifi/dbs/elki/visualization/visualizers/vis2d/TooltipScoreVisualization.java b/src/de/lmu/ifi/dbs/elki/visualization/visualizers/vis2d/TooltipScoreVisualization.java
new file mode 100644
index 00000000..160fad55
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/visualization/visualizers/vis2d/TooltipScoreVisualization.java
@@ -0,0 +1,230 @@
+package de.lmu.ifi.dbs.elki.visualization.visualizers.vis2d;
+/*
+This file is part of ELKI:
+Environment for Developing KDD-Applications Supported by Index-Structures
+
+Copyright (C) 2011
+Ludwig-Maximilians-Universität München
+Lehr- und Forschungseinheit für Datenbanksysteme
+ELKI Development Team
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import java.text.NumberFormat;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.batik.util.SVGConstants;
+import org.w3c.dom.Element;
+
+import de.lmu.ifi.dbs.elki.data.NumberVector;
+import de.lmu.ifi.dbs.elki.database.ids.DBID;
+import de.lmu.ifi.dbs.elki.database.relation.Relation;
+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.result.outlier.OutlierResult;
+import de.lmu.ifi.dbs.elki.utilities.iterator.IterableUtil;
+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.constraints.GreaterEqualConstraint;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.IntParameter;
+import de.lmu.ifi.dbs.elki.visualization.css.CSSClass;
+import de.lmu.ifi.dbs.elki.visualization.projections.Projection;
+import de.lmu.ifi.dbs.elki.visualization.projections.Projection2D;
+import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
+import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
+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.VisualizationTask;
+import de.lmu.ifi.dbs.elki.visualization.visualizers.VisualizerUtil;
+
+/**
+ * Generates a SVG-Element containing Tooltips. Tooltips remain invisible until
+ * their corresponding Marker is touched by the cursor and stay visible as long
+ * as the cursor lingers on the marker.
+ *
+ * @author Remigius Wojdanowski
+ */
+public class TooltipScoreVisualization<NV extends NumberVector<NV, ?>> extends TooltipVisualization<NV> {
+ /**
+ * A short name characterizing this Visualizer.
+ */
+ public static final String NAME = "Outlier Score Tooltips";
+
+ /**
+ * Number format.
+ */
+ NumberFormat nf;
+
+ /**
+ * Number value to visualize
+ */
+ private Relation<? extends Number> result;
+
+ /**
+ * Font size to use.
+ */
+ private double fontsize;
+
+ /**
+ * Constructor
+ *
+ * @param task Task
+ * @param nf Number Format
+ */
+ public TooltipScoreVisualization(VisualizationTask task, NumberFormat nf) {
+ super(task);
+ this.result = task.getResult();
+ this.nf = nf;
+ this.fontsize = 3 * context.getStyleLibrary().getTextSize(StyleLibrary.PLOT);
+ synchronizedRedraw();
+ }
+
+ @Override
+ protected Element makeTooltip(DBID id, double x, double y, double dotsize) {
+ return svgp.svgText(x + dotsize, y + fontsize * 0.07, nf.format(result.get(id).doubleValue()));
+ }
+
+ /**
+ * Registers the Tooltip-CSS-Class at a SVGPlot.
+ *
+ * @param svgp the SVGPlot to register the Tooltip-CSS-Class.
+ */
+ @Override
+ protected void setupCSS(SVGPlot svgp) {
+ final StyleLibrary style = context.getStyleLibrary();
+ final double fontsize = style.getTextSize(StyleLibrary.PLOT);
+ final String fontfamily = style.getFontFamily(StyleLibrary.PLOT);
+
+ CSSClass tooltiphidden = new CSSClass(svgp, TOOLTIP_HIDDEN);
+ tooltiphidden.setStatement(SVGConstants.CSS_FONT_SIZE_PROPERTY, fontsize);
+ tooltiphidden.setStatement(SVGConstants.CSS_FONT_FAMILY_PROPERTY, fontfamily);
+ tooltiphidden.setStatement(SVGConstants.CSS_DISPLAY_PROPERTY, SVGConstants.CSS_NONE_VALUE);
+ svgp.addCSSClassOrLogError(tooltiphidden);
+
+ CSSClass tooltipvisible = new CSSClass(svgp, TOOLTIP_VISIBLE);
+ tooltipvisible.setStatement(SVGConstants.CSS_FONT_SIZE_PROPERTY, fontsize);
+ tooltipvisible.setStatement(SVGConstants.CSS_FONT_FAMILY_PROPERTY, fontfamily);
+ svgp.addCSSClassOrLogError(tooltipvisible);
+
+ CSSClass tooltipsticky = new CSSClass(svgp, TOOLTIP_STICKY);
+ tooltipsticky.setStatement(SVGConstants.CSS_FONT_SIZE_PROPERTY, fontsize);
+ tooltipsticky.setStatement(SVGConstants.CSS_FONT_FAMILY_PROPERTY, fontfamily);
+ svgp.addCSSClassOrLogError(tooltipsticky);
+
+ // invisible but sensitive area for the tooltip activator
+ CSSClass tooltiparea = new CSSClass(svgp, TOOLTIP_AREA);
+ tooltiparea.setStatement(SVGConstants.CSS_FILL_PROPERTY, SVGConstants.CSS_RED_VALUE);
+ tooltiparea.setStatement(SVGConstants.CSS_STROKE_PROPERTY, SVGConstants.CSS_NONE_VALUE);
+ tooltiparea.setStatement(SVGConstants.CSS_FILL_OPACITY_PROPERTY, "0");
+ tooltiparea.setStatement(SVGConstants.CSS_CURSOR_PROPERTY, SVGConstants.CSS_POINTER_VALUE);
+ svgp.addCSSClassOrLogError(tooltiparea);
+ }
+
+ /**
+ * Factory for tooltip visualizers
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.stereotype factory
+ * @apiviz.uses TooltipScoreVisualization oneway - - «create»
+ *
+ * @param <NV> Data type visualized.
+ */
+ public static class Factory<NV extends NumberVector<NV, ?>> extends AbstractVisFactory {
+ /**
+ * Parameter for the gamma-correction.
+ *
+ * <p>
+ * Key: {@code -tooltip.digits}
+ * </p>
+ *
+ * <p>
+ * Default value: 4
+ * </p>
+ */
+ public static final OptionID DIGITS_ID = OptionID.getOrCreateOptionID("tooltip.digits", "Number of digits to show (e.g. when visualizing outlier scores)");
+
+ /**
+ * Number formatter used for visualization
+ */
+ NumberFormat nf = null;
+
+ /**
+ * Constructor.
+ *
+ * @param digits number of digits
+ */
+ public Factory(int digits) {
+ super();
+ nf = NumberFormat.getInstance(Locale.ROOT);
+ nf.setGroupingUsed(false);
+ nf.setMaximumFractionDigits(digits);
+ }
+
+ @Override
+ public Visualization makeVisualization(VisualizationTask task) {
+ return new TooltipScoreVisualization<NV>(task, nf);
+ }
+
+ @Override
+ public void processNewResult(HierarchicalResult baseResult, Result result) {
+ Iterator<Relation<? extends NumberVector<?, ?>>> reps = VisualizerUtil.iterateVectorFieldRepresentations(baseResult);
+ for(Relation<? extends NumberVector<?, ?>> rep : IterableUtil.fromIterator(reps)) {
+ // TODO: we can also visualize other scores!
+ List<OutlierResult> ors = ResultUtil.filterResults(result, OutlierResult.class);
+ for(OutlierResult o : ors) {
+ final VisualizationTask task = new VisualizationTask(NAME, o.getScores(), rep, this, P2DVisualization.class);
+ task.put(VisualizationTask.META_TOOL, true);
+ baseResult.getHierarchy().add(o.getScores(), task);
+ }
+ }
+ }
+
+ @Override
+ public Class<? extends Projection> getProjectionType() {
+ return Projection2D.class;
+ }
+
+ /**
+ * Parameterization class.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ public static class Parameterizer<NV extends NumberVector<NV, ?>> extends AbstractParameterizer {
+ protected int digits = 4;
+
+ @Override
+ protected void makeOptions(Parameterization config) {
+ super.makeOptions(config);
+ IntParameter DIGITS_PARAM = new IntParameter(DIGITS_ID, new GreaterEqualConstraint(0), 4);
+
+ if(config.grab(DIGITS_PARAM)) {
+ digits = DIGITS_PARAM.getValue();
+ }
+ }
+
+ @Override
+ protected Factory<NV> makeInstance() {
+ return new Factory<NV>(digits);
+ }
+ }
+ }
+} \ No newline at end of file