annotate yetilab/plot/plot.yeti @ 137:b28512329efc

Offscreen rendering & save-to-file (save-to-file works, offscreen currently doesn't)
author Chris Cannam
date Tue, 23 Apr 2013 16:27:28 +0100
parents 1101ecb57e47
children f68c92bd2adb
rev   line source
Chris@108 1 module yetilab.plot.plot;
Chris@108 2
Chris@108 3 import org.jzy3d.plot3d.builder: Mapper;
Chris@128 4 import org.jzy3d.plot3d.text.drawable: DrawableTextBillboard, DrawableTextBitmap;
Chris@119 5 import org.jzy3d.maths: Range, Coord3d;
Chris@126 6 import org.jzy3d.plot3d.primitives: Shape, HistogramBar, FlatLine2d, Polygon, Quad, Point;
Chris@119 7 import org.jzy3d.plot3d.primitives.axes.layout.providers: StaticTickProvider;
Chris@133 8 import org.jzy3d.plot3d.primitives.axes.layout.renderers: ITickRenderer, TickLabelMap;
Chris@108 9 import org.jzy3d.chart: Chart, ChartLauncher;
Chris@108 10 import org.jzy3d.plot3d.builder: Builder;
Chris@108 11 import org.jzy3d.plot3d.builder.concrete: OrthonormalGrid;
Chris@108 12 import org.jzy3d.colors.colormaps: ColorMapRainbow;
Chris@119 13 import org.jzy3d.colors: ColorMapper, Color;
Chris@108 14 import org.jzy3d.plot3d.rendering.canvas: Quality;
Chris@119 15 import org.jzy3d.plot3d.rendering.view.modes: ViewPositionMode;
Chris@108 16
Chris@137 17 import javax.imageio: ImageIO;
Chris@137 18
Chris@137 19 import java.io: File;
Chris@137 20
Chris@132 21 chartColours = array [
Chris@132 22 { r = 82, g = 126, b = 154 }, // dark steel blue
Chris@132 23 { r = 161, g = 54, b = 2 }, // red
Chris@132 24 { r = 207, g = 228, b = 148 }, // grey-green
Chris@132 25 { r = 21, g = 183, b = 197 }, // light blue
Chris@132 26 { r = 251, g = 116, b = 43 }, // light red
Chris@132 27 { r = 200, g = 125, b = 234 }, // light purple
Chris@132 28 { r = 126, g = 33, b = 28 }, // dried blood!
Chris@132 29 { r = 188, g = 13, b = 207 }, // mid purple
Chris@131 30 ];
Chris@131 31
Chris@132 32 chartColour n =
Chris@132 33 if n < 0
Chris@132 34 then chartColour (-n)
Chris@132 35 else
Chris@132 36 rgb = chartColours[n % (length chartColours)];
Chris@132 37 new Color(rgb.r / 255.0, rgb.g / 255.0, rgb.b / 255.0);
Chris@132 38 fi;
Chris@132 39
Chris@108 40 newMatrixMapper matrix =
Chris@108 41 (class MMapper extends Mapper
Chris@108 42 double f(double x, double y)
Chris@117 43 result = matrix.getAt y x;
Chris@117 44 println "f(\(x),\(y)) -> \(result)";
Chris@117 45 result
Chris@108 46 end;
Chris@108 47 new MMapper());
Chris@108 48
Chris@108 49 newMatrixLogMapper matrix =
Chris@108 50 (class MMapper extends Mapper
Chris@108 51 double f(double x, double y)
Chris@108 52 ln (matrix.getAt y x)
Chris@108 53 end;
Chris@108 54 new MMapper());
Chris@108 55
Chris@108 56 newMapper mapFunction =
Chris@108 57 (class FMapper extends Mapper
Chris@108 58 double f(double x, double y)
Chris@108 59 mapFunction x y
Chris@108 60 end;
Chris@108 61 new FMapper());
Chris@108 62
Chris@133 63 newPercentTickRenderer () =
Chris@133 64 (f v = " \(int (v * 100))%";
Chris@133 65 class PercentageTickRenderer extends ITickRenderer
Chris@133 66 String format(double value) f value,
Chris@133 67 String format(float value) f value
Chris@133 68 end;
Chris@133 69 new PercentageTickRenderer());
Chris@133 70
Chris@132 71 parseOptions options defaultKeys defaultXKeys =
Chris@132 72 (parsed = {
Chris@133 73 var keys = array (sort defaultKeys),
Chris@132 74 var labels = [:],
Chris@132 75 var animated = false,
Chris@132 76 var normalised = false,
Chris@132 77 var unit = "",
Chris@137 78 var xkeys = array (sort defaultXKeys),
Chris@137 79 var saveTo = "",
Chris@137 80 var display = true,
Chris@132 81 };
Chris@132 82 for options
Chris@132 83 \case of
Chris@133 84 Keys kk: parsed.keys := array kk;
Chris@133 85 XKeys xk: parsed.xkeys := array xk;
Chris@132 86 Animated a: parsed.animated := a;
Chris@132 87 Normalised n: parsed.normalised := n;
Chris@132 88 Unit u: parsed.unit := u;
Chris@132 89 Labels ll: parsed.labels := ll;
Chris@137 90 SaveTo file: parsed.saveTo := file;
Chris@137 91 Display d: parsed.display := d;
Chris@132 92 esac;
Chris@132 93 if empty? parsed.labels then
Chris@132 94 parsed.labels := mapIntoHash id id parsed.keys
Chris@132 95 fi;
Chris@132 96 parsed);
Chris@132 97
Chris@137 98 newChart opts =
Chris@137 99 (quality = Quality#Fastest;
Chris@137 100 quality#setAnimated(opts.animated);
Chris@137 101 // if opts.display then
Chris@137 102 new Chart(quality);
Chris@137 103 // else
Chris@137 104 // new Chart(quality, "offscreen,640,640");
Chris@137 105 // fi);
Chris@137 106 );
Chris@137 107
Chris@137 108 showChart opts chart is 'a -> ~Chart -> () =
Chris@137 109 (//if opts.display then
Chris@137 110 \() ChartLauncher#openChart(chart);
Chris@137 111 // fi;
Chris@137 112 if opts.saveTo != "" then
Chris@137 113 \() chart#screenshot(opts.saveTo);
Chris@137 114 fi);
Chris@137 115
Chris@115 116 plotMatrix matrix =
Chris@117 117 (mapper = newMatrixMapper matrix;
Chris@108 118 size = matrix.size;
Chris@119 119 xrange = new Range(0, size.columns - 1);
Chris@119 120 yrange = new Range(0, size.rows - 1);
Chris@108 121 grid = new OrthonormalGrid(xrange, size.columns, yrange, size.rows);
Chris@112 122 println "Matrix size: \(size)";
Chris@117 123 surface = Builder#buildOrthonormal(grid, mapper); //??? big?
Chris@117 124 println "Z Bounds: \(surface#getBounds()#getZmin()) -> \(surface#getBounds()#getZmax())";
Chris@121 125 surface#setFaceDisplayed(true);
Chris@108 126 surface#setWireframeDisplayed(true);
Chris@108 127 surface#setWireframeColor(Color#BLACK);
Chris@112 128 // chart = new Chart(Quality#Fastest, "swing");
Chris@112 129 chart = new Chart(Quality#Nicest);
Chris@108 130 chart#getScene()#getGraph()#add(surface);
Chris@115 131 ChartLauncher#openChart(chart);
Chris@115 132 ());
Chris@108 133
Chris@132 134 plotBarChart options values =
Chris@132 135 (opts = parseOptions options (keys values) [];
Chris@137 136 chart = newChart opts;
Chris@132 137 var n = length opts.keys;
Chris@119 138 scene = chart#getScene();
Chris@137 139 ticks = new double[n+1];
Chris@119 140 tickLabels = new TickLabelMap();
Chris@132 141 var i = 0;
Chris@132 142 var x = n - i - 1;
Chris@134 143 total = sum (map do k: if k in values then values[k] else 0 fi done opts.keys);
Chris@132 144 for opts.keys do k:
Chris@136 145 bar = new HistogramBar();
Chris@134 146 v = if k in values then values[k] else 0 fi;
Chris@133 147 v = if opts.normalised and total > 0 then v / total else v fi;
Chris@136 148 bar#setData(new Coord3d(x, 0, 0), v, 0.45, chartColour i);
Chris@136 149 bar#setWireframeDisplayed(false);
Chris@136 150 scene#add(bar);
Chris@132 151 ticks[i] := i;
Chris@132 152 tickLabels#register(x, opts.labels[k]);
Chris@132 153 i := i + 1;
Chris@132 154 x := x - 1;
Chris@119 155 done;
Chris@136 156 chart#getView()#setViewPoint(new Coord3d(pi/2, 0, 0));
Chris@136 157 axes = chart#getAxeLayout();
Chris@136 158 axes#setXAxeLabelDisplayed(false);
Chris@136 159 axes#setYAxeLabelDisplayed(false);
Chris@136 160 axes#setZAxeLabelDisplayed(true);
Chris@136 161 if opts.normalised then
Chris@136 162 axes#setZAxeLabel("");
Chris@136 163 axes#setZTickRenderer(newPercentTickRenderer ());
Chris@135 164 else
Chris@136 165 axes#setZAxeLabel(opts.unit);
Chris@135 166 fi;
Chris@119 167 axes#setXTickProvider(new StaticTickProvider(ticks));
Chris@119 168 axes#setXTickRenderer(tickLabels);
Chris@136 169 axes#setYTickLabelDisplayed(false);
Chris@137 170 showChart opts chart);
Chris@119 171
Chris@132 172 plotLines options values =
Chris@132 173 (opts = parseOptions options (keys values) (keys values[head (keys values)]);
Chris@137 174 chart = newChart opts;
Chris@124 175 scene = chart#getScene();
Chris@132 176 n = length opts.xkeys;
Chris@124 177 var z = 0;
Chris@132 178 for opts.keys do k:
Chris@124 179 v = values[k];
Chris@124 180 x = new float[n];
Chris@124 181 y = new float[n];
Chris@124 182 var i = 0;
Chris@132 183 for opts.xkeys do xk:
Chris@124 184 x[i] := i;
Chris@124 185 y[i] := if xk in v then v[xk] else 0 fi;
Chris@124 186 i := i + 1;
Chris@124 187 done;
Chris@124 188 line = new FlatLine2d(x, y, z);
Chris@124 189 line#setWireframeDisplayed(true);
Chris@132 190 line#setWireframeColor(chartColour z);
Chris@124 191 line#setWireframeWidth(2);
Chris@124 192 line#setFaceDisplayed(false);
Chris@124 193 scene#add(line);
Chris@124 194 z := z + 1;
Chris@124 195 done;
Chris@124 196 chart#getView()#setViewPoint(new Coord3d(0, 0, 0));
Chris@124 197 axes = chart#getAxeLayout();
Chris@124 198 axes#setXAxeLabelDisplayed(false);
Chris@124 199 axes#setYAxeLabelDisplayed(false);
Chris@124 200 axes#setZAxeLabelDisplayed(true);
Chris@132 201 axes#setZAxeLabel(opts.unit);
Chris@124 202 axes#setYTickLabelDisplayed(false);
Chris@137 203 showChart opts chart);
Chris@124 204
Chris@129 205 stack keys xkeys values normalised =
Chris@127 206 (stacked = mapIntoHash id \(mapIntoHash id \{ y0 = 0, y1 = 0 } xkeys) keys;
Chris@125 207 prev = mapIntoHash id \0 xkeys;
Chris@129 208 valueOf k xk = if xk in values[k] then values[k][xk] else 0 fi;
Chris@125 209 for xkeys do xk:
Chris@129 210 total = sum (map do k: valueOf k xk done keys);
Chris@125 211 for keys do k:
Chris@129 212 value =
Chris@129 213 if normalised and total > 0
Chris@129 214 then (valueOf k xk) / total
Chris@129 215 else (valueOf k xk)
Chris@129 216 fi;
Chris@125 217 height = prev[xk] + value;
Chris@127 218 stacked[k][xk] := { y0 = prev[xk], y1 = height };
Chris@125 219 prev[xk] := height;
Chris@125 220 done;
Chris@125 221 done;
Chris@125 222 stacked);
Chris@125 223
Chris@136 224 newRect x y0 y1 z colour is number -> number -> number -> number -> ~Color -> 'a =
Chris@136 225 (poly = new Quad();
Chris@136 226 poly#add(new Point(new Coord3d(x + 0.5, z, y0)));
Chris@136 227 poly#add(new Point(new Coord3d(x + 0.5, z, y1)));
Chris@136 228 poly#add(new Point(new Coord3d(x - 0.5, z, y1)));
Chris@136 229 poly#add(new Point(new Coord3d(x - 0.5, z, y0)));
Chris@136 230 poly#setWireframeDisplayed(true);
Chris@136 231 poly#setWireframeColor(colour);
Chris@136 232 poly#setFaceDisplayed(true);
Chris@136 233 poly#setColor(colour);
Chris@136 234 poly);
Chris@136 235
Chris@132 236 plotStacked options values =
Chris@132 237 (opts = parseOptions options (keys values) (keys values[head (keys values)]);
Chris@137 238 chart = newChart opts;
Chris@125 239 scene = chart#getScene();
Chris@132 240 stacked = stack opts.keys opts.xkeys values opts.normalised;
Chris@125 241 var z = 0;
Chris@130 242 var ty = 0;
Chris@133 243 xtickLabels = new TickLabelMap();
Chris@133 244 for [0..length opts.xkeys - 1] do x:
Chris@133 245 xtickLabels#register(x, opts.xkeys[x]);
Chris@133 246 done;
Chris@132 247 for opts.keys do k:
Chris@127 248 ranges = stacked[k];
Chris@132 249 c = chartColour z;
Chris@133 250 for [0..length opts.xkeys - 1] do x:
Chris@133 251 xk = opts.xkeys[x];
Chris@127 252 rect = newRect x ranges[xk].y0 ranges[xk].y1 z c;
Chris@127 253 scene#add(rect);
Chris@125 254 done;
Chris@132 255 text = new DrawableTextBitmap(opts.labels[k], new Coord3d(-5, z, ty), c);
Chris@128 256 scene#add(text);
Chris@126 257 z := z - 1;
Chris@130 258 ty := ty + 0.1;
Chris@125 259 done;
Chris@129 260 chart#getView()#setViewPoint(new Coord3d(-pi/2, 0, 0));
Chris@125 261 axes = chart#getAxeLayout();
Chris@125 262 axes#setXAxeLabelDisplayed(false);
Chris@133 263 axes#setXTickRenderer(xtickLabels);
Chris@125 264 axes#setYAxeLabelDisplayed(false);
Chris@125 265 axes#setZAxeLabelDisplayed(true);
Chris@133 266 if opts.normalised then
Chris@133 267 axes#setZAxeLabel("");
Chris@133 268 axes#setZTickRenderer(newPercentTickRenderer ());
Chris@133 269 else
Chris@133 270 axes#setZAxeLabel(opts.unit);
Chris@133 271 fi;
Chris@125 272 axes#setYTickLabelDisplayed(false);
Chris@137 273 showChart opts chart);
Chris@124 274
Chris@110 275 plotStructure structure =
Chris@110 276 case structure of
Chris@110 277 Grid matrix:
Chris@115 278 plotMatrix matrix;
Chris@110 279 //!!!
Chris@110 280 _: failWith "Cannot plot this structure (only grids implemented so far)";
Chris@110 281 esac;
Chris@108 282
Chris@115 283 {
Chris@119 284 newMatrixMapper,
Chris@119 285 newMatrixLogMapper,
Chris@119 286 newMapper,
Chris@115 287 plotMatrix,
Chris@124 288 plotBarChart,
Chris@124 289 plotLines,
Chris@125 290 stack,
Chris@125 291 plotStacked,
Chris@119 292 plotStructure,
Chris@115 293 }
Chris@110 294