/* * Author: tdanford * Date: Sep 16, 2008 */ package org.seqcode.viz.eye; import java.awt.*; import java.lang.reflect.*; import java.util.*; import org.seqcode.genome.location.Region; import org.seqcode.genome.location.ScoredPoint; import org.seqcode.genome.location.ScoredRegion; import org.seqcode.gseutils.Pair; import org.seqcode.gseutils.models.Model; import org.seqcode.gseutils.models.ModelFieldAnalysis; import org.seqcode.viz.colors.Coloring; import org.seqcode.viz.paintable.*; public class ModelWeightedRangeValues extends AbstractModelPaintable { public static final String boundsKey = "bounds"; public static final String scaleKey = "scale"; public static final String colorKey = "color"; public static final String strokeKey = "stroke"; public static final String axisColorKey = "axis-color"; public static final String drawWeightKey = "draw-weight"; private String xFieldName, yFieldName, scoreFieldName; private Vector<Pair<Integer,Integer>> ranges; private Vector<Double> scores; private Vector<Model> models; public ModelWeightedRangeValues() { xFieldName = "start"; yFieldName = "end"; scoreFieldName = "score"; ranges = new Vector<Pair<Integer,Integer>>(); scores = new Vector<Double>(); models = new Vector<Model>(); Color transblue = Color.blue; transblue = Coloring.clearer(Coloring.clearer(transblue)); initProperty(new PropertyValueWrapper<Integer[]>(boundsKey, new Integer[] { 0, 1 })); initProperty(new PropertyValueWrapper<PaintableScale>(scaleKey, new PaintableScale(0.0, 1.0))); initProperty(new PropertyValueWrapper<Color>(colorKey, transblue)); initProperty(new PropertyValueWrapper<Float>(strokeKey, (float)3.0)); initProperty(new PropertyValueWrapper<Boolean>(drawWeightKey, Boolean.FALSE)); } public ModelWeightedRangeValues(String xfield, String yfield, String scoreField) { this(); xFieldName = xfield; yFieldName = yfield; scoreFieldName = scoreField; } public void addValue(Object value) { if (value instanceof ScoredRegion) { ScoredRegion r = (ScoredRegion)value; int start = r.getStart(), end = r.getEnd(); double s = r.getScore(); models.add(new ScoredRangeModel(start, end, s)); addScoredRangeValue(start, end, s); } else { super.addValue(value); } } public void addModel(Model m) { Class modelClass = m.getClass(); ModelFieldAnalysis analysis = new ModelFieldAnalysis(modelClass); Field xfield = analysis.findField(xFieldName); Field yfield = analysis.findField(yFieldName); Field scorefield = analysis.findField(scoreFieldName); if(xfield != null && yfield != null && scorefield != null) { try { Object xvalue = xfield.get(m); Object yvalue = yfield.get(m); Object svalue = scorefield.get(m); if(xvalue != null && yvalue != null && scorefield != null) { Class xclass = xvalue.getClass(); Class yclass = yvalue.getClass(); Class sclass = svalue.getClass(); if(!Model.isSubclass(xclass, Integer.class)) { throw new IllegalArgumentException("Start value must be an Integer"); } if(!Model.isSubclass(yclass, Integer.class)) { throw new IllegalArgumentException("End value must be an Integer"); } if(!Model.isSubclass(sclass, Number.class)) { throw new IllegalArgumentException("Score value must be an Number"); } Integer xnumber = (Integer)xvalue; Integer ynumber = (Integer)yvalue; Number snumber = (Number)svalue; int x = xnumber.intValue(); int y = ynumber.intValue(); double sc = snumber.doubleValue(); models.add(m); addScoredRangeValue(x, y, sc); } else { throw new IllegalArgumentException("location or value was null"); } } catch (IllegalAccessException e) { throw new IllegalArgumentException("location or value field was inaccessible", e); } } else { String msg = "No Fields:"; if(xfield == null) { msg += String.format(" %s", xFieldName); } if(yfield == null) { msg += String.format(" %s", yFieldName); } if(scorefield == null) { msg += String.format(" %s", scoreFieldName); } throw new IllegalArgumentException(msg); } } private void addScoredRangeValue(int x, int y, double s) { if(x > y) { throw new IllegalArgumentException(); } PaintableScale scale = getPropertyValue(scaleKey); ModelPaintableProperty boundsProp = getProperty(boundsKey); Integer[] bounds = (Integer[])boundsProp.getValue(); ranges.add(new Pair<Integer,Integer>(x, y)); scores.add(s); if(x < bounds[0] || y > bounds[1]) { bounds[0] = Math.min(x, bounds[0]); bounds[1] = Math.max(y, bounds[1]); setProperty(new PropertyValueWrapper<Integer[]>(boundsKey, bounds)); } scale.updateScale(s); dispatchChangedEvent(); } public void addModels(Iterator<? extends Model> itr) { while(itr.hasNext()) { addModel(itr.next()); } } public void clearModels() { ranges.clear(); models.clear(); scores.clear(); dispatchChangedEvent(); } public void paintItem(Graphics g, int x1, int y1, int x2, int y2) { Integer[] bounds = getPropertyValue(boundsKey); Color color = getPropertyValue(colorKey, Color.red); float stroke = getPropertyValue(strokeKey, (float)1.0); int strokeWidth = Math.max(1, (int)Math.floor(stroke)); Color axisColor = getPropertyValue(axisColorKey, Color.black); PaintableScale yScale = getPropertyValue(scaleKey); Boolean drawWeights = getPropertyValue(drawWeightKey); int length = Math.max(1, bounds[1] - bounds[0] + 1); int w = x2-x1, h = y2-y1; Graphics2D g2 = (Graphics2D)g; Stroke oldStroke = g2.getStroke(); g2.setStroke(new BasicStroke(stroke)); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); /** Painting Code **/ // Axes g2.setColor(axisColor); g2.drawRect(x1, y1, w-1, h-1); int wArea = w - strokeWidth*2; // Points for(int i = 0; i < ranges.size(); i++) { Pair<Integer,Integer> r = ranges.get(i); Double score = scores.get(i); int start = r.getFirst(); int end = r.getLast(); //System.out.println(String.format("=> %d, %d : %.3f", start, end, score)); double xf = (double)(start-bounds[0]) / (double)length; double yf = (double)(end-bounds[0]+1) / (double)length; double zf = yScale.fractionalOffset(score); int px = x1 + (int)Math.round(xf * (double)wArea); int py = x1 + (int)Math.round(yf * (double)wArea); int pz = y2 - (int)Math.round(zf * (double)h); g2.setColor(color); g2.fillRect(px, pz, py-px, y2-pz); g2.setColor(Color.black); g2.drawLine(px, pz, py, pz); if(drawWeights) { g2.drawString(String.format("%.2", score), px+(py-px)/2, y2-pz-1); } } g2.setStroke(oldStroke); } public static class ScoredRangeModel extends Model { public Integer start, end; public Double score; public ScoredRangeModel(int s, int e, double ss) { start = s; end = e; score = ss; } } }