The F# Powerpack contains charting modules that can use Excel or XCeed.

John Harrop recommends componentXtra's XYGraph Lite control in his F# for Scientists book.

I've used the open source Visifire to create some quite pretty WPF based charts, but there are plenty of other open source options out there to choose from.

For fun, the following 100 line F# script will give a simple plot window on a function using only WPF:

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
// Reference WPF dlls
#r "PresentationCore.dll"
#r "PresentationFramework.dll"
#r "WindowsBase.dll"

open System
open System.Windows
open System.Windows.Media

type Axis (low:double, high:double) =
    member this.Min = low
    member this.Max = high
    member this.Length = high - low

    static member Create (values:seq<float>) =
        let f (l,h) x = min l x, max h x
        Axis(values |> Seq.fold f (0.0,0.0))        

    static member CreateTransform(rect:Rect,xAxis:Axis,yAxis:Axis) =        
        let transform = Matrix.Identity
        transform.Translate(rect.Left, rect.Bottom)        
        transform.ScaleAtPrepend(
            rect.Width / xAxis.Length, 
            -rect.Height / yAxis.Length,
            xAxis.Min, 
            yAxis.Min)
        transform               

type Plot (f:float -> float, xs:seq<float>) =
    inherit System.Windows.Controls.ItemsControl ()    

    /// Creates formatted text
    let CreateText =
        let typeface = new Typeface("Verdana")               
        fun (s, emSize) ->
            new FormattedText(
                s,
                System.Globalization.CultureInfo.InvariantCulture,
                FlowDirection.LeftToRight,
                typeface,
                emSize,
                Brushes.Black)

    /// Renders plot               
    override this.OnRender (context) =
        /// Plot area               
        let rect = 
            let width, height =             
                this.ActualWidth-this.Margin.Left+this.Margin.Right),        
                this.ActualHeight-(this.Margin.Top+this.Margin.Bottom) 
            new Rect(
                this.Margin.Left, 
                this.Margin.Top, 
                max 0.0 width, 
                max 0.0 height)

        // Render background
        let bg = LinearGradientBrush(Colors.White,Colors.LightGray, 90.0)
        context.DrawRectangle(bg, new Pen(Brushes.Black, 1.0), rect)

        /// Calculated values        
        let ys = xs |> Seq.map (fun x -> f x)

        let xAxis, yAxis = Axis.Create xs, Axis.Create ys        

        let transform = Axis.CreateTransform (rect, xAxis, yAxis)

        let DrawXLabel x = 
            let label = CreateText(x.ToString(), 9.0)
            let p1 = Point(x, yAxis.Min) * transform
            let p2 = Point(x, yAxis.Max) * transform
            context.DrawText(label, 
                new Point(p1.X-(label.Width/2.0), p1.Y+4.0))
            context.DrawText(label,
                new Point(p2.X-(label.Width/2.0), p2.Y-label.Height-4.0))

        let DrawYLabel y = 
            let label = CreateText(y.ToString(), 9.0)
            let p1 = Point(xAxis.Min, y) * transform
            let p2 = Point(xAxis.Max, y) * transform
            context.DrawText(label, 
                new Point(p1.X-label.Width-4.0, p2.Y-(label.Height/2.0)))
            context.DrawText(label, 
                new Point(p2.X+4.0, p2.Y-(label.Height/2.0)))        

        DrawXLabel xAxis.Min; DrawXLabel xAxis.Max        
        DrawYLabel yAxis.Min; DrawYLabel yAxis.Max

        // Render lines                        
        let pen = new Pen(Brushes.Red, 1.0)        
        Seq.zip xs ys
        |> Seq.pairwise 
        |> Seq.iter (fun ((x0,y0),(x1,y1)) -> 
            context.DrawLine(pen, 
                new Point(x0,y0) * transform, 
                new Point(x1,y1) * transform)
        )                               

let PlotWindow (f:(float -> float), xs:seq<float>) =
    let plot = new Plot(f, xs, Margin=Thickness(16.0))
    new Window(Title="Plot",Width=640.0,Height=480.0,Content=plot)           

do  let f x = 3.0 * x * x + 2.0 * x + 2.0

let win = PlotWindow (f, seq {-2.0..0.01..2.0})

do win.Show() |> ignore
By on 7/27/2009 1:08 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper