/**
* 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.viewer;
import java.awt.Color;
import java.awt.event.MouseEvent;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.swing.table.JTableHeader;
import com.rapidminer.example.Attribute;
import com.rapidminer.example.AttributeRole;
import com.rapidminer.example.ExampleSet;
import com.rapidminer.example.set.ExampleSetUtilities;
import com.rapidminer.gui.look.Colors;
import com.rapidminer.gui.look.RapidLookTools;
import com.rapidminer.gui.tools.AttributeGuiTools;
import com.rapidminer.gui.tools.CellColorProvider;
import com.rapidminer.gui.tools.ExtendedJTable;
import com.rapidminer.gui.tools.ProgressThread;
import com.rapidminer.gui.viewer.metadata.model.AbstractAttributeStatisticsModel;
import com.rapidminer.gui.viewer.metadata.model.DateTimeAttributeStatisticsModel;
import com.rapidminer.gui.viewer.metadata.model.NominalAttributeStatisticsModel;
import com.rapidminer.gui.viewer.metadata.model.NumericalAttributeStatisticsModel;
import com.rapidminer.tools.I18N;
import com.rapidminer.tools.Ontology;
import com.rapidminer.tools.Tools;
/**
* Can be used to display (parts of) the data by means of a JTable. Used to display
* {@link ExampleSet} results in the {@link DataViewer}.
*
* @author Ingo Mierswa
*/
public class DataViewerTable extends ExtendedJTable {
private static final int MAXIMAL_CONTENT_LENGTH = 200;
private static final long serialVersionUID = 5535239693801265693L;
private int[] dateColumns;
private Map<String, Color> mappingAttributeNamesToColor;
private DataViewerTableModel dvTableModel;
private Map<String, AbstractAttributeStatisticsModel> mappingAttributeNamesToAttributeStatisticsModel = new HashMap<>();
private boolean statsInitState = true;
private WeakReference<ExampleSet> exampleSetReference;
private Map<Integer, String> toolTipMessagesMap = new HashMap<>();
public DataViewerTable() {
this.mappingAttributeNamesToColor = new HashMap<>();
setAutoResizeMode(AUTO_RESIZE_OFF);
setFixFirstColumnForRearranging(true);
installToolTip();
setRowHeight(getRowHeight() + 5);
// handles the highlighting of the currently hovered row
setRowHighlighting(true);
}
public void setExampleSet(ExampleSet exampleSet) {
this.dvTableModel = new DataViewerTableModel(exampleSet);
this.exampleSetReference = new WeakReference<>(exampleSet);
setModel(dvTableModel);
dateColumns = new int[exampleSet.getAttributes().allSize() + 1];
dateColumns[0] = NO_DATE_FORMAT;
int index = 1;
List<AttributeRole> specialAttributes = new ArrayList<>(exampleSet.getAttributes().specialSize());
Iterator<AttributeRole> s = exampleSet.getAttributes().specialAttributes();
while (s.hasNext()) {
specialAttributes.add(s.next());
}
Collections.sort(specialAttributes, ExampleSetUtilities.SPECIAL_ATTRIBUTES_ROLE_COMPARATOR);
for (AttributeRole attributeRole : specialAttributes) {
Attribute attribute = attributeRole.getAttribute();
String attributeRoleLabel = exampleSet.getAttributes().getRole(attribute).getSpecialName();
Color specialColor = AttributeGuiTools.getColorForAttributeRole(attributeRoleLabel);
mappingAttributeNamesToColor.put(attribute.getName(), specialColor);
if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(attribute.getValueType(), Ontology.DATE)) {
dateColumns[index] = DATE_FORMAT;
} else if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(attribute.getValueType(), Ontology.TIME)) {
dateColumns[index] = TIME_FORMAT;
} else if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(attribute.getValueType(), Ontology.DATE_TIME)) {
dateColumns[index] = DATE_TIME_FORMAT;
} else {
dateColumns[index] = NO_DATE_FORMAT;
}
index++;
}
for (Attribute attribute : exampleSet.getAttributes()) {
mappingAttributeNamesToColor.put(attribute.getName(), Colors.WHITE);
if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(attribute.getValueType(), Ontology.DATE)) {
dateColumns[index] = DATE_FORMAT;
} else if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(attribute.getValueType(), Ontology.TIME)) {
dateColumns[index] = TIME_FORMAT;
} else if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(attribute.getValueType(), Ontology.DATE_TIME)) {
dateColumns[index] = DATE_TIME_FORMAT;
} else {
dateColumns[index] = NO_DATE_FORMAT;
}
index++;
}
setCellColorProvider(new CellColorProvider() {
@Override
public Color getCellColor(int row, int column) {
int col = convertColumnIndexToModel(column);
Color returnCol;
if (dvTableModel != null && dvTableModel.getColumnAttribute(col) != null) {
Color color = mappingAttributeNamesToColor.get(dvTableModel.getColumnAttribute(col).getName());
returnCol = color;
} else {
returnCol = Colors.WHITE;
}
return returnCol;
}
});
setGridColor(Colors.TABLE_CELL_BORDER);
setCutOnLineBreak(true);
setMaximalTextLength(MAXIMAL_CONTENT_LENGTH);
ProgressThread createStatsThread = new ProgressThread("update_result_statistics") {
@Override
public void run() {
statsInitState = true;
toolTipMessagesMap.clear();
// iterate over all attributes, create models for them
ExampleSet exampleSet = DataViewerTable.this.exampleSetReference.get();
if (exampleSet != null) {
Iterator<Attribute> attributeIterator = exampleSet.getAttributes().allAttributes();
while (attributeIterator.hasNext()) {
Attribute att = attributeIterator.next();
AbstractAttributeStatisticsModel statModel;
if (att.isNumerical()) {
statModel = new NumericalAttributeStatisticsModel(exampleSet, att);
} else if (att.isNominal()) {
statModel = new NominalAttributeStatisticsModel(exampleSet, att);
} else {
statModel = new DateTimeAttributeStatisticsModel(exampleSet, att);
}
statModel.updateStatistics(exampleSet);
mappingAttributeNamesToAttributeStatisticsModel.put(att.getName(), statModel);
}
}
statsInitState = false;
}
};
createStatsThread.start();
}
/** This method ensures that the correct tool tip for the current column is delivered. */
@Override
protected JTableHeader createDefaultTableHeader() {
JTableHeader header = new JTableHeader(columnModel) {
private static final long serialVersionUID = 1L;
@Override
public String getToolTipText(MouseEvent e) {
java.awt.Point p = e.getPoint();
int index = columnModel.getColumnIndexAtX(p.x);
int realColumnIndex = convertColumnIndexToModel(index);
return DataViewerTable.this.getHeaderToolTipText(realColumnIndex);
}
};
header.putClientProperty(RapidLookTools.PROPERTY_TABLE_HEADER_BACKGROUND, Colors.WHITE);
return header;
}
@Override
public int getDateFormat(int row, int column) {
return dateColumns[column];
}
private String getHeaderToolTipText(int realColumnIndex) {
if (realColumnIndex == 0) {
// tooltip text for the column containing the example index
return I18N.getMessage(I18N.getGUIBundle(), "gui.label.data_view.example_index.tooltip");
}
if (statsInitState) {
// tooltip text for when the statistics are not yet calculated
return I18N.getMessage(I18N.getGUIBundle(), "gui.label.data_view.calc_stats.tooltip");
}
if (toolTipMessagesMap.containsKey(realColumnIndex)) {
// if the tooltip string was already constructed, use the cached string
return toolTipMessagesMap.get(realColumnIndex);
}
AbstractAttributeStatisticsModel statsModel = mappingAttributeNamesToAttributeStatisticsModel.get(getModel()
.getColumnName(realColumnIndex));
if (statsModel != null && statsModel.getExampleSetOrNull() != null) {
statsModel.updateStatistics(statsModel.getExampleSetOrNull());
double missingValues = statsModel.getNumberOfMissingValues();
if (Double.isNaN(missingValues)) {
// tooltip text for when the statistics are not yet calculated
return I18N.getMessage(I18N.getGUIBundle(), "gui.label.data_view.calc_stats.tooltip");
}
// construct the tooltip text when the statistics have been calculated
String attRole = statsModel.getExampleSetOrNull().getAttributes().getRole(statsModel.getAttribute())
.getSpecialName();
String valueTypeString = Ontology.ATTRIBUTE_VALUE_TYPE.mapIndex(statsModel.getAttribute().getValueType());
valueTypeString = valueTypeString.replaceAll("_", " ");
valueTypeString = String.valueOf(valueTypeString.charAt(0)).toUpperCase() + valueTypeString.substring(1);
String I18NStatsKey = "gui.label.attribute_statistics.statistics.";
String toolTipText = "<html>";
toolTipText += "<b>" + getModel().getColumnName(realColumnIndex) + "</b>";
if (attRole != null) {
toolTipText += "<font color=\"#666666\"> (" + attRole + ")</font>";
}
toolTipText += "<br><i>" + valueTypeString + "</i><br><br style=\"font-size:3px;\">";
toolTipText += I18N.getMessage(I18N.getGUIBundle(), I18NStatsKey + "values_missing") + ": "
+ Tools.formatIntegerIfPossible(missingValues) + "<br>";
if (statsModel instanceof NumericalAttributeStatisticsModel) {
NumericalAttributeStatisticsModel numStatsModel = (NumericalAttributeStatisticsModel) statsModel;
toolTipText += I18N.getMessage(I18N.getGUIBundle(), I18NStatsKey + "min.label") + ": "
+ Tools.formatIntegerIfPossible(numStatsModel.getMinimum()) + "<br>";
toolTipText += I18N.getMessage(I18N.getGUIBundle(), I18NStatsKey + "max.label") + ": "
+ Tools.formatIntegerIfPossible(numStatsModel.getMaximum()) + "<br>";
toolTipText += I18N.getMessage(I18N.getGUIBundle(), I18NStatsKey + "avg.label") + ": "
+ Tools.formatIntegerIfPossible(numStatsModel.getAverage()) + "<br>";
} else if (statsModel instanceof NominalAttributeStatisticsModel) {
NominalAttributeStatisticsModel nomStatsModel = (NominalAttributeStatisticsModel) statsModel;
toolTipText += I18N.getMessage(I18N.getGUIBundle(), I18NStatsKey + "least.label") + ": "
+ nomStatsModel.getLeast() + "<br>";
toolTipText += I18N.getMessage(I18N.getGUIBundle(), I18NStatsKey + "most.label") + ": "
+ nomStatsModel.getMost() + "<br>";
} else if (statsModel instanceof DateTimeAttributeStatisticsModel) {
DateTimeAttributeStatisticsModel dateStatsModel = (DateTimeAttributeStatisticsModel) statsModel;
toolTipText += I18N.getMessage(I18N.getGUIBundle(), I18NStatsKey + "duration.label") + ": "
+ dateStatsModel.getDuration() + "<br>";
toolTipText += I18N.getMessage(I18N.getGUIBundle(), I18NStatsKey + "from.label") + ": "
+ dateStatsModel.getFrom() + "<br>";
toolTipText += I18N.getMessage(I18N.getGUIBundle(), I18NStatsKey + "until.label") + ": "
+ dateStatsModel.getUntil() + "<br>";
}
toolTipMessagesMap.put(realColumnIndex, toolTipText);
return toolTipText;
}
return null;
}
}