/** * 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.metadata.model; import com.rapidminer.example.Attribute; import com.rapidminer.example.ExampleSet; import com.rapidminer.example.Statistics; import com.rapidminer.gui.tools.AttributeGuiTools; import com.rapidminer.gui.viewer.metadata.AttributeStatisticsPanel; import com.rapidminer.tools.I18N; import com.rapidminer.tools.Ontology; import com.rapidminer.tools.container.ValueAndCount; import java.awt.Color; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; import org.jfree.chart.plot.CategoryPlot; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.renderer.category.BarRenderer; import org.jfree.chart.renderer.category.StandardBarPainter; import org.jfree.data.category.CategoryDataset; import org.jfree.data.category.DefaultCategoryDataset; /** * Model for {@link AttributeStatisticsPanel}s which are backed by a nominal {@link Attribute}. * * @author Marco Boeck * */ public class NominalAttributeStatisticsModel extends AbstractAttributeStatisticsModel { /** the index for the barchart */ private static final int INDEX_BAR_CHART = 0; /** the max number of bars in the barchart */ private static final int MAX_BARS = 5; /** used to color the chart background invisible */ private static final Color COLOR_INVISIBLE = new Color(255, 255, 255, 0); /** the default number of displayed nominal values when NOT enlarged */ private static final int DEFAULT_MAX_DISPLAYED_VALUES = 2; /** the default number of displayed nominal values when enlarged */ public static final int DEFAULT_MAX_DISPLAYED_VALUES_ENLARGED = 4; /** {@value} */ private static final String LABEL_DOTS = "..."; /** {@value} */ private static final String PARENTHESIS_CLOSE = ")"; /** {@value} */ private static final String PARANTHESIS_OPEN = " ("; /** {@value} */ private static final String BRACKET_OPEN = " ["; /** {@value} */ private static final String BRACKET_CLOSE = "]"; /** the list containing the nominal values and their count */ private List<ValueAndCount> nominalValues; /** array of charts for this model */ private JFreeChart[] chartsArray; /** * Creates a new {@link NominalAttributeStatisticsModel}. * * @param exampleSet * @param attribute */ public NominalAttributeStatisticsModel(ExampleSet exampleSet, Attribute attribute) { super(exampleSet, attribute); nominalValues = new LinkedList<>(); chartsArray = new JFreeChart[1]; } @Override public void updateStatistics(ExampleSet exampleSet) { missing = exampleSet.getStatistics(getAttribute(), Statistics.UNKNOWN); // count nominal values int totalNumberOfValues = getAttribute().getMapping().size(); if (totalNumberOfValues > 0) { // create a list of all nominal values and their corresponding count Iterator<String> i = getAttribute().getMapping().getValues().iterator(); nominalValues.clear(); while (i.hasNext()) { String value = i.next(); nominalValues.add(new ValueAndCount(value, (int) exampleSet.getStatistics(getAttribute(), Statistics.COUNT, value))); } Collections.sort(nominalValues); } fireStatisticsChangedEvent(); } @Override public JFreeChart getChartOrNull(int index) { prepareCharts(); if (index == INDEX_BAR_CHART) { return chartsArray[index]; } return null; } @Override public void prepareCharts() { if (chartsArray[INDEX_BAR_CHART] == null) { chartsArray[INDEX_BAR_CHART] = createBarChart(); } } /** * Returns a {@link List} of nominal values and their count. * * @return */ public List<ValueAndCount> getNominalValuesAndCount() { return new LinkedList<>(nominalValues); } /** * Returns a {@link List} of all value {@link String}s which should be shown. * * @return */ public List<String> getValueStrings() { List<String> list = new LinkedList<>(); int maxDisplayValues = !isEnlarged() ? DEFAULT_MAX_DISPLAYED_VALUES : DEFAULT_MAX_DISPLAYED_VALUES_ENLARGED; Iterator<ValueAndCount> it = new LinkedList<>(nominalValues).iterator(); int n = 0; while (it.hasNext() && n < maxDisplayValues) { ValueAndCount value = it.next(); n++; list.add(value.getValue() + PARANTHESIS_OPEN + value.getCount() + PARENTHESIS_CLOSE); } // count how many we could not display int omittedCount = 0; while (it.hasNext()) { it.next(); omittedCount++; } if (omittedCount > 0) { list.add(LABEL_DOTS + BRACKET_OPEN + omittedCount + " " + I18N.getMessage(I18N.getGUIBundle(), "gui.label.attribute_statistics.statistics.values_more") + BRACKET_CLOSE); } return list; } /** * Returns the {@link String} value which appears the least in the nominal mapping. * * @return */ public String getLeast() { if (nominalValues.size() == 0) { return ""; } ValueAndCount value = nominalValues.get(nominalValues.size() - 1); return value.getValue() + PARANTHESIS_OPEN + value.getCount() + PARENTHESIS_CLOSE; } /** * Returns the {@link String} value which appears the most in the nominal mapping. * * @return */ public String getMost() { if (nominalValues.size() == 0) { return ""; } ValueAndCount value = nominalValues.get(0); return value.getValue() + PARANTHESIS_OPEN + value.getCount() + PARENTHESIS_CLOSE; } /** * Creates the histogram chart. * * @return */ private JFreeChart createBarChart() { JFreeChart chart = ChartFactory.createBarChart(null, null, null, createBarDataset(), PlotOrientation.VERTICAL, false, false, false); AbstractAttributeStatisticsModel.setDefaultChartFonts(chart); chart.setBackgroundPaint(null); chart.setBackgroundImageAlpha(0.0f); CategoryPlot plot = (CategoryPlot) chart.getPlot(); plot.setRangeGridlinesVisible(false); plot.setDomainGridlinesVisible(false); plot.setOutlineVisible(false); plot.setRangeZeroBaselineVisible(false); plot.setDomainGridlinesVisible(false); plot.setBackgroundPaint(COLOR_INVISIBLE); plot.setBackgroundImageAlpha(0.0f); BarRenderer renderer = (BarRenderer) plot.getRenderer(); renderer.setSeriesPaint(0, AttributeGuiTools.getColorForValueType(Ontology.NOMINAL)); renderer.setBarPainter(new StandardBarPainter()); renderer.setDrawBarOutline(true); renderer.setShadowVisible(false); return chart; } /** * Creates a {@link CategoryDataset} for this {@link Attribute}. * * @param exampleSet * @return */ private CategoryDataset createBarDataset() { Iterator<ValueAndCount> it = new LinkedList<>(nominalValues).iterator(); LinkedList<ValueAndCount> listOfBarValues = new LinkedList<>(); int n = 0; while (it.hasNext() && n < MAX_BARS) { ValueAndCount value = it.next(); n++; listOfBarValues.add(value); } // fill dataset with top 5 string values (if possible) final DefaultCategoryDataset dataset = new DefaultCategoryDataset(); for (ValueAndCount value : listOfBarValues) { dataset.addValue(value.getCount(), "", value.getValue()); } return dataset; } }