package automenta.vivisect;
import java.awt.Color;
import java.util.TreeMap;
import org.encog.ml.data.MLData;
import org.encog.ml.data.basic.BasicMLDataCentroid;
import org.encog.util.kmeans.Centroid;
/**
* Used by Chart, a chart data set is a container to store chart data.
* TODO add ArrayDeque implementation as originally, for fast insertion/removal
*/
public class TreeMLData implements MLData {
//TODO use a primitive collection
public final TreeMap<Integer,Double> values;
/** RGBA */
protected int colour;
//protected double strokeWeight = 1;
//protected int[] colors = new int[0];
boolean resetRangeEachCycle = true;
public final String label;
protected int capacity;
private double[] specificMinMax;
private boolean specificRange;
double defaultValue = Double.NaN;
/** initializes with no fixed capacity */
public TreeMLData(String theName, Color color) {
this(theName, color, -1);
}
public TreeMLData(TreeMLData t) {
this.label = t.label;
this.colour = t.colour;
this.capacity = t.capacity;
this.values = t.values;
}
public TreeMLData(String theName, Color color, int historySize) {
this(theName, color.getRGB(), historySize);
}
public TreeMLData(String theName, int color, int historySize) {
label = theName;
this.colour = color;
capacity = historySize;
values = new TreeMap();
}
public TreeMLData setRange(double min, double max) {
this.specificRange = true;
this.specificMinMax = new double[] { min, max };
return this;
}
public int getColor() {
return colour;
}
public int getStart() {
if (values.isEmpty())
return 0;
return values.firstKey();
}
public int getEnd() {
if (values.isEmpty())
return 0;
Integer ret=null;
try{
ret=values.lastKey();
}
catch(Exception ex) {}
if(ret==null)
return 0;
return ret;
}
@Override
public void clear() {
values.clear();
}
public void setCapacity(int capacity) {
this.capacity = capacity;
}
public TreeMLData setDefaultValue(double defaultValue) {
this.defaultValue = defaultValue;
return this;
}
@Override
public void add(final int t, final double f) {
setData(t, f);
}
public void addPlus(final int t, final double f) {
Double x = getData(t);
if (x == null) setData(t, f);
else
setData(t, f + x.doubleValue());
}
@Override
public void setData(final int t, final double f) {
values.put(t, f);
if (capacity!=-1) {
while (values.size() > capacity) {
//TODO configurable removal policy
values.remove(values.firstKey());
}
}
}
/** clears the values and sets the data as if it were an array, starting at index 0 */
@Override public void setData(double[] doubles) {
values.clear();
int j = 0;
for (double d : doubles) {
setData(j++, d);
}
}
public double getSpecificMin() {
return specificMinMax[0];
}
public double getSpecificMax() {
return specificMinMax[1];
}
@Override
public double getData(int t) {
Double f=null;
try{
f = values.get(t);
}catch(Exception ex){}
if (f == null) {
return defaultValue;
}
return f;
}
@Override
public double[] getData() {
int size = size();
double[] n = new double[size];
int j = 0;
for (int i = getStart(); i <= getEnd(); i++) {
n[j++] = getData(i);
}
return n;
}
@Override
public TreeMLData clone() {
return new TreeMLData(this);
}
public double[] getMinMax(int start, int end) {
if (specificRange)
return specificMinMax;
double min=Double.POSITIVE_INFINITY, max=Double.NEGATIVE_INFINITY;
for (int i = start; i < end; i++) {
Double v = values.get(i);
if (v == null)
continue;
if (i == start)
min = max = v;
else {
if (v < min) min = v;
if (v > max) max = v;
}
}
return new double[] { min, max };
}
@Override
public int size() {
return (int) (getEnd() - getStart());
}
public double[] getMinMax() {
return getMinMax(getStart(), getEnd());
}
@Override
public Centroid<MLData> createCentroid() {
return new BasicMLDataCentroid(this);
}
public void push(double v) {
if (values.isEmpty())
setData(0, v);
else
setData(getEnd()+1, v);
}
public boolean max(int time, double newValue) {
double v = getData(time);
if ((Double.isNaN(v)) || (v < newValue)) {
setData(time, newValue);
return true;
}
return false;
}
public void removeData(int t) {
values.remove(t);
}
public static class FirstOrderDifferenceTimeSeries extends TreeMLData {
public final TreeMLData data;
public FirstOrderDifferenceTimeSeries(String name, TreeMLData s) {
super(name, Video.getColor(name, 0.8f, 0.8f), 1);
this.data = s;
}
@Override
public double getData(final int t) {
double prev = data.getData(t - 1);
if (Double.isNaN(prev)) {
return 0;
}
double cur = data.getData(t);
if (Double.isNaN(cur)) {
return 0;
}
return cur - prev;
}
}
@Override
public String toString() {
return values.toString();
}
}
//
///**
// * Use charts to display double array data as line chart, yet experimental, but see the ControlP5chart example
// * for more details.
// *
// * @example controllers/ControlP5chart
// */
//public class Chart extends Controller<Chart> {
//
// public final static int LINE = 0;
//
// public final static int BAR = 1;
//
// public final static int BAR_CENTERED = 2;
//
// public final static int HISTOGRAM = 3;
//
// public final static int PIE = 4;
//
// public final static int AREA = 5;
//
// protected final LinkedHashMap<String, ChartDataSet> _myDataSet;
//
// protected double resolution = 1;
//
// protected double strokeWeight = 1;
//
// protected double _myMin = 0;
//
// protected double _myMax = 1;
//
// /**
// * Convenience constructor to extend Chart.
// *
// * @example use/ControlP5extendController
// * @param theControlP5
// * @param theName
// */
// public Chart(ControlP5 theControlP5, String theName) {
// this(theControlP5, theControlP5.getDefaultTab(), theName, 0, 0, 200, 100);
// theControlP5.register(theControlP5.papplet, theName, this);
// }
//
// public Chart(ControlP5 theControlP5, ControllerGroup<?> theParent, String theName, double theX, double theY,
// int theWidth, int theHeight) {
// super(theControlP5, theParent, theName, theX, theY, theWidth, theHeight);
// setRange(0, theHeight);
// _myDataSet = new LinkedHashMap<String, ChartDataSet>();
// }
//
// public Chart setRange(double theMin, double theMax) {
// _myMin = theMin;
// _myMax = theMax;
// return this;
// }
//
// public Chart setColors(String theSetIndex, int... theColors) {
// getDataSet().get(theSetIndex).setColors(theColors);
// return this;
// }
//
// public Chart addData(ChartData theItem) {
// return addData(getFirstDataSetIndex(), theItem);
// }
//
// private String getFirstDataSetIndex() {
// return getDataSet().keySet().iterator().next();
// }
//
// public Chart addData(String theSetIndex, ChartData theItem) {
// getDataSet(theSetIndex).add(theItem);
// return this;
// }
//
// public Chart addData(double theValue) {
// ChartData cdi = new ChartData(theValue);
// getDataSet(getFirstDataSetIndex()).add(cdi);
// return this;
// }
//
// public Chart addData(String theSetIndex, double theValue) {
// ChartData cdi = new ChartData(theValue);
// getDataSet(theSetIndex).add(cdi);
// return this;
// }
//
// public Chart addData(ChartDataSet theChartData, double theValue) {
// ChartData cdi = new ChartData(theValue);
// theChartData.add(cdi);
// return this;
// }
//
// // array operations see syntax
// // http://www.w3schools.com/jsref/jsref_obj_array.asp
//
// /**
// * adds a new double at the beginning of the data set.
// */
// public Chart unshift(double theValue) {
// return unshift(getFirstDataSetIndex(), theValue);
// }
//
// public Chart unshift(String theSetIndex, double theValue) {
// if (getDataSet(theSetIndex).size() > (width / resolution)) {
// removeLast(theSetIndex);
// }
// return addFirst(theSetIndex, theValue);
// }
//
// public Chart add(double theValue) {
// return add(getFirstDataSetIndex(), theValue);
// }
//
// public Chart add(String theSetIndex, double theValue) {
// if (getDataSet(theSetIndex).size() > (width / resolution)) {
// removeFirst(theSetIndex);
// }
// return addLast(theSetIndex, theValue);
// }
//
// public Chart addFirst(double theValue) {
// return addFirst(getFirstDataSetIndex(), theValue);
// }
//
// public Chart addFirst(String theSetIndex, double theValue) {
// ChartData cdi = new ChartData(theValue);
// getDataSet(theSetIndex).add(0, cdi);
// return this;
// }
//
// public Chart addLast(double theValue) {
// return addLast(getFirstDataSetIndex(), theValue);
// }
//
// public Chart addLast(String theSetIndex, double theValue) {
// ChartData cdi = new ChartData(theValue);
// getDataSet(theSetIndex).add(cdi);
// return this;
// }
//
// public Chart removeLast() {
// return removeLast(getFirstDataSetIndex());
// }
//
// public Chart removeLast(String theSetIndex) {
// return removeData(theSetIndex, getDataSet(theSetIndex).size() - 1);
// }
//
// public Chart removeFirst() {
// return removeFirst(getFirstDataSetIndex());
// }
//
// public Chart removeFirst(String theSetIndex) {
// return removeData(theSetIndex, 0);
// }
//
// public Chart removeData(ChartData theItem) {
// removeData(getFirstDataSetIndex(), theItem);
// return this;
// }
//
// public Chart removeData(String theSetIndex, ChartData theItem) {
// getDataSet(theSetIndex).remove(theItem);
// return this;
// }
//
// public Chart removeData(int theItemIndex) {
// removeData(getFirstDataSetIndex(), theItemIndex);
// return this;
// }
//
// public Chart removeData(String theSetIndex, int theItemIndex) {
// if (getDataSet(theSetIndex).size() < 1) {
// return this;
// }
// getDataSet(theSetIndex).remove(theItemIndex);
// return this;
// }
//
// public Chart setData(int theItemIndex, ChartData theItem) {
// getDataSet(getFirstDataSetIndex()).set(theItemIndex, theItem);
// return this;
// }
//
// public Chart setData(String theSetItem, int theItemIndex, ChartData theItem) {
// getDataSet(theSetItem).set(theItemIndex, theItem);
// return this;
// }
//
// public Chart addDataSet(String theName) {
// getDataSet().put(theName, new ChartDataSet(theName));
// return this;
// }
//
// public Chart setDataSet(ChartDataSet theItems) {
// setDataSet(getFirstDataSetIndex(), theItems);
// return this;
// }
//
// public Chart setDataSet(String theSetIndex, ChartDataSet theChartData) {
// getDataSet().put(theSetIndex, theChartData);
// return this;
// }
//
// public Chart removeDataSet(String theIndex) {
// getDataSet().remove(theIndex);
// return this;
// }
//
// public Chart setData(double... theValues) {
// setData(getFirstDataSetIndex(), theValues);
// return this;
// }
//
// public Chart setData(String theSetIndex, double... theValues) {
// if (getDataSet().get(theSetIndex).size() != theValues.length) {
// getDataSet().get(theSetIndex).clear();
// for (int i = 0; i < theValues.length; i++) {
// getDataSet().get(theSetIndex).add(new ChartData(0));
// }
// }
// int n = 0;
// resolution = (double) width / (getDataSet().get(theSetIndex).size() - 1);
// for (double f : theValues) {
// getDataSet().get(theSetIndex).get(n++).setValue(f);
// }
// return this;
// }
//
// public Chart updateData(double... theValues) {
// return setData(theValues);
// }
//
// public Chart updateData(String theSetIndex, double... theValues) {
// return setData(theSetIndex, theValues);
// }
//
// public LinkedHashMap<String, ChartDataSet> getDataSet() {
// return _myDataSet;
// }
//
// public ChartDataSet getDataSet(String theIndex) {
// return getDataSet().get(theIndex);
// }
//
// public double[] getValuesFrom(String theIndex) {
// return getDataSet(theIndex).getValues();
// }
//
// public ChartData getData(String theIndex, int theItemIndex) {
// return getDataSet(theIndex).get(theItemIndex);
// }
//
// public int size() {
// return getDataSet().size();
// }
//
// @Override
// public void onEnter() {
// }
//
// @Override
// public void onLeave() {
// }
//
// @Override
// public Chart setValue(double theValue) {
// // TODO Auto-generated method stub
// return this;
// }
//
// public Chart setStrokeWeight(double theWeight) {
// strokeWeight = theWeight;
// for (ChartDataSet c : getDataSet().values()) {
// c.setStrokeWeight(theWeight);
// }
// return this;
// }
//
// public double getStrokeWeight() {
// return strokeWeight;
// }
//
// /**
// * ?
// *
// * @param theValue
// * @return
// */
// public Chart setResolution(int theValue) {
// resolution = theValue;
// return this;
// }
//
// public int getResolution() {
// return (int) resolution;
// }
//
// /**
// * @exclude
// */
// @ControlP5.Invisible
// public Chart updateDisplayMode(ControllerViewType theMode) {
// displayMode = theMode;
// switch (theMode) {
// case DEFAULT:
// controllerView = new ChartViewPie();
// break;
// case IMAGE:
// // _myDisplay = new ChartImageDisplay();
// break;
// case SPRITE:
// // _myDisplay = new ChartSpriteDisplay();
// break;
// case CUSTOM:
// default:
// break;
// }
// return this;
// }
//
// public class ChartViewBar implements ControllerView<Chart> {
//
// @Override
// public void display(PApplet theApplet, Chart theController) {
// theApplet.pushStyle();
// theApplet.fill(getColour().getBackground());
// theApplet.rect(0, 0, getWidth(), getHeight());
// theApplet.noStroke();
//
// Iterator<String> it = getDataSet().keySet().iterator();
// String index = null;
// double o = 0;
// while (it.hasNext()) {
// index = it.next();
// double s = getDataSet(index).size();
// for (int i = 0; i < s; i++) {
// theApplet.fill(getDataSet(index).getColor(i));
// double ww = ((width / s));
// double hh = PApplet.map(getDataSet(index).get(i).getData(), _myMin, _myMax, 0, getHeight());
// theApplet.rect(o + i * ww, getHeight(), (ww / getDataSet().size()),
// -PApplet.min(getHeight(), PApplet.max(0, hh)));
// }
// o += ((width / s)) / getDataSet().size();
// }
// theApplet.popStyle();
// }
// }
//
// public class ChartViewBarCentered implements ControllerView<Chart> {
//
// @Override
// public void display(PApplet theApplet, Chart theController) {
// theApplet.pushStyle();
// theApplet.fill(getColour().getBackground());
// theApplet.rect(0, 0, getWidth(), getHeight());
// theApplet.noStroke();
//
// Iterator<String> it = getDataSet().keySet().iterator();
// String index = null;
// double o = 0;
// int n = 4;
// int off = (getDataSet().size() - 1) * n;
// while (it.hasNext()) {
// index = it.next();
// int s = getDataSet(index).size();
// double step = (double) width / (double) (s);
// double ww = step - (width % step);
// ww -= 1;
// ww = PApplet.max(1, ww);
//
// for (int i = 0; i < s; i++) {
// theApplet.fill(getDataSet(index).getColor(i));
// ww = ((width / s) * 0.5f);
// double hh = PApplet.map(getDataSet(index).get(i).getData(), _myMin, _myMax, 0, getHeight());
// theApplet.rect(-off / 2 + o + i * ((width / s)) + ww / 2, getHeight(), ww,
// -PApplet.min(getHeight(), PApplet.max(0, hh)));
// }
// o += n;
// }
// theApplet.popStyle();
// }
// }
//
// public class ChartViewLine implements ControllerView<Chart> {
//
// @Override
// public void display(PApplet theApplet, Chart theController) {
//
// theApplet.pushStyle();
// theApplet.fill(getColour().getBackground());
// theApplet.rect(0, 0, getWidth(), getHeight());
// theApplet.noFill();
// Iterator<String> it = getDataSet().keySet().iterator();
// String index = null;
// while (it.hasNext()) {
// index = it.next();
// theApplet.stroke(getDataSet(index).getColor(0));
// theApplet.strokeWeight(getDataSet(index).getStrokeWeight());
//
// theApplet.beginShape();
// double res = ((double) getWidth()) / (getDataSet(index).size() - 1);
// for (int i = 0; i < getDataSet(index).size(); i++) {
// double hh = PApplet.map(getDataSet(index).get(i).getData(), _myMin, _myMax, getHeight(), 0);
// theApplet.vertex(i * res, PApplet.min(getHeight(), PApplet.max(0, hh)));
// }
// theApplet.endShape();
// }
// theApplet.noStroke();
// theApplet.popStyle();
// }
// }
//
// public class ChartViewArea implements ControllerView<Chart> {
//
// @Override
// public void display(PApplet theApplet, Chart theController) {
//
// theApplet.pushStyle();
// theApplet.fill(getColour().getBackground());
// theApplet.rect(0, 0, getWidth(), getHeight());
// theApplet.noStroke();
//
// Iterator<String> it = getDataSet().keySet().iterator();
// String index = null;
// while (it.hasNext()) {
// index = it.next();
// double res = ((double) getWidth()) / (getDataSet(index).size() - 1);
//
// theApplet.fill(getDataSet(index).getColor(0));
// theApplet.beginShape();
// theApplet.vertex(0, getHeight());
//
// for (int i = 0; i < getDataSet(index).size(); i++) {
// double hh = PApplet.map(getDataSet(index).get(i).getData(), _myMin, _myMax, getHeight(), 0);
// theApplet.vertex(i * res, PApplet.min(getHeight(), PApplet.max(0, hh)));
// }
// theApplet.vertex(getWidth(), getHeight());
// theApplet.endShape(PConstants.CLOSE);
// }
// theApplet.noStroke();
// theApplet.popStyle();
// }
// }
//
// public class ChartViewPie implements ControllerView<Chart> {
//
// @Override
// public void display(PApplet theApplet, Chart theController) {
// theApplet.pushStyle();
// theApplet.pushMatrix();
//
// Iterator<String> it = getDataSet().keySet().iterator();
// String index = null;
// while (it.hasNext()) {
// index = it.next();
// double total = 0;
// for (int i = 0; i < getDataSet(index).size(); i++) {
// total += getDataSet(index).get(i).getData();
// }
//
// double segment = ControlP5.TWO_PI / total;
// double angle = -ControlP5.HALF_PI;
//
// theApplet.noStroke();
// for (int i = 0; i < getDataSet(index).size(); i++) {
// theApplet.fill(getDataSet(index).getColor(i));
// double nextAngle = angle + getDataSet(index).get(i).getData() * segment;
//
// // a tiny offset to even out render artifacts when in smooth() mode.
// double a = PApplet.max(0, PApplet.map(getWidth(), 0, 200, 0.05f, 0.01f));
//
// theApplet.arc(0, 0, getWidth(), getHeight(), angle - a, nextAngle);
// angle = nextAngle;
// }
// theApplet.translate(0, (getHeight() + 10));
// }
// theApplet.popMatrix();
// theApplet.popStyle();
// }
// }
//
// public Chart setView(int theType) {
// switch (theType) {
// case (PIE):
// setView(new ChartViewPie());
// break;
// case (LINE):
// setView(new ChartViewLine());
// break;
// case (BAR):
// setView(new ChartViewBar());
// break;
// case (BAR_CENTERED):
// setView(new ChartViewBarCentered());
// break;
// case (AREA):
// setView(new ChartViewArea());
// break;
// default:
// System.out.println("Sorry, this ChartView does not exist");
// break;
// }
// return this;
// }
//
// @Override
// public String getInfo() {
// return "type:\tChart\n" + super.toString();
// }
//
// @Override
// public String toString() {
// return super.toString() + " [ " + getData() + " ]" + " Chart " + "(" + this.getClass().getSuperclass() + ")";
// }
//
//}
/*
* NOTES what is the difference in meaning between chart and graph
* http://answers.yahoo.com/question/index?qid=20090101193325AA3mgMl
*/