使用 FSharp.Chartting 探索 F# 我以为我会从一个简单的"hello world"开始,但它给我留下了更多的问题,然后是代码行。
#load @"..packagesFSharp.Charting.0.90.14FSharp.Charting.fsx"
open FSharp.Charting
let chart = Chart.Line([ for x in 0 .. 10 -> x, x*x ])
chart.ShowChart()
chart.SaveChartAs(@"C:Tempchart.png",ChartTypes.ChartImageFormat.Png)
这在VS的交互式窗口中工作,但我想做的是从cmd行执行此脚本(使用fsi.exe)。我将 fsx 文件与 fsi 相关联,但是当我执行它时,它会打开 fsi,但没有创建图表。我需要做什么?
简短回答:在程序末尾添加以下行:
System.Windows.Forms.Application.Run()
长答案:
图表确实被创建,但它会立即消失,因为您的程序在创建图表后立即退出。这不会在 Visual Studio 的 F# 交互窗口中发生,因为 F# 交互窗口不会在执行程序后立即关闭 - 它只是挂在那里,等待你提交更多代码进行执行。
为了使程序不会立即退出,您可以实现一些等待机制,例如等待设定的时间(见System.Threading.Thread.Sleep
)或等待用户按Enter键(通过stdin.ReadLine()
)等。
但是,这实际上对您没有帮助,因为还有下一个问题:图表是通过 Windows 窗体绘制的,它依赖于运行的消息循环 - 否则窗口无法接收消息,因此无法绘制事件本身。
FSI 确实有自己的内置事件循环,这就是您的程序在 VS 下的工作方式。但是,如果您实施"等待"机制(例如stdin.ReadLine()
),此事件循环将被阻止 - 将无法泵送消息。因此,防止程序退出而不干扰图表窗口功能的唯一合理方法是启动您自己的事件循环。这正是Application.Run()
所做的。
保存到磁盘而不显示:
(回应评论)
据我了解,FSharp.Charting
库旨在作为一种在屏幕上显示图表的快速而肮脏的方式,主要用例是在 F# 交互中实时探索数据集。更具体地说,Chart
对象的某些关键属性(如ChartAreas
和Series
)不会在创建图表时初始化,而仅在屏幕上显示时才初始化(请参阅源代码),如果没有这些属性,图表将保持为空。
除了向库提交拉取请求外,我建议下拉到底层System.Windows.Forms.DataVisualization.Charting.Chart
:
open System.Windows.Forms.DataVisualization.Charting
let ch = new Chart()
ch.ChartAreas.Add( new ChartArea() )
let s = new Series( ChartType = SeriesChartType.Line )
s.Points.DataBind( [for x in 1..10 -> x, x*x], "Item1", "Item2", "" )
ch.Series.Add s;
ch.SaveImage(@"C:Tempchart.png", System.Drawing.Imaging.ImageFormat.Png)