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 */