/* * RapidMiner * * Copyright (C) 2001-2014 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.datatable; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import com.rapidminer.gui.new_plotter.utility.DataStructureUtils; import com.rapidminer.tools.container.Pair; /** * A view on a dataTable which changes the mapping of nominal values such that nominal values * or ordered lexically ascending or descending with increasing index values. * * Uses lazy initialization, i.e. the mapping is only created on first access. * * @author Marius Helf * */ public class NominalSortingDataTableMapping implements BidirectionalMappingProvider, DataTableListener { /** * Maps values from the parent table to the new values. */ Map<Double,Double> parentToChildMapping = null; Map<Double,Double> childToParentMapping = null; private boolean ascending; private int columnIdx; private final DataTable originalDataTable; public NominalSortingDataTableMapping(ValueMappingDataTableView dataTable, int columnIdx, boolean ascending) { if (!dataTable.isNominal(columnIdx)) { throw new IllegalArgumentException("NominalSortingDataTableMapping can only work on nominal columns."); } this.ascending = ascending; this.columnIdx = columnIdx; this.originalDataTable = dataTable.getParent(); originalDataTable.addDataTableListener(this, true); } private void updateMapping(DataTable dataTable, int columnIdx, boolean ascending) { List<Double> distinctValues = DataStructureUtils.getDistinctDataTableValues(dataTable, columnIdx); List<Pair<Double,String>> valueStrings = new LinkedList<Pair<Double,String>>(); for (double value : distinctValues) { valueStrings.add(new Pair<Double, String>(value, dataTable.mapIndex(columnIdx, (int)value))); } Collections.sort(valueStrings, new DataStructureUtils.PairComparator<Double,String>(ascending)); parentToChildMapping = new HashMap<Double, Double>(); childToParentMapping = new HashMap<Double, Double>(); double idx = 0.0; for (Pair<Double,String> entry : valueStrings) { parentToChildMapping.put(entry.getFirst(), idx); childToParentMapping.put(idx, entry.getFirst()); idx += 1; } } @Override public double mapFromParentValue(double originalValue) { if (parentToChildMapping == null) { updateMapping(originalDataTable, columnIdx, ascending); } return parentToChildMapping.get(originalValue); } @Override public void dataTableUpdated(DataTable source) { // invalidate mapping (will be recalculated on next access) parentToChildMapping = null; childToParentMapping = null; } @Override public double mapToParentValue(double value) { if (childToParentMapping == null) { updateMapping(originalDataTable, columnIdx, ascending); } return childToParentMapping.get(value); } }