F#圖表之FSharpChart


     FSharpChart是類型System.Windows.Forms.DataVisualization.Charting的F#友好包裝, 使之可以再F# Interactive 中交互表現數據。FSharpChart的最新版本是FSharpChart0.6,是微軟的Carl Nolan's提供的。在MSDN的Chart Controls章節里可以瀏覽到更多FChart Controls的相關信息。當然有關FSharpChart的更多的信息,你也可以親自去瀏覽Carl Nolan’s的博客

最新版本的提供了,以下新的功能:

  • 剪切板的另存為功能
  • 屬性改變事件
  • 支持3D圖表
  • BoxPlot圖表的數據命名

在這之前需要新建一個F#的應用程序項目,添加對以下DLL的引用:

  • System.Windows.Forms.dll
  • System.Drawing.dll
  • System.Windows.Forms.DataVisualization.dll
  • WindowsFormsIntegration.dll

      由於我想使用WPF(Windows Presentation Foundation)來承載Chart,所以需要對以下DLL的引用(我的另一篇文章有比較詳細的過程描述):

  • System.Core.dll
  • System.Xaml.dl
  • PresentationCore.dll
  • PresentationFramework.dll

      FSharpChart本質上是屬於WinForm的控件,所以在WPF中要用WindowsFormsHost來承載。

一 , 基本功能

    FSharpChart支持System.Windows.Forms.DataVisualization.Charting命名控件你的所有類型。通過使用FSharpChart類型的靜態方法創建所有的chart類型,並且可以再智能感知瀏覽,如下圖所示:

image

      這些方法在chart上顯示數據變得更加容易。

      如:

let line = 
    let line  = [for x in 0.0 .. 0.2 .. 10.0 –> sin x ]|> FSharpChart.Line
    new ChartControl(line)

      將以下圖形包裝為ChartControl控件:

image

    每一個chart控件都有一個context menu菜單,可以輕松將chart復制到剪切板,保存為文件,查看(或者修改)詳細的chart屬性。

    在一個Chart畫兩條曲線(組合其他圖形的時也可以使用該Combine方法):

let lines = 
    let line1  = [for x in 0.0 .. 0.02 .. 10.0 -> sin x ]|> FSharpChart.Line
    let line2  = [for x in 0.0 .. 0.02 .. 10.0 -> cos x ]|> FSharpChart.Line
    new ChartControl( FSharpChart.Combine [line1;line2] )

   如下圖:

image

      chart創建方法的重載版本,運行數據通過不同的方法來指定。基本上,大部分的chart都允許通過以下機制來指定chart的數據源:

  • 只含有y軸數據的隊列(sequence)(x軸的數據,隱式的從1開始被自動指定,就如同上面chart的創建方式一樣)
  • x軸和y軸的兩個獨立隊列(sequence)
  • (x,y)向量隊列
  • y軸或者(x,y)的System.IObservable類型,允許在添加數據時及時更新chart

     此外,並沒有限定x或者y軸的數據必須是浮點數,這些數據只需要是實現了System.IConvertible.IConvertible 接口的類型即可。這就意味着,很容易創建數據被分類命名的chart圖表:

let pie = 
    let c = [(“A”,1); (“B”,3); (“C”,2)]
            |> FSharpChart.Pie
    new ChartControl(c,Dock=DockStyle.Fill)

image

當然也就很容易的,用時間或者日期創建plot 圖表:

let column  = 
    let r = Random() 
    let c m=
        [for d in -30 .. m –>; 
            (DateTime.Today.AddDays(float  d) , r.Next(0 , 10))] |> FSharpChart.Spline
    let c = FSharpChart.Combine [c 10; c 12]
    new ChartControl(c)

image

二,新版本新增功能

    1,復制到剪切板和另存功能  

      最新版本中,以及擴展了復制圖片到剪切板和將chart另存為圖片的功能,復制圖片到剪切板以及支持EMF(Enhanced(Extended)Windows Metafile Format)格式。

image

    同時也支持保存為不同格式圖片:

image

       對於復制圖片和另存為功能,也添加代碼編程的支持。將chart復制到剪切板,僅僅只需要調用CopyToClipBoard方法:

[ for f in 1.0 .. 0.1 .. 10.0 -> sin (f * 2.0) + cos f ]
    |> FSharpChart.Line
    |> FSharpChart.WithCreate
    |> FSharpChart.CopyToClipboard

同樣的,調用Save和CopyToClipboard相似。

     2,Property Changed Event

     新版本中一種改進是當某些GenericChart屬性發生改變時支持Event事件,包括:Name,Title,Margin,Legend和所有的常用屬性。這些事件也在代碼內部使用,用來傳遞GenericChart的改變到綁定的chart。

     這種功能支持以下代碼:

chart.Margin <- (2.0f, 12.0f, 2.0f, 2.0f)
    chart.Title <- Helper.CreateTitle(“Chart Sin/Cosine”, Font = new Font(“Arial”, 12.0f, FontStyle.Bold))
    chart.Legend <- Helper.CreateLegend(InsideArea = false, Font = new Font(“Arial”, 8.0f),
                                    Alignment = StringAlignment.Center, Docking = Docking.Top)

    3,3D chart

     正如你所知道的,Windows Forms charting支持3D渲染,現在也包括了用於GenericChart 3D屬性的支持。作為一個例子,PieChart餅狀圖啟用3D效果:

let chart = 
    let c = [(“A”,1); (“B”,3); (“C”,2)]
            |> FSharpChart.Pie
            |> FSharpChart.WithArea.Area3DStyle(Enable3D=true,Inclination=70)
    new ChartControl(c,Dock=DockStyle.Fill)

image

     這種功能支持全部的特性,包括:Inclination,IsClustered,IsRightAngleAxes,LightStyle,Perspective,PointDepth,PointGapDepth,Rotation,WallWidth。使用3Dchart 只需要設置

"Enable3D = true"即可。

     4,BoxPlot Data Series

     如您所熟悉的,BoxPlot圖表是顯示幾個系列數據的好方法,然而以前那個實現,在呈現幾個系列數據時,總是默認的標記每個軸為1,2,3等,而這個新版本如所期望的一樣,支持為每個數據系列自定義標簽。因此現在可以用下面的代碼,新建一個BoxPlot圖表:

let boxplot =
    let plot =
        FSharpChart.BoxPlot
            ( [ "Eggs", [| for i in 0 .. 20 -> float (rnd.Next 20) |]
                "Bacon", [| for i in 0 .. 20 -> float (rnd.Next 15 + 2) |]
                "Sausage";, [| for i in 0 .. 20 -> float (rnd.Next 5 + 5) |]
                "Beans";, [| for i in 0 .. 20 –> float (rnd.Next 10 + 3) |]
                "Mushroom";, [| for i in 0 .. 20 –> float (rnd.Next 15 + 5) |] ],
                Name = "Breakfast Food BoxPlot")
            |> FSharpChart.WithMargin(1.0f, 5.0f, 1.0f, 1.0f) 
            |> FSharpChart.WithSeries.Style(Color = Color.SeaGreen)
            |> FSharpChart.WithLegend(InsideArea = false, Font = new Font(“Arial”, 8.0f),
                Alignment = StringAlignment.Center, Docking = Docking.Top) 
    new  ChartControl (plot)

image,

5, Stacked Chart     

      在之前FSharpChart版本中,繪制一個堆疊的圖表(Stacked Chart)不是很直觀。一個不得不做的事情是定義一個CombinedChart,同時將定義多個chart與相同的StackedGroupName屬性值相結合:

let rnd = new System.Random ()
let datax() = [ for  f in 1 .. 10 –> rnd.NextDouble( ) * 10.0]
let starckbar =
    let bar =
        FSharpChart.Combine
            [
                FSharpChart.StackedBar100(datax(),StackedGroupName=”g1”)
                FSharpChart.StackedBar100(datax(),StackedGroupName=”g1”)
                FSharpChart.StackedBar100(datax(),StackedGroupName=”g1”)
            ]
    new ChartControl(bar)

image

       這種方法還允許通過使用不同StackedGroupName屬性值,很輕松聯合多個Stacked Chart:

FSharpChart.Combine
  [ FSharpChart.StackedBar(dataX(), StackedGroupName = “g1”)
    FSharpChart.StackedBar(dataX(), StackedGroupName = “g1”)
    FSharpChart.StackedBar(dataX(), StackedGroupName = “g1”)
    FSharpChart.StackedBar(dataX(), StackedGroupName = “g2”)
    FSharpChart.StackedBar(dataX(), StackedGroupName = “g2”) ]

image

       當然,對於Stacked Charts,一個更加直觀的方法是僅僅指定一個數據列的列表。在這個新的版本中,現在可以使用如下格式:

list<list<'TY>>
list<list<'TX * 'TY>>

現在允許這樣的一個定義,如下一個StackedColumn圖表,使用一個簡單得多表達式:

let rndStacked = new System.Random()
let dataXY() = [ for f in 1 .. 10 –> (f, round (rndStacked.NextDouble() * 100.0))]

[dataXY(); dataXY(); dataXY()]
|> FSharpChart.StackedColumn
|> FSharpChart.WithSeries.DataPoint(Label=”#VAL”)

image

6,在數據列中添加標記

      如下面代碼所示,可以數據列中添加標記點

let markLine = 
    let rnd = new System.Random()
    let line = 
        [for i in 1..20..1000 -> i , rnd.NextDouble()]
        |> FSharpChart.Line 
        |> FSharpChart.WithSeries.Marker(Color = Color.Red ,Style=MarkerStyle.Circle)
    new ChartControl(line)

 

image

    控制橫縱坐標的顯示與否,可以使用FSharpChart.WithArea.AxisY或者FSharpChart.WithArea.AxisX函數來處理,設這標題使用FSharpChart.WithTitle函數。如下:

let markLine = 
    let rnd = new System.Random()
    let line = 
        [for i in 1..20..1000 –> i , rnd.NextDouble()]
        |> FSharpChart.Line 
        |> FSharpChart.WithTitle(“Hello”,TextStyle=TextStyle.Frame,Font = new Font(“Arial”, 28.0f))
        |> FSharpChart.WithSeries.Marker(Color = Color.Red ,Style=MarkerStyle.Circle)
        |>FSharpChart.WithArea.AxisX(MajorGrid = Grid(LineColor = Color.White))
    new ChartControl(line)

image

最后一個提供一個更完整點的代碼段(當然得如本文開頭介紹的添加相應的DLL引用)如下:

open System    
open System.Windows
open System.Windows.Controls
open System.Windows.Forms.Integration
open System.Windows.Forms.DataVisualization.Charting
open System.Windows.Forms
open MSDN.FSharp.Charting
open System.Drawing // for Color

let markLine = 
    let rnd = new System.Random()
    let line = 
        [for i in 1..20..1000 -> i , rnd.NextDouble()]
        |> FSharpChart.Line 
        |> FSharpChart.WithTitle("Hello",TextStyle=TextStyle.Frame,Font = new Font("Arial", 28.0f))
        |> FSharpChart.WithSeries.Marker(Color = Color.Red ,Style=MarkerStyle.Circle)
        |>FSharpChart.WithArea.AxisX(MajorGrid = Grid(LineColor = Color.White))
    new ChartControl(line)

let mainNoXaml() = 
    let formsHost =new  WindowsFormsHost(Child = markLine)//(Child=starckbar)
    let window = Window()
    window.Content <- formsHost
    let app =new System.Windows.Application() in app.Run(window) |> ignore

[<STAThread>]
do mainNoXaml()

總結:感謝Carl Nolan's的辛勤勞動,更多的相關信息還請參考Carl Nolans的博客

同本文有關的更多示例代碼下載:Demo.rar


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM