/****************************************************************************************
* Copyright (c) 2014 Michael Goldbach <michael@wildplot.com> *
* *
* This program is free software; you can redistribute it and/or modify it under *
* the terms of the GNU 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License along with *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
package com.wildplot.android.rendering;
import com.wildplot.android.rendering.graphics.wrapper.ColorWrap;
import com.wildplot.android.rendering.graphics.wrapper.GraphicsWrap;
import com.wildplot.android.rendering.graphics.wrapper.RectangleWrap;
import com.wildplot.android.rendering.interfaces.Drawable;
/**
* Histogram plot, detailed informations regarding histograms are available in the internets
*
*
*/
public class YAxisHistoGram implements Drawable {
private double extraScaleFactor = 1;
private boolean autoscale = false;
private double scaleFactor = 10;
private boolean isOnFrame = false;
private double xOffset = 0;
private PlotSheet plotSheet;
private double[][] points;
private double start = 0;
private double binSize = 1;
private double size = 1;
private ColorWrap color;
private ColorWrap fillColor;
private boolean filling = false;
private boolean isOnReset = false;
/**
* @param plotSheet
* @param points the points used for calculating histogram data
* @param start relative start position of histogram bars the other bars will be aligned to
* @param size size of bars from left to right
* @param color border color of bars, for filling color use setFilling() and setFillingColor()
*/
public YAxisHistoGram(PlotSheet plotSheet, double[][] points, double start, double size, ColorWrap color) {
super();
this.plotSheet = plotSheet;
this.points = points;
this.start = start;
this.size = size;
this.color = color;
}
/**
* determine if bars are filled with color or not
* @param filling true if bars should be filled
*/
public void setFilling(boolean filling) {
this.filling = filling;
if(this.fillColor == null && filling) {
this.fillColor = this.color.brighter();
}
}
/**
* set filling color for bars
* @param fillColor
*/
public void setFillColor(ColorWrap fillColor) {
this.fillColor = fillColor;
}
/* (non-Javadoc)
* @see rendering.Drawable#paint(java.awt.Graphics)
*/
@Override
public void paint(GraphicsWrap g) {
isOnReset = false;
ColorWrap oldColor = g.getColor();
RectangleWrap field = g.getClipBounds();
g.setColor(color);
if(autoscale){
double[] start = this.plotSheet.toCoordinatePoint(0, 0, field);
double[] end = this.plotSheet.toCoordinatePoint(
0+this.plotSheet.getFrameThickness()[PlotSheet.LEFT_FRAME_THICKNESS_INDEX], 0, field);
this.scaleFactor = Math.abs(end[0] - start[0]);
// this.scaleFactor *= binSize;
} else {
this.scaleFactor = 1.0;
}
if(this.isOnFrame)
xOffset = plotSheet.getxRange()[0];
double steps = this.size;
double tmp = (int)((0-plotSheet.getyRange()[0])/steps);
tmp = (start - tmp*steps);
while(tmp <= plotSheet.getyRange()[1]) {
if(isOnReset)
return;
double sizeInRange = getSizeInRange(tmp, tmp+size);
if(sizeInRange != 0)
drawBar(tmp, sizeInRange*scaleFactor*extraScaleFactor, g, field);
tmp += steps;
//System.err.println("xaxisHisto"+tmp + ": " + sizeInRange);
}
g.setColor(oldColor);
}
public double getMaxValue(){
double max = Double.NEGATIVE_INFINITY;
double steps = this.size;
double tmp = (int)((0-plotSheet.getyRange()[0])/steps);
tmp = (start - tmp*steps);
while(tmp <= plotSheet.getyRange()[1]) {
double sizeInRange = getSizeInRange(tmp, tmp+size);
if(max < sizeInRange)
max = sizeInRange;
tmp += steps;
//System.err.println("xaxisHisto"+tmp + ": " + sizeInRange);
}
return max;
}
/**
* draw a single bar at given coordinate and with the given height
* @param x coordinate on plot
* @param y height
* @param g graphic object used to draw this bar
* @param field bounds of plot
*/
private void drawBar(double x, double y, GraphicsWrap g, RectangleWrap field) {
drawBar(x,y,g,field,this.size);
}
/**
* draw a single bar at given coordinate and with the given height with given specific size
* @param y coordinate on plot
* @param heigth height
* @param g graphic object used to draw this bar
* @param field bounds of plot
* @param size specific size (width) of this bar
*/
private void drawBar(double y, double heigth, GraphicsWrap g, RectangleWrap field, double size) {
float[] pointUpLeft = plotSheet.toGraphicPoint(0,y+size , field);
float[] pointUpRight = plotSheet.toGraphicPoint(0+heigth,y+size , field);
float[] pointBottomLeft = plotSheet.toGraphicPoint(0,y , field);
if(heigth < 0) {
pointUpLeft = plotSheet.toGraphicPoint(0+heigth,y+size , field);
pointUpRight = plotSheet.toGraphicPoint(0,y+size , field);
pointBottomLeft = plotSheet.toGraphicPoint(0+heigth,y , field);
}
if(this.isOnFrame) {
pointUpLeft = plotSheet.toGraphicPoint(this.xOffset-heigth,y+size , field);
pointUpRight = plotSheet.toGraphicPoint(this.xOffset,y+size , field);
pointBottomLeft = plotSheet.toGraphicPoint(this.xOffset-heigth,y , field);
}
if(filling){
ColorWrap oldColor = g.getColor();
if(this.fillColor != null)
g.setColor(fillColor);
g.fillRect(pointUpLeft[0], pointUpLeft[1], pointUpRight[0]-pointUpLeft[0], pointBottomLeft[1]-pointUpLeft[1]);
//g.fillRect(pointUpLeft[0], pointUpLeft[1], pointUpRight[0]-pointUpLeft[0], pointBottomLeft[1]-pointUpLeft[1]);
g.setColor(oldColor);
}
g.drawRect(pointUpLeft[0], pointUpLeft[1], pointUpRight[0]-pointUpLeft[0], pointBottomLeft[1]-pointUpLeft[1]);
// g.drawLine(pointUpLeft[0], pointUpLeft[1], pointUpRight[0], pointUpRight[1]);
// g.drawLine(pointUpLeft[0], pointUpLeft[1], pointBottomLeft[0], pointBottomLeft[1]);
// g.drawLine(pointBottomRight[0], pointBottomRight[1], pointBottomLeft[0], pointBottomLeft[1]);
}
//TODO: schauen, ob es Regeln folgt, die Ronny spezifiziert hat
/**
* get height of bar for given classification
* @param leftBorder
* @param rightBorder
* @return
*/
private double getSizeInRange(double leftBorder, double rightBorder){
//System.err.println("XHisto: " + leftBorder + " : "+ rightBorder);
int cnt = 0;
for(int i = 0; i<this.points[1].length; i++) {
if(points[1][i] >= leftBorder && points[1][i] < rightBorder) {
cnt++;
//System.err.println("XHist cnt++");
}
}
return (double)cnt/((double)points[1].length*this.size);
}
/**
* unset the axis to draw on the border between outer frame and plot
*/
public void unsetOnFrame() {
this.isOnFrame = false;
xOffset = 0;
}
public void setOnFrame(double extraSpace) {
this.isOnFrame = true;
xOffset = plotSheet.getxRange()[0]+ extraSpace;
}
public void setOnFrame() {
setOnFrame(0);
}
/**
* returns if this histogram is can draw on the outer frame of plot
*/
public boolean isOnFrame() {
return true;
}
public void setAutoscale(double binWidth) {
this.binSize = binWidth;
this.autoscale = true;
}
public void unsetAutoscale() {
this.autoscale = false;
}
public double getExtraScaleFactor() {
return extraScaleFactor;
}
public void setExtraScaleFactor(double extraScaleFactor) {
this.extraScaleFactor = extraScaleFactor;
}
@Override
public void abortAndReset() {
isOnReset = true;
}
@Override
public boolean isClusterable() {
return true;
}
@Override
public boolean isCritical() {
return false;
}
}