annotate yetilab/plot/plot.yeti @ 136:1101ecb57e47

Backed out changeset b1968c825a53 Horizontal bar chart doesn't work any better for us than vertical, and this polygon structure doesn't seem to render as cleanly
author Chris Cannam
date Tue, 23 Apr 2013 13:51:12 +0100
parents b1968c825a53
children b28512329efc
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@136 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@136 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@136 124 bar#setData(new Coord3d(x, 0, 0), v, 0.45, chartColour i);
Chris@136 125 bar#setWireframeDisplayed(false);
Chris@136 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@136 132 chart#getView()#setViewPoint(new Coord3d(pi/2, 0, 0));
Chris@136 133 axes = chart#getAxeLayout();
Chris@136 134 axes#setXAxeLabelDisplayed(false);
Chris@136 135 axes#setYAxeLabelDisplayed(false);
Chris@136 136 axes#setZAxeLabelDisplayed(true);
Chris@136 137 if opts.normalised then
Chris@136 138 axes#setZAxeLabel("");
Chris@136 139 axes#setZTickRenderer(newPercentTickRenderer ());
Chris@135 140 else
Chris@136 141 axes#setZAxeLabel(opts.unit);
Chris@135 142 fi;
Chris@119 143 axes#setXTickProvider(new StaticTickProvider(ticks));
Chris@119 144 axes#setXTickRenderer(tickLabels);
Chris@136 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@136 204 newRect x y0 y1 z colour is number -> number -> number -> number -> ~Color -> 'a =
Chris@136 205 (poly = new Quad();
Chris@136 206 poly#add(new Point(new Coord3d(x + 0.5, z, y0)));
Chris@136 207 poly#add(new Point(new Coord3d(x + 0.5, z, y1)));
Chris@136 208 poly#add(new Point(new Coord3d(x - 0.5, z, y1)));
Chris@136 209 poly#add(new Point(new Coord3d(x - 0.5, z, y0)));
Chris@136 210 poly#setWireframeDisplayed(true);
Chris@136 211 poly#setWireframeColor(colour);
Chris@136 212 poly#setFaceDisplayed(true);
Chris@136 213 poly#setColor(colour);
Chris@136 214 poly);
Chris@136 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