/**
* 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 java.awt.Color;
import java.text.DateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Locale;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StandardXYBarPainter;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.data.statistics.HistogramDataset;
import com.rapidminer.example.Attribute;
import com.rapidminer.example.Example;
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;
/**
* Model for {@link AttributeStatisticsPanel}s which are backed by a date_time {@link Attribute}.
*
* @author Marco Boeck
*
*/
public class DateTimeAttributeStatisticsModel extends AbstractAttributeStatisticsModel {
/** the index for the histogram chart */
private static final int INDEX_HISTOGRAM_CHART = 0;
/** the max number of bins */
private static final int MAX_BINS_HISTOGRAM = 10;
/** used to color the chart background invisible */
private static final Color COLOR_INVISIBLE = new Color(255, 255, 255, 0);
/** @{value */
private static final String WHITESPACE = " ";
/** short symbol for day: {@value} */
private static final String SHORT_DAY = "d";
/** short symbol for hour: {@value} */
private static final String SHORT_HOUR = "h";
/** short symbol for minute: {@value} */
private static final String SHORT_MINUTE = "m";
/** short symbol for second: {@value} */
private static final String SHORT_SECOND = "s";
/** {@value} */
private static final double MS_IN_S = 1000.0d;
/** {@value} */
private static final double S_IN_M = 60.0d;
/** {@value} */
private static final double M_IN_H = 60.0d;
/** {@value} */
private static final double H_IN_D = 24.0d;
/** the formatter for date_time values */
private final DateFormat FORMAT_DATE = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault());
/** the formatter for date_time values */
private final DateFormat FORMAT_TIME = DateFormat.getTimeInstance(DateFormat.MEDIUM, Locale.getDefault());
/** the formatter for date_time values */
private final DateFormat FORMAT_DATE_TIME = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT,
Locale.getDefault());
/** the duration of the date_time values */
private String duration;
/** the minimum of the date_time values */
private String from;
/** the maximum of the date_time values */
private String until;
/** array of charts for this model */
private final JFreeChart[] chartsArray;
/**
* Creates a new {@link DateTimeAttributeStatisticsModel}.
*
* @param exampleSet
* @param attribute
*/
public DateTimeAttributeStatisticsModel(final ExampleSet exampleSet, final Attribute attribute) {
super(exampleSet, attribute);
chartsArray = new JFreeChart[1];
}
@Override
public void updateStatistics(final ExampleSet exampleSet) {
final String days = WHITESPACE
+ I18N.getMessage(I18N.getGUIBundle(), "gui.label.attribute_statistics.statistics.days.label");
final String hours = WHITESPACE
+ I18N.getMessage(I18N.getGUIBundle(), "gui.label.attribute_statistics.statistics.hours.label");
long minMilliseconds = (long) exampleSet.getStatistics(getAttribute(), Statistics.MINIMUM);
long maxMilliseconds = (long) exampleSet.getStatistics(getAttribute(), Statistics.MAXIMUM);
long difference = maxMilliseconds - minMilliseconds;
String dura = "";
if (getAttribute().getValueType() == Ontology.DATE) {
// days
dura += com.rapidminer.tools.Tools.formatIntegerIfPossible(
Math.floor(difference / (H_IN_D * M_IN_H * S_IN_M * MS_IN_S)), 3)
+ days;
} else if (getAttribute().getValueType() == Ontology.TIME) {
// hours
dura += com.rapidminer.tools.Tools.formatIntegerIfPossible(Math.floor(difference / (M_IN_H * S_IN_M * MS_IN_S)),
3) + hours;
} else if (getAttribute().getValueType() == Ontology.DATE_TIME) {
// days + hours + minutes + seconds
dura += com.rapidminer.tools.Tools.formatIntegerIfPossible(
Math.floor(difference / (H_IN_D * M_IN_H * S_IN_M * MS_IN_S)), 3)
+ SHORT_DAY;
dura += WHITESPACE;
double leftoverMilliSeconds = difference % (H_IN_D * M_IN_H * S_IN_M * MS_IN_S);
dura += com.rapidminer.tools.Tools.formatIntegerIfPossible(
Math.floor(leftoverMilliSeconds / (M_IN_H * S_IN_M * MS_IN_S)), 3)
+ SHORT_HOUR;
dura += WHITESPACE;
leftoverMilliSeconds = leftoverMilliSeconds % (M_IN_H * S_IN_M * MS_IN_S);
dura += com.rapidminer.tools.Tools.formatIntegerIfPossible(
Math.floor(leftoverMilliSeconds / (S_IN_M * MS_IN_S)), 3) + SHORT_MINUTE;
dura += WHITESPACE;
leftoverMilliSeconds = leftoverMilliSeconds % (S_IN_M * MS_IN_S);
dura += com.rapidminer.tools.Tools.formatIntegerIfPossible(Math.floor(leftoverMilliSeconds / MS_IN_S), 3)
+ SHORT_SECOND;
}
String minResult = null;
String maxResult = null;
if (getAttribute().getValueType() == Ontology.DATE) {
minResult = FORMAT_DATE.format(new Date(minMilliseconds));
maxResult = FORMAT_DATE.format(new Date(maxMilliseconds));
} else if (getAttribute().getValueType() == Ontology.TIME) {
minResult = FORMAT_TIME.format(new Date(minMilliseconds));
maxResult = FORMAT_TIME.format(new Date(maxMilliseconds));
} else if (getAttribute().getValueType() == Ontology.DATE_TIME) {
minResult = FORMAT_DATE_TIME.format(new Date(minMilliseconds));
maxResult = FORMAT_DATE_TIME.format(new Date(maxMilliseconds));
}
missing = exampleSet.getStatistics(getAttribute(), Statistics.UNKNOWN);
from = minResult;
until = maxResult;
duration = dura;
fireStatisticsChangedEvent();
}
/**
* Gets the duration of the date_time values.
*
* @return
*/
public String getDuration() {
return duration;
}
/**
* Gets the from value (min) of the date_time values.
*
* @return
*/
public String getFrom() {
return from;
}
/**
* Gets the until value (max) of the date_time values.
*
* @return
*/
public String getUntil() {
return until;
}
@Override
public JFreeChart getChartOrNull(final int index) {
prepareCharts();
if (index == INDEX_HISTOGRAM_CHART) {
return chartsArray[index];
}
return null;
}
/**
* Creates a {@link HistogramDataset} for this {@link Attribute}.
*
* @param exampleSet
* @return
*/
private HistogramDataset createHistogramDataset(final ExampleSet exampleSet) {
HistogramDataset dataset = new HistogramDataset();
double[] array = new double[exampleSet.size()];
int count = 0;
for (Example example : exampleSet) {
double value = example.getDataRow().get(getAttribute());
// don't use missing values because otherwise JFreeChart tries to plot them too which
// can lead to false histograms
if (!Double.isNaN(value)) {
array[count++] = value;
}
}
// add points to data set (if any)
if (count > 0) {
// truncate array if necessary
if (count < array.length) {
array = Arrays.copyOf(array, count);
}
dataset.addSeries(getAttribute().getName(), array, Math.min(array.length, MAX_BINS_HISTOGRAM));
}
return dataset;
}
/**
* Creates the histogram chart.
*
* @param exampleSet
* @return
*/
private JFreeChart createHistogramChart(final ExampleSet exampleSet) {
JFreeChart chart = ChartFactory.createHistogram(null, null, null, createHistogramDataset(exampleSet),
PlotOrientation.VERTICAL, false, false, false);
AbstractAttributeStatisticsModel.setDefaultChartFonts(chart);
chart.setBackgroundPaint(null);
chart.setBackgroundImageAlpha(0.0f);
XYPlot plot = (XYPlot) chart.getPlot();
plot.setRangeGridlinesVisible(false);
plot.setDomainGridlinesVisible(false);
plot.setOutlineVisible(false);
plot.setRangeZeroBaselineVisible(false);
plot.setDomainZeroBaselineVisible(false);
plot.getDomainAxis().setTickLabelsVisible(false);
plot.setBackgroundPaint(COLOR_INVISIBLE);
plot.setBackgroundImageAlpha(0.0f);
XYBarRenderer renderer = (XYBarRenderer) plot.getRenderer();
renderer.setSeriesPaint(0, AttributeGuiTools.getColorForValueType(Ontology.DATE_TIME));
renderer.setBarPainter(new StandardXYBarPainter());
renderer.setDrawBarOutline(true);
renderer.setShadowVisible(false);
return chart;
}
@Override
public void prepareCharts() {
if (chartsArray[INDEX_HISTOGRAM_CHART] == null && getExampleSetOrNull() != null) {
chartsArray[INDEX_HISTOGRAM_CHART] = createHistogramChart(getExampleSetOrNull());
}
}
}