/*
GeoGebra - Dynamic Mathematics for Everyone
http://www.geogebra.org
This file is part of GeoGebra.
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.
*/
package org.geogebra.common.kernel.statistics;
import java.util.ArrayList;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.commands.Commands;
import org.geogebra.common.kernel.geos.GeoBoolean;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoList;
import org.geogebra.common.kernel.geos.GeoNumeric;
import org.geogebra.common.kernel.geos.GeoPoint;
/**
* Create a dot plot.
*
* Input: list of unsorted raw numeric data Output: sorted list of points
* forming a dot plot of the raw data
*
* A dot plot is a set of points for which: x coordinates = values from a list
* of numeric data y coordinates = number of times the x data value has occurred
*
* example: raw data = { 5,11,12,12,12,5 } dot plot = { (5,1), (5,2), (11,1),
* (12,1), (12,2), (12,3) }
*
* Adapted from AlgoSort and AlgoPointList
*
* @author G.Sturr
* @version 2010-8-10
*/
public class AlgoDotPlot extends AlgoUsingUniqueAndFrequency {
private GeoList inputList; // input
private GeoBoolean stackAdjacentDots;// input
private GeoNumeric scale;// input
private GeoList outputList; // output
private int size;
private int oldListSize;
private String toolTipText;
private double scaleFactor;
public AlgoDotPlot(Construction cons, String label, GeoList inputList) {
this(cons, inputList, null, null);
outputList.setLabel(label);
}
public AlgoDotPlot(Construction cons, GeoList inputList) {
this(cons, inputList, null, null);
}
protected AlgoDotPlot(Construction cons, String label, GeoList inputList,
GeoNumeric scale) {
this(cons, inputList, null, scale);
outputList.setLabel(label);
}
protected AlgoDotPlot(Construction cons, String label, GeoList inputList,
GeoBoolean stackDots) {
this(cons, inputList, stackDots, null);
outputList.setLabel(label);
}
protected AlgoDotPlot(Construction cons, String label, GeoList inputList,
GeoBoolean stackDots, GeoNumeric scale) {
this(cons, inputList, stackDots, scale);
outputList.setLabel(label);
}
protected AlgoDotPlot(Construction cons, GeoList inputList,
GeoBoolean stackDots, GeoNumeric scale) {
super(cons);
this.inputList = inputList;
this.stackAdjacentDots = stackDots;
this.scale = scale;
outputList = new GeoList(cons) {
// allow custom tool tips for individual points
@Override
public String getTooltipText(boolean colored, boolean alwaysOn) {
return ((AlgoDotPlot) getParentAlgorithm()).getTooltipText();
}
};
setInputOutput();
compute();
}
@Override
public Commands getClassName() {
return Commands.DotPlot;
}
/**
* set the input
*/
protected void setInput() {
ArrayList<GeoElement> tempList = new ArrayList<GeoElement>();
tempList.add(inputList);
if (stackAdjacentDots != null) {
tempList.add(stackAdjacentDots);
}
if (scale != null) {
tempList.add(scale);
}
input = new GeoElement[tempList.size()];
input = tempList.toArray(input);
}
@Override
protected void setInputOutput() {
createHelperAlgos(inputList);
setInput();
setOutputLength(1);
setOutput(0, outputList);
setDependencies(); // done by AlgoElement
}
public GeoList getResult() {
return outputList;
}
@Override
public void compute() {
size = inputList.size();
if (!inputList.isDefined() || size == 0) {
outputList.setUndefined();
return;
}
if (scale != null) {
scaleFactor = scale.getValue();
} else {
scaleFactor = 1.0;
}
// ========================================
// sort the raw data
GeoList list1 = algoFreq.getValue();
GeoList list2 = algoFreq.getResult();
// prepare output list. Pre-existing geos will be recycled,
// but extra geos are removed when outputList is too long
outputList.setDefined(true);
for (int i = outputList.size() - 1; i >= size; i--) {
GeoElement extraGeo = outputList.get(i);
extraGeo.remove();
outputList.remove(extraGeo);
}
oldListSize = outputList.size();
// ========================================
// create dot plot points
int index = 0;
for (int i = 0; i < list1.size(); i++) {
double x;
if (list1.get(i).isGeoNumeric()) {
x = list1.get(i).evaluateDouble();
} else {
// use integers 1,2,3 ... to position non-numeric data
x = i + 1;
}
int height = (int) list2.get(i).evaluateDouble();
for (int y = 1; y <= height; y++) {
double scaledY = getScaledY(y);
if (index < oldListSize) {
((GeoPoint) outputList.get(index)).setCoords(x, scaledY,
1.0);
} else {
outputList.addPoint(x, scaledY, 1.0, null);
}
index++;
}
}
}
/**
*
* @param y
* current height
* @return scaled y
*/
protected double getScaledY(int y) {
if (scale != null) {
return y * scaleFactor;
}
return y;
}
public GeoList getUniqueXList() {
return algoFreq.getValue();
}
public GeoList getFrequencyList() {
return algoFreq.getResult();
}
public String getTooltipText() {
return toolTipText;
}
public void setToolTipPointText(String text) {
toolTipText = text;
}
public boolean stackAdjacentDots() {
if (stackAdjacentDots != null) {
return stackAdjacentDots.getBoolean();
}
return false;
}
public double getScaleFactor() {
return scaleFactor;
}
}