F# charting example
I would like to do some basic charting in F# using build in features or a free library. And I would be very very pleased with a very basic example of it, a pie chart if possible.
Example data :
[("John",34);("Sara",30);("Will",20);("Maria",16)]
Where the ints are percentages to be represented in the pie.
I have recently installed VSLab and though I find a lot of 3D examples, I am only looking for a simple pie chart...
It is also fine to use excel features by the way, not开发者_开发知识库 free, but installed nevertheless..
Here's something I smashed together using the Google Chart API, I hope the code is clear enough without further explanation:
//Built with F# 1.9.7.8
open System.IO
open System.Net
open Microsoft.FSharp.Control.WebExtensions
//Add references for the namespaces below if you're not running this code in F# interactive
open System.Drawing
open System.Windows.Forms
let buildGoogleChartUri input =
let chartWidth, chartHeight = 250,100
let labels,data = List.unzip input
let dataString =
data
|> List.map (box>>string) //in this way, data can be anything for which ToString() turns it into a number
|> List.toArray |> String.concat ","
let labelString = labels |> List.toArray |> String.concat "|"
sprintf "http://chart.apis.google.com/chart?chs=%dx%d&chd=t:%s&cht=p3&chl=%s"
chartWidth chartHeight dataString labelString
//Bake a bitmap from the google chart URI
let buildGoogleChart myData =
async {
let req = HttpWebRequest.Create(buildGoogleChartUri myData)
let! response = req.AsyncGetResponse()
return new Bitmap(response.GetResponseStream())
} |> Async.RunSynchronously
//invokes the google chart api to build a chart from the data, and presents the image in a form
//Excuse the sloppy winforms code
let test() =
let myData = [("John",34);("Sara",30);("Will",20);("Maria",16)]
let image = buildGoogleChart myData
let frm = new Form()
frm.BackgroundImage <- image
frm.BackgroundImageLayout <- ImageLayout.Center
frm.ClientSize <- image.Size
frm.Show()
It's easy to do "made in home" pie chart: open System.Drawing
let red = new SolidBrush(Color.Red) in
let green = new SolidBrush(Color.Green) in
let blue = new SolidBrush(Color.Blue) in
let rec colors =
seq {
yield red
yield green
yield blue
yield! colors
}
let pie data (g: Graphics) (r: Rectangle) =
let vals = 0.0 :: List.map snd data
let total = List.sum vals
let angles = List.map (fun v -> v/total*360.0) vals
let p = new Pen(Color.Black,1)
Seq.pairwise vals |> Seq.zip colors |> Seq.iter (fun (c,(a1,a2)) -> g.DrawPie(p,r,a1,a2); g.FillPie(c,r,a1,a2))
Old question, but technology changing.
in vs 2013, F# 3, and installing the nuget Package
Install-Package FSharp.Charting
Add reference to:
System.Windows.Forms
System.Windows.Forms.DataVisualization
and with one line of code:
Application.Run ((Chart.Pie data).ShowChart())
The following F# code generate the bie chart:
open System
open System.Windows.Forms
open FSharp.Charting
[<EntryPoint>]
let main argv =
Application.EnableVisualStyles()
Application.SetCompatibleTextRenderingDefault false
let data =[("John",34);("Sara",30);("Will",20);("Maria",16)]
Application.Run ((Chart.Pie data).ShowChart())
0
and you get the following chart:
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
- in a stackoverflow.com answer by ildjarn where he shows stunning (at least for me) usage of
List.scan
- at a c-sharpcorner.com blog by Shalini Juneja where she shows how to create and draw a simple resizeable windows forms dialog with F# (in fact she also shows how to display a pie)
精彩评论