Package de.lmu.ifi.dbs.elki.visualization.visualizers.optics

Source Code of de.lmu.ifi.dbs.elki.visualization.visualizers.optics.OPTICSPlotCutVisualization$Factory

package de.lmu.ifi.dbs.elki.visualization.visualizers.optics;

/*
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.util.Iterator;

import org.apache.batik.util.SVG12Constants;
import org.apache.batik.util.SVGConstants;
import org.w3c.dom.Element;
import org.w3c.dom.events.Event;
import org.w3c.dom.svg.SVGPoint;

import de.lmu.ifi.dbs.elki.data.Clustering;
import de.lmu.ifi.dbs.elki.data.model.Model;
import de.lmu.ifi.dbs.elki.distance.distancevalue.Distance;
import de.lmu.ifi.dbs.elki.distance.distancevalue.DoubleDistance;
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.optics.ClusterOrderResult;
import de.lmu.ifi.dbs.elki.utilities.FormatUtil;
import de.lmu.ifi.dbs.elki.utilities.iterator.IterableUtil;
import de.lmu.ifi.dbs.elki.visualization.VisualizationTask;
import de.lmu.ifi.dbs.elki.visualization.batikutil.DragableArea;
import de.lmu.ifi.dbs.elki.visualization.css.CSSClass;
import de.lmu.ifi.dbs.elki.visualization.opticsplot.OPTICSCut;
import de.lmu.ifi.dbs.elki.visualization.projector.OPTICSProjector;
import de.lmu.ifi.dbs.elki.visualization.style.StyleLibrary;
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;

/**
* Visualizes a cut in an OPTICS Plot to select an Epsilon value and generate a
* new clustering result
*
* @author Heidi Kolb
*
* @param <D> distance type
*/
public class OPTICSPlotCutVisualization<D extends Distance<D>> extends AbstractOPTICSVisualization<D> implements DragableArea.DragListener {
  /**
   * A short name characterizing this Visualizer.
   */
  private static final String NAME = "OPTICS Cut";

  /**
   * CSS-Styles
   */
  protected static final String CSS_LINE = "opticsPlotLine";

  /**
   * CSS-Styles
   */
  protected final static String CSS_EPSILON = "opticsPlotEpsilonValue";

  /**
   * The current epsilon value.
   */
  private double epsilon = 0.0;

  /**
   * Sensitive (clickable) area
   */
  private DragableArea eventarea = null;

  /**
   * The label element
   */
  private Element elemText = null;

  /**
   * The line element
   */
  private Element elementLine = null;

  /**
   * The drag handle element
   */
  private Element elementPoint = null;

  /**
   * Constructor.
   *
   * @param task Task
   */
  public OPTICSPlotCutVisualization(VisualizationTask task) {
    super(task);
  }

  @Override
  protected void redraw() {
    incrementalRedraw();
  }

  @Override
  protected void incrementalRedraw() {
    if(layer == null) {
      makeLayerElement();
      addCSSClasses();
    }

    // TODO make the number of digits configurable
    final String label = (epsilon != 0.0) ? FormatUtil.format(epsilon, 4) : "";
    // compute absolute y-value of bar
    final double yAct = plotheight - getYFromEpsilon(epsilon);

    if(elemText == null) {
      elemText = svgp.svgText(StyleLibrary.SCALE * 1.05, yAct, label);
      SVGUtil.setAtt(elemText, SVGConstants.SVG_CLASS_ATTRIBUTE, CSS_EPSILON);
      layer.appendChild(elemText);
    }
    else {
      elemText.setTextContent(label);
      SVGUtil.setAtt(elemText, SVGConstants.SVG_Y_ATTRIBUTE, yAct);
    }

    // line and handle
    if(elementLine == null) {
      elementLine = svgp.svgLine(0, yAct, StyleLibrary.SCALE * 1.04, yAct);
      SVGUtil.addCSSClass(elementLine, CSS_LINE);
      layer.appendChild(elementLine);
    }
    else {
      SVGUtil.setAtt(elementLine, SVG12Constants.SVG_Y1_ATTRIBUTE, yAct);
      SVGUtil.setAtt(elementLine, SVG12Constants.SVG_Y2_ATTRIBUTE, yAct);
    }
    if(elementPoint == null) {
      elementPoint = svgp.svgCircle(StyleLibrary.SCALE * 1.04, yAct, StyleLibrary.SCALE * 0.004);
      SVGUtil.addCSSClass(elementPoint, CSS_LINE);
      layer.appendChild(elementPoint);
    }
    else {
      SVGUtil.setAtt(elementPoint, SVG12Constants.SVG_CY_ATTRIBUTE, yAct);
    }

    if(eventarea == null) {
      eventarea = new DragableArea(svgp, StyleLibrary.SCALE, 0, StyleLibrary.SCALE * 0.1, plotheight, this);
      layer.appendChild(eventarea.getElement());
    }
  }

  @Override
  public void destroy() {
    super.destroy();
    eventarea.destroy();
  }

  /**
   * Get epsilon from y-value
   *
   * @param y y-Value
   * @return epsilon
   */
  protected double getEpsilonFromY(double y) {
    if(y < 0) {
      y = 0;
    }
    if(y > plotheight) {
      y = plotheight;
    }
    return optics.getOPTICSPlot(context).getScale().getUnscaled(y / plotheight);
  }

  /**
   * Get y-value from epsilon
   *
   * @param epsilon epsilon
   * @return y-Value
   */
  protected double getYFromEpsilon(double epsilon) {
    double y = optics.getOPTICSPlot(context).getScale().getScaled(epsilon) * plotheight;
    if(y < 0) {
      y = 0;
    }
    if(y > plotheight) {
      y = plotheight;
    }
    return y;
  }

  @Override
  public boolean startDrag(SVGPoint start, Event evt) {
    epsilon = getEpsilonFromY(plotheight - start.getY());
    // opvis.unsetEpsilonExcept(this);
    synchronizedRedraw();
    return true;
  }

  @Override
  public boolean duringDrag(SVGPoint start, SVGPoint end, Event evt, boolean inside) {
    if(inside) {
      epsilon = getEpsilonFromY(plotheight - end.getY());
    }
    // opvis.unsetEpsilonExcept(this);
    synchronizedRedraw();
    return true;
  }

  @Override
  public boolean endDrag(SVGPoint start, SVGPoint end, Event evt, boolean inside) {
    if(inside) {
      epsilon = getEpsilonFromY(plotheight - end.getY());
      // opvis.unsetEpsilonExcept(this);

      // FIXME: replace an existing optics cut result!
      final ClusterOrderResult<D> order = optics.getResult();
      Clustering<Model> cl = OPTICSCut.makeOPTICSCut(order, optics.getOPTICSPlot(context).getDistanceAdapter(), epsilon);
      order.addChildResult(cl);
    }
    context.resultChanged(this.task);
    // synchronizedRedraw();
    return true;
  }

  /**
   * Reset the epsilon value.
   */
  public void unsetEpsilon() {
    epsilon = 0.0;
  }

  /**
   * Adds the required CSS-Classes
   */
  private void addCSSClasses() {
    // Class for the epsilon-value
    if(!svgp.getCSSClassManager().contains(CSS_EPSILON)) {
      final CSSClass label = new CSSClass(svgp, CSS_EPSILON);
      label.setStatement(SVGConstants.CSS_FILL_PROPERTY, context.getStyleLibrary().getTextColor(StyleLibrary.AXIS_LABEL));
      label.setStatement(SVGConstants.CSS_FONT_FAMILY_PROPERTY, context.getStyleLibrary().getFontFamily(StyleLibrary.AXIS_LABEL));
      label.setStatement(SVGConstants.CSS_FONT_SIZE_PROPERTY, context.getStyleLibrary().getTextSize(StyleLibrary.AXIS_LABEL));
      svgp.addCSSClassOrLogError(label);
    }
    // Class for the epsilon cut line
    if(!svgp.getCSSClassManager().contains(CSS_LINE)) {
      final CSSClass lcls = new CSSClass(svgp, CSS_LINE);
      lcls.setStatement(SVGConstants.CSS_STROKE_PROPERTY, context.getStyleLibrary().getColor(StyleLibrary.PLOT));
      lcls.setStatement(SVGConstants.CSS_STROKE_WIDTH_PROPERTY, 0.5 * context.getStyleLibrary().getLineWidth(StyleLibrary.PLOT));
      svgp.addCSSClassOrLogError(lcls);
    }
  }

  /**
   * Factory class
   *
   * @author Erich Schubert
   *
   * @apiviz.stereotype factory
   * @apiviz.uses OPTICSPlotCutVisualization oneway - - «create»
   */
  public static class Factory extends AbstractVisFactory {
    public Factory() {
      super();
    }

    @Override
    public void processNewResult(HierarchicalResult baseResult, Result result) {
      Iterator<OPTICSProjector<?>> ops = ResultUtil.filteredResults(result, OPTICSProjector.class);
      for(OPTICSProjector<?> p : IterableUtil.fromIterator(ops)) {
        final VisualizationTask task = new VisualizationTask(NAME, p, null, this);
        task.put(VisualizationTask.META_LEVEL, VisualizationTask.LEVEL_INTERACTIVE);
        baseResult.getHierarchy().add(p, task);
      }
    }

    @Override
    public Visualization makeVisualization(VisualizationTask task) {
      return new OPTICSPlotCutVisualization<DoubleDistance>(task);
    }

    @Override
    public boolean allowThumbnails(VisualizationTask task) {
      // Don't use thumbnails
      return false;
    }
  }
}
TOP

Related Classes of de.lmu.ifi.dbs.elki.visualization.visualizers.optics.OPTICSPlotCutVisualization$Factory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.