1 /**
2     This module contains the different examples that are shown in the README
3 
4     It will only be included in unittest code, but is empty otherwise.
5 */
6 module example;
7 
8 version (unittest)
9 
10 import dunit.toolkit;
11 import std.stdio : writeln;
12 
13 ///
14 unittest
15 {
16     /// http://blackedder.github.io/ggplotd/images/function.png
17     import std.random : uniform;
18     import std.typecons : Tuple;
19     import ggplotd.stat : statFunction;
20     import ggplotd.ggplotd : GGPlotD;
21     import ggplotd.geom : geomLine, geomPoint;
22     import ggplotd.range : mergeRange;
23 
24     auto f = (double x) { return x / (1 + x); };
25 
26     auto aes = statFunction(f, 0.0, 10);
27     auto gg = GGPlotD().put(geomLine(aes));
28 
29     // Generate some noisy points 
30     auto f2 = (double x) { return x / (1 + x) * uniform(0.75, 1.25); };
31     auto aes2 = f2.statFunction(0.0, 10, 25);
32 
33     // Show points in different colour
34     auto withColour = Tuple!(string, "colour")("aquamarine").mergeRange(aes2);
35     gg = gg.put(withColour.geomPoint);
36 
37     gg.save("function.png");
38 }
39 
40 ///
41 unittest
42 {
43     /// http://blackedder.github.io/ggplotd/images/hist2D.svg
44     import std.array : array;
45     import std.algorithm : map;
46     import std.range : iota, zip;
47     import std.random : uniform;
48 
49     import ggplotd.aes : aes;
50     import ggplotd.colour : colourGradient;
51     import ggplotd.colourspace : XYZ;
52     import ggplotd.geom : geomHist2D;
53     import ggplotd.ggplotd : GGPlotD, putIn;
54     import ggplotd.legend : continuousLegend;
55 
56     auto xs = iota(0,500,1).map!((x) => uniform(0.0,5)+uniform(0.0,5))
57         .array;
58     auto ys = iota(0,500,1).map!((y) => uniform(0.0,5)+uniform(0.0,5))
59         .array;
60     auto gg = xs.zip(ys)
61                 .map!((t) => aes!("x","y")(t[0], t[1]))
62                 .geomHist2D.putIn(GGPlotD());
63     // Use a different colour scheme
64     gg.put( colourGradient!XYZ( "white-cornflowerBlue-crimson" ) );
65 
66     gg.put(continuousLegend);
67 
68     gg.save( "hist2D.svg" );
69 }
70 
71 ///
72 unittest
73 {
74     /// http://blackedder.github.io/ggplotd/images/filled_density.svg
75     import std.array : array;
76     import std.algorithm : map;
77     import std.range : repeat, iota, chain, zip;
78     import std.random : uniform;
79 
80     import ggplotd.aes : aes;
81     import ggplotd.geom : geomDensity;
82     import ggplotd.ggplotd : GGPlotD, putIn;
83     import ggplotd.legend : discreteLegend;
84     auto xs = iota(0,50,1).map!((x) => uniform(0.0,5)+uniform(0.0,5)).array;
85     auto cols = "a".repeat(25).chain("b".repeat(25));
86     auto gg = xs.zip(cols, 0.45.repeat(xs.length))
87         .map!((a) => aes!("x", "colour", "fill")(a[0], a[1], a[2]))
88         .geomDensity
89         .putIn(GGPlotD());
90     gg = discreteLegend.putIn(gg);
91     gg.save( "filled_density.svg" );
92 }
93 
94 ///
95 unittest
96 {
97     /// http://blackedder.github.io/ggplotd/images/density2D.png
98     import std.algorithm : map;
99     import std.range : iota, zip;
100     import std.random : uniform, Random, unpredictableSeed;
101 
102     import ggplotd.aes : aes;
103     import ggplotd.colour : colourGradient;
104     import ggplotd.colourspace : XYZ;
105     import ggplotd.geom : geomDensity2D;
106     import ggplotd.ggplotd : GGPlotD, putIn;
107     import ggplotd.legend : continuousLegend;
108 
109     // For debugging reasons, print out the current seed
110     import std.stdio : writeln;
111     auto rnd = Random(unpredictableSeed);
112     writeln("Random seed: ", rnd.front);
113 
114     auto xs = iota(0,500,1).map!((x) => uniform(0.0,5, rnd)+uniform(0.0,5, rnd));
115     auto ys = iota(0,500,1).map!((y) => uniform(0.5,1.5, rnd)+uniform(0.5,1.5, rnd));
116     auto gg = zip(xs, ys)
117         .map!((a) => aes!("x","y")(a[0], a[1]))
118         .geomDensity2D
119         .putIn( GGPlotD() );
120     // Use a different colour scheme
121     gg.put( colourGradient!XYZ( "white-cornflowerBlue-crimson" ) );
122     gg.put(continuousLegend);
123 
124     gg.save( "density2D.png" );
125 }
126 
127 ///
128 unittest
129 {
130     /// http://blackedder.github.io/ggplotd/images/labels.png
131     import std.algorithm : map;
132     import std.range : zip;
133     import std.math : PI;
134 
135     import ggplotd.aes : aes;
136     import ggplotd.geom : geomPoint, geomLabel;
137     import ggplotd.ggplotd : GGPlotD;
138     import ggplotd.axes : xaxisRange, yaxisRange;
139     auto dt = zip( [0.0,1,2,3,4], [4.0,3,2,1,0], 
140         ["center", "left", "right", "bottom", "top"],
141         [0.0, 0.0, 0.0, 0.0, 0.0],
142         ["center", "left", "right", "bottom", "top"])
143         .map!((a) => aes!("x", "y", "label", "angle", "justify")
144             (a[0], a[1], a[2], a[3], a[4]));
145 
146     auto gg = GGPlotD()
147         .put(geomPoint( dt ))
148         .put(geomLabel(dt))
149         .put(xaxisRange(-2,11))
150         .put(yaxisRange(-2,11));
151 
152     auto dt2 = zip( [1.0,2,3,4,5], [5.0,4,3,2,1], 
153         ["center", "left", "right", "bottom", "top"],
154         [0.5*PI, 0.5*PI, 0.5*PI, 0.5*PI, 0.5*PI],
155         ["center", "left", "right", "bottom", "top"])
156         .map!((a) => aes!("x", "y", "label", "angle", "justify")
157             (a[0], a[1], a[2], a[3], a[4]));
158     gg.put( geomLabel(dt2) ).put(geomPoint(dt2));
159 
160     auto dt3 = zip( [1.0,2,4,6,7], [8.0,7,5,3,2], 
161         ["center", "left", "right", "bottom", "top"],
162         [0.25*PI, 0.25*PI, 0.25*PI, 0.25*PI, 0.25*PI],
163         ["center", "left", "right", "bottom", "top"])
164         .map!((a) => aes!("x", "y", "label", "angle", "justify")
165             (a[0], a[1], a[2], a[3], a[4]));
166     gg.put( geomLabel(dt3) ).put(geomPoint(dt3));
167 
168     gg.save( "labels.png" );
169 }
170 
171 auto runMCMC() {
172     import std.algorithm : map;
173     import std.array : array;
174     import std.math : pow;
175     import std.range : iota;
176     import std.random : Random, unpredictableSeed;
177 
178     // For debugging reasons, print out the current seed
179     import std.stdio : writeln;
180     auto rnd = Random(unpredictableSeed);
181     //auto rnd = Random(1193462362); // This is a seed that currently fails. Use it for debugging
182     writeln("Random seed MCMC: ", rnd.front);
183 
184     import dstats.random : rNorm;
185     return iota(0,1000).map!((i) {
186         auto x = rNorm(1, 0.5, rnd);
187         auto y = rNorm(pow(x,3), 0.5, rnd);
188         auto z = rNorm(x + y, 0.5, rnd);
189         return [x, y, z];
190     }).array;
191 }
192 
193 ///
194 unittest
195 {
196     // http://blackedder.github.io/ggplotd/images/parameter_distribution.png
197     import std.algorithm : map;
198     import std.format : format;
199     import ggplotd.aes : aes;
200     import ggplotd.axes : xaxisLabel, yaxisLabel;
201     import ggplotd.geom : geomDensity, geomDensity2D;
202     import ggplotd.ggplotd : Facets, GGPlotD, putIn;
203     import ggplotd.colour : colourGradient;
204     import ggplotd.colourspace : XYZ;
205 
206     // Running MCMC for a model that takes 3 parameters
207     // Will return 1000 posterior samples for the 3 parameters
208     // [[par1, par2, par3], ...]
209     auto samples = runMCMC();
210 
211     // Facets can be used for multiple subplots
212     Facets facets;
213 
214     // Cycle over the parameters
215     foreach(i; 0..3) 
216     {
217         foreach(j; 0..3) 
218         {
219             auto gg = GGPlotD();
220 
221             gg = format("Parameter %s", i).xaxisLabel.putIn(gg);
222             if (i != j)
223             {
224                 // Change the colourGradient used
225                 gg = colourGradient!XYZ( "white-cornflowerBlue-crimson" )
226                     .putIn(gg);
227                 gg = format("Parameter %s", j).yaxisLabel.putIn(gg);
228                 gg = samples.map!((sample) => aes!("x", "y")(sample[i], sample[j]))
229                     .geomDensity2D
230                     .putIn(gg);
231             } else {
232                 gg = "Density".yaxisLabel.putIn(gg);
233                 gg = samples.map!((sample) => aes!("x", "y")(sample[i], sample[j]))
234                     .geomDensity
235                     .putIn(gg);
236             }
237             facets = gg.putIn(facets);
238         }
239     }
240     facets.save("parameter_distribution.png", 670, 670);
241 }
242 
243 ///
244 unittest
245 {
246     // http://blackedder.github.io/ggplotd/images/diamonds.png
247     import std.csv : csvReader; import std.file : readText;
248     import std.algorithm : map;
249     import std.array : array;
250     import ggplotd.aes : aes;
251     import ggplotd.axes : xaxisLabel, yaxisLabel;
252     import ggplotd.ggplotd : GGPlotD, putIn;
253     import ggplotd.geom : geomPoint;
254 
255 
256     struct Diamond {
257         double carat;
258         string clarity;
259         double price;
260     }
261 
262     // Read the data
263     auto diamonds = readText("test_files/diamonds.csv").csvReader!(Diamond)(
264     ["carat","clarity","price"]);
265 
266     auto gg = diamonds.map!((diamond) => 
267         // Map data to aesthetics (x, y and colour)
268         aes!("x", "y", "colour", "size")(diamond.carat, diamond.price, diamond.clarity, 0.8))
269     .array
270     // Draw points
271     .geomPoint.putIn(GGPlotD());
272 
273     // Axis labels
274     gg = "Carat".xaxisLabel.putIn(gg);
275     gg = "Price".yaxisLabel.putIn(gg);
276     gg.save("diamonds.png"); 
277 }
278 
279 /// Multiple histograms examples
280 unittest
281 {
282     // http://blackedder.github.io/ggplotd/images/filled_hist.svg
283     import std.array : array;
284     import std.algorithm : map;
285     import std.range : repeat, iota, chain, zip;
286     import std.random : uniform;
287 
288     import ggplotd.aes : aes;
289     import ggplotd.geom : geomHist;
290     import ggplotd.ggplotd : putIn, GGPlotD;
291 
292     auto xs = iota(0,50,1).map!((x) => uniform(0.0,5)+uniform(0.0,5)).array;
293     auto cols = "a".repeat(25).chain("b".repeat(25));
294     auto gg = xs.zip(cols)
295         .map!((a) => aes!("x", "colour", "fill")(a[0], a[1], 0.45))
296         .geomHist
297         .putIn(GGPlotD());
298     gg.save( "filled_hist.svg" );
299 }
300 
301 /// Size as third dimension
302 unittest
303 {
304     import std.range : zip;
305     import std.algorithm : map;
306     import ggplotd.aes : aes;
307     import ggplotd.geom : geomPoint;
308     import ggplotd.ggplotd : putIn, GGPlotD;
309     import ggplotd.axes : xaxisRange, yaxisRange;
310 
311     auto gg = [0.0,1.0,2.0].zip([0.5, 0.25, 0.75], [1000, 10000, 50000])
312         .map!((a) => aes!("x", "y", "size")(a[0], a[1], a[2]))
313         .geomPoint
314         .putIn(GGPlotD());
315     gg.put(xaxisRange(-0.5, 2.5));
316     gg.put(yaxisRange(0, 1));
317     gg.save("sizeStore.png");
318 }
319 
320 /// Boxplot example
321 unittest
322 {
323     // http://blackedder.github.io/ggplotd/images/boxplot.svg
324     import std.array : array;
325     import std.algorithm : map;
326     import std.range : repeat, iota, chain, zip;
327     import std.random : uniform;
328 
329     import ggplotd.aes : aes;
330     import ggplotd.geom : geomBox;
331     import ggplotd.ggplotd : GGPlotD, putIn;
332 
333     auto xs = iota(0,50,1).map!((x) => uniform(0.0,5)+uniform(0.0,5));
334     auto cols = "a".repeat(25).chain("b".repeat(25));
335     auto gg = xs.zip(cols)
336         .map!((a) => aes!("x", "colour", "fill", "label" )(a[0], a[1], 0.45, a[1]))
337         .geomBox
338         .putIn(GGPlotD());
339     gg.save( "boxplot.svg" );
340 }
341 
342 /// Changing axes details
343 unittest
344 {
345     // http://blackedder.github.io/ggplotd/images/axes.svg
346     import std.array : array;
347     import std.math : sqrt;
348     import std.algorithm : map;
349     import std.range : iota;
350 
351     import ggplotd.aes : aes;
352     import ggplotd.axes : xaxisLabel, yaxisLabel, xaxisOffset, yaxisOffset, xaxisRange, yaxisRange;
353     import ggplotd.geom : geomLine;
354     import ggplotd.ggplotd : GGPlotD, putIn, Margins, title;
355     import ggplotd.stat : statFunction;
356 
357     auto f = (double x) { return x/(1+x); };
358     auto gg = statFunction(f, 0, 10.0)
359         .geomLine
360         .putIn(GGPlotD());
361 
362     // Setting range and label for xaxis
363     gg.put( xaxisRange( 0, 8 ) ).put( xaxisLabel( "My xlabel" ) );
364     // Setting range and label for yaxis
365     gg.put( yaxisRange( 0, 2.0 ) ).put( yaxisLabel( "My ylabel" ) );
366 
367     // change offset
368     gg.put( xaxisOffset( 0.25 ) ).put( yaxisOffset( 0.5 ) );
369 
370     // Change Margins 
371     gg.put( Margins( 60, 60, 40, 30 ) );
372 
373     // Set a title
374     gg.put( title( "And now for something completely different" ) );
375 
376     // Saving on a 500x300 pixel surface
377     gg.save( "axes.svg", 500, 300 );
378 }
379 
380 /// Example from the readme using aes and merge
381 unittest
382 {
383     import ggplotd.aes : aes, merge;
384     struct Data1
385     {
386         double value1 = 1.0;
387         double value2 = 2.0;
388     }
389 
390     Data1 dat1;
391 
392     // Merge to add a value
393     auto merged = aes!("x", "y")(dat1.value1, dat1.value2)
394         .merge(
395             aes!("colour")("a")
396         );
397     assertEqual(merged.x, 1.0);
398     assertEqual(merged.colour, "a");
399 
400     // Merge to a second data struct
401     struct Data2 { string colour = "b"; } 
402     Data2 dat2;
403 
404     auto merged2 = aes!("x", "y")(dat1.value1, dat1.value2)
405         .merge( dat2 );
406     assertEqual(merged2.x, 1.0);
407     assertEqual(merged2.colour, "b");
408 
409     // Overriding a field 
410     auto merged3 = aes!("x", "y")(dat1.value1, dat1.value2)
411         .merge(
412             aes!("y")("a")
413         );
414     assertEqual(merged3.y, "a");
415 }
416 
417 /// Polygon
418 unittest
419 {
420     import std.range : zip;
421     import std.algorithm : map;
422     import ggplotd.aes : aes;
423     import ggplotd.geom : geomPolygon;
424     import ggplotd.ggplotd : GGPlotD, putIn;
425 
426     // http://blackedder.github.io/ggplotd/images/polygon.png
427     auto gg = zip([1, 0, 0.0], [1, 1, 0.0], [1, 0.1, 0])
428         .map!((a) => aes!("x", "y", "colour")(a[0], a[1], a[2]))
429         .geomPolygon
430         .putIn(GGPlotD());
431     gg.save( "polygon.png" );
432 }