Originally I only tried to complement ssp's example here with a very simple windows form dialog which shows a pie. But trying this I found a bug in ssp's code: on the one hand Seq.pairwise
operates on vals
instead of angles
and on the other hand it obviously doesn't consider that pie slices will be drawn beginning from start angle along sweep angle.
I corrected the bug, commented, rearranged, reformatted and renamed some things - and made it both #load
-able in fsi.exe and compilable with fsc.exe:
#light
module YourNamespace.PieExample
open System
open System.Drawing
open System.ComponentModel
open System.Windows.Forms
(* (circular) sequence of three colors *)
#nowarn "40"
let red = new SolidBrush(Color.Red)
let green = new SolidBrush(Color.Green)
let blue = new SolidBrush(Color.Blue)
let rec colors =
seq { yield red
yield green
yield blue
yield! colors }
(* core function to build up and show a pie diagram *)
let pie data (g: Graphics) (r: Rectangle) =
// a pen for borders of pie slices
let p = new Pen(Color.Black, 1.0f)
// retrieve pie shares from data and sum 'em up
let vals = List.map snd data
let total = List.sum vals
// baking a pie starts here with ...
vals
// scaling vals in total to a full circle
|> List.map (fun v -> v * 360.0 / total)
// transform list of angles to list of pie slice delimiting angles
|> List.scan (+) 0.0
// turn them into a list of tuples consisting of start and end angles
|> Seq.pairwise
// intermix the colors successively
|> Seq.zip colors
// and at last do FillPies and DrawPies with these ingredients
|> Seq.iter (fun (c,(starta,enda))
-> g.FillPie(c,r,(float32 starta)
,(float32 (enda - starta)))
g.DrawPie(p,r,(float32 starta)
,(float32 (enda - starta))))
(* demo data *)
let demolist = [ ("a", 1.); ("b", 2.); ("c", 3.);
("d", 2.); ("e", 2.); ("f", 2.) ]
(* finally a simple resizable form showing demo data as pie with 6 slices *)
let mainform = new Form(MinimumSize = Size(200,200))
// add two event handlers
mainform.Paint.Add (fun e -> pie demolist e.Graphics mainform.ClientRectangle)
mainform.Resize.Add (fun _ -> mainform.Invalidate())
#if COMPILED
Application.Run(mainform)
#else
mainform.ShowDialog() |> ignore
#endif
Last but not least I want to mention two helpful hints I found useful