开发者

F# charting example

开发者 https://www.devze.com 2022-12-12 14:13 出处:网络
I would like to do some basic charting in F# using build in features or a free library. And I would be very very pleasedwith a very basic example of it, a pie chart if possible.

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:

F# charting example


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)
0

精彩评论

暂无评论...
验证码 换一张
取 消