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

Source Code of de.lmu.ifi.dbs.elki.visualization.VisualizerContext

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

/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures

Copyright (C) 2012
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.Collection;
import java.util.List;

import javax.swing.event.EventListenerList;

import de.lmu.ifi.dbs.elki.algorithm.clustering.trivial.ByLabelHierarchicalClustering;
import de.lmu.ifi.dbs.elki.algorithm.clustering.trivial.TrivialAllInOne;
import de.lmu.ifi.dbs.elki.data.Clustering;
import de.lmu.ifi.dbs.elki.data.NumberVector;
import de.lmu.ifi.dbs.elki.data.model.Model;
import de.lmu.ifi.dbs.elki.data.type.NoSupportedDataTypeException;
import de.lmu.ifi.dbs.elki.data.type.TypeUtil;
import de.lmu.ifi.dbs.elki.database.Database;
import de.lmu.ifi.dbs.elki.database.datastore.DataStoreEvent;
import de.lmu.ifi.dbs.elki.database.datastore.DataStoreListener;
import de.lmu.ifi.dbs.elki.database.relation.Relation;
import de.lmu.ifi.dbs.elki.logging.Logging;
import de.lmu.ifi.dbs.elki.result.DBIDSelection;
import de.lmu.ifi.dbs.elki.result.HierarchicalResult;
import de.lmu.ifi.dbs.elki.result.Result;
import de.lmu.ifi.dbs.elki.result.ResultHierarchy;
import de.lmu.ifi.dbs.elki.result.ResultListener;
import de.lmu.ifi.dbs.elki.result.ResultUtil;
import de.lmu.ifi.dbs.elki.result.SelectionResult;
import de.lmu.ifi.dbs.elki.visualization.projector.ProjectorFactory;
import de.lmu.ifi.dbs.elki.visualization.style.ClusterStylingPolicy;
import de.lmu.ifi.dbs.elki.visualization.style.PropertiesBasedStyleLibrary;
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.visualizers.VisFactory;
import de.lmu.ifi.dbs.elki.visualization.visualizers.VisualizerUtil;

/**
* Map to store context information for the visualizer. This can be any data
* that should to be shared among plots, such as line colors, styles etc.
*
* @author Erich Schubert
*
*         TODO: remove this class
*
* @apiviz.landmark
* @apiviz.uses ContextChangedEvent oneway - - «emit»
* @apiviz.composedOf StyleLibrary
* @apiviz.composedOf SelectionResult
* @apiviz.composedOf ResultHierarchy
* @apiviz.composedOf EventListenerList
*/
public class VisualizerContext implements DataStoreListener, Result {
  /**
   * Logger.
   */
  private static final Logging logger = Logging.getLogger(VisualizerContext.class);

  /**
   * The full result object
   */
  private HierarchicalResult result;

  /**
   * The event listeners for this context.
   */
  private EventListenerList listenerList = new EventListenerList();

  /**
   * The style library of this context
   */
  private StyleLibrary stylelib;

  /**
   * Projectors to use
   */
  private Collection<ProjectorFactory> projectors;

  /**
   * Factories to use
   */
  private Collection<VisFactory> factories;

  /**
   * Selection result
   */
  private SelectionResult selection;

  /**
   * Styling result
   */
  private StyleResult styleresult;

  /**
   * Constructor. We currently require a Database and a Result.
   *
   * @param result Result
   * @param stylelib Style library
   * @param projectors Projectors to use
   * @param factories Visualizer Factories to use
   */
  public VisualizerContext(HierarchicalResult result, StyleLibrary stylelib, Collection<ProjectorFactory> projectors, Collection<VisFactory> factories) {
    super();
    this.result = result;
    this.stylelib = stylelib;
    this.projectors = projectors;
    this.factories = factories;

    // Ensure that various common results needed by visualizers are
    // automatically created
    final Database db = ResultUtil.findDatabase(result);
    ResultUtil.ensureClusteringResult(db, result);
    this.selection = ResultUtil.ensureSelectionResult(db);
    for(Relation<?> rel : ResultUtil.getRelations(result)) {
      ResultUtil.getSamplingResult(rel);
      // FIXME: this is a really ugly workaround. :-(
      if(TypeUtil.NUMBER_VECTOR_FIELD.isAssignableFromType(rel.getDataTypeInformation())) {
        @SuppressWarnings("unchecked")
        Relation<? extends NumberVector<?, ?>> vrel = (Relation<? extends NumberVector<?, ?>>) rel;
        ResultUtil.getScalesResult(vrel);
      }
    }
    getStyleResult();

    // result.getHierarchy().add(result, this);

    // Add visualizers.
    processNewResult(result, result);

    // For proxying events.
    ResultUtil.findDatabase(result).addDataStoreListener(this);
    // Add a result listener. Don't expose these methods to avoid inappropriate use.
    addResultListener(new ResultListener() {
      @Override
      public void resultAdded(Result child, Result parent) {
        processNewResult(getResult(), child);
      }

      @Override
      public void resultChanged(Result current) {
        // FIXME: need to do anything?
      }

      @Override
      public void resultRemoved(Result child, Result parent) {
        // FIXME: implement
      }
    });
  }

  /**
   * Get the full result object
   *
   * @return result object
   */
  public HierarchicalResult getResult() {
    return result;
  }

  /**
   * Get the hierarchy object
   *
   * @return hierarchy object
   */
  public ResultHierarchy getHierarchy() {
    return result.getHierarchy();
  }

  /**
   * Get the style library
   *
   * @return style library
   */
  public StyleLibrary getStyleLibrary() {
    if(stylelib == null) {
      stylelib = new PropertiesBasedStyleLibrary();
    }
    return stylelib;
  }

  /**
   * Get the style result.
   *
   * @return Style result
   */
  public StyleResult getStyleResult() {
    if(styleresult == null) {
      styleresult = new StyleResult();
      List<Clustering<? extends Model>> clusterings = ResultUtil.getClusteringResults(result);
      if(clusterings.size() > 0) {
        styleresult.setStylingPolicy(new ClusterStylingPolicy(clusterings.get(0), stylelib));
        result.getHierarchy().add(result, styleresult);
        return styleresult;
      }
      Clustering<Model> c = generateDefaultClustering();
      styleresult.setStylingPolicy(new ClusterStylingPolicy(c, stylelib));
      result.getHierarchy().add(result, styleresult);
      return styleresult;
    }
    return styleresult;
  }

  /**
   * Generate a default (fallback) clustering.
   *
   * @return generated clustering
   */
  private Clustering<Model> generateDefaultClustering() {
    final Database db = ResultUtil.findDatabase(getResult());
    Clustering<Model> c = null;
    try {
      // Try to cluster by labels
      ByLabelHierarchicalClustering split = new ByLabelHierarchicalClustering();
      c = split.run(db);
    }
    catch(NoSupportedDataTypeException e) {
      // Put everything into one
      c = new TrivialAllInOne().run(db);
    }
    return c;
  }

  // TODO: add ShowVisualizer,HideVisualizer with tool semantics.

  /**
   * Get the current selection.
   *
   * @return selection
   */
  public DBIDSelection getSelection() {
    return selection.getSelection();
  }

  /**
   * Set a new selection.
   *
   * @param sel Selection
   */
  public void setSelection(DBIDSelection sel) {
    selection.setSelection(sel);
    getHierarchy().resultChanged(selection);
  }

  /**
   * Change a visualizers visibility.
   *
   * When a Tool visualizer is made visible, other tools are hidden.
   *
   * @param task Visualization task
   * @param visibility new visibility
   *
   * @deprecated Use {@link VisualizerUtil#setVisible}
   */
  @Deprecated
  public void setVisualizationVisibility(VisualizationTask task, boolean visibility) {
    VisualizerUtil.setVisible(this, task, visibility);
  }

  /**
   * Adds a listener for the <code>DataStoreEvent</code> posted after the
   * content changes.
   *
   * @param l the listener to add
   * @see #removeDataStoreListener
   */
  public void addDataStoreListener(DataStoreListener l) {
    listenerList.add(DataStoreListener.class, l);
  }

  /**
   * Removes a listener previously added with <code>addDataStoreListener</code>.
   *
   * @param l the listener to remove
   * @see #addDataStoreListener
   */
  public void removeDataStoreListener(DataStoreListener l) {
    listenerList.remove(DataStoreListener.class, l);
  }

  /**
   * Proxy datastore event to child listeners.
   */
  @Override
  public void contentChanged(DataStoreEvent e) {
    for(DataStoreListener listener : listenerList.getListeners(DataStoreListener.class)) {
      listener.contentChanged(e);
    }
  }

  /**
   * Process a particular result.
   *
   * @param baseResult Base Result
   * @param newResult Newly added Result
   */
  private void processNewResult(HierarchicalResult baseResult, Result newResult) {
    for(ProjectorFactory p : projectors) {
      try {
        p.processNewResult(baseResult, newResult);
      }
      catch(Throwable e) {
        logger.warning("ProjectorFactory " + p.getClass().getCanonicalName() + " failed:", e);
      }
    }
    // Collect all visualizers.
    for(VisFactory f : factories) {
      try {
        f.processNewResult(baseResult, newResult);
      }
      catch(Throwable e) {
        logger.warning("VisFactory " + f.getClass().getCanonicalName() + " failed:", e);
      }
    }
  }

  /**
   * Register a result listener.
   *
   * @param listener Result listener.
   */
  public void addResultListener(ResultListener listener) {
    getHierarchy().addResultListener(listener);
  }

  /**
   * Remove a result listener.
   *
   * @param listener Result listener.
   */
  public void removeResultListener(ResultListener listener) {
    getHierarchy().removeResultListener(listener);
  }

  @Override
  public String getLongName() {
    return "Visualizer context";
  }

  @Override
  public String getShortName() {
    return "vis-context";
  }
}
TOP

Related Classes of de.lmu.ifi.dbs.elki.visualization.VisualizerContext

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.