/** * Copyright (C) 2001-2017 by RapidMiner and the contributors * * Complete list of developers available at our web site: * * http://rapidminer.com * * 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 com.rapidminer.gui.plotter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.rapidminer.datatable.DataTable; import com.rapidminer.datatable.DataTableExampleSetAdapter; import com.rapidminer.gui.MainFrame; import com.rapidminer.tools.ParameterService; /** * Control class used to handle the logic behind preselecting plotter axes. * * @author David Arnu, Nils Woehler * */ public class HeuristicPlotterConfigurator { public static final int DEFAULT_SELECTION_NUMBER = 3; public static final int MAX_NOMINAL_VALUES = 200; private static final String AGGREGATIOTN_DEFAULT_FUNCTION = "count"; private static final String SUM = "sum"; public static final String NUMERICAL = "Numerical"; public static final String NOMINAL = "Nominal"; public static final String DATE = "Date"; public static final String LABEL = "Label"; private Map<String, List<String>> categoryToColumnListMap; private final String[] columnNames; private final PlotterConfigurationModel settings; public HeuristicPlotterConfigurator(PlotterConfigurationModel plotterSettings, DataTable dataTable) { List<String> columnNamesNotTooBig = new ArrayList<>(); // only take nominal columns with not to many values for (int i = 0; i < dataTable.getNumberOfColumns(); i++) { if (!(dataTable.isNominal(i) && dataTable.getNumberOfValues(i) > MAX_NOMINAL_VALUES)) { columnNamesNotTooBig.add(dataTable.getColumnName(i)); } } this.columnNames = columnNamesNotTooBig.toArray(new String[columnNamesNotTooBig.size()]); this.settings = plotterSettings; this.categoryToColumnListMap = new HashMap<>(); populateCategoryMap(dataTable); } private void populateCategoryMap(DataTable dataTable) { this.categoryToColumnListMap.put(HeuristicPlotterConfigurator.NUMERICAL, new ArrayList<String>()); this.categoryToColumnListMap.put(HeuristicPlotterConfigurator.LABEL, new ArrayList<String>()); this.categoryToColumnListMap.put(HeuristicPlotterConfigurator.NOMINAL, new ArrayList<String>()); this.categoryToColumnListMap.put(HeuristicPlotterConfigurator.DATE, new ArrayList<String>()); for (int i = 0; i < dataTable.getNumberOfColumns(); i++) { if (dataTable.isNumerical(i)) { this.categoryToColumnListMap.get(HeuristicPlotterConfigurator.NUMERICAL).add(dataTable.getColumnName(i)); } if (dataTable.isNominal(i)) { if (dataTable.getNumberOfValues(i) <= MAX_NOMINAL_VALUES) { this.categoryToColumnListMap.get(HeuristicPlotterConfigurator.NOMINAL).add(dataTable.getColumnName(i)); } } if (dataTable.isDateTime(i)) { this.categoryToColumnListMap.get(HeuristicPlotterConfigurator.DATE).add(dataTable.getColumnName(i)); } } if (dataTable instanceof DataTableExampleSetAdapter) { DataTableExampleSetAdapter mine = (DataTableExampleSetAdapter) dataTable; String labelName = mine.getLabelName(); if (labelName != null) { if (mine.isLabelNominal()) { // only add nominal labels with less than MAX_NOMINAL_VALUES different values if (mine.getNumberOfValues(mine.getColumnIndex(labelName)) <= MAX_NOMINAL_VALUES) { this.categoryToColumnListMap.get(HeuristicPlotterConfigurator.NOMINAL).add(labelName); this.categoryToColumnListMap.get(HeuristicPlotterConfigurator.LABEL).add(labelName); } } else { this.categoryToColumnListMap.get(HeuristicPlotterConfigurator.LABEL).add(labelName); } // remove Label from the numerical attribute list if (this.categoryToColumnListMap.get(HeuristicPlotterConfigurator.NUMERICAL).contains(labelName)) { this.categoryToColumnListMap.get(HeuristicPlotterConfigurator.NUMERICAL).remove(labelName); } } // if there is a cluster attribute it can be handled as an additional label for axis // selection: if (mine.getClusterName() != null) { this.categoryToColumnListMap.get(HeuristicPlotterConfigurator.LABEL).add(mine.getClusterName()); } } else { // set empty values unless Label and Nominal are already set if (categoryToColumnListMap.get(HeuristicPlotterConfigurator.LABEL).isEmpty()) { this.categoryToColumnListMap.put(HeuristicPlotterConfigurator.LABEL, new ArrayList<String>()); } if (categoryToColumnListMap.get(HeuristicPlotterConfigurator.NOMINAL).isEmpty()) { this.categoryToColumnListMap.put(HeuristicPlotterConfigurator.NOMINAL, new ArrayList<String>()); } } } /** * Returns name of the n-th entry of the specified value type or an empty String. * * @param type * The wanted value type * @param number * Which entry of the specific value type should be returned * @return The name list entry or an empty String. Default case is the first entry in the list. */ private String getNameListEntry(String type, int number) { String selection = ""; if (categoryToColumnListMap.get(type).size() > number) { selection = categoryToColumnListMap.get(type).get(number); } else { if (!type.equals(DATE) && columnNames.length != 0) { selection = columnNames[0]; // default case } // selection remains empty for "Date" if there is no Date value or if the columnNames // list is empty } return selection; } public HashMap<String, String> getDefaultSelection(HashMap<String, String> settings) { int maxDataPoints = Integer.parseInt(ParameterService .getParameterValue(MainFrame.PROPERTY_RAPIDMINER_GUI_PLOTTER_DEFAULT_MAXIMUM)); if (this.settings.getDataTable().getNumberOfRows() > maxDataPoints && maxDataPoints != -1) { return settings; // return empty settings to prevent blocking the GUI } settings.put(PlotterConfigurationSettings.AXIS_X, getNameListEntry(NUMERICAL, 0)); settings.put(PlotterConfigurationSettings.AXIS_Y, getNameListEntry(NUMERICAL, 1)); settings.put(PlotterConfigurationSettings.AXIS_Z, getNameListEntry(NUMERICAL, 2)); settings.put(PlotterConfigurationSettings.BUBBLE_SIZE, getNameListEntry(NUMERICAL, 2)); settings.put(PlotterConfigurationSettings.AXIS_PLOT_COLUMN, getNameListEntry(LABEL, 0)); settings.put(PlotterConfigurationSettings.CLASS_COLUMN, getNameListEntry(LABEL, 0)); String multipleNames = getNameListEntry(NUMERICAL, 1); // selected axes for multiple // selection field for (int i = 2; i <= DEFAULT_SELECTION_NUMBER; i++) { if (i >= categoryToColumnListMap.get(NUMERICAL).size()) { break; } multipleNames = multipleNames.concat(", " + getNameListEntry(NUMERICAL, i)); } settings.put(PlotterConfigurationSettings.AXIS_PLOT_COLUMNS, multipleNames); settings.put(PlotterConfigurationSettings.AGGREGATION, AGGREGATIOTN_DEFAULT_FUNCTION); settings.put(PlotterConfigurationSettings.GROUP_BY_COLUMN, getNameListEntry(NOMINAL, 0)); settings.put(PlotterConfigurationSettings.POINT_COLOR, getNameListEntry(LABEL, 0)); settings.put(PlotterConfigurationSettings.AXIS_HISTOGRAM, getNameListEntry(NUMERICAL, 0)); settings.put(PlotterConfigurationSettings.DIMENSION, getNameListEntry(NUMERICAL, 0)); settings.put(PlotterConfigurationSettings.INDEX_DIMENSION, getNameListEntry(DATE, 0)); settings.put(PlotterConfigurationSettings.AXIS_STACK_COLUMN, getNameListEntry(LABEL, 0)); // declare and overwrite special cases for certain renderer types here: if (this.settings.getAvailablePlotters().containsKey(PlotterConfigurationModel.LINES_PLOT)) { // AttributeWeight // IOObject settings.remove(PlotterConfigurationSettings.AGGREGATION); settings.put(PlotterConfigurationSettings.AGGREGATION, SUM); settings.remove(PlotterConfigurationSettings.AXIS_PLOT_COLUMN); settings.put(PlotterConfigurationSettings.AXIS_PLOT_COLUMN, getNameListEntry(NUMERICAL, 0)); } return settings; } public String getDefaultPlotter() { if (categoryToColumnListMap.get(DATE).size() != 0 && this.settings.getAvailablePlotters().containsKey(PlotterConfigurationModel.SERIES_PLOT)) { return PlotterConfigurationModel.SERIES_PLOT; } if (categoryToColumnListMap.get(NUMERICAL).size() < 2 && this.settings.getAvailablePlotters().containsKey(PlotterConfigurationModel.BAR_CHART)) { // no // numerical // values // present return PlotterConfigurationModel.BAR_CHART; } if (this.settings.getAvailablePlotters().containsKey(PlotterConfigurationModel.LINES_PLOT)) { // AttributeWeight // IOObject return PlotterConfigurationModel.LINES_PLOT; } return PlotterConfigurationModel.SCATTER_PLOT; // default case } }