/*
* Author: tdanford
* Date: Jun 3, 2009
*/
package org.seqcode.viz.eye;
import java.util.*;
import java.lang.reflect.*;
import java.awt.*;
import java.io.*;
import org.seqcode.gseutils.models.*;
import org.seqcode.ml.regression.DataFrame;
import org.seqcode.viz.paintable.PaintableFrame;
import org.seqcode.viz.paintable.PaintableScale;
import org.seqcode.viz.paintable.VerticalScalePainter;
public class ModelBarChart extends AbstractModelPaintable {
public static void main(String[] args) {
File f = new File(args[0]);
try {
DataFrame<BarValue> frame = new DataFrame<BarValue>(BarValue.class, f, false, "x", "y");
System.out.println(String.format("Loaded %d values.", frame.size()));
ModelBarChart chart = new ModelBarChart();
chart.addModels(frame.iterator());
//chart.setProperty(new PropertyValueWrapper(labelKey, Boolean.FALSE));
chart.setProperty(new PropertyValueWrapper(sortedKey, Boolean.TRUE));
PaintableFrame pf = new PaintableFrame(f.getName(), chart);
} catch (IOException e) {
e.printStackTrace();
}
}
public static final String scaleKey = "scale";
public static final String colorKey = "color";
public static final String labelKey = "labels";
public static final String outlineKey = "outlines";
public static final String sortedKey = "sorted";
private LinkedList<Model> models;
private Map<String,Double> values;
private String xField, yField;
public ModelBarChart() {
this("x", "y");
}
public ModelBarChart(String x, String y) {
xField = x;
yField = y;
models = new LinkedList<Model>();
values = new LinkedHashMap<String,Double>();
initProperty(new PropertyValueWrapper(scaleKey, new PaintableScale(0.0, 1.0)));
initProperty(new PropertyValueWrapper(colorKey, Color.blue));
initProperty(new PropertyValueWrapper(labelKey, Boolean.TRUE));
initProperty(new PropertyValueWrapper(outlineKey, Boolean.TRUE));
initProperty(new PropertyValueWrapper(sortedKey, Boolean.FALSE));
}
public void addModel(Model m) {
ModelFieldAnalysis analysis = new ModelFieldAnalysis(m.getClass());
Field xfld = analysis.findTypedField(xField, String.class);
Field yfld = analysis.findTypedField(yField, Number.class);
if(xfld != null && yfld != null) {
try {
String xvalue = (String) xfld.get(m);
Number yvalue = ((Number)yfld.get(m));
if(xvalue != null && yvalue != null) {
models.add(m);
double y = yvalue.doubleValue();
PaintableScale scale = getPropertyValue(scaleKey);
scale.updateScale(y);
values.put(xvalue, y);
dispatchChangedEvent();
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
public void addModels(Iterator<? extends Model> itr) {
while(itr.hasNext()) {
addModel(itr.next());
}
}
public BarValue[] values() {
BarValue[] varray = new BarValue[values.size()];
int i = 0;
for(String key : values.keySet()) {
varray[i++] = new BarValue(key, values.get(key));
}
Arrays.sort(varray);
return varray;
}
private Collection<String> sortedKeys() {
BarValue[] varray = values();
LinkedList<String> keys = new LinkedList<String>();
for(int i = 0; i < varray.length; i++) {
keys.add(varray[i].x);
}
return keys;
}
public void clearModels() {
models.clear();
values.clear();
}
public void paintItem(Graphics g, int x1, int y1, int x2, int y2) {
PaintableScale scale = getPropertyValue(scaleKey);
Color color = getPropertyValue(colorKey);
Boolean labels = getPropertyValue(labelKey);
Boolean outlines = getPropertyValue(outlineKey);
Boolean sorted = getPropertyValue(sortedKey);
int w = x2-x1, h = y2-y1;
Graphics2D g2 = (Graphics2D)g;
Font oldFont = g2.getFont();
int fontSize = 28;
Font newFont = new Font("Times New Roman", Font.PLAIN, fontSize);
g2.setFont(newFont);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
FontMetrics fm = g2.getFontMetrics();
int textHeight = fm.getAscent() + fm.getDescent();
int numValues = Math.max(1, values.size());
int strips = (values.size()*2) + 1;
int stripWidth = (int)Math.floor((double)w / (double)strips);
int labelHeight = labels ? (int)Math.floor((double)h / 5.0) : 0;
int dataHeight = h - labelHeight;
while(textHeight > stripWidth*2 && fontSize > 1) {
fontSize -= 1;
newFont = new Font(newFont.getFamily(), Font.PLAIN, fontSize);
g2.setFont(newFont);
fm = g2.getFontMetrics();
textHeight = fm.getAscent() + fm.getDescent();
}
int i = 0;
Collection<String> keys = sorted ? sortedKeys() : values.keySet();
for(String key : keys) {
int x = stripWidth + (i*2*stripWidth);
double value = values.get(key);
double valuef = scale.fractionalOffset(value);
int barHeight = (int)Math.round(valuef * (double)dataHeight);
int y = y1 + dataHeight - barHeight;
g.setColor(color);
g.fillRect(x, y, stripWidth, barHeight);
if(outlines) {
g.setColor(Color.black);
Stroke oldStroke = g2.getStroke();
Stroke newStroke = new BasicStroke((float)2.0);
g2.drawRect(x, y, stripWidth, barHeight);
g2.setStroke(oldStroke);
}
if(labels) {
g.setColor(Color.black);
int textWidth = fm.charsWidth(key.toCharArray(), 0, key.length());
FontMetrics cfm = fm;
Font currentFont = g2.getFont();
int currentFontSize = fontSize;
while(textWidth > (h - dataHeight) &&
currentFontSize > 1) {
currentFontSize -= 1;
currentFont = new Font(currentFont.getFamily(), Font.PLAIN, currentFontSize);
g2.setFont(currentFont);
cfm = g2.getFontMetrics();
textWidth = cfm.charsWidth(key.toCharArray(), 0, key.length());
}
//int tx = x + stripWidth/2 - textWidth/2;
//int ty = y + barHeight + fm.getAscent() + 2;
int tx = x + stripWidth/2 - cfm.getDescent();
int ty = y2 - labelHeight + 2;
g2.translate(tx, ty);
g2.rotate(Math.PI/2.0);
//g2.drawString(key, tx, ty);
g2.drawString(key, 0, 0);
g2.rotate(-Math.PI / 2.0);
g2.translate(-tx, -ty);
g2.setFont(newFont);
}
i += 1;
}
VerticalScalePainter vsp = new VerticalScalePainter(scale);
g.setColor(Color.black);
g.drawLine(x1, y1+dataHeight, x2, y1+dataHeight);
vsp.paintItem(g, x1, y1, x2, y1+dataHeight);
g2.setFont(oldFont);
}
public static class BarValue extends Model implements Comparable<BarValue> {
public String x;
public Double y;
public BarValue() {}
public BarValue(String x, Double y) {
this.x = x;
this.y = y;
}
public int hashCode() { return x.hashCode(); }
public boolean equals(Object o) {
if(!(o instanceof BarValue)) { return false; }
BarValue v = (BarValue)o;
if(!x.equals(v.x)) { return false; }
return true;
}
public int compareTo(BarValue v) {
if(y > v.y) { return -1; }
if(y < v.y) { return 1; }
return x.compareTo(v.x);
}
}
}