annotate yetilab/plot/plot.yeti @ 134:194fff15f56f

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