blob: 71408719fee6d4380e1bc7b9be81a9fac77aef08 [file] [log] [blame]
/*
* Copyright (c) 2013 DataTorrent, Inc. ALL Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.datatorrent.lib.chart;
import com.datatorrent.api.Context.OperatorContext;
import com.datatorrent.lib.util.HighLow;
import java.util.TreeMap;
/**
* This is the base implementation of a histogram charting operator. 
* Subclasses of this operator must implement the method which determines the histogram bucket each tuple belongs to.
* <p></p>
* @displayName Abstract Histogram Chart
* @category Charting
* @tags output operator
*
* @param <K> The key type
* @since 0.3.2
*/
public abstract class HistogramChartOperator<K, V extends Number> extends EnumChartOperator<K, HighLow<V>>
{
protected Number high;
protected Number low;
protected int numDivisions;
protected NumberType xNumberType = NumberType.INTEGER;
protected TreeMap<Number, HighLow<V>> highLows = new TreeMap<Number, HighLow<V>>();
@Override
public Type getChartType()
{
return Type.HISTOGRAM;
}
/**
* Gets the upper bound on the x-axis for the histogram
* @return the high number
*/
public Number getHigh()
{
return high;
}
/**
* Sets the upper bound on the x-axis for the histogram
* @param high
*/
public void setHigh(Number high)
{
this.high = high;
}
/**
* Gets the lower bound on the x-axis for the histogram
* @return the low number
*/
public Number getLow()
{
return low;
}
/**
* Sets the lower bound on the x-axis for the histogram
* @param low
*/
public void setLow(Number low)
{
this.low = low;
}
/**
* Gets the number of divisions on the x-axis for the histogram
* @return the number of devisions
*/
public int getNumDivisions()
{
return numDivisions;
}
/**
* Gets the number type of the values on the X-axis
* @return the x number type
*/
public NumberType getxNumberType()
{
return xNumberType;
}
/**
* Sets the number type of the values on the X-axis
* @param xNumberType
*/
public void setxNumberType(NumberType xNumberType)
{
this.xNumberType = xNumberType;
}
/**
* Sets the number of divisions on the x-axis for the histogram
* @param numDivisions
*/
public void setNumDivisions(int numDivisions)
{
this.numDivisions = numDivisions;
}
@Override
public void setup(OperatorContext context)
{
super.setup(context);
if (numDivisions == 0) {
throw new RuntimeException("setNumDivisions() must be called first");
}
if (xNumberType == NumberType.FLOAT) {
double increment = (high.doubleValue() - low.doubleValue()) / numDivisions;
double current = low.doubleValue();
if (increment <= 0) {
throw new RuntimeException("increment will be <= 0 given high, low and numDivisions");
}
for (int i = 0; i < numDivisions; i++) {
highLows.put(current, new HighLow(i == numDivisions - 1 ? high : current + increment, current));
current += increment;
}
}
else {
long increment = (high.longValue() - low.longValue()) / numDivisions;
long current = low.longValue();
if (increment <= 0) {
throw new RuntimeException("increment will be < 0 given high, low and numDivisions");
}
for (int i = 0; i < numDivisions; i++) {
if (current + increment - 1 > high.longValue()) {
throw new RuntimeException("Too many divisions for long (integer) x values");
}
highLows.put(current, new HighLow(i == numDivisions - 1 ? high : current + increment - 1, current));
current += increment;
}
}
}
/**
* Tells the histogram chart operator how to get the X value given the tuple.
* The value will be used to determine which bucket of the X-axis the tuple belongs to
* @param tuple
* @return The X value
*/
public abstract Number convertTupleToXSource(Object tuple);
@Override
public HighLow<V> convertTupleToX(Object tuple)
{
Number number = convertTupleToXSource(tuple);
if (xNumberType == NumberType.FLOAT) {
if (number.doubleValue() < low.doubleValue() || number.doubleValue() > high.doubleValue()) {
// out of range
return null;
}
}
else {
if (number.longValue() < low.longValue() || number.longValue() > high.longValue()) {
return null;
}
}
return highLows.higherEntry(number).getValue();
}
}