summaryrefslogtreecommitdiff
path: root/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style
diff options
context:
space:
mode:
Diffstat (limited to 'addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style')
-rw-r--r--addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/ClassStylingPolicy.java74
-rw-r--r--addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/ClusterStylingPolicy.java167
-rw-r--r--addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/PropertiesBasedStyleLibrary.java344
-rw-r--r--addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/SingleObjectsStylingPolicy.java34
-rwxr-xr-xaddons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/StyleLibrary.java277
-rw-r--r--addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/StylingPolicy.java48
-rw-r--r--addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/lines/DashedLineStyleLibrary.java159
-rw-r--r--addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/lines/LineStyleLibrary.java76
-rw-r--r--addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/lines/SolidLineStyleLibrary.java106
-rwxr-xr-xaddons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/lines/package-info.java27
-rw-r--r--addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker/CircleMarkers.java90
-rwxr-xr-xaddons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker/MarkerLibrary.java56
-rwxr-xr-xaddons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker/MinimalMarkers.java90
-rwxr-xr-xaddons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker/PrettyMarkers.java235
-rwxr-xr-xaddons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker/package-info.java27
-rwxr-xr-xaddons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/package-info.java27
16 files changed, 1837 insertions, 0 deletions
diff --git a/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/ClassStylingPolicy.java b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/ClassStylingPolicy.java
new file mode 100644
index 00000000..7bc50182
--- /dev/null
+++ b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/ClassStylingPolicy.java
@@ -0,0 +1,74 @@
+package de.lmu.ifi.dbs.elki.visualization.style;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2015
+ 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 de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
+import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
+
+/**
+ * Styling policy that is based on <em>classes</em>, for example clusters or
+ * labels. This allows for certain optimizations such as marker reuse, and thus
+ * is preferred when possible.
+ *
+ * @author Erich Schubert
+ */
+public interface ClassStylingPolicy extends StylingPolicy {
+ /**
+ * Get the style number for a particular object
+ *
+ * @param id Object ID
+ * @return Style number
+ */
+ int getStyleForDBID(DBIDRef id);
+
+ /**
+ * Get the minimum style in use.
+ *
+ * @return Style number
+ */
+ int getMinStyle();
+
+ /**
+ * Get the maximum style in use.
+ *
+ * @return Style number
+ */
+ int getMaxStyle();
+
+ /**
+ * Iterate over all objects from a given class.
+ *
+ * @param cnum Class number
+ * @return Iterator over object IDs
+ */
+ DBIDIter iterateClass(int cnum);
+
+ /**
+ * Get the number of elements in the styling class.
+ *
+ * @param cnum Class number
+ * @return Size of class.
+ */
+ int classSize(int cnum);
+} \ No newline at end of file
diff --git a/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/ClusterStylingPolicy.java b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/ClusterStylingPolicy.java
new file mode 100644
index 00000000..643f4328
--- /dev/null
+++ b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/ClusterStylingPolicy.java
@@ -0,0 +1,167 @@
+package de.lmu.ifi.dbs.elki.visualization.style;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2015
+ 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 gnu.trove.list.array.TIntArrayList;
+import gnu.trove.map.TObjectIntMap;
+import gnu.trove.map.hash.TObjectIntHashMap;
+
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import de.lmu.ifi.dbs.elki.data.Cluster;
+import de.lmu.ifi.dbs.elki.data.Clustering;
+import de.lmu.ifi.dbs.elki.database.ids.DBIDIter;
+import de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
+import de.lmu.ifi.dbs.elki.database.ids.DBIDUtil;
+import de.lmu.ifi.dbs.elki.database.ids.DBIDs;
+import de.lmu.ifi.dbs.elki.logging.LoggingUtil;
+import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
+import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
+
+/**
+ * Styling policy based on cluster membership.
+ *
+ * @author Erich Schubert
+ *
+ */
+// TODO: fast enough? Some other kind of mapping we can use?
+public class ClusterStylingPolicy implements ClassStylingPolicy {
+ /**
+ * Object IDs
+ */
+ ArrayList<DBIDs> ids;
+
+ /**
+ * Map from cluster objects to color offsets.
+ */
+ TObjectIntMap<Cluster<?>> cmap;
+
+ /**
+ * Colors
+ */
+ TIntArrayList colors;
+
+ /**
+ * Clustering in use.
+ */
+ Clustering<?> clustering;
+
+ /**
+ * Constructor.
+ *
+ * @param clustering Clustering to use.
+ */
+ public ClusterStylingPolicy(Clustering<?> clustering, StyleLibrary style) {
+ super();
+ this.clustering = clustering;
+ ColorLibrary colorset = style.getColorSet(StyleLibrary.PLOT);
+ List<? extends Cluster<?>> clusters = clustering.getAllClusters();
+ ids = new ArrayList<>(clusters.size());
+ colors = new TIntArrayList(clusters.size());
+ cmap = new TObjectIntHashMap<>(clusters.size(), .5f, -1);
+
+ Iterator<? extends Cluster<?>> ci = clusters.iterator();
+ for (int i = 0; ci.hasNext(); i++) {
+ Cluster<?> c = ci.next();
+ ids.add(DBIDUtil.ensureSet(c.getIDs()));
+ cmap.put(c, i);
+ Color col = SVGUtil.stringToColor(colorset.getColor(i));
+ if (col != null) {
+ colors.add(col.getRGB());
+ } else {
+ LoggingUtil.warning("Unrecognized color name: " + colorset.getColor(i));
+ }
+ if (!ci.hasNext()) {
+ break;
+ }
+ }
+ }
+
+ @Override
+ public int getStyleForDBID(DBIDRef id) {
+ for (int i = 0; i < ids.size(); i++) {
+ if (ids.get(i).contains(id)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public int getColorForDBID(DBIDRef id) {
+ for (int i = 0; i < ids.size(); i++) {
+ if (ids.get(i).contains(id)) {
+ return colors.get(i);
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public int getMinStyle() {
+ return 0;
+ }
+
+ @Override
+ public int getMaxStyle() {
+ return ids.size();
+ }
+
+ @Override
+ public DBIDIter iterateClass(int cnum) {
+ return ids.get(cnum).iter();
+ }
+
+ @Override
+ public int classSize(int cnum) {
+ return ids.get(cnum).size();
+ }
+
+ /**
+ * Get the clustering used by this styling policy
+ *
+ * @return Clustering in use
+ */
+ public Clustering<?> getClustering() {
+ return clustering;
+ }
+
+ /**
+ * Get the style number for a cluster.
+ *
+ * @param c Cluster
+ * @return Style number
+ */
+ public int getStyleForCluster(Cluster<?> c) {
+ return cmap.get(c);
+ }
+
+ @Override
+ public String getMenuName() {
+ return clustering.getLongName();
+ }
+}
diff --git a/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/PropertiesBasedStyleLibrary.java b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/PropertiesBasedStyleLibrary.java
new file mode 100644
index 00000000..c8440067
--- /dev/null
+++ b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/PropertiesBasedStyleLibrary.java
@@ -0,0 +1,344 @@
+package de.lmu.ifi.dbs.elki.visualization.style;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2015
+ 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.io.File;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import de.lmu.ifi.dbs.elki.logging.Logging;
+import de.lmu.ifi.dbs.elki.utilities.FileUtil;
+import de.lmu.ifi.dbs.elki.utilities.FormatUtil;
+import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException;
+import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
+import de.lmu.ifi.dbs.elki.visualization.colors.ListBasedColorLibrary;
+import de.lmu.ifi.dbs.elki.visualization.style.lines.LineStyleLibrary;
+import de.lmu.ifi.dbs.elki.visualization.style.lines.SolidLineStyleLibrary;
+import de.lmu.ifi.dbs.elki.visualization.style.marker.MarkerLibrary;
+import de.lmu.ifi.dbs.elki.visualization.style.marker.PrettyMarkers;
+
+/**
+ * Style library loading the parameters from a properties file.
+ *
+ * @author Erich Schubert
+ */
+// TODO: also use Caching for String values?
+public class PropertiesBasedStyleLibrary implements StyleLibrary {
+ /**
+ * Logger
+ */
+ private static final Logging LOG = Logging.getLogger(PropertiesBasedStyleLibrary.class);
+
+ /**
+ * Name of the default color scheme.
+ */
+ public static final String DEFAULT_SCHEME_NAME = "Default";
+
+ /**
+ * File name of the default color scheme.
+ */
+ public static final String DEFAULT_SCHEME_FILENAME = "default";
+
+ /**
+ * File extension
+ */
+ public static final String DEFAULT_PROPERTIES_EXTENSION = ".properties";
+
+ /**
+ * Default properties path
+ */
+ private static final String DEFAULT_PROPERTIES_PATH = PropertiesBasedStyleLibrary.class.getPackage().getName().replace('.', File.separatorChar) + File.separatorChar;
+
+ /**
+ * Separator for lists.
+ */
+ public static final String LIST_SEPARATOR = ",";
+
+ /**
+ * Property string for the line style library
+ */
+ public static final String PROP_LINES_LIBRARY = "lines-library";
+
+ /**
+ * Property string for the marker style library
+ */
+ public static final String PROP_MARKER_LIBRARY = "marker-library";
+
+ /**
+ * Properties file to use.
+ */
+ private Properties properties;
+
+ /**
+ * Style scheme name
+ */
+ private String name;
+
+ /**
+ * Cache
+ */
+ private Map<String, Object> cache = new HashMap<>();
+
+ /**
+ * Line style library to use
+ */
+ private LineStyleLibrary linelib = null;
+
+ /**
+ * Marker library to use
+ */
+ private MarkerLibrary markerlib = null;
+
+ /**
+ * Constructor without a properties file name.
+ */
+ public PropertiesBasedStyleLibrary() {
+ this(DEFAULT_SCHEME_FILENAME, DEFAULT_SCHEME_NAME);
+ }
+
+ /**
+ * Constructor with a given file name.
+ *
+ * @param filename Name of properties file.
+ * @param name NAme for this style
+ */
+ public PropertiesBasedStyleLibrary(String filename, String name) {
+ this.properties = new Properties();
+ this.name = name;
+ InputStream stream = null;
+ try {
+ stream = FileUtil.openSystemFile(filename);
+ } catch (FileNotFoundException e) {
+ try {
+ stream = FileUtil.openSystemFile(filename + DEFAULT_PROPERTIES_EXTENSION);
+ } catch (FileNotFoundException e2) {
+ try {
+ stream = FileUtil.openSystemFile(DEFAULT_PROPERTIES_PATH + filename + DEFAULT_PROPERTIES_EXTENSION);
+ } catch (FileNotFoundException e3) {
+ throw new AbortException("Could not find style scheme file '" + filename + "' for scheme '" + name + "'!");
+ }
+ }
+ }
+ try {
+ properties.load(stream);
+ } catch (Exception e) {
+ throw new AbortException("Error loading properties file " + filename + ".\n", e);
+ }
+ }
+
+ /**
+ * Get the style scheme name.
+ *
+ * @return the name
+ */
+ protected String getName() {
+ return name;
+ }
+
+ /**
+ * Get a value from the cache (to avoid repeated parsing)
+ *
+ * @param <T> Type
+ * @param prefix Tree name
+ * @param postfix Property name
+ * @param cls Class restriction
+ * @return Resulting value
+ */
+ private <T> T getCached(String prefix, String postfix, Class<T> cls) {
+ return cls.cast(cache.get(prefix + '.' + postfix));
+ }
+
+ /**
+ * Set a cache value
+ *
+ * @param <T> Type
+ * @param prefix Tree name
+ * @param postfix Property name
+ * @param data Data
+ */
+ private <T> void setCached(String prefix, String postfix, T data) {
+ cache.put(prefix + '.' + postfix, data);
+ }
+
+ /**
+ * Retrieve the property value for a particular path + type pair.
+ *
+ * @param prefix Path
+ * @param postfix Type
+ * @return Value
+ */
+ protected String getPropertyValue(String prefix, String postfix) {
+ String ret = properties.getProperty(prefix + "." + postfix);
+ if (ret != null) {
+ // logger.debugFine("Found property: "+prefix + "." +
+ // postfix+" for "+prefix);
+ return ret;
+ }
+ int pos = prefix.length();
+ while (pos > 0) {
+ pos = prefix.lastIndexOf('.', pos - 1);
+ if (pos <= 0) {
+ break;
+ }
+ ret = properties.getProperty(prefix.substring(0, pos) + '.' + postfix);
+ if (ret != null) {
+ // logger.debugFine("Found property: "+prefix.substring(0, pos) + "." +
+ // postfix+" for "+prefix);
+ return ret;
+ }
+ }
+ ret = properties.getProperty(postfix);
+ if (ret != null) {
+ // logger.debugFine("Found property: "+postfix+" for "+prefix);
+ return ret;
+ }
+ return null;
+ }
+
+ @Override
+ public String getColor(String key) {
+ return getPropertyValue(key, COLOR);
+ }
+
+ @Override
+ public String getBackgroundColor(String key) {
+ return getPropertyValue(key, BACKGROUND_COLOR);
+ }
+
+ @Override
+ public String getTextColor(String key) {
+ return getPropertyValue(key, TEXT_COLOR);
+ }
+
+ @Override
+ public ColorLibrary getColorSet(String key) {
+ ColorLibrary cl = getCached(key, COLORSET, ColorLibrary.class);
+ if (cl == null) {
+ String[] colors = getPropertyValue(key, COLORSET).split(LIST_SEPARATOR);
+ cl = new ListBasedColorLibrary(colors, "Default");
+ setCached(key, COLORSET, cl);
+ }
+ return cl;
+ }
+
+ @Override
+ public double getLineWidth(String key) {
+ Double lw = getCached(key, LINE_WIDTH, Double.class);
+ if (lw == null) {
+ try {
+ lw = Double.valueOf(FormatUtil.parseDouble(getPropertyValue(key, LINE_WIDTH)) * SCALE);
+ } catch (NullPointerException e) {
+ throw new AbortException("Missing/invalid value in style library: " + key + '.' + LINE_WIDTH);
+ }
+ }
+ return lw.doubleValue();
+ }
+
+ @Override
+ public double getTextSize(String key) {
+ Double lw = getCached(key, TEXT_SIZE, Double.class);
+ if (lw == null) {
+ try {
+ lw = Double.valueOf(FormatUtil.parseDouble(getPropertyValue(key, TEXT_SIZE)) * SCALE);
+ } catch (NullPointerException e) {
+ throw new AbortException("Missing/invalid value in style library: " + key + '.' + TEXT_SIZE);
+ }
+ }
+ return lw.doubleValue();
+ }
+
+ @Override
+ public String getFontFamily(String key) {
+ return getPropertyValue(key, FONT_FAMILY);
+ }
+
+ @Override
+ public double getSize(String key) {
+ Double lw = getCached(key, GENERIC_SIZE, Double.class);
+ if (lw == null) {
+ try {
+ lw = Double.valueOf(FormatUtil.parseDouble(getPropertyValue(key, GENERIC_SIZE)) * SCALE);
+ } catch (NullPointerException e) {
+ throw new AbortException("Missing/invalid value in style library: " + key + '.' + GENERIC_SIZE);
+ }
+ }
+ return lw.doubleValue();
+ }
+
+ @Override
+ public double getOpacity(String key) {
+ Double lw = getCached(key, OPACITY, Double.class);
+ if (lw == null) {
+ try {
+ lw = Double.valueOf(FormatUtil.parseDouble(getPropertyValue(key, OPACITY)));
+ } catch (NullPointerException e) {
+ throw new AbortException("Missing/invalid value in style library: " + key + '.' + OPACITY);
+ }
+ }
+ return lw.doubleValue();
+ }
+
+ @Override
+ public LineStyleLibrary lines() {
+ if (linelib == null) {
+ String libname = properties.getProperty(PROP_LINES_LIBRARY, SolidLineStyleLibrary.class.getName());
+ try {
+ Class<?> cls;
+ try {
+ cls = Class.forName(libname);
+ } catch (ClassNotFoundException e) {
+ cls = Class.forName(LineStyleLibrary.class.getPackage().getName() + '.' + libname);
+ }
+ linelib = (LineStyleLibrary) cls.getConstructor(StyleLibrary.class).newInstance(this);
+ } catch (Exception e) {
+ LOG.exception(e);
+ linelib = new SolidLineStyleLibrary(this);
+ }
+ }
+ return linelib;
+ }
+
+ @Override
+ public MarkerLibrary markers() {
+ if (markerlib == null) {
+ String libname = properties.getProperty(PROP_MARKER_LIBRARY, PrettyMarkers.class.getName());
+ try {
+ Class<?> cls;
+ try {
+ cls = Class.forName(libname);
+ } catch (ClassNotFoundException e) {
+ cls = Class.forName(MarkerLibrary.class.getPackage().getName() + '.' + libname);
+ }
+ markerlib = (MarkerLibrary) cls.getConstructor(StyleLibrary.class).newInstance(this);
+ } catch (Exception e) {
+ LOG.exception(e);
+ markerlib = new PrettyMarkers(this);
+ }
+ }
+ return markerlib;
+ }
+}
diff --git a/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/SingleObjectsStylingPolicy.java b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/SingleObjectsStylingPolicy.java
new file mode 100644
index 00000000..0e26bf80
--- /dev/null
+++ b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/SingleObjectsStylingPolicy.java
@@ -0,0 +1,34 @@
+package de.lmu.ifi.dbs.elki.visualization.style;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2015
+ 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/>.
+ */
+
+/**
+ * Styling policy based on assigning objects individual colors.
+ *
+ * @author Erich Schubert
+ */
+public interface SingleObjectsStylingPolicy extends StylingPolicy {
+ // TODO: finish and use, e.g. for outliers and density visualization
+ // TODO: do we need anything here beyond "not a class styling policy"?
+}
diff --git a/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/StyleLibrary.java b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/StyleLibrary.java
new file mode 100755
index 00000000..5ca93be6
--- /dev/null
+++ b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/StyleLibrary.java
@@ -0,0 +1,277 @@
+package de.lmu.ifi.dbs.elki.visualization.style;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2015
+ 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 de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
+import de.lmu.ifi.dbs.elki.visualization.style.lines.LineStyleLibrary;
+import de.lmu.ifi.dbs.elki.visualization.style.marker.MarkerLibrary;
+
+/**
+ * Style library interface. A style library allows the user to customize the
+ * visual rendering, for example for print media or screen presentation without
+ * having to change program code.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.composedOf ColorLibrary
+ * @apiviz.composedOf LineStyleLibrary
+ * @apiviz.composedOf MarkerLibrary
+ */
+public interface StyleLibrary {
+ /**
+ * Default
+ */
+ final static String DEFAULT = "";
+
+ /**
+ * Page
+ */
+ final static String PAGE = "page";
+
+ /**
+ * Plot
+ */
+ final static String PLOT = "plot";
+
+ /**
+ * Axis
+ */
+ final static String AXIS = "axis";
+
+ /**
+ * Axis tick
+ */
+ final static String AXIS_TICK = "axis.tick";
+
+ /**
+ * Axis minor tick
+ */
+ final static String AXIS_TICK_MINOR = "axis.tick.minor";
+
+ /**
+ * Axis label
+ */
+ final static String AXIS_LABEL = "axis.label";
+
+ /**
+ * Key
+ */
+ final static String KEY = "key";
+
+ /**
+ * Clusterorder
+ */
+ final static String CLUSTERORDER = "plot.clusterorder";
+
+ /**
+ * Margin
+ */
+ final static String MARGIN = "margin";
+
+ /**
+ * Bubble size
+ */
+ final static String BUBBLEPLOT = "plot.bubble";
+
+ /**
+ * Marker size
+ */
+ final static String MARKERPLOT = "plot.marker";
+
+ /**
+ * Dot size
+ */
+ final static String DOTPLOT = "plot.dot";
+
+ /**
+ * Grayed out objects
+ */
+ final static String PLOTGREY = "plot.grey";
+
+ /**
+ * Reference points color and size
+ */
+ final static String REFERENCE_POINTS = "plot.referencepoints";
+
+ /**
+ * Polygons style
+ */
+ final static String POLYGONS = "plot.polygons";
+
+ /**
+ * Selection color and opacity
+ */
+ final static String SELECTION = "plot.selection";
+
+ /**
+ * Selection color and opacity during selecting process
+ */
+ final static String SELECTION_ACTIVE = "plot.selection.active";
+
+ /**
+ * Scaling constant. Keep in sync with
+ * {@link de.lmu.ifi.dbs.elki.visualization.projections.Projection#SCALE}
+ */
+ public static final double SCALE = 100.0;
+
+ /* ** Property types ** */
+ /**
+ * Color
+ */
+ final static String COLOR = "color";
+
+ /**
+ * Background color
+ */
+ final static String BACKGROUND_COLOR = "background-color";
+
+ /**
+ * Text color
+ */
+ final static String TEXT_COLOR = "text-color";
+
+ /**
+ * Color set
+ */
+ final static String COLORSET = "colorset";
+
+ /**
+ * Line width
+ */
+ final static String LINE_WIDTH = "line-width";
+
+ /**
+ * Text size
+ */
+ final static String TEXT_SIZE = "text-size";
+
+ /**
+ * Font family
+ */
+ final static String FONT_FAMILY = "font-family";
+
+ /**
+ * Generic size
+ */
+ final static String GENERIC_SIZE = "size";
+
+ /**
+ * Opacity (transparency)
+ */
+ final static String OPACITY = "opacity";
+
+ /**
+ * XY curve styling.
+ */
+ static final String XYCURVE = "xycurve";
+
+ /**
+ * Retrieve a color for an item
+ *
+ * @param name Reference name
+ * @return color in CSS/SVG valid format: hexadecimal (#aabbcc) or names such
+ * as "red"
+ */
+ public String getColor(String name);
+
+ /**
+ * Retrieve background color for an item
+ *
+ * @param name Reference name
+ * @return color in CSS/SVG valid format: hexadecimal (#aabbcc) or names such
+ * as "red"
+ */
+ public String getBackgroundColor(String name);
+
+ /**
+ * Retrieve text color for an item
+ *
+ * @param name Reference name
+ * @return color in CSS/SVG valid format: hexadecimal (#aabbcc) or names such
+ * as "red"
+ */
+ public String getTextColor(String name);
+
+ /**
+ * Retrieve colorset for an item
+ *
+ * @param name Reference name
+ * @return color library
+ */
+ public ColorLibrary getColorSet(String name);
+
+ /**
+ * Get line width
+ *
+ * @param key Key
+ * @return line width as double
+ */
+ public double getLineWidth(String key);
+
+ /**
+ * Get generic size
+ *
+ * @param key Key
+ * @return size as double
+ */
+ public double getSize(String key);
+
+ /**
+ * Get text size
+ *
+ * @param key Key
+ * @return line width as double
+ */
+ public double getTextSize(String key);
+
+ /**
+ * Get font family
+ *
+ * @param key Key
+ * @return font family CSS string
+ */
+ public String getFontFamily(String key);
+
+ /**
+ * Get opacity
+ *
+ * @param key Key
+ * @return size as double
+ */
+ public double getOpacity(String key);
+
+ /**
+ * Get the line style library to use.
+ *
+ * @return line style library
+ */
+ public LineStyleLibrary lines();
+
+ /**
+ * Get the marker library to use.
+ *
+ * @return marker library
+ */
+ public MarkerLibrary markers();
+} \ No newline at end of file
diff --git a/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/StylingPolicy.java b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/StylingPolicy.java
new file mode 100644
index 00000000..406b6aff
--- /dev/null
+++ b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/StylingPolicy.java
@@ -0,0 +1,48 @@
+package de.lmu.ifi.dbs.elki.visualization.style;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2015
+ 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 de.lmu.ifi.dbs.elki.database.ids.DBIDRef;
+import de.lmu.ifi.dbs.elki.visualization.VisualizationItem;
+
+/**
+ * Styling policy.
+ *
+ * Implementations <em>must</em> implement either {@link ClassStylingPolicy} or
+ * {@link SingleObjectsStylingPolicy} interfaces, as most visualizers will only
+ * support these known interfaces.
+ *
+ * @author Erich Schubert
+ */
+public interface StylingPolicy extends VisualizationItem {
+ /**
+ * Get the color for an individual object.
+ *
+ * Note: if possible, use a class styling policy which can optimize better.
+ *
+ * @param id Object ID
+ * @return Color value
+ */
+ public int getColorForDBID(DBIDRef id);
+}
diff --git a/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/lines/DashedLineStyleLibrary.java b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/lines/DashedLineStyleLibrary.java
new file mode 100644
index 00000000..49b8cc91
--- /dev/null
+++ b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/lines/DashedLineStyleLibrary.java
@@ -0,0 +1,159 @@
+package de.lmu.ifi.dbs.elki.visualization.style.lines;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2015
+ 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 org.apache.batik.util.CSSConstants;
+
+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.style.StyleLibrary;
+import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
+
+/**
+ * Line library using various dashed and dotted line styles.
+ *
+ * This library is particularly useful for black and white output.
+ *
+ * {@link LineStyleLibrary#FLAG_STRONG} will result in thicker lines.
+ *
+ * {@link LineStyleLibrary#FLAG_WEAK} will result in thinner and
+ * semi-transparent lines.
+ *
+ * {@link LineStyleLibrary#FLAG_INTERPOLATED} will result in shorter dashing
+ * patterns.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.composedOf ColorLibrary
+ */
+public class DashedLineStyleLibrary implements LineStyleLibrary {
+ /**
+ * The style library we use for colors
+ */
+ private ColorLibrary colors;
+
+ /** Dash patterns to regularly use */
+ private double[][] dashpatterns = {
+ // solid, no dashing
+ {},
+ // half-half
+ { .5, .5 },
+ // quarters
+ { .25, .25, .25, .25 },
+ // alternating long-quart
+ { .75, .25 },
+ // dash-dot
+ { .7, .1, .1, .1 }, };
+
+ /** Replacement for the solid pattern in 'interpolated' mode */
+ private double[] solidreplacement = { .1, .1 };
+
+ private int dashnum = dashpatterns.length;
+
+ /**
+ * Color of "uncolored" dots
+ */
+ private String dotcolor;
+
+ /**
+ * Color of "greyed out" dots
+ */
+ private String greycolor;
+
+ /**
+ * Constructor
+ *
+ * @param style Style library
+ */
+ public DashedLineStyleLibrary(StyleLibrary style) {
+ super();
+ this.colors = style.getColorSet(StyleLibrary.PLOT);
+ this.dotcolor = style.getColor(StyleLibrary.MARKERPLOT);
+ this.greycolor = style.getColor(StyleLibrary.PLOTGREY);
+ }
+
+ @Override
+ public void formatCSSClass(CSSClass cls, int style, double width, Object... flags) {
+ if(style == -2) {
+ cls.setStatement(CSSConstants.CSS_STROKE_PROPERTY, greycolor);
+ }
+ else if(style == -1) {
+ cls.setStatement(CSSConstants.CSS_STROKE_PROPERTY, dotcolor);
+ }
+ else {
+ cls.setStatement(CSSConstants.CSS_STROKE_PROPERTY, colors.getColor(style));
+ }
+ boolean interpolated = false;
+ // process flavoring flags
+ for(Object flag : flags) {
+ if(LineStyleLibrary.FLAG_STRONG.equals(flag)) {
+ width = width * 1.5;
+ }
+ else if(LineStyleLibrary.FLAG_WEAK.equals(flag)) {
+ cls.setStatement(CSSConstants.CSS_STROKE_OPACITY_PROPERTY, ".50");
+ width = width * 0.75;
+ }
+ else if(LineStyleLibrary.FLAG_INTERPOLATED.equals(flag)) {
+ interpolated = true;
+ }
+ }
+ cls.setStatement(CSSConstants.CSS_STROKE_WIDTH_PROPERTY, SVGUtil.fmt(width));
+ // handle dashing
+ int styleflav = (style > 0) ? (style % dashnum) : (-style % dashnum);
+ if(!interpolated) {
+ double[] pat = dashpatterns[styleflav];
+ assert (pat.length % 2 == 0);
+ if(pat.length > 0) {
+ StringBuilder pattern = new StringBuilder();
+ for(int i = 0; i < pat.length; i++) {
+ if(i > 0) {
+ pattern.append(',');
+ }
+ pattern.append(SVGUtil.fmt(pat[i] * width * 30));
+ // pattern.append("%");
+ }
+ cls.setStatement(CSSConstants.CSS_STROKE_DASHARRAY_PROPERTY, pattern.toString());
+ }
+ }
+ else {
+ double[] pat = dashpatterns[styleflav];
+ if(styleflav == 0) {
+ pat = solidreplacement;
+ }
+ assert (pat.length % 2 == 0);
+ // TODO: add dotting.
+ if(pat.length > 0) {
+ StringBuilder pattern = new StringBuilder();
+ for(int i = 0; i < pat.length; i++) {
+ if(i > 0) {
+ pattern.append(',');
+ }
+ pattern.append(SVGUtil.fmt(pat[i] * width));
+ // pattern.append("%");
+ }
+ cls.setStatement(CSSConstants.CSS_STROKE_DASHARRAY_PROPERTY, pattern.toString());
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/lines/LineStyleLibrary.java b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/lines/LineStyleLibrary.java
new file mode 100644
index 00000000..48212f16
--- /dev/null
+++ b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/lines/LineStyleLibrary.java
@@ -0,0 +1,76 @@
+package de.lmu.ifi.dbs.elki.visualization.style.lines;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2015
+ 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 de.lmu.ifi.dbs.elki.visualization.css.CSSClass;
+
+/**
+ * Interface to obtain CSS classes for plot lines.
+ *
+ * {@code meta} is a set of Objects, usually constants that may or may not be
+ * used by the {@link LineStyleLibrary} to generate variants of the style.
+ *
+ * Predefined meta flags that are usually supported are:
+ * <dl>
+ * <dt>{@link #FLAG_STRONG}</dt>
+ * <dd>Request a "stronger" version of the same style</dd>
+ * <dt>{@link #FLAG_WEAK}</dt>
+ * <dd>Request a "weaker" version of the same style</dd>
+ * <dt>{@link #FLAG_INTERPOLATED}</dt>
+ * <dd>Request an "interpolated" version of the same style (e.g. lighter or
+ * dashed)</dd>
+ * </dl>
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.uses CSSClass oneway
+ */
+public interface LineStyleLibrary {
+ /**
+ * Meta flag to request a 'stronger' version of the style
+ */
+ public static final String FLAG_STRONG = "strong";
+
+ /**
+ * Meta flag to request a 'weaker' version of the style
+ */
+ public static final String FLAG_WEAK = "weak";
+
+ /**
+ * Meta flag to request an 'interpolated' version of the style
+ */
+ public static final String FLAG_INTERPOLATED = "interpolated";
+
+ /**
+ * Add the formatting statements to the given CSS class.
+ *
+ * Note: this can overwrite some existing properties of the CSS class.
+ *
+ * @param cls CSS class to modify
+ * @param style style number
+ * @param width line width
+ * @param meta meta objects to request line variants
+ */
+ public void formatCSSClass(CSSClass cls, int style, double width, Object... meta);
+}
diff --git a/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/lines/SolidLineStyleLibrary.java b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/lines/SolidLineStyleLibrary.java
new file mode 100644
index 00000000..61765f1a
--- /dev/null
+++ b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/lines/SolidLineStyleLibrary.java
@@ -0,0 +1,106 @@
+package de.lmu.ifi.dbs.elki.visualization.style.lines;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2015
+ 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 org.apache.batik.util.CSSConstants;
+
+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.style.StyleLibrary;
+import de.lmu.ifi.dbs.elki.visualization.svg.SVGUtil;
+
+/**
+ * Line style library featuring solid lines for default styles only (combine
+ * with a color library to obtain enough classes!)
+ *
+ * {@link LineStyleLibrary#FLAG_STRONG} will result in thicker lines.
+ *
+ * {@link LineStyleLibrary#FLAG_WEAK} will result in thinner and
+ * semi-transparent lines.
+ *
+ * {@link LineStyleLibrary#FLAG_INTERPOLATED} will result in dashed lines.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.composedOf ColorLibrary
+ */
+public class SolidLineStyleLibrary implements LineStyleLibrary {
+ /**
+ * Reference to the color library.
+ */
+ private ColorLibrary colors;
+
+ /**
+ * Color of "uncolored" dots
+ */
+ private String dotcolor;
+
+ /**
+ * Color of "greyed out" dots
+ */
+ private String greycolor;
+
+ /**
+ * Constructor.
+ *
+ * @param style Style library to use.
+ */
+ public SolidLineStyleLibrary(StyleLibrary style) {
+ super();
+ this.colors = style.getColorSet(StyleLibrary.PLOT);
+ this.dotcolor = style.getColor(StyleLibrary.MARKERPLOT);
+ this.greycolor = style.getColor(StyleLibrary.PLOTGREY);
+ }
+
+ @Override
+ public void formatCSSClass(CSSClass cls, int style, double width, Object... flags) {
+ if(style == -2) {
+ cls.setStatement(CSSConstants.CSS_STROKE_PROPERTY, greycolor);
+ }
+ else if(style == -1) {
+ cls.setStatement(CSSConstants.CSS_STROKE_PROPERTY, dotcolor);
+ }
+ else {
+ cls.setStatement(CSSConstants.CSS_STROKE_PROPERTY, colors.getColor(style));
+ }
+ boolean interpolated = false;
+ // process flavoring flags
+ for(Object flag : flags) {
+ if(LineStyleLibrary.FLAG_STRONG.equals(flag)) {
+ width = width * 1.5;
+ }
+ else if(LineStyleLibrary.FLAG_WEAK.equals(flag)) {
+ cls.setStatement(CSSConstants.CSS_STROKE_OPACITY_PROPERTY, ".50");
+ width = width * 0.75;
+ }
+ else if(LineStyleLibrary.FLAG_INTERPOLATED.equals(flag)) {
+ interpolated = true;
+ }
+ }
+ cls.setStatement(CSSConstants.CSS_STROKE_WIDTH_PROPERTY, SVGUtil.fmt(width));
+ if(interpolated) {
+ cls.setStatement(CSSConstants.CSS_STROKE_DASHARRAY_PROPERTY, "" + SVGUtil.fmt(width / StyleLibrary.SCALE * 2.) + "," + SVGUtil.fmt(width / StyleLibrary.SCALE * 2.));
+ }
+ }
+}
diff --git a/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/lines/package-info.java b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/lines/package-info.java
new file mode 100755
index 00000000..69790fdf
--- /dev/null
+++ b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/lines/package-info.java
@@ -0,0 +1,27 @@
+/**
+ * <p>Generate line styles for plotting in CSS</p>
+ *
+ */
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2015
+ 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/>.
+ */
+package de.lmu.ifi.dbs.elki.visualization.style.lines; \ No newline at end of file
diff --git a/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker/CircleMarkers.java b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker/CircleMarkers.java
new file mode 100644
index 00000000..c4078091
--- /dev/null
+++ b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker/CircleMarkers.java
@@ -0,0 +1,90 @@
+package de.lmu.ifi.dbs.elki.visualization.style.marker;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2015
+ 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 org.apache.batik.util.SVGConstants;
+import org.w3c.dom.Element;
+
+import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
+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.svg.SVGUtil;
+
+/**
+ * Simple marker library that just draws colored circles at the given
+ * coordinates.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.composedOf ColorLibrary
+ */
+public class CircleMarkers implements MarkerLibrary {
+ /**
+ * Color library
+ */
+ private ColorLibrary colors;
+
+ /**
+ * Color of "uncolored" dots
+ */
+ private String dotcolor = "black";
+
+ /**
+ * Color of "greyed out" dots
+ */
+ private String greycolor = "gray";
+
+ /**
+ * Constructor
+ *
+ * @param style Style library to use
+ */
+ public CircleMarkers(StyleLibrary style) {
+ super();
+ this.colors = style.getColorSet(StyleLibrary.MARKERPLOT);
+ this.dotcolor = style.getColor(StyleLibrary.MARKERPLOT);
+ this.greycolor = style.getColor(StyleLibrary.PLOTGREY);
+ }
+
+ /**
+ * Use a given marker on the document.
+ */
+ @Override
+ public Element useMarker(SVGPlot plot, Element parent, double x, double y, int stylenr, double size) {
+ Element marker = plot.svgCircle(x, y, size * .5);
+ final String col;
+ if(stylenr == -1) {
+ col = dotcolor;
+ }
+ else if(stylenr == -2) {
+ col = greycolor;
+ }
+ else {
+ col = colors.getColor(stylenr);
+ }
+ SVGUtil.setStyle(marker, SVGConstants.CSS_FILL_PROPERTY + ":" + col);
+ parent.appendChild(marker);
+ return marker;
+ }
+} \ No newline at end of file
diff --git a/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker/MarkerLibrary.java b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker/MarkerLibrary.java
new file mode 100755
index 00000000..522097aa
--- /dev/null
+++ b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker/MarkerLibrary.java
@@ -0,0 +1,56 @@
+package de.lmu.ifi.dbs.elki.visualization.style.marker;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2015
+ 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 org.w3c.dom.Element;
+
+import de.lmu.ifi.dbs.elki.visualization.svg.SVGPlot;
+
+/**
+ * A marker library is a class that can generate and draw various styles of
+ * markers. Different uses might require different marker libraries (e.g. full
+ * screen, thumbnail, print)
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.uses Element oneway - - «create»
+ */
+public interface MarkerLibrary {
+ /**
+ * Insert a marker at the given coordinates. Markers will be defined in the
+ * defs part of the document, and then SVG-"use"d at the given coordinates.
+ * This supposedly is more efficient and significantly reduces file size.
+ * Symbols will be named "s0", "s1" etc.; these names must not be used by
+ * other elements in the SVG document!
+ *
+ * @param plot Plot to draw on
+ * @param parent parent node
+ * @param x coordinate
+ * @param y coordinate
+ * @param style style (enumerated)
+ * @param size size
+ * @return Element node generated.
+ */
+ public Element useMarker(SVGPlot plot, Element parent, double x, double y, int style, double size);
+} \ No newline at end of file
diff --git a/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker/MinimalMarkers.java b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker/MinimalMarkers.java
new file mode 100755
index 00000000..a3390a6d
--- /dev/null
+++ b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker/MinimalMarkers.java
@@ -0,0 +1,90 @@
+package de.lmu.ifi.dbs.elki.visualization.style.marker;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2015
+ 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 org.apache.batik.util.SVGConstants;
+import org.w3c.dom.Element;
+
+import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
+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.svg.SVGUtil;
+
+/**
+ * Simple marker library that just draws colored rectangles at the given
+ * coordinates.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.composedOf ColorLibrary
+ */
+public class MinimalMarkers implements MarkerLibrary {
+ /**
+ * Color library
+ */
+ private ColorLibrary colors;
+
+ /**
+ * Color of "uncolored" dots
+ */
+ private String dotcolor = "black";
+
+ /**
+ * Color of "greyed out" dots
+ */
+ private String greycolor = "gray";
+
+ /**
+ * Constructor
+ *
+ * @param style Style library to use
+ */
+ public MinimalMarkers(StyleLibrary style) {
+ super();
+ this.colors = style.getColorSet(StyleLibrary.MARKERPLOT);
+ this.dotcolor = style.getColor(StyleLibrary.MARKERPLOT);
+ this.greycolor = style.getColor(StyleLibrary.PLOTGREY);
+ }
+
+ /**
+ * Use a given marker on the document.
+ */
+ @Override
+ public Element useMarker(SVGPlot plot, Element parent, double x, double y, int stylenr, double size) {
+ Element marker = plot.svgRect(x - size * .5, y - size * .5, size, size);
+ final String col;
+ if(stylenr == -1) {
+ col = dotcolor;
+ }
+ else if(stylenr == -2) {
+ col = greycolor;
+ }
+ else {
+ col = colors.getColor(stylenr);
+ }
+ SVGUtil.setStyle(marker, SVGConstants.CSS_FILL_PROPERTY + ":" + col);
+ parent.appendChild(marker);
+ return marker;
+ }
+} \ No newline at end of file
diff --git a/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker/PrettyMarkers.java b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker/PrettyMarkers.java
new file mode 100755
index 00000000..be99c6b1
--- /dev/null
+++ b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker/PrettyMarkers.java
@@ -0,0 +1,235 @@
+package de.lmu.ifi.dbs.elki.visualization.style.marker;
+
+/*
+ This file is part of ELKI:
+ Environment for Developing KDD-Applications Supported by Index-Structures
+
+ Copyright (C) 2015
+ 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 org.apache.batik.util.SVGConstants;
+import org.w3c.dom.Element;
+
+import de.lmu.ifi.dbs.elki.visualization.colors.ColorLibrary;
+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.svg.SVGUtil;
+
+/**
+ * Marker library achieving a larger number of styles by combining different
+ * shapes with different colors. Uses object ID management by SVGPlot.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.composedOf ColorLibrary
+ */
+public class PrettyMarkers implements MarkerLibrary {
+ /**
+ * Color library
+ */
+ private ColorLibrary colors;
+
+ /**
+ * Default prefix to use.
+ */
+ private static final String DEFAULT_PREFIX = "s";
+
+ /**
+ * Prefix for the IDs generated.
+ */
+ private String prefix;
+
+ /**
+ * Color of "uncolored" dots
+ */
+ private String dotcolor;
+
+ /**
+ * Color of "greyed out" dots
+ */
+ private String greycolor;
+
+ /**
+ * Constructor
+ *
+ * @param prefix prefix to use.
+ * @param style style library to use
+ */
+ public PrettyMarkers(String prefix, StyleLibrary style) {
+ this.prefix = prefix;
+ this.colors = style.getColorSet(StyleLibrary.MARKERPLOT);
+ this.dotcolor = style.getColor(StyleLibrary.MARKERPLOT);
+ this.greycolor = style.getColor(StyleLibrary.PLOTGREY);
+ }
+
+ /**
+ * Constructor without prefix argument, will use {@link #DEFAULT_PREFIX} as
+ * prefix.
+ *
+ * @param style Style library to use
+ */
+ public PrettyMarkers(StyleLibrary style) {
+ this(DEFAULT_PREFIX, style);
+ }
+
+ /**
+ * Draw an marker used in scatter plots. If you intend to use the markers
+ * multiple times, you should consider using the {@link #useMarker} method
+ * instead, which exploits the SVG features of symbol definition and use
+ *
+ * @param plot containing plot
+ * @param parent parent node
+ * @param x position
+ * @param y position
+ * @param style marker style (enumerated)
+ * @param size size
+ */
+ public void plotMarker(SVGPlot plot, Element parent, double x, double y, int style, double size) {
+ assert (parent != null);
+ if (style == -1) {
+ plotUncolored(plot, parent, x, y, size);
+ return;
+ }
+ if (style == -2) {
+ plotGray(plot, parent, x, y, size);
+ return;
+ }
+ // TODO: add more styles.
+ String colorstr = colors.getColor(style);
+ String strokestyle = SVGConstants.CSS_STROKE_PROPERTY + ":" + colorstr + ";" + SVGConstants.CSS_STROKE_WIDTH_PROPERTY + ":" + SVGUtil.fmt(size / 6);
+
+ switch(style % 8){
+ case 0: {
+ // + cross
+ Element line1 = plot.svgLine(x, y - size / 2.2, x, y + size / 2.2);
+ SVGUtil.setStyle(line1, strokestyle);
+ parent.appendChild(line1);
+ Element line2 = plot.svgLine(x - size / 2.2, y, x + size / 2.2, y);
+ SVGUtil.setStyle(line2, strokestyle);
+ parent.appendChild(line2);
+ break;
+ }
+ case 1: {
+ // X cross
+ Element line1 = plot.svgLine(x - size / 2.828427, y - size / 2.828427, x + size / 2.828427, y + size / 2.828427);
+ SVGUtil.setStyle(line1, strokestyle);
+ parent.appendChild(line1);
+ Element line2 = plot.svgLine(x - size / 2.828427, y + size / 2.828427, x + size / 2.828427, y - size / 2.828427);
+ SVGUtil.setStyle(line2, strokestyle);
+ parent.appendChild(line2);
+ break;
+ }
+ case 2: {
+ // O hollow circle
+ Element circ = plot.svgCircle(x, y, size / 2.2);
+ SVGUtil.setStyle(circ, "fill: none;" + strokestyle);
+ parent.appendChild(circ);
+ break;
+ }
+ case 3: {
+ // [] hollow rectangle
+ Element rect = plot.svgRect(x - size / 2.4, y - size / 2.4, size / 1.2, size / 1.2);
+ SVGUtil.setStyle(rect, "fill: none;" + strokestyle);
+ parent.appendChild(rect);
+ break;
+ }
+ case 4: {
+ // <> hollow diamond
+ Element rect = plot.svgRect(x - size / 2.7, y - size / 2.7, size / 1.35, size / 1.35);
+ SVGUtil.setStyle(rect, "fill: none;" + strokestyle);
+ SVGUtil.setAtt(rect, SVGConstants.SVG_TRANSFORM_ATTRIBUTE, "rotate(45," + SVGUtil.fmt(x) + "," + SVGUtil.fmt(y) + ")");
+ parent.appendChild(rect);
+ break;
+ }
+ case 5: {
+ // O filled circle
+ Element circ = plot.svgCircle(x, y, size * .5);
+ SVGUtil.setStyle(circ, SVGConstants.CSS_FILL_PROPERTY + ":" + colorstr);
+ parent.appendChild(circ);
+ break;
+ }
+ case 6: {
+ // [] filled rectangle
+ Element rect = plot.svgRect(x - size / 2.2, y - size / 2.2, size / 1.1, size / 1.1);
+ SVGUtil.setStyle(rect, "fill:" + colorstr);
+ parent.appendChild(rect);
+ break;
+ }
+ case 7: {
+ // <> filled diamond
+ Element rect = plot.svgRect(x - size / 2.5, y - size / 2.5, size / 1.25, size / 1.25);
+ SVGUtil.setStyle(rect, "fill:" + colorstr);
+ SVGUtil.setAtt(rect, SVGConstants.SVG_TRANSFORM_ATTRIBUTE, "rotate(45," + SVGUtil.fmt(x) + "," + SVGUtil.fmt(y) + ")");
+ parent.appendChild(rect);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Plot a replacement marker when an object is to be plotted as "disabled", usually gray.
+ *
+ * @param plot Plot to draw to
+ * @param parent Parent element
+ * @param x X position
+ * @param y Y position
+ * @param size Size
+ */
+ protected void plotGray(SVGPlot plot, Element parent, double x, double y, double size) {
+ Element marker = plot.svgCircle(x, y, size * .5);
+ SVGUtil.setStyle(marker, SVGConstants.CSS_FILL_PROPERTY + ":" + greycolor);
+ parent.appendChild(marker);
+ }
+
+ /**
+ * Plot a replacement marker when no color is set; usually black
+ *
+ * @param plot Plot to draw to
+ * @param parent Parent element
+ * @param x X position
+ * @param y Y position
+ * @param size Size
+ */
+ protected void plotUncolored(SVGPlot plot, Element parent, double x, double y, double size) {
+ Element marker = plot.svgCircle(x, y, size * .5);
+ SVGUtil.setStyle(marker, SVGConstants.CSS_FILL_PROPERTY + ":" + dotcolor);
+ parent.appendChild(marker);
+ }
+
+ @Override
+ public Element useMarker(SVGPlot plot, Element parent, double x, double y, int style, double size) {
+ String id = prefix + style + "_" + size;
+ Element existing = plot.getIdElement(id);
+ if(existing == null) {
+ Element symbol = plot.svgElement(SVGConstants.SVG_SYMBOL_TAG);
+ SVGUtil.setAtt(symbol, SVGConstants.SVG_ID_ATTRIBUTE, id);
+ plotMarker(plot, symbol, 2 * size, 2 * size, style, 2 * size);
+ plot.getDefs().appendChild(symbol);
+ plot.putIdElement(id, symbol);
+ }
+ Element use = plot.svgElement(SVGConstants.SVG_USE_TAG);
+ use.setAttributeNS(SVGConstants.XLINK_NAMESPACE_URI, SVGConstants.XLINK_HREF_QNAME, "#" + id);
+ SVGUtil.setAtt(use, SVGConstants.SVG_X_ATTRIBUTE, x - 2 * size);
+ SVGUtil.setAtt(use, SVGConstants.SVG_Y_ATTRIBUTE, y - 2 * size);
+ if(parent != null) {
+ parent.appendChild(use);
+ }
+ return use;
+ }
+} \ No newline at end of file
diff --git a/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker/package-info.java b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker/package-info.java
new file mode 100755
index 00000000..293d5a67
--- /dev/null
+++ b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/marker/package-info.java
@@ -0,0 +1,27 @@
+/**
+ * <p>Draw plot markers</p>
+ *
+ */
+/*
+This file is part of ELKI:
+Environment for Developing KDD-Applications Supported by Index-Structures
+
+Copyright (C) 2015
+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/>.
+*/
+package de.lmu.ifi.dbs.elki.visualization.style.marker; \ No newline at end of file
diff --git a/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/package-info.java b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/package-info.java
new file mode 100755
index 00000000..90c548cd
--- /dev/null
+++ b/addons/batikvis/src/main/java/de/lmu/ifi/dbs/elki/visualization/style/package-info.java
@@ -0,0 +1,27 @@
+/**
+ * <p>Style management for ELKI visualizations.</p>
+ *
+ */
+/*
+This file is part of ELKI:
+Environment for Developing KDD-Applications Supported by Index-Structures
+
+Copyright (C) 2015
+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/>.
+*/
+package de.lmu.ifi.dbs.elki.visualization.style; \ No newline at end of file