-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathrss.xml
More file actions
667 lines (656 loc) · 88.6 KB
/
rss.xml
File metadata and controls
667 lines (656 loc) · 88.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<title>Diagrams Blog - RSS feed</title>
<link>http://projects.haskell.org/diagrams</link>
<description><![CDATA[Diagrams Blog Posts]]></description>
<atom:link href="http://projects.haskell.org/diagrams/rss.xml" rel="self"
type="application/rss+xml" />
<lastBuildDate>Tue, 03 Jan 2017 00:00:00 UT</lastBuildDate>
<item>
<title>Diagrams 1.4</title>
<link>http://projects.haskell.org/diagrams/blog/2017-01-03-diagrams-1.4.html</link>
<description><![CDATA[<div class="blog-header">
<p>by <em>Brent Yorgey</em> on <strong>January 3, 2017</strong></p>
<p>Tagged as: <a title="All pages tagged 'release'." href="http://projects.haskell.org/diagrams/tags/release.html" rel="tag">release</a>, <a title="All pages tagged 'features'." href="http://projects.haskell.org/diagrams/tags/features.html" rel="tag">features</a>, <a title="All pages tagged 'announcement'." href="http://projects.haskell.org/diagrams/tags/announcement.html" rel="tag">announcement</a>, <a title="All pages tagged '1.4'." href="http://projects.haskell.org/diagrams/tags/1.4.html" rel="tag">1.4</a>.</p>
</div>
<div>
<?xml version="1.0" encoding="UTF-8" ?>
<div class="container bs-docs-container"><div class="row"><div class="col-md-3"><div class="bs-sidebar hidden-print" role="complementary" data-spy="affix"></div></div><div class="col-md-9"><h1 class="title">Diagrams 1.4</h1><p>The diagrams team is very pleased to announce the release of diagrams
1.4. The release actually happened a few months ago, in October—we
just hadn't gotten around to writing about it yet. But in any case
this was a fairly quiet release, with very few breaking changes;
mostly 1.4 just introduced new features. There is a <a class="reference external" href="https://wiki.haskell.org/Diagrams/Dev/Migrate1.4">migration
guide</a> which lists a few known potentially breaking changes, but most
users should have no trouble. The rest of this post highlights some
of the new features in 1.4.</p><div class="section" id="alignment-and-layout"><h1>Alignment and layout</h1><div class="section" id="radial-tree-layout"><h2>Radial tree layout</h2><p>The existing <code>Diagrams.TwoD.Layout.Tree</code> module from
<span class="package"><a href="http://hackage.haskell.org/package/diagrams-contrib"><code>diagrams-contrib</code></a></span> has been extended with a new <code class="sourceCode">radialLayout</code>
function, based on an <a class="reference external" href="http://www.cs.cmu.edu/~pavlo/static/papers/APavloThesis032006.pdf">algorithm by Andy Pavlo</a>.</p><div class="dia-lhs panel panel-default"><div class="panel-body"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/69c4f35e79910ce9.png" width="500" height="200" /></div><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> <span class="kw">import </span><span class="dt">Diagrams.TwoD.Layout.Tree</span>
<span class="ot">></span> <span class="kw">import </span><span class="dt">Data.Tree</span>
<span class="ot">></span>
<span class="ot">></span> t <span class="fu">=</span> <span class="dt">Node</span> <span class="ch">'A'</span>
<span class="ot">></span> [ <span class="dt">Node</span> <span class="ch">'B'</span> (map lf <span class="st">"CDE"</span>)
<span class="ot">></span> , <span class="dt">Node</span> <span class="ch">'F'</span> [<span class="dt">Node</span> <span class="ch">'G'</span> (map lf <span class="st">"HIJKLM"</span>), <span class="dt">Node</span> <span class="ch">'N'</span> (map lf <span class="st">"OPQRS"</span>)]
<span class="ot">></span> , <span class="dt">Node</span> <span class="ch">'T'</span> (map lf <span class="st">"UVWXYZ"</span>)
<span class="ot">></span> ]
<span class="ot">></span> <span class="kw">where</span> lf x <span class="fu">=</span> <span class="dt">Node</span> x []
<span class="ot">></span>
<span class="ot">></span> example <span class="fu">=</span>
<span class="ot">></span> renderTree (\n <span class="ot">-></span> (text (show n) <span class="fu">#</span> fontSizeG <span class="fl">0.5</span>
<span class="ot">></span> <span class="fu"><></span> circle <span class="fl">0.5</span> <span class="fu">#</span> fc white))
<span class="ot">></span> (<span class="fu">~~</span>) (radialLayout t)
<span class="ot">></span> <span class="fu">#</span> centerXY <span class="fu">#</span> frame <span class="fl">0.5</span></code></pre></div></div></div></div><div class="section" id="aligned-composition"><h2>Aligned composition</h2><p>Sometimes, it is desirable to compose some diagrams according to a
certain alignment, but without affecting their local origins. The
<code class="sourceCode">composeAligned</code> function can be used for this purpose. It takes as
arguments an alignment function (such as <code class="sourceCode">alignT</code> or <code class="sourceCode">snugL</code>), a
composition function of type <code>[Diagram] -> Diagram</code>, and produces a
new composition function which works by first aligning the diagrams
before composing them.</p><div class="dia-lhs panel panel-default"><div class="panel-body"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/efb94a1abf753555.png" width="500" height="200" /></div><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">> example ::</span> <span class="dt">Diagram</span> <span class="dt">B</span>
<span class="ot">></span> example <span class="fu">=</span> (hsep <span class="dv">2</span> <span class="fu">#</span> composeAligned alignT) (map circle [<span class="dv">5</span>,<span class="dv">1</span>,<span class="dv">3</span>,<span class="dv">2</span>])
<span class="ot">></span> <span class="fu">#</span> showOrigin</code></pre></div></div></div><p>The example above shows using <code class="sourceCode">hsep <span class="dv">2</span></code> to compose a collection of
top-aligned circles. Notice how the origin of the composed diagram is
still at the center of the leftmost circle, instead of at its top edge
(where it would normally be placed by <code class="sourceCode">alignT</code>).</p></div><div class="section" id="constrained-layout"><h2>Constrained layout</h2><p>The new <code>Diagrams.TwoD.Layout.Constrained</code> module from
<span class="package"><a href="http://hackage.haskell.org/package/diagrams-contrib"><code>diagrams-contrib</code></a></span> implements basic linear constraint-based
layout. As a simple example of something that would be tedious to
draw without some kind of constraint solving, consider this diagram
which consists of a vertical stack of circles of different sizes,
along with an accompanying set of squares, such that (1) each square
is constrained to lie on the same horizontal line as a circle, and (2)
the squares all lie on a diagonal line.</p><div class="dia-lhs panel panel-default"><div class="panel-body"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/9072ef90694fb4b9.png" width="500" height="200" /></div><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> <span class="kw">import </span><span class="dt">Diagrams.TwoD.Layout.Constrained</span>
<span class="ot">></span> <span class="kw">import </span><span class="dt">Control.Monad</span> (zipWithM_)
<span class="ot">></span>
<span class="ot">> example ::</span> <span class="dt">Diagram</span> <span class="dt">B</span>
<span class="ot">></span> example <span class="fu">=</span> frame <span class="dv">1</span> <span class="fu">$</span> layout <span class="fu">$</span> <span class="kw">do</span>
<span class="ot">></span> <span class="kw">let</span> rs <span class="fu">=</span> [<span class="dv">2</span>,<span class="dv">2</span>,<span class="dv">4</span>,<span class="dv">3</span>,<span class="dv">5</span>,<span class="dv">6</span>]
<span class="ot">></span> cirs <span class="ot"><-</span> newDias (map circle rs <span class="fu">#</span> fc blue)
<span class="ot">></span> sqs <span class="ot"><-</span> newDias (replicate (length rs) (square <span class="dv">2</span>) <span class="fu">#</span> fc orange)
<span class="ot">></span> constrainWith vcat cirs
<span class="ot">></span> zipWithM_ sameY cirs sqs
<span class="ot">></span> constrainWith hcat [cirs <span class="fu">!!</span> <span class="dv">0</span>, sqs <span class="fu">!!</span> <span class="dv">0</span>]
<span class="ot">></span> along (direction (<span class="dv">1</span> <span class="fu">^&</span> (<span class="fu">-</span><span class="dv">1</span>))) (map centerOf sqs)</code></pre></div></div></div><p>See the <a class="reference external" href="http://projects.haskell.org/diagrams/haddock/diagrams-contrib/Diagrams-TwoD-Layout-Constrained.html">package documentation</a> for more examples and documentation.</p></div><div class="section" id="anchors"><h2>Anchors</h2><p>Another new module in <span class="package"><a href="http://hackage.haskell.org/package/diagrams-contrib"><code>diagrams-contrib</code></a></span>,
<code>Diagrams.Anchors</code>, provides a convenient interface for aligning
diagrams relative to named anchor points. This can be useful, for
example, when laying out diagrams composed of pieces that should
"attach" to each other at various points.</p><p>We don't have an example of its use at the moment—if you play with
it and create a nice example, let us know!</p></div></div><div class="section" id="paths"><h1>Paths</h1><div class="section" id="boolean-path-operations"><h2>Boolean path operations</h2><p>The new <code>Diagrams.TwoD.Path.Boolean</code> module from
<span class="package"><a href="http://hackage.haskell.org/package/diagrams-contrib"><code>diagrams-contrib</code></a></span> contains functions for computing boolean
combinations of paths, such as union, intersection, difference, and
symmetric difference.</p><div class="dia-lhs panel panel-default"><div class="panel-body"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/842ddb95b25d4e23.png" width="500" height="200" /></div><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> <span class="kw">import qualified</span> <span class="dt">Diagrams.TwoD.Path.Boolean</span> <span class="kw">as</span> <span class="dt">B</span>
<span class="ot">></span>
<span class="ot">></span> thing1,<span class="ot"> thing2 ::</span> <span class="dt">Path</span> <span class="dt">V2</span> <span class="dt">Double</span>
<span class="ot">></span> thing1 <span class="fu">=</span> square <span class="dv">1</span>
<span class="ot">></span> thing2 <span class="fu">=</span> circle <span class="fl">0.5</span> <span class="fu">#</span> translate (<span class="fl">0.5</span> <span class="fu">^&</span> (<span class="fu">-</span><span class="fl">0.5</span>))
<span class="ot">></span>
<span class="ot">></span> example <span class="fu">=</span> hsep <span class="fl">0.5</span> <span class="fu">.</span> fc green <span class="fu">.</span> map strokePath <span class="fu">$</span>
<span class="ot">></span> [ B.union <span class="dt">Winding</span> (thing1 <span class="fu"><></span> thing2)
<span class="ot">></span> , B.intersection <span class="dt">Winding</span> thing1 thing2
<span class="ot">></span> , B.difference <span class="dt">Winding</span> thing1 thing2
<span class="ot">></span> , B.exclusion <span class="dt">Winding</span> thing1 thing2
<span class="ot">></span> ]</code></pre></div></div></div></div><div class="section" id="cubic-b-splines"><h2>Cubic B-splines</h2><p><code>Diagrams.CubicSpline</code> has a new function, <code class="sourceCode">bspline</code>, which
creates a smooth curve (to be precise, a [uniform cubic
B-spline](<a class="reference external" href="https://en.wikipedia.org/wiki/B-spline">https://en.wikipedia.org/wiki/B-spline</a>) ) with the given
points as control points. The curve begins and ends at the first and
last points, and is tangent to the lines to the second-to-last control
points. It does not, in general, pass through the intermediate
control points.</p><div class="dia-lhs panel panel-default"><div class="panel-body"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/06ce1d338b86a736.png" width="500" height="200" /></div><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> pts <span class="fu">=</span> map p2 (zip [<span class="dv">0</span> <span class="fu">..</span> <span class="dv">8</span>] (cycle [<span class="dv">0</span>, <span class="dv">1</span>]))
<span class="ot">></span> example <span class="fu">=</span> mconcat
<span class="ot">></span> [ bspline pts
<span class="ot">></span> , mconcat <span class="fu">$</span> map (place (circle <span class="fl">0.1</span> <span class="fu">#</span> fc blue <span class="fu">#</span> lw none)) pts
<span class="ot">></span> ]</code></pre></div></div></div><p>One major difference between <code class="sourceCode">cubicSpline</code> and <code class="sourceCode">bspline</code> is that the
curves generated by <code class="sourceCode">cubicSpline</code> depend on the control points in a
global way—that is, changing one control point could alter the
entire curve—whereas with <code class="sourceCode">bspline</code>, each control point only affects
a local portion of the curve.</p></div><div class="section" id="following-composition"><h2>Following composition</h2><p><span class="package"><a href="http://hackage.haskell.org/package/diagrams-contrib"><code>diagrams-contrib</code></a></span> has a new module,
<code>Diagrams.TwoD.Path.Follow</code>, which defines a wrapper type
<code class="sourceCode"><span class="dt">Following</span> n</code>. <code class="sourceCode"><span class="dt">Following</span></code> is just like <code class="sourceCode"><span class="dt">Trail'</span> <span class="dt">Line</span> <span class="dt">V2</span></code>, except that
it has a different <code class="sourceCode"><span class="dt">Monoid</span></code> instance: following values are
concatenated, just like regular lines, except that they are also
rotated so the tangents match at the join point. In addition, they are
normalized so the tangent at the start point is in the direction of
the positive \(x\) axis (essentially we are considering trails
equivalent up to rotation).</p><div class="dia-lhs panel panel-default"><div class="panel-body"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/87d7f30846d9e30a.png" width="500" height="200" /></div><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> <span class="kw">import </span><span class="dt">Control.Lens</span> (ala)
<span class="ot">></span> <span class="kw">import </span><span class="dt">Diagrams.TwoD.Path.Follow</span>
<span class="ot">></span>
<span class="ot">> wibble ::</span> <span class="dt">Trail'</span> <span class="dt">Line</span> <span class="dt">V2</span> <span class="dt">Double</span>
<span class="ot">></span> wibble <span class="fu">=</span> hrule <span class="dv">1</span> <span class="fu"><></span> hrule <span class="fl">0.5</span> <span class="fu">#</span> rotateBy (<span class="dv">1</span><span class="fu">/</span><span class="dv">6</span>) <span class="fu"><></span> hrule <span class="fl">0.5</span> <span class="fu">#</span> rotateBy (<span class="fu">-</span><span class="dv">1</span><span class="fu">/</span><span class="dv">6</span>) <span class="fu"><></span> a
<span class="ot">></span> <span class="kw">where</span> a <span class="fu">=</span> arc (xDir <span class="fu">#</span> rotateBy (<span class="fu">-</span><span class="dv">1</span><span class="fu">/</span><span class="dv">4</span>)) (<span class="dv">1</span><span class="fu">/</span><span class="dv">5</span> <span class="fu">@@</span> turn)
<span class="ot">></span> <span class="fu">#</span> scale <span class="fl">0.7</span>
<span class="ot">></span>
<span class="ot">></span> example <span class="fu">=</span>
<span class="ot">></span> [ wibble
<span class="ot">></span> , wibble
<span class="ot">></span> <span class="fu">#</span> replicate <span class="dv">5</span>
<span class="ot">></span> <span class="fu">#</span> ala follow foldMap
<span class="ot">></span> ]
<span class="ot">></span> <span class="fu">#</span> map stroke
<span class="ot">></span> <span class="fu">#</span> map centerXY
<span class="ot">></span> <span class="fu">#</span> hsep <span class="dv">1</span>
<span class="ot">></span> <span class="fu">#</span> frame <span class="fl">0.3</span></code></pre></div></div></div><p>Notice how the above example makes use of the <code class="sourceCode">ala</code> combinator from
<code class="sourceCode"><span class="dt">Control.Lens</span></code> to automatically wrap all the <code class="sourceCode"><span class="dt">Line</span></code>s using <code class="sourceCode">follow</code>
before combining and then unwrap the result.</p></div></div><div class="section" id="fun"><h1>Fun</h1><div class="section" id="l-systems"><h2>L-systems</h2><p>The new module <code>Diagrams.TwoD.Path.LSystem</code> in
<span class="package"><a href="http://hackage.haskell.org/package/diagrams-contrib"><code>diagrams-contrib</code></a></span> draws L-systems described by recursive string
rewriting rules, and provides a number of examples that can be used as
starting points for exploration.</p><div class="dia-lhs panel panel-default"><div class="panel-body"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/c669472f67c0a554.png" width="500" height="200" /></div><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> <span class="kw">import </span><span class="dt">Diagrams.TwoD.Path.LSystem</span>
<span class="ot">></span> <span class="kw">import qualified</span> <span class="dt">Data.Map</span> <span class="kw">as</span> <span class="dt">M</span>
<span class="ot">></span>
<span class="ot">> tree ::</span> <span class="dt">RealFloat</span> n <span class="ot">=></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">TurtleState</span> n
<span class="ot">></span> tree n <span class="fu">=</span> lSystem n (<span class="dv">1</span><span class="fu">/</span><span class="dv">18</span> <span class="fu">@@</span> turn) (symbols <span class="st">"F"</span>) rules
<span class="ot">></span> <span class="kw">where</span>
<span class="ot">></span> rules <span class="fu">=</span> M.fromList [rule <span class="ch">'F'</span> <span class="st">"F[+>>>F]F[->>>F][>>>F]"</span>]
<span class="ot">></span>
<span class="ot">></span> example <span class="fu">=</span> getTurtleDiagram <span class="fu">$</span> tree <span class="dv">6</span></code></pre></div></div></div><p>This example is already provided by the module as <code class="sourceCode">tree2</code>.</p></div><div class="section" id="xkcd-colors"><h2>XKCD colors</h2><p>Randall Munroe, of xkcd fame, ran a survey to determine commonly used
names for colors, and published a list of the 954 most common colors
based on the results. <code>Diagrams.Color.XKCD</code> from
<span class="package"><a href="http://hackage.haskell.org/package/diagrams-contrib"><code>diagrams-contrib</code></a></span> provides all these color names.</p><div class="dia-lhs panel panel-default"><div class="panel-body"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/4dacb58d9aec6e70.png" width="500" height="200" /></div><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> <span class="kw">import </span><span class="dt">Diagrams.Color.XKCD</span>
<span class="ot">></span>
<span class="ot">></span> colors <span class="fu">=</span> [booger, poisonGreen, cinnamon, petrol, vibrantPurple]
<span class="ot">></span> example <span class="fu">=</span> hsep <span class="fl">0.1</span> (zipWith fcA colors (repeat (circle <span class="dv">1</span> <span class="fu">#</span> lw none)))</code></pre></div></div></div></div></div></div></div></div>
</div>]]></description>
<pubDate>Tue, 03 Jan 2017 00:00:00 UT</pubDate>
<guid>http://projects.haskell.org/diagrams/blog/2017-01-03-diagrams-1.4.html</guid>
<dc:creator>diagrams contributors</dc:creator>
</item>
<item>
<title>Diagrams + Cairo + Gtk + Mouse picking, Reloaded</title>
<link>http://projects.haskell.org/diagrams/blog/2015-04-30-GTK-coordinates.html</link>
<description><![CDATA[<div class="blog-header">
<p>by <em>Brent Yorgey</em> on <strong>April 30, 2015</strong></p>
<p>Tagged as: <a title="All pages tagged 'cairo'." href="http://projects.haskell.org/diagrams/tags/cairo.html" rel="tag">cairo</a>, <a title="All pages tagged 'GTK'." href="http://projects.haskell.org/diagrams/tags/GTK.html" rel="tag">GTK</a>, <a title="All pages tagged 'mouse'." href="http://projects.haskell.org/diagrams/tags/mouse.html" rel="tag">mouse</a>, <a title="All pages tagged 'coordinates'." href="http://projects.haskell.org/diagrams/tags/coordinates.html" rel="tag">coordinates</a>, <a title="All pages tagged 'transformation'." href="http://projects.haskell.org/diagrams/tags/transformation.html" rel="tag">transformation</a>, <a title="All pages tagged 'features'." href="http://projects.haskell.org/diagrams/tags/features.html" rel="tag">features</a>, <a title="All pages tagged '1.3'." href="http://projects.haskell.org/diagrams/tags/1.3.html" rel="tag">1.3</a>.</p>
</div>
<div>
<?xml version="1.0" encoding="UTF-8" ?>
<div class="container bs-docs-container"><div class="row"><div class="col-md-3"><div class="bs-sidebar hidden-print" role="complementary" data-spy="affix"></div></div><div class="col-md-9"><h1 class="title">Diagrams + Cairo + Gtk + Mouse picking, reloaded</h1><p>A little over a year ago, Christopher Mears wrote <a class="reference external" href="http://www.cmears.id.au/articles/diagrams-gtk-mouse.html">a nice article on
how to match up mouse clicks in a GTK window with parts of a
diagram</a>. The only downside was that to make it work, you had to
explicitly construct the diagram in such a way that its coordinate
system precisely matched the coordinates of the window you wanted to
use, so that there was essentially no "translation" to do. This was
unfortunate, since constructing a diagram in a particular global
coordinate system is not a very "diagrams-y" sort of thing to do.
However, the 1.3 release of diagrams includes a new feature that makes
matching up mouse clicks and diagrams much easier and more idiomatic,
and I thought it would be worth updating Chris's original example to
work more idiomatically in diagrams 1.3. The complete code is listed
at the end.</p><p>First, here's how we construct the house. This is quite different
from the way Chris did it; I have tried to make it more idiomatic by
focusing on local relationships of constituent pieces, rather than
putting everything at absolute global coordinates. We first create
all the constituent pieces:</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> <span class="co">-- The diagram to be drawn, with features tagged by strings.</span>
<span class="ot">> prettyHouse ::</span> <span class="dt">QDiagram</span> <span class="dt">Cairo</span> <span class="dt">V2</span> <span class="dt">Double</span> [<span class="dt">String</span>]
<span class="ot">></span> prettyHouse <span class="fu">=</span> house
<span class="ot">></span> <span class="kw">where</span>
<span class="ot">></span> roof <span class="fu">=</span> triangle <span class="dv">1</span> <span class="fu">#</span> scaleToY <span class="fl">0.75</span> <span class="fu">#</span> centerY <span class="fu">#</span> fc blue
<span class="ot">></span> door <span class="fu">=</span> rect <span class="fl">0.2</span> <span class="fl">0.4</span> <span class="fu">#</span> fc red
<span class="ot">></span> handle <span class="fu">=</span> circle <span class="fl">0.02</span> <span class="fu">#</span> fc black
<span class="ot">></span> wall <span class="fu">=</span> square <span class="dv">1</span> <span class="fu">#</span> fc yellow
<span class="ot">></span> chimney <span class="fu">=</span> fromOffsets [<span class="dv">0</span> <span class="fu">^&</span> <span class="fl">0.25</span>, <span class="fl">0.1</span> <span class="fu">^&</span> <span class="dv">0</span>, <span class="dv">0</span> <span class="fu">^&</span> (<span class="fu">-</span><span class="fl">0.4</span>)]
<span class="ot">></span> <span class="fu">#</span> closeTrail <span class="fu">#</span> strokeT <span class="fu">#</span> fc green
<span class="ot">></span> <span class="fu">#</span> centerX
<span class="ot">></span> <span class="fu">#</span> named <span class="st">"chimney"</span>
<span class="ot">></span> smoke <span class="fu">=</span> mconcat
<span class="ot">></span> [ circle <span class="fl">0.05</span> <span class="fu">#</span> translate v
<span class="ot">></span> <span class="fu">|</span> v <span class="ot"><-</span> [ zero, <span class="fl">0.05</span> <span class="fu">^&</span> <span class="fl">0.15</span> ]
<span class="ot">></span> ]
<span class="ot">></span> <span class="fu">#</span> fc grey</code></pre></div></div><p>We then put the pieces together, labeling each by its name with the
<code class="sourceCode">value</code> function. Diagrams can be valuated by any monoid; when two
diagrams are combined, the value at each point will be the <code class="sourceCode">mappend</code>
of the values of the two component diagrams. In this case, each point
in the final diagram will accumulate a list of <code class="sourceCode"><span class="dt">String</span></code>s
corresponding to the pieces of the house which are under that point.
Note how we make use of combinators like <code class="sourceCode">vcat</code> and <code class="sourceCode">mconcat</code>,
alignments like <code class="sourceCode">alignB</code>, <code class="sourceCode">snugL</code> and <code class="sourceCode">snugR</code>, and the use of a named
subdiagram (the chimney) to position the components relative to each
other. (You can click on any of the above function names to go to
their documentation!)</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> house <span class="fu">=</span> vcat
<span class="ot">></span> [ mconcat
<span class="ot">></span> [ roof <span class="fu">#</span> snugR <span class="fu">#</span> value [<span class="st">"roof"</span>]
<span class="ot">></span> , chimney <span class="fu">#</span> snugL <span class="fu">#</span> value [<span class="st">"chimney"</span>]
<span class="ot">></span> ]
<span class="ot">></span> <span class="fu">#</span> centerX
<span class="ot">></span> , mconcat
<span class="ot">></span> [ handle <span class="fu">#</span> translate (<span class="fl">0.05</span> <span class="fu">^&</span> <span class="fl">0.2</span>) <span class="fu">#</span> value [<span class="st">"handle"</span>]
<span class="ot">></span> , door <span class="fu">#</span> alignB <span class="fu">#</span> value [<span class="st">"door"</span>]
<span class="ot">></span> , wall <span class="fu">#</span> alignB <span class="fu">#</span> value [<span class="st">"wall"</span>]
<span class="ot">></span> ]
<span class="ot">></span> ]
<span class="ot">></span> <span class="fu">#</span> withName <span class="st">"chimney"</span> (\chim <span class="ot">-></span>
<span class="ot">></span> atop (smoke <span class="fu">#</span> moveTo (location chim) <span class="fu">#</span> translateY <span class="fl">0.4</span>
<span class="ot">></span> <span class="fu">#</span> value [<span class="st">"smoke"</span>]
<span class="ot">></span> )
<span class="ot">></span> )</code></pre></div></div><div class="exampleimg"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/37edfa0badeed824.png" width="500" height="200" /></div></div><p>Now, when we render the diagram to a GTK window, we can get diagrams
to give us an affine transformation that mediates between the
diagram's local coordinates and the GTK window's coordinates. I'll
just highlight a few pieces of the code; the complete listing can be
found at the end of the post. We first create an <code>IORef</code> to hold
the transformation:</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> gtk2DiaRef <span class="ot"><-</span> (newIORef<span class="ot"> mempty ::</span> <span class="dt">IO</span> (<span class="dt">IORef</span> (<span class="dt">T2</span> <span class="dt">Double</span>)))</code></pre></div></div><p>We initialize it with the identity transformation. We use the
<code class="sourceCode">renderDiaT</code> function to get not only a rendering action but also the
transformation from diagram to GTK coordinates; we save the inverse of
the transformation in the <code>IORef</code> (since we will want to convert
from GTK to diagram coordinates):</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> <span class="kw">let</span> (dia2gtk, (_,r)) <span class="fu">=</span> renderDiaT <span class="dt">Cairo</span>
<span class="ot">></span> (<span class="dt">CairoOptions</span> <span class="st">""</span> (mkWidth <span class="dv">250</span>) <span class="dt">PNG</span> <span class="dt">False</span>)
<span class="ot">></span> prettyHouse
<span class="ot">></span>
<span class="ot">></span> <span class="co">-- store the inverse of the diagram -> window coordinate transformation</span>
<span class="ot">></span> <span class="co">-- for later use in interpreting mouse clicks</span>
<span class="ot">></span> writeIORef gtk2DiaRef (inv dia2gtk)</code></pre></div></div><p>(Note that if it is possible for the first motion notify event to
happen before the expose event, then such mouse motions will be
computed to correspond to the wrong part of the diagram, but who
cares.) Now, when we receive a mouse click, we apply the stored
transformation to convert to a point in diagram coordinates, and pass
it to the <code class="sourceCode">sample</code> function to extract a list of house components at
that location.</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> (x,y) <span class="ot"><-</span> eventCoordinates
<span class="ot">></span>
<span class="ot">></span> <span class="co">-- transform the mouse click back into diagram coordinates.</span>
<span class="ot">></span> gtk2Dia <span class="ot"><-</span> liftIO <span class="fu">$</span> readIORef gtk2DiaRef
<span class="ot">></span> <span class="kw">let</span> pt' <span class="fu">=</span> transform gtk2Dia (p2 (x,y))
<span class="ot">></span>
<span class="ot">></span> liftIO <span class="fu">$</span> <span class="kw">do</span>
<span class="ot">></span> putStrLn <span class="fu">$</span> show (x,y) <span class="fu">++</span> <span class="st">": "</span>
<span class="ot">></span> <span class="fu">++</span> intercalate <span class="st">" "</span> (sample prettyHouse pt')</code></pre></div></div><p>The final product ends up looking and behaving identically to the
<a class="reference external" href="https://www.youtube.com/watch?v=vwf9aVdDipo">video that Chris made</a>.</p><p>Finally, here's the complete code. A lot of it is just boring
standard GTK setup.</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> <span class="kw">import </span><span class="dt">Control.Monad</span> (void)
<span class="ot">></span> <span class="kw">import </span><span class="dt">Control.Monad.IO.Class</span> (liftIO)
<span class="ot">></span> <span class="kw">import </span><span class="dt">Data.IORef</span>
<span class="ot">></span> <span class="kw">import </span><span class="dt">Data.List</span> (intercalate)
<span class="ot">></span> <span class="kw">import </span><span class="dt">Diagrams.Backend.Cairo</span>
<span class="ot">></span> <span class="kw">import </span><span class="dt">Diagrams.Backend.Cairo.Internal</span>
<span class="ot">></span> <span class="kw">import </span><span class="dt">Diagrams.Prelude</span>
<span class="ot">></span> <span class="kw">import </span><span class="dt">Graphics.UI.Gtk</span>
<span class="ot">></span>
<span class="ot">> main ::</span> <span class="dt">IO</span> ()
<span class="ot">></span> main <span class="fu">=</span> <span class="kw">do</span>
<span class="ot">></span> <span class="co">-- Ordinary Gtk setup.</span>
<span class="ot">></span> void initGUI
<span class="ot">></span> w <span class="ot"><-</span> windowNew
<span class="ot">></span> da <span class="ot"><-</span> drawingAreaNew
<span class="ot">></span> w <span class="ot">`containerAdd`</span> da
<span class="ot">></span> void <span class="fu">$</span> w <span class="ot">`on`</span> deleteEvent <span class="fu">$</span> liftIO mainQuit <span class="fu">>></span> return <span class="dt">True</span>
<span class="ot">></span>
<span class="ot">></span> <span class="co">-- Make an IORef to hold the transformation from window to diagram</span>
<span class="ot">></span> <span class="co">-- coordinates.</span>
<span class="ot">></span> gtk2DiaRef <span class="ot"><-</span> (newIORef<span class="ot"> mempty ::</span> <span class="dt">IO</span> (<span class="dt">IORef</span> (<span class="dt">T2</span> <span class="dt">Double</span>)))
<span class="ot">></span>
<span class="ot">></span> <span class="co">-- Render the diagram on the drawing area and save the transformation.</span>
<span class="ot">></span> void <span class="fu">$</span> da <span class="ot">`on`</span> exposeEvent <span class="fu">$</span> liftIO <span class="fu">$</span> <span class="kw">do</span>
<span class="ot">></span> dw <span class="ot"><-</span> widgetGetDrawWindow da
<span class="ot">></span>
<span class="ot">></span> <span class="co">-- renderDiaT returns both a rendering result as well as the</span>
<span class="ot">></span> <span class="co">-- transformation from diagram to output coordinates.</span>
<span class="ot">></span> <span class="kw">let</span> (dia2gtk, (_,r)) <span class="fu">=</span> renderDiaT <span class="dt">Cairo</span>
<span class="ot">></span> (<span class="dt">CairoOptions</span> <span class="st">""</span> (mkWidth <span class="dv">250</span>) <span class="dt">PNG</span> <span class="dt">False</span>)
<span class="ot">></span> prettyHouse
<span class="ot">></span>
<span class="ot">></span> <span class="co">-- store the inverse of the diagram -> window coordinate transformation</span>
<span class="ot">></span> <span class="co">-- for later use in interpreting mouse clicks</span>
<span class="ot">></span> writeIORef gtk2DiaRef (inv dia2gtk)
<span class="ot">></span>
<span class="ot">></span> renderWithDrawable dw r
<span class="ot">></span> return <span class="dt">True</span>
<span class="ot">></span>
<span class="ot">></span> <span class="co">-- When the mouse moves, show the coordinates and the objects under</span>
<span class="ot">></span> <span class="co">-- the pointer.</span>
<span class="ot">></span> void <span class="fu">$</span> da <span class="ot">`on`</span> motionNotifyEvent <span class="fu">$</span> <span class="kw">do</span>
<span class="ot">></span> (x,y) <span class="ot"><-</span> eventCoordinates
<span class="ot">></span>
<span class="ot">></span> <span class="co">-- transform the mouse click back into diagram coordinates.</span>
<span class="ot">></span> gtk2Dia <span class="ot"><-</span> liftIO <span class="fu">$</span> readIORef gtk2DiaRef
<span class="ot">></span> <span class="kw">let</span> pt' <span class="fu">=</span> transform gtk2Dia (p2 (x,y))
<span class="ot">></span>
<span class="ot">></span> liftIO <span class="fu">$</span> <span class="kw">do</span>
<span class="ot">></span> putStrLn <span class="fu">$</span> show (x,y) <span class="fu">++</span> <span class="st">": "</span>
<span class="ot">></span> <span class="fu">++</span> intercalate <span class="st">" "</span> (sample prettyHouse pt')
<span class="ot">></span> return <span class="dt">True</span>
<span class="ot">></span>
<span class="ot">></span> <span class="co">-- Run the Gtk main loop.</span>
<span class="ot">></span> da <span class="ot">`widgetAddEvents`</span> [<span class="dt">PointerMotionMask</span>]
<span class="ot">></span> widgetShowAll w
<span class="ot">></span> mainGUI
<span class="ot">></span>
<span class="ot">></span> <span class="co">-- The diagram to be drawn, with features tagged by strings.</span>
<span class="ot">> prettyHouse ::</span> <span class="dt">QDiagram</span> <span class="dt">Cairo</span> <span class="dt">V2</span> <span class="dt">Double</span> [<span class="dt">String</span>]
<span class="ot">></span> prettyHouse <span class="fu">=</span> house
<span class="ot">></span> <span class="kw">where</span>
<span class="ot">></span> roof <span class="fu">=</span> triangle <span class="dv">1</span> <span class="fu">#</span> scaleToY <span class="fl">0.75</span> <span class="fu">#</span> centerY <span class="fu">#</span> fc blue
<span class="ot">></span> door <span class="fu">=</span> rect <span class="fl">0.2</span> <span class="fl">0.4</span> <span class="fu">#</span> fc red
<span class="ot">></span> handle <span class="fu">=</span> circle <span class="fl">0.02</span> <span class="fu">#</span> fc black
<span class="ot">></span> wall <span class="fu">=</span> square <span class="dv">1</span> <span class="fu">#</span> fc yellow
<span class="ot">></span> chimney <span class="fu">=</span> fromOffsets [<span class="dv">0</span> <span class="fu">^&</span> <span class="fl">0.25</span>, <span class="fl">0.1</span> <span class="fu">^&</span> <span class="dv">0</span>, <span class="dv">0</span> <span class="fu">^&</span> (<span class="fu">-</span><span class="fl">0.4</span>)]
<span class="ot">></span> <span class="fu">#</span> closeTrail <span class="fu">#</span> strokeT <span class="fu">#</span> fc green
<span class="ot">></span> <span class="fu">#</span> centerX
<span class="ot">></span> <span class="fu">#</span> named <span class="st">"chimney"</span>
<span class="ot">></span> smoke <span class="fu">=</span> mconcat
<span class="ot">></span> [ circle <span class="fl">0.05</span> <span class="fu">#</span> translate v
<span class="ot">></span> <span class="fu">|</span> v <span class="ot"><-</span> [ zero, <span class="fl">0.05</span> <span class="fu">^&</span> <span class="fl">0.15</span> ]
<span class="ot">></span> ]
<span class="ot">></span> <span class="fu">#</span> fc grey
<span class="ot">></span> house <span class="fu">=</span> vcat
<span class="ot">></span> [ mconcat
<span class="ot">></span> [ roof <span class="fu">#</span> snugR <span class="fu">#</span> value [<span class="st">"roof"</span>]
<span class="ot">></span> , chimney <span class="fu">#</span> snugL <span class="fu">#</span> value [<span class="st">"chimney"</span>]
<span class="ot">></span> ]
<span class="ot">></span> <span class="fu">#</span> centerX
<span class="ot">></span> , mconcat
<span class="ot">></span> [ handle <span class="fu">#</span> translate (<span class="fl">0.05</span> <span class="fu">^&</span> <span class="fl">0.2</span>) <span class="fu">#</span> value [<span class="st">"handle"</span>]
<span class="ot">></span> , door <span class="fu">#</span> alignB <span class="fu">#</span> value [<span class="st">"door"</span>]
<span class="ot">></span> , wall <span class="fu">#</span> alignB <span class="fu">#</span> value [<span class="st">"wall"</span>]
<span class="ot">></span> ]
<span class="ot">></span> ]
<span class="ot">></span> <span class="fu">#</span> withName <span class="st">"chimney"</span> (\chim <span class="ot">-></span>
<span class="ot">></span> atop (smoke <span class="fu">#</span> moveTo (location chim) <span class="fu">#</span> translateY <span class="fl">0.4</span>
<span class="ot">></span> <span class="fu">#</span> value [<span class="st">"smoke"</span>]
<span class="ot">></span> )
<span class="ot">></span> )</code></pre></div></div></div></div></div>
</div>]]></description>
<pubDate>Thu, 30 Apr 2015 00:00:00 UT</pubDate>
<guid>http://projects.haskell.org/diagrams/blog/2015-04-30-GTK-coordinates.html</guid>
<dc:creator>diagrams contributors</dc:creator>
</item>
<item>
<title>Diagrams 1.3</title>
<link>http://projects.haskell.org/diagrams/blog/2015-04-24-diagrams-1.3.html</link>
<description><![CDATA[<div class="blog-header">
<p>by <em>Brent Yorgey</em> on <strong>April 25, 2015</strong></p>
<p>Tagged as: <a title="All pages tagged 'release'." href="http://projects.haskell.org/diagrams/tags/release.html" rel="tag">release</a>, <a title="All pages tagged 'features'." href="http://projects.haskell.org/diagrams/tags/features.html" rel="tag">features</a>, <a title="All pages tagged 'announcement'." href="http://projects.haskell.org/diagrams/tags/announcement.html" rel="tag">announcement</a>, <a title="All pages tagged '1.3'." href="http://projects.haskell.org/diagrams/tags/1.3.html" rel="tag">1.3</a>.</p>
</div>
<div>
<?xml version="1.0" encoding="UTF-8" ?>
<div class="container bs-docs-container"><div class="row"><div class="col-md-3"><div class="bs-sidebar hidden-print" role="complementary" data-spy="affix"></div></div><div class="col-md-9"><h1 class="title">Diagrams 1.3</h1><p>The diagrams team is very pleased to announce the release of diagrams
1.3. The actual release to Hackage happened a week or so ago, and by
now I think we have most of the little kinks ironed out. This is an
exciting release that represents a great deal of effort from a lot of
people (see the list of contributors at the end of this post). Here's
a quick rundown of some of the new features. If you're just looking
for help porting your diagrams code to work with 1.3, see the
<a class="reference external" href="https://wiki.haskell.org/Diagrams/Dev/Migrate1.3">migration guide</a>.</p><div class="section" id="path-intersection"><h1>Path intersection</h1><p>Using the functions <code class="sourceCode">intersectPointsP</code> and <code class="sourceCode">intersectPointsT</code>, it is
now possible to find the points of intersection between two paths or
two trails, respectively. This is not so hard for paths with straight
segments, but for cubic Bezier curves, finding intersection points is
nontrivial!</p><div class="dia-lhs panel panel-default"><div class="panel-body"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/53b7dfdadc9debac.png" width="500" height="200" /></div><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> <span class="ot">{-# LANGUAGE TupleSections #-}</span>
<span class="ot">></span>
<span class="ot">> example ::</span> <span class="dt">Diagram</span> <span class="dt">B</span>
<span class="ot">></span> example <span class="fu">=</span> mconcat (map (place pt) points) <span class="fu"><></span> mconcat ellipses
<span class="ot">></span> <span class="kw">where</span>
<span class="ot">></span> ell <span class="fu">=</span> circle <span class="dv">1</span> <span class="fu">#</span> scaleX <span class="dv">2</span>
<span class="ot">></span> pt <span class="fu">=</span> circle <span class="fl">0.05</span> <span class="fu">#</span> fc blue <span class="fu">#</span> lw none
<span class="ot">></span> ellipses <span class="fu">=</span> [ ell <span class="fu">#</span> rotateBy r <span class="fu">#</span> translateX (<span class="dv">2</span><span class="fu">*</span>r) <span class="fu">|</span> r <span class="ot"><-</span> [<span class="dv">0</span>, <span class="dv">1</span><span class="fu">/</span><span class="dv">12</span> <span class="fu">..</span> <span class="dv">5</span><span class="fu">/</span><span class="dv">12</span>] ]
<span class="ot">></span> points <span class="fu">=</span> allPairs ellipses <span class="fu">>>=</span> uncurry (intersectPointsP' 1e<span class="fu">-</span><span class="dv">8</span>)
<span class="ot">></span> allPairs [] <span class="fu">=</span> []
<span class="ot">></span> allPairs (x<span class="fu">:</span>xs) <span class="fu">=</span> map (x,) xs <span class="fu">++</span> allPairs xs</code></pre></div></div></div><p>Note that this feature is something of a "technology preview" in
diagrams 1.3: the API will probably change and grow in the next
release (for example, giving a way to find the <em>parameters</em> of
intersection points).</p></div><div class="section" id="affine-maps-and-projections"><h1>Affine maps and projections</h1><p>Affine maps have been added to <code>Diagrams.LinearMap</code> that can map
between <em>different</em> vector spaces. The <code>Deformable</code> class has
also been generalized to map between spaces. Helper functions have
been added to <code>Diagrams.ThreeD.Projection</code> for basic orthographic
and perspective projections.</p><p>In the below example, we construct a 3-dimensional path representing
the wireframe of a simple house, and then project it into 2 dimensions
using perspective, orthographic, and isometric projections.</p><div class="dia-lhs panel panel-default"><div class="panel-body"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/7c1f2b73130edf93.png" width="500" height="200" /></div><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> <span class="kw">import </span><span class="dt">Diagrams.ThreeD.Transform</span> (translateZ)
<span class="ot">></span> <span class="kw">import </span><span class="dt">Diagrams.ThreeD.Projection</span>
<span class="ot">></span> <span class="kw">import </span><span class="dt">Diagrams.LinearMap</span> (amap)
<span class="ot">></span> <span class="kw">import </span><span class="dt">Linear.Matrix</span> ((!*!))
<span class="ot">></span>
<span class="ot">> box ::</span> <span class="dt">Path</span> <span class="dt">V3</span> <span class="dt">Double</span>
<span class="ot">></span> box <span class="fu">=</span> <span class="dt">Path</span> [f p1 <span class="fu">~~</span> f p2 <span class="fu">|</span> p1 <span class="ot"><-</span> ps, p2 <span class="ot"><-</span> ps, quadrance (p1 <span class="fu">.-.</span> p2) <span class="fu">==</span> <span class="dv">4</span>]
<span class="ot">></span> <span class="kw">where</span>
<span class="ot">></span> ps <span class="fu">=</span> getAllCorners <span class="fu">$</span> fromCorners (<span class="fu">-</span><span class="dv">1</span>) <span class="dv">1</span>
<span class="ot">></span> f <span class="fu">=</span> fmap fromIntegral
<span class="ot">></span>
<span class="ot">> roof ::</span> <span class="dt">Path</span> <span class="dt">V3</span> <span class="dt">Double</span>
<span class="ot">></span> roof <span class="fu">=</span> <span class="dt">Path</span>
<span class="ot">></span> [ mkP3 <span class="dv">1</span> <span class="dv">1</span> <span class="dv">1</span> <span class="fu">~~</span> mkP3 <span class="dv">1</span> <span class="dv">0</span> <span class="fl">1.4</span>
<span class="ot">></span> , mkP3 <span class="dv">1</span> (<span class="fu">-</span><span class="dv">1</span>) <span class="dv">1</span> <span class="fu">~~</span> mkP3 <span class="dv">1</span> <span class="dv">0</span> <span class="fl">1.4</span>
<span class="ot">></span> , mkP3 <span class="dv">1</span> <span class="dv">0</span> <span class="fl">1.4</span> <span class="fu">~~</span> mkP3 (<span class="fu">-</span><span class="dv">1</span>) <span class="dv">0</span> <span class="fl">1.4</span>
<span class="ot">></span> , mkP3 (<span class="fu">-</span><span class="dv">1</span>) <span class="dv">1</span> <span class="dv">1</span> <span class="fu">~~</span> mkP3 (<span class="fu">-</span><span class="dv">1</span>) <span class="dv">0</span> <span class="fl">1.4</span>
<span class="ot">></span> , mkP3 (<span class="fu">-</span><span class="dv">1</span>) (<span class="fu">-</span><span class="dv">1</span>) <span class="dv">1</span> <span class="fu">~~</span> mkP3 (<span class="fu">-</span><span class="dv">1</span>) <span class="dv">0</span> <span class="fl">1.4</span>
<span class="ot">></span> ]
<span class="ot">></span>
<span class="ot">> door ::</span> <span class="dt">Path</span> <span class="dt">V3</span> <span class="dt">Double</span>
<span class="ot">></span> door <span class="fu">=</span> fromVertices
<span class="ot">></span> [ mkP3 <span class="dv">1</span> (<span class="fu">-</span><span class="fl">0.2</span>) (<span class="fu">-</span><span class="dv">1</span>)
<span class="ot">></span> , mkP3 <span class="dv">1</span> (<span class="fu">-</span><span class="fl">0.2</span>) (<span class="fu">-</span><span class="fl">0.4</span>)
<span class="ot">></span> , mkP3 <span class="dv">1</span> (<span class="fl">0.2</span>) (<span class="fu">-</span><span class="fl">0.4</span>)
<span class="ot">></span> , mkP3 <span class="dv">1</span> (<span class="fl">0.2</span>) (<span class="fu">-</span><span class="dv">1</span>)
<span class="ot">></span> ]
<span class="ot">></span>
<span class="ot">></span> house <span class="fu">=</span> door <span class="fu"><></span> roof <span class="fu"><></span> box
<span class="ot">></span>
<span class="ot">></span> <span class="co">-- Perspective projection</span>
<span class="ot">></span> <span class="co">-- these bits are from Linear.Projection</span>
<span class="ot">></span> m <span class="fu">=</span> lookAt (<span class="dt">V3</span> <span class="fl">3.4</span> <span class="dv">4</span> <span class="fl">2.2</span>) zero unitZ
<span class="ot">></span> pm <span class="fu">=</span> perspective (pi<span class="fu">/</span><span class="dv">3</span>) <span class="fl">0.8</span> <span class="dv">1</span> <span class="dv">3</span> <span class="fu">!*!</span> m
<span class="ot">></span>
<span class="ot">></span> pd <span class="fu">=</span> m44Deformation pm
<span class="ot">></span> perspectiveHouse <span class="fu">=</span> stroke <span class="fu">$</span> deform pd (translateZ (<span class="fu">-</span><span class="dv">1</span>) house)
<span class="ot">></span>
<span class="ot">></span> <span class="co">-- Orthogonal projection</span>
<span class="ot">></span> am <span class="fu">=</span> lookingAt (mkP3 <span class="fl">3.4</span> <span class="dv">4</span> <span class="fl">2.2</span>) zero zDir
<span class="ot">></span> orthogonalHouse <span class="fu">=</span> stroke <span class="fu">$</span> amap am house
<span class="ot">></span>
<span class="ot">></span> <span class="co">-- Isometric projection (specialised orthogonal)</span>
<span class="ot">></span> isometricHouse <span class="fu">=</span> stroke <span class="fu">$</span> isometricApply zDir house
<span class="ot">></span>
<span class="ot">> example ::</span> <span class="dt">Diagram</span> <span class="dt">B</span>
<span class="ot">></span> example <span class="fu">=</span> hsep <span class="dv">1</span> <span class="fu">.</span> map (sized (mkHeight <span class="dv">3</span>) <span class="fu">.</span> centerXY) <span class="fu">$</span>
<span class="ot">></span> [ perspectiveHouse, orthogonalHouse, isometricHouse ]</code></pre></div></div></div><p>Note that this should also be considered a "technology preview".
Future releases of diagrams will likely include higher-level ways to
do projections.</p></div><div class="section" id="grouping-for-opacity"><h1>Grouping for opacity</h1><p>A few backends (<span class="package"><a href="http://hackage.haskell.org/package/diagrams-svg"><code>diagrams-svg</code></a></span>, <span class="package"><a href="http://hackage.haskell.org/package/diagrams-pgf"><code>diagrams-pgf</code></a></span>, and
<span class="package"><a href="http://hackage.haskell.org/package/diagrams-rasterific"><code>diagrams-rasterific</code></a></span> as of version 1.3.1) support <em>grouped
transparency</em>. The idea is that transparency can be applied to <em>a
group of diagrams as a whole</em> rather than to individual diagrams. The
difference is in what happens when diagrams overlap: if they are
individually transparent, the overlapping section will be darker, as
if two pieces of colored cellophane were overlapped. If transparency
is applied to a group instead, the transparency is uniformly applied
to the rendered output of the group of diagrams, as if a single piece
of colored cellophane were cut out in the shape of the group of
diagrams.</p><p>An example should help make this clear. In the example to the left
below, the section where the two transparent circles overlap is
darker. On the right, the call to <code class="sourceCode">groupOpacity</code> means that the
entire shape formed form the union of the two circles is given a
uniform opacity; there is no darker region where the circles overlap.</p><div class="dia-lhs panel panel-default"><div class="panel-body"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/1e4dc4eb4637abc7.png" width="500" height="200" /></div><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> cir <span class="fu">=</span> circle <span class="dv">1</span> <span class="fu">#</span> lw none <span class="fu">#</span> fc red
<span class="ot">></span> overlap <span class="fu">=</span> (cir <span class="fu"><></span> cir <span class="fu">#</span> translateX <span class="dv">1</span>)
<span class="ot">></span>
<span class="ot">></span> example <span class="fu">=</span> hsep <span class="dv">1</span> [ overlap <span class="fu">#</span> opacity <span class="fl">0.3</span>, overlap <span class="fu">#</span> opacityGroup <span class="fl">0.3</span> ]
<span class="ot">></span> <span class="fu">#</span> centerX
<span class="ot">></span> <span class="fu"><></span> rect <span class="dv">9</span> <span class="fl">0.1</span> <span class="fu">#</span> fc lightblue <span class="fu">#</span> lw none</code></pre></div></div></div></div><div class="section" id="visualizing-envelopes-and-traces"><h1>Visualizing envelopes and traces</h1><p>Some new functions have been added to help visualize (approximations
of) the <a class="reference external" href="http://projects.haskell.org/diagrams/doc/manual.html#envelopes-and-local-vector-spaces">envelope</a> and <a class="reference external" href="http://projects.haskell.org/diagrams/doc/manual.html#traces">trace</a> of a diagram. For example:</p><div class="dia-lhs panel panel-default"><div class="panel-body"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/3244e52088b4bb59.png" width="500" height="200" /></div><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> d1,<span class="ot"> d2 ::</span> <span class="dt">Diagram</span> <span class="dt">B</span>
<span class="ot">></span> d1 <span class="fu">=</span> circle <span class="dv">1</span>
<span class="ot">></span> d2 <span class="fu">=</span> (pentagon <span class="dv">1</span> <span class="fu">===</span> roundedRect <span class="fl">1.5</span> <span class="fl">0.7</span> <span class="fl">0.3</span>)
<span class="ot">></span>
<span class="ot">></span> example <span class="fu">=</span> hsep <span class="dv">1</span>
<span class="ot">></span> [ (d1 <span class="fu">|||</span> d2) <span class="fu">#</span> showEnvelope' (with <span class="fu">&</span> ePoints <span class="fu">.~</span> <span class="dv">360</span>) <span class="fu">#</span> showOrigin
<span class="ot">></span> , (d1 <span class="fu">|||</span> d2) <span class="fu">#</span> center <span class="fu">#</span> showEnvelope' (with <span class="fu">&</span> ePoints <span class="fu">.~</span> <span class="dv">360</span>) <span class="fu">#</span> showOrigin
<span class="ot">></span> , (d1 <span class="fu">|||</span> d2) <span class="fu">#</span> center <span class="fu">#</span> showTrace' (with <span class="fu">&</span> tPoints <span class="fu">.~</span> <span class="dv">20</span>) <span class="fu">#</span> showOrigin
<span class="ot">></span> ]</code></pre></div></div></div></div><div class="section" id="better-command-line-looping"><h1>Better command-line looping</h1><p>For some time, many diagrams backends have had a "looped compilation
mode", where the diagram-rendering executables produced take a
<code>--loop</code> option, causing them to watch for changes to a source file,
recompile and relaunch themselves. Support for this feature is now
greatly improved. We have switched to use <span class="package"><a href="http://hackage.haskell.org/package/fsnotify"><code>fsnotify</code></a></span>, which
eliminates polling and allows the feature to work on Windows for the
first time (previous versions depended on the <span class="package"><a href="http://hackage.haskell.org/package/unix"><code>unix</code></a></span> package).
The output of the <code>--loop</code> mode has also been improved.</p></div><div class="section" id="new-backends"><h1>New backends</h1><p>The <span class="package"><a href="http://hackage.haskell.org/package/diagrams-postscript"><code>diagrams-postscript</code></a></span>, <span class="package"><a href="http://hackage.haskell.org/package/diagrams-svg"><code>diagrams-svg</code></a></span>,
<span class="package"><a href="http://hackage.haskell.org/package/diagrams-cairo"><code>diagrams-cairo</code></a></span>, <span class="package"><a href="http://hackage.haskell.org/package/diagrams-gtk"><code>diagrams-gtk</code></a></span>, and
<span class="package"><a href="http://hackage.haskell.org/package/diagrams-rasterific"><code>diagrams-rasterific</code></a></span> backends are all still going strong and
fully supported. We now have several new backends as well:
<span class="package"><a href="http://hackage.haskell.org/package/diagrams-html5"><code>diagrams-html5</code></a></span> generates Javascript which sets up an HTML5
canvas containing the diagram; <span class="package"><a href="http://hackage.haskell.org/package/diagrams-canvas"><code>diagrams-canvas</code></a></span> also targets
HTML5 canvas, but uses the <span class="package"><a href="http://hackage.haskell.org/package/blank-canvas"><code>blank-canvas</code></a></span> package to interact
directly with an HTML5 canvas, enabling various sorts of
interactivity. We also have a new backend <span class="package"><a href="http://hackage.haskell.org/package/diagrams-pgf"><code>diagrams-pgf</code></a></span> which
generates PGF/TikZ code suitable for including in \(\TeX\)
documents—one can even have embedded text in diagrams typeset by
\(\TeX\), allowing <em>e.g.</em> mathematical formulas as labels for
things in your diagram.</p></div><div class="section" id="generalized-numerics"><h1>Generalized numerics</h1><p>It used to be that diagrams were hard-coded to use <code>Double</code>. As of
version 1.3, <code>Double</code> is no longer baked in: diagrams are now
parameterized by a suitable numeric type. It's too early to tell what
the full implications of this will be, but in theory it opens up
opportunities for things like automatic differentiation, constraint
solving, and using diagrams in conjunction with deeply embedded DSLs.</p><p>This feature in particular was a tough nut to crack and is the fruit
of a lot of labor. I want to especially highlight the work of Jan
Bracker, Allan Gardner, and Frank Staals, all of whom did a lot of
work attempting to generalize diagrams in this way. Although their
code ultimately did not get merged, we learned a lot from their
attempts! The fourth attempt, by Chris Chalmers, actually stuck. A
big factor in his success was to simultaneously replace the
<span class="package"><a href="http://hackage.haskell.org/package/vector-space"><code>vector-space</code></a></span> package with <span class="package"><a href="http://hackage.haskell.org/package/linear"><code>linear</code></a></span>, which turns out to
work very nicely with diagrams and with generalized numeric types in
particular.</p><p>Note that this is a Very Breaking Change as the types of almost
everything changed. Anything which used to take a single type
representing a vector space (such as <code class="sourceCode"><span class="dt">R2</span></code>) as an argument now takes
two arguments, one for the structure/dimension of the vector space
(<em>e.g.</em> <code class="sourceCode"><span class="dt">V2</span></code>) and one for the numeric/scalar type. See the <a class="reference external" href="https://wiki.haskell.org/Diagrams/Dev/Migrate1.3">migration
guide</a> for more specific information and help upgrading!</p></div><div class="section" id="and-lots-more"><h1>And lots more...</h1><p>Of course, there are lots of other miscellaneous improvements, added
type class instances, new lenses and prisms, bug fixes, and the like.
For a full rundown see the <a class="reference external" href="http://projects.haskell.org/diagrams/releases.html">release notes</a>. There is also lots more
exciting stuff in the pipeline!</p></div><div class="section" id="contributors"><h1>Contributors</h1><p>We now have a team of 5 people working very actively on diagrams
(Chris Chalmers, Daniel Bergey, Jeff Rosenbluth, Ryan Yates, and
myself), with many, many more contributing here and there. As a way
to say thank you for all the great contributions and hard work by many
in the community, below is a (probably incomplete) list of people who
have contributed to diagrams in some way — all 67 of them! We
<a class="reference external" href="http://projects.haskell.org/diagrams/community.html">welcome involvement</a> from anyone, regardless of experience. If you'd
like to get involved, come chat with us on the <a class="reference external" href="http://webchat.freenode.net/?channels=diagrams">#diagrams IRC channel</a>
on freenode, or send a message to the <a class="reference external" href="http://groups.google.com/group/diagrams-discuss">mailing list</a>.</p><p>Diagrams contributors:</p><p>Alexis Praga /
Allan Gardner /
Andy Gill /
Anthony Cowley /
Bartosz Nitka /
Ben Gamari /
Brent Yorgey /
Carlos Scheidegger /
Carter Tazio Schonwald /
Chris Mears /
Christopher Chalmers /
Claude Heiland-Allen /
Conal Elliott /
Daniel Bergey /
Daniel Kröni /
Daniel Wagner /
Daniil Frumin /
Deepak Jois /
Denys Duchier /
Dominic Steinitz /
Doug Beardsley /
Felipe Lessa /
Florent Becker /
Gabor Greif /
Hans Höglund /
Heinrich Apfelmus /
Ian Ross /
Jan Bracker /
Jeffrey Rosenbluth /
Jeremy Gibbons /
Jeroen Bransen /
Jim Snavely /
Joachim Breitner /
Joel Burget /
John Lato /
John Tromp /
Jonas Haag /
Kanchalai Suveepattananont /
Kaspar Emanuel /
Konrad Madej /
Konstantin Zudov /
Luite Stegeman /
Michael Sloan /
Michael Thompson /
Moiman /
Niklas Haas /
Peter Hall /
Pontus Granström /
Robbie Gleichman /
Robert Vollmert /
Ryan Scott /
Ryan Yates /
Sam Griffin /
Scott Walck /
Sergei Trofimovich /
sleepyMonad /
soapie /
Steve Sprang /
Steven Smith /
Tad Doxsee /
Taneb /
Taru Karttunen /
Tillmann Vogt /
Tim Docker /
Vilhelm Sjöberg /
Vincent Berthoux /
Yiding Jia</p></div></div></div></div>
</div>]]></description>
<pubDate>Sat, 25 Apr 2015 00:00:00 UT</pubDate>
<guid>http://projects.haskell.org/diagrams/blog/2015-04-24-diagrams-1.3.html</guid>
<dc:creator>diagrams contributors</dc:creator>
</item>
<item>
<title>Introduction to Palette, Part 2</title>
<link>http://projects.haskell.org/diagrams/blog/2013-12-03-Palette2.html</link>
<description><![CDATA[<div class="blog-header">
<p>by <em>Jeffrey Rosenbluth</em> on <strong>December 4, 2013</strong></p>
<p>Tagged as: <a title="All pages tagged 'color'." href="http://projects.haskell.org/diagrams/tags/color.html" rel="tag">color</a>, <a title="All pages tagged 'palette'." href="http://projects.haskell.org/diagrams/tags/palette.html" rel="tag">palette</a>, <a title="All pages tagged 'harmony'." href="http://projects.haskell.org/diagrams/tags/harmony.html" rel="tag">harmony</a>.</p>
</div>
<div>
<?xml version="1.0" encoding="UTF-8" ?>
<div class="container bs-docs-container"><div class="row"><div class="col-md-3"><div class="bs-sidebar hidden-print" role="complementary" data-spy="affix"></div></div><div class="col-md-9"><h1 class="title">Introducing the Palette Package, Part II</h1><p>In part 1 of this post we talked mostly about borrowing a set of colors that was made by someone else. In this part we talk about tools we can use to make our own color schemes.</p><p>Most software provides some type of color picker for selecting a single color. To choose a color we are often given the choice between several different color panels, including a color wheel, color sliders, and others. The sliders metaphor works well for choosing a single color, but it doesn't provide us with an intuitive way to choose a color scheme.</p><p>The color wheel is more promising. A color wheel is designed to have pure hues on the perimeter, that means saturation and brightness are set to 100%. If you look at this type of color wheel, that is one based on HSB or HSL, you will notice that the red, green and blue sections are 120 degrees apart. If you look at <a class="reference external" href="https://kuler.adobe.com/create/color-wheel/">Adobe Kuler</a> on the other hand you will see that red and green lie on opposite poles of the wheel. That's a better way to visualize the color wheel since red and green are complimentary colors (They produce black or white when combined in the correct proportions). <a class="reference external" href="http://en.wikipedia.org/wiki/Complementary_colors">Complimentary colors</a></p><p>The point is that when picking colors for a scheme, traditional color harmony defines which colors are chosen by choosing a base color and other colors on the wheel at specific angles apart. The wheel that is used though is one with complimentary colors opposite each other like in Kuler. This is the so called traditional or artist's color wheel. We call it the RYB (red, yellow, blue) wheel since it is based on those three being the primary colors and colors in between as mixtures of those.</p><p>The RYB color wheel and the color schemes we will design below are easy to view using the <code class="sourceCode">wheel</code> function. <code class="sourceCode">wheel</code> takes a list of colors and makes a color wheel out of them by placing the first color in the list at the top of the wheel.</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> wheel cs <span class="fu">=</span> wheel' <span class="fu">#</span> rotate r
<span class="ot">></span> <span class="kw">where</span>
<span class="ot">></span> wheel' <span class="fu">=</span> mconcat <span class="fu">$</span> zipWith fc cs (iterateN n (rotate a) w)
<span class="ot">></span> n <span class="fu">=</span> length cs
<span class="ot">></span> a <span class="fu">=</span> <span class="dv">1</span> <span class="fu">/</span> (fromIntegral n) <span class="fu">@@</span> turn
<span class="ot">></span> w <span class="fu">=</span> wedge <span class="dv">1</span> xDir a <span class="fu">#</span> lwG <span class="dv">0</span>
<span class="ot">></span> r <span class="fu">=</span> (<span class="dv">1</span><span class="fu">/</span><span class="dv">4</span> <span class="fu">@@</span> turn) <span class="fu">^-^</span> (<span class="dv">1</span><span class="fu">/</span>(<span class="dv">2</span><span class="fu">*</span>(fromIntegral n)) <span class="fu">@@</span> turn)</code></pre></div></div><p>Here is the RYB color wheel. Notice that colors we perceive as opposites, e.g. red and green are 180 degrees apart on the wheel. In <code class="sourceCode">harmony</code> the RYB color wheel is created by shrinking and stretching sections of the HSB color wheel so that complimentary colors are always on opposite sides of the wheel.</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> ryb <span class="fu">=</span> [rybColor n <span class="fu">|</span> n <span class="ot"><-</span> [<span class="dv">0</span><span class="fu">..</span><span class="dv">23</span>]]
<span class="ot">></span> example <span class="fu">=</span> wheel ryb</code></pre></div></div><div class="exampleimg"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/a6dcc8e92e13b199.png" width="500" height="200" /></div></div><p>Although we have described the base color as a pure hue, we are actually free to choose any color we like at the base color. In order to create the harmonies we desire, we want a function that takes a given color and returns the color a certain number of degrees away on the RYB wheel. For that <code class="sourceCode">harmony</code> provides the function <code class="sourceCode">rotateColor</code>. Here is the original d3 color set and the same set rotated by 60 degrees (counter clockwise).</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> d3 <span class="fu">=</span> [d3Colors1 n <span class="fu">|</span> n <span class="ot"><-</span> [<span class="dv">0</span><span class="fu">..</span><span class="dv">9</span>]]
<span class="ot">></span> example <span class="fu">=</span> hcat' (with <span class="fu">&</span> sep <span class="fu">.~</span> <span class="fl">0.5</span>) [bar d3, bar <span class="fu">$</span> map (rotateColor <span class="dv">60</span>) d3]</code></pre></div></div><div class="exampleimg"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/f98628fad77fff48.png" width="500" height="200" /></div></div><p>Let's pick a base color to demonstrate the classic color harmonies and how to use the <code class="sourceCode"><span class="dt">Harmony</span></code> functions. How about a nice mustardy yellow "#FFC200".</p><div class="exampleimg"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/d2d8c9d36ab6cf19.png" width="500" height="200" /></div></div><p>Since we have been talking about complimentary colors, the first scheme we describe is unsurprisingly called <em>Complimentary</em>. It's based on two complimentary colors and in the <code class="sourceCode"><span class="dt">Harmony</span></code> module three other colors are chosen by shading and tinting those two colors.</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> example <span class="fu">=</span> hcat' (with <span class="fu">&</span> sep <span class="fu">.~</span> <span class="fl">0.5</span>) [ bar (take <span class="dv">2</span> (complement base))
<span class="ot">></span> , wheel <span class="fu">$</span> complement base]</code></pre></div></div><div class="exampleimg"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/389f3f9ec40dae86.png" width="500" height="200" /></div></div><p>A <em>Monochromatic</em> color harmony consists of the base color plus various tints, shades and tones.</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> example <span class="fu">=</span> wheel <span class="fu">$</span> monochrome base</code></pre></div></div><div class="exampleimg"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/b1a4f8860b996bf7.png" width="500" height="200" /></div></div><p>The following scheme does not have a name as far as I know. We take the base color and mix a little bit of it into black, grey, and white. In <code class="sourceCode"><span class="dt">Harmony</span></code> the function is called <code class="sourceCode">bwg</code>.</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> example <span class="fu">=</span> wheel <span class="fu">$</span> bwg base</code></pre></div></div><div class="exampleimg"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/f77d30e198ff0881.png" width="500" height="200" /></div></div><p>Sometimes it is useful to view a color scheme like a wheel but with the base color as a disc in the center. We define the function <code class="sourceCode">pie</code> for this purpose.</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> pie (c<span class="fu">:</span>cs) <span class="fu">=</span> ring <span class="fu"><></span> center
<span class="ot">></span> <span class="kw">where</span>
<span class="ot">></span> center <span class="fu">=</span> circle <span class="fl">0.5</span> <span class="fu">#</span> fc c <span class="fu">#</span> lwG <span class="dv">0</span>
<span class="ot">></span> ring <span class="fu">=</span> mconcat <span class="fu">$</span> zipWith fc cs (iterateN n (rotate a) w)
<span class="ot">></span> n <span class="fu">=</span> length cs
<span class="ot">></span> a <span class="fu">=</span> <span class="dv">1</span> <span class="fu">/</span> (fromIntegral n) <span class="fu">@@</span> turn
<span class="ot">></span> w <span class="fu">=</span> annularWedge <span class="fl">0.5</span> <span class="dv">1</span> xDir a <span class="fu">#</span> lwG <span class="dv">0</span></code></pre></div></div><p>The <em>Analogic</em> color scheme is the base color plus the two colors 30 degrees apart on each side. As usual we add in some tints, shades, and tones to fill out a 5 color scheme. <em>Accent Analogic</em> is similar but we add in the color complimentary to the base color.</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> example <span class="fu">=</span> hcat' (with <span class="fu">&</span> sep <span class="fu">.~</span> <span class="fl">0.5</span>) [ pie <span class="fu">$</span> analogic base
<span class="ot">></span> , pie <span class="fu">$</span> accentAnalogic base]</code></pre></div></div><div class="exampleimg"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/55f196f05ec655fd.png" width="500" height="200" /></div></div><p>The lase two schemes provided by <code class="sourceCode"><span class="dt">Harmony</span></code> are <em>Triad</em>, with colors 120 degrees apart and <em>Tetrad</em> with colors on the corners of a rectangle inscribed in the color wheel.</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> example <span class="fu">=</span> hcat' (with <span class="fu">&</span> sep <span class="fu">.~</span> <span class="fl">0.5</span>) [ pie <span class="fu">$</span> triad base
<span class="ot">></span> , pie <span class="fu">$</span> tetrad base]</code></pre></div></div><div class="exampleimg"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/18b18d4e8e3f2a9c.png" width="500" height="200" /></div></div></div></div></div>
</div>]]></description>
<pubDate>Wed, 04 Dec 2013 00:00:00 UT</pubDate>
<guid>http://projects.haskell.org/diagrams/blog/2013-12-03-Palette2.html</guid>
<dc:creator>diagrams contributors</dc:creator>
</item>
<item>
<title>Introduction to Palette, Part 1</title>
<link>http://projects.haskell.org/diagrams/blog/2013-12-03-Palette1.html</link>
<description><![CDATA[<div class="blog-header">
<p>by <em>Jeffrey Rosenbluth</em> on <strong>December 3, 2013</strong></p>
<p>Tagged as: <a title="All pages tagged 'color'." href="http://projects.haskell.org/diagrams/tags/color.html" rel="tag">color</a>, <a title="All pages tagged 'palette'." href="http://projects.haskell.org/diagrams/tags/palette.html" rel="tag">palette</a>, <a title="All pages tagged 'brewer'." href="http://projects.haskell.org/diagrams/tags/brewer.html" rel="tag">brewer</a>, <a title="All pages tagged 'd3'." href="http://projects.haskell.org/diagrams/tags/d3.html" rel="tag">d3</a>.</p>
</div>
<div>
<?xml version="1.0" encoding="UTF-8" ?>
<div class="container bs-docs-container"><div class="row"><div class="col-md-3"><div class="bs-sidebar hidden-print" role="complementary" data-spy="affix"></div></div><div class="col-md-9"><h1 class="title">Introducing the Palette Package, Part I</h1><subtitle ids="introduction" names="introduction">Introduction</subtitle><p>Choosing a set of colors that look good together can be quite a challenge. The task comes up in a variety of different contexts including: website design, print design, cartography, and as we will discuss here, making diagrams. The problem comes down to a balancing act between two issues; first is that the chosen set of colors is aesthetically pleasing, and second is that there is enough contrast between them.</p><p>The easiest approach is to borrow a set of colors from someone who has already put in the time and effort to create it. The Palette package "Data.Colour.Palette.ColorSet" provides access to a few different predefined color sets including <a class="reference external" href="https://github.com/mbostock/d3/wiki/Ordinal-Scales">the ones in d3</a> and the package "Data.Colour.Palette.BrewerSet" contains a large variety of color schemes created by Cynthia Brewer for use in map making see <a class="reference external" href="http://colorbrewer2.org/">colorbrewer 2.0</a>.</p><p>Let's start out by building some tools in Diagrams, the Haskell drawing framework. We will use the golden ration to give us some pleasing proportions.</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> gr <span class="fu">=</span> (<span class="dv">1</span> <span class="fu">+</span> sqrt <span class="dv">5</span>) <span class="fu">/</span> <span class="dv">2</span></code></pre></div></div><p>The function <code class="sourceCode">bar</code> takes a list of colors which we define here as <code class="sourceCode">[<span class="dt">Colour</span> <span class="dt">Double</span>]</code> (we often use the type synonym <code class="sourceCode">[<span class="dt">Kolor</span>]</code>). We set the length of the color bar to the golden ratio and the height to 1.</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> bar cs <span class="fu">=</span> hcat [square gr <span class="fu">#</span> scaleX s <span class="fu">#</span> fc k <span class="fu">#</span> lwG <span class="dv">0</span> <span class="fu">|</span> k <span class="ot"><-</span> cs] <span class="fu">#</span> centerXY
<span class="ot">></span> <span class="kw">where</span> s <span class="fu">=</span> gr <span class="fu">/</span> (fromIntegral (length cs))</code></pre></div></div><p>We can use <code class="sourceCode">bar</code> to view the color sets in <code class="sourceCode"><span class="dt">Palette</span></code>. Let's make a few color bars. We will use functions provided in <code class="sourceCode"><span class="dt">Palette</span></code> to make the color lists and then use <code class="sourceCode">bar</code> to make the diagrams. The function <code class="sourceCode">d3Colors1</code> takes an <code class="sourceCode"><span class="dt">Int</span></code> between 0 and 9 and returns a color from the set.</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> d3 <span class="fu">=</span> [d3Colors1 n <span class="fu">|</span> n <span class="ot"><-</span> [<span class="dv">0</span><span class="fu">..</span><span class="dv">9</span>]]
<span class="ot">></span> example <span class="fu">=</span> bar d3</code></pre></div></div><div class="exampleimg"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/a7fbf9bf3aaad2a8.png" width="500" height="200" /></div></div><p>The function we use to access schemes from <code class="sourceCode"><span class="dt">Data.Colour.Palette.Brewerset</span></code> is <code class="sourceCode">brewerSet</code>. It takes two arguments: the category of the set <code class="sourceCode"><span class="dt">ColorCat</span></code> (see the haddocks documentation for a list of categories), and an integer representing how many colors in the set. The sets are divided up into 3 categories primarily for showing different types of data on a map: sequential, diverging and qualitative. But they are useful for making diagrams as well.</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> gb <span class="fu">=</span> bar <span class="fu">$</span> brewerSet <span class="dt">GnBu</span> <span class="dv">9</span> <span class="co">-- green/blue, sequential multihue</span>
<span class="ot">></span> po <span class="fu">=</span> bar <span class="fu">$</span> brewerSet <span class="dt">PuOr</span> <span class="dv">11</span> <span class="co">-- purple/orange, diverging</span>
<span class="ot">></span> bs <span class="fu">=</span> bar <span class="fu">$</span> brewerSet <span class="dt">Paired</span> <span class="dv">11</span> <span class="co">-- qualitative</span>
<span class="ot">></span> example <span class="fu">=</span> hcat' (with <span class="fu">&</span> sep <span class="fu">.~</span> <span class="fl">0.5</span>) [gb, po, bs]</code></pre></div></div><div class="exampleimg"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/4e375f484cb7e16f.png" width="500" height="200" /></div></div><p>Some of the color sets provided in <code class="sourceCode"><span class="dt">ColorSet</span></code> occur with 2 or 4 brightness levels. <code class="sourceCode"><span class="kw">data</span> <span class="dt">Brightness</span> <span class="fu">=</span> <span class="dt">Darkest</span> <span class="fu">|</span> <span class="dt">Dark</span> <span class="fu">|</span> <span class="dt">Light</span> <span class="fu">|</span> <span class="dt">Lightest</span></code> with <code class="sourceCode"><span class="dt">Darkest</span> <span class="fu">==</span> <span class="dt">Dark</span></code> and similarly for <code class="sourceCode"><span class="dt">Light</span></code> when using a two set variant. The <code class="sourceCode">grid</code> function is useful for visualizing these.</p><p><code class="sourceCode">grid</code> takes a nested list of colors <code class="sourceCode">[[<span class="dt">Kolor</span>]]</code> and returns a grid of vertically stacked bars.</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> grid cs <span class="fu">=</span> centerXY <span class="fu">$</span> vcat [bar c <span class="fu">#</span> scaleY s <span class="fu">|</span> c <span class="ot"><-</span> cs]
<span class="ot">></span> <span class="kw">where</span> s <span class="fu">=</span> <span class="dv">1</span> <span class="fu">/</span> (fromIntegral (length cs))
<span class="ot">></span>
<span class="ot">></span> d3Pairs <span class="fu">=</span> [[d3Colors2 <span class="dt">Dark</span> n <span class="fu">|</span> n <span class="ot"><-</span> [<span class="dv">0</span><span class="fu">..</span><span class="dv">9</span>]], [d3Colors2 <span class="dt">Light</span> n <span class="fu">|</span> n <span class="ot"><-</span> [<span class="dv">0</span><span class="fu">..</span><span class="dv">9</span>]]]
<span class="ot">></span> g2 <span class="fu">=</span> grid d3Pairs
<span class="ot">></span>
<span class="ot">></span> d3Quads <span class="fu">=</span> [[d3Colors4 b n <span class="fu">|</span> n <span class="ot"><-</span> [<span class="dv">0</span><span class="fu">..</span><span class="dv">9</span>]] <span class="fu">|</span> b <span class="ot"><-</span> [<span class="dt">Darkest</span>, <span class="dt">Dark</span>, <span class="dt">Light</span>, <span class="dt">Lightest</span>]]
<span class="ot">></span> g4 <span class="fu">=</span> grid d3Quads
<span class="ot">></span> example <span class="fu">=</span> hcat' (with <span class="fu">&</span> sep <span class="fu">.~</span> <span class="fl">0.5</span>) [g2, g4]</code></pre></div></div><div class="exampleimg"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/394a64915f14d3f1.png" width="500" height="200" /></div></div><p>The are over 300 colors that W3C recommends that every browser support. These are usually list in alphabetical order, which needless to say does not separate similar colors well. <code class="sourceCode"><span class="dt">Palette</span></code> provides the function <code class="sourceCode">webColors</code> which takes an integer <em>n</em> returns the <em>n</em> th color in a list which has first been sorted by hue and then traversed by skipping every 61 elements. This cycles through a good amount of colors before repeating similar hues. The variant <code class="sourceCode">infiniteWebColors</code> recycles this list. When using these colors it's a good idea to pick some random starting point and increment the color number by 1 every time a new color is required.</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> web <span class="fu">=</span> [[webColors (<span class="dv">19</span> <span class="fu">*</span> j <span class="fu">+</span> i) <span class="fu">|</span> i <span class="ot"><-</span> [<span class="dv">0</span><span class="fu">..</span><span class="dv">8</span>]] <span class="fu">|</span> j <span class="ot"><-</span> [<span class="dv">0</span><span class="fu">..</span><span class="dv">8</span>]]
<span class="ot">></span> w1 <span class="fu">=</span> grid web
<span class="ot">></span>
<span class="ot">></span> web2 <span class="fu">=</span> [[webColors (<span class="dv">19</span> <span class="fu">*</span> j <span class="fu">+</span> i) <span class="fu">|</span> i <span class="ot"><-</span> [<span class="dv">0</span><span class="fu">..</span><span class="dv">19</span>]] <span class="fu">|</span> j <span class="ot"><-</span> [<span class="dv">0</span><span class="fu">..</span><span class="dv">14</span>]]
<span class="ot">></span> w2 <span class="fu">=</span> grid web2
<span class="ot">></span> example <span class="fu">=</span> hcat' (with <span class="fu">&</span> sep <span class="fu">.~</span> <span class="fl">0.5</span>) [w1, w2]</code></pre></div></div><div class="exampleimg"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/1890ba105bcb8e3c.png" width="500" height="200" /></div></div><p>If none of the above color schemes suit your purposes or if you just want to create your own - use the functions in <code class="sourceCode"><span class="dt">Data.Colour.Palette.Harmony</span></code>. The module provides some basic functions for adjusting colors plus a programmatic interface to tools like <a class="reference external" href="https://kuler.adobe.com/create/color-wheel/">Adobe Kuler</a> and <a class="reference external" href="http://colorschemedesigner.com/">Color Scheme Designer</a>. We'll finish Part 1 of this post by examining some of the functions provided to tweak a color: <code class="sourceCode">shade</code>, <code class="sourceCode">tone</code> and <code class="sourceCode">tint</code>. These three functions mix a given color with black, gray, and white respectively. So if for example we wanted a darker version of the d3 scheme, we can apply a shade.
Or we can add some gray to the brewer set <code class="sourceCode"><span class="dt">GnBu</span></code> from above.</p><div class="examplesrc"><div class="sourceCode"><pre class="sourceCode"><code class="sourceCode"><span class="ot">></span> s <span class="fu">=</span> bar <span class="fu">$</span> map (shade <span class="fl">0.75</span>) d3
<span class="ot">></span> t <span class="fu">=</span> bar <span class="fu">$</span> map (tone <span class="fl">0.65</span>) (brewerSet <span class="dt">GnBu</span> <span class="dv">9</span>)
<span class="ot">></span> example <span class="fu">=</span> hcat' (with <span class="fu">&</span> sep <span class="fu">.~</span> <span class="fl">0.5</span>) [s, t]</code></pre></div></div><div class="exampleimg"><div style="text-align: center"><img src="http://projects.haskell.org/diagrams/blog/images/bc276864403a1672.png" width="500" height="200" /></div></div><p>In part II we will talk just a bit about color theory and explain more of the functions in <code class="sourceCode"><span class="dt">Harmony</span></code>.</p></div></div></div>
</div>]]></description>
<pubDate>Tue, 03 Dec 2013 00:00:00 UT</pubDate>
<guid>http://projects.haskell.org/diagrams/blog/2013-12-03-Palette1.html</guid>
<dc:creator>diagrams contributors</dc:creator>
</item>
</channel>
</rss>