Exception using XPlot from fsi - f#

I'm trying to run a simple example of Xplot from FSI. I've installed all the nuget packages of XPLot and I copied the example in their hello world page.
#r "../packages/Google.DataTable.Net.Wrapper.1.0.0/lib/Google.DataTable.Net.Wrapper.dll"
#r "../packages/Newtonsoft.Json.3.5.8/lib/35/Newtonsoft.Json.dll"
#r "System.Core.dll"
#r "System.dll"
#r "System.Numerics.dll"
#r "../packages/XPlot.GoogleCharts.1.3.1/lib/net45/XPlot.GoogleCharts.dll"
open XPlot.GoogleCharts
let Bolivia = [("2004", 400.0); ("2005", 500.0); ("2006", 900.0); ("2007", 700.0) ]
let Ecuador = [("2004", 500.0); ("2005", 700.0); ("2006", 600.0); ("2007", 900.0) ]
let Madagascar = [("2004", 100.0); ("2005", 200.0); ("2006", 300.0); ("2007", 400.0) ]
let series = [ "bars"; "bars"; "bars"]
let inputs = [ Bolivia; Ecuador; Madagascar ]
let chart =
inputs
|> Chart.Combo
|> Chart.WithOptions
(Options(title = "Coffee Production", series =
[| for typ in series -> Series(typ) |]))
|> Chart.WithLabels
["Bolivia"; "Ecuador"; "Madagascar"]
|> Chart.WithLegend true
|> Chart.WithSize (600, 250)
Now, when I try, for example, to get the HTML of the chart...
chart.Html
...I'm getting the following error:
> System.TypeLoadException: Could not load type 'Google.DataTable.Net.Wrapper.Extension.SystemDataTableExtension' from assembly 'Google.DataTable.Net.Wrapper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
at XPlot.GoogleCharts.GoogleChart.get_Js()
at XPlot.GoogleCharts.GoogleChart.get_Html() in C:\Users\AHMED\Documents\GitHub\XPlot\src\XPlot.GoogleCharts\Main.fs:line 282
at <StartupCode$FSI_0006>.$FSI_0006.main#() in C:\Projects\XPlotTest\XPlotTest\Script.fsx:line 18
What I'm doing wrong here? How can I make it work?
Thank you very much,

Try updating Google.DataTable.Net.Wrapper to latest version (3.1.2)
#r "../packages/Google.DataTable.Net.Wrapper.3.1.2.0\lib\Google.DataTable.Net.Wrapper.dll"
(...)
let html = chart.Html
:
val html : string =
"<!DOCTYPE html>
<html>
<head>
<met"+[1535 chars]

Related

FolderBrowserDialog not opening in fsharp script

I am having a simple script to select a folder,
the process is not responding on call to ShowDialog(),
below is script file, runtime config file and cli command to run,
I think I’m missing something, or my understanding is wrong,
test.fsx
#I #"C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\6.0.10\ref\net6.0"
#r "System.Windows.Forms"
open System
open System.Windows.Forms
let folderPath = new Label()
let button = new Button(Text = "Select Folder")
let ini_dir = #"C:\Users\hayeskev\source\Workspaces"
let openFolderHandler =
EventHandler(fun _ _ ->
let folderDlg = new FolderBrowserDialog()
folderDlg.InitialDirectory <- ini_dir
folderDlg.ShowNewFolderButton <- true
let dlgResult = folderDlg.ShowDialog()
if dlgResult.Equals(DialogResult.OK) then
folderPath.Text <- folderDlg.SelectedPath
else
folderPath.Text <- "Error")
button.Click.AddHandler(openFolderHandler)
let layout = new FlowLayoutPanel(Dock=DockStyle.Fill)
layout.Controls.Add(button)
layout.Controls.Add(folderPath)
let form = new Form()
form.Controls.Add(layout)
form.ShowDialog()
C:\Program Files\dotnet\sdk\6.0.402\FSharp\fsi.runtimeconfig.json
{
"runtimeOptions": {
"tfm": "net6.0",
"frameworks": [
{
"name": "Microsoft.NETCore.App",
"version": "6.0.10"
},
{
"name": "Microsoft.WindowsDesktop.App",
"version": "6.0.10"
}
],
"configProperties": {
"System.Reflection.Metadata.MetadataUpdater.IsSupported": false
}
}
}
running using
dotnet fsi test.fsx
also tried it with sta thread attribute
[<STAThread>]
do
Application.EnableVisualStyles()
Application.SetCompatibleTextRenderingDefault(false)
use form = new MainGuiForm()
Application.Run(form)
I reproduced this using a regular F# project and got the same behavior. To fix it, I had to call AddHandler on the STA thread. So my working code is:
open System
open System.Windows.Forms
let folderPath = new Label()
let button = new Button(Text = "Select Folder")
let ini_dir = #"C:\Users\hayeskev\source\Workspaces"
let openFolderHandler =
EventHandler(fun _ _ ->
let folderDlg = new FolderBrowserDialog()
folderDlg.InitialDirectory <- ini_dir
folderDlg.ShowNewFolderButton <- true
let dlgResult = folderDlg.ShowDialog()
if dlgResult.Equals(DialogResult.OK) then
folderPath.Text <- folderDlg.SelectedPath
else
folderPath.Text <- "Error")
[<STAThread>]
button.Click.AddHandler(openFolderHandler) // IMPORTANT: Must follow <STAThread>
let layout = new FlowLayoutPanel(Dock=DockStyle.Fill)
layout.Controls.Add(button)
layout.Controls.Add(folderPath)
let form = new Form()
form.Controls.Add(layout)
form.ShowDialog() |> ignore
Result looks like:

Are options and WithSize etc in XPlot specific to only certain charts?

I've tried Chart.WithSize and displayZoomButtons = true in the FSLab tutorial, but nothing seems to change the output.
Same thing in other projects using XPlot.GoogleCharts directly.
Am I missing something?
Download Plotly 1.4.2 from nuget and replace the dlls in the FSLab packages directory for XPlotly (see Plotting with Xplotly Q). Then you can use Xplotly's controls to zoom in and out, save the chart, etc. For example:
#load #"..\..\FSLAB\packages\FsLab\FsLab.fsx"
open XPlot.Plotly
open XPlot.Plotly.Graph
open XPlot.Plotly.Html
//open XPlot.GoogleCharts
let layout = Layout(title = "Basic Bar Chart")
["giraffes", 20; "orangutans", 14; "monkeys", 23]
|> Chart.Bar
|> Chart.WithLayout layout
|> Chart.WithHeight 400
|> Chart.WithWidth 700
|> Chart.Show
Very barebones charting solution using Plotly (and it works):
open Newtonsoft.Json
let html = """<head>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>
<div id="myDiv" style="width: 100%; height: 100%;"></div>
<script>
var data = __DATA__;
var layout = __LAYOUT__;
Plotly.newPlot('myDiv', data, layout);
</script>
</body>"""
let (=>) k v = k, (v:>obj)
let doPlot data layout =
let data = JsonConvert.SerializeObject data
let layout = JsonConvert.SerializeObject layout
let path = Path.GetTempPath() + DateTime.Now.Ticks.ToString() + ".html"
File.WriteAllText(path, html.Replace("__DATA__", data).Replace("__LAYOUT__", layout))
System.Diagnostics.Process.Start(path)
let layout =
[ "title" => "Plot"
"xaxis" => dict [
"title" => "Ticks"
"showgrid" => false
"zeroline" => false
]
"yaxis" => dict [
"title" => "Price"
"showline" => false
]
] |> dict
let data = [
dict [ "x" => [1999; 2000; 2001; 2002]
"y" => [16; 5; 11; 9]
]
]
doPlot data layout

F# Yaml type provider

I have tried using a Yaml collection of maps in my config file :
Companies:
- code: 11
name: A
country: FR
functionalCurrency: EUR
- code: 12
name: B
country: GB
functionalCurrency: GBP
However, when trying to read it with the type provider, it only finds the first result of the list.
With :
open FSharp.Configuration
type CompaniesConfig = YamlConfig<"Config.yaml">
let config = CompaniesConfig()
the output is :
val config : CompaniesConfig =
Companies:
- code: 11
name: A
country: FR
functionalCurrency: EUR
Trying to parse the code online worked, hence I wonder if that is a library limitation or... ?
Thanks for your help
You need to actually load the file, not only get the schema if you want to work with it directly: config.Load(yamlFile). This should probably more explicit in the documentation. I used the sample file in the link.
#if INTERACTIVE
#r #"..\packages\FSharp.Configuration.0.6.1\lib\net40\FSharp.Configuration.dll"
#endif
open FSharp.Configuration
open System.IO
/// https://github.com/fsprojects/FSharp.Configuration/blob/master/tests/FSharp.Configuration.Tests/Lists.yaml
[<Literal>]
let yamlFile = __SOURCE_DIRECTORY__ + "..\Lists.yaml"
File.Exists yamlFile
type TestConfig = YamlConfig<yamlFile>
let config = TestConfig()
config.Load(yamlFile)
config.items.Count
config.items
And I get both items:
>
val it : int = 2
>
val it : System.Collections.Generic.IList<TestConfig.items_Item_Type> =
seq
[FSharp.Configuration.TestConfig+items_Item_Type
{descrip = "Water Bucket (Filled)";
part_no = "A4786";
price = 147;
quantity = 4;};
FSharp.Configuration.TestConfig+items_Item_Type
{descrip = "High Heeled "Ruby" Slippers";
part_no = "E1628";
price = 10027;
quantity = 1;}]
>

How to set the quality of grids for xaxis grid in Fsharp.Charting?

I use Yahoo Finance data to compare two company's close price:
#load "C:\Users\Nick\Documents\Visual Studio 2013\packages\FSharp.Charting.0.90.9\FSharp.Charting.fsx"
open FSharp.Data
open FSharp.Charting
open System
open System.Drawing
open System.Windows.Forms.DataVisualization.Charting
type Stocks = CsvProvider<"http://ichart.finance.yahoo.com/table.csv?s=FB">
let plotprice nasdaqcode =
let url = "http://ichart.finance.yahoo.com/table.csv?s=" + nasdaqcode
let company = Stocks.Load(url)
let companyPrices =
[ for r in company.Rows do
if r.Date > DateTime(2010, 1, 1) (* && r.Date < DateTime(2015, 1, 1) *) then
yield r.Date, r.Close ]
Chart.Line(companyPrices,Name=nasdaqcode)
|> Chart.WithLegend(Enabled=true,Docking=ChartTypes.Docking.Bottom, InsideArea=false)
Chart.Combine ([plotprice "VLKPY";plotprice "TM"])
|> Chart.WithXAxis(LabelStyle = ChartTypes.LabelStyle(Angle = -45),MajorGrid=ChartTypes.Grid(Enabled=true, LineColor=Color.LightGray))
|> Chart.WithYAxis(MajorGrid=ChartTypes.Grid(Enabled=true, LineColor=Color.LightGray))
And here is what I got:
Question:
As the picutre shows, there're only two grid lines (year 2012/1/1 and 2014/1/1). I would like to have a finer grid on the X axis: one line for each year from 2010 to 2015. Is it possible to setup the grid this way?
You can use the Interval parameter of the Grid type:
Chart.Combine ([plotprice "VLKPY";plotprice "TM"])
|> Chart.WithXAxis
( MajorGrid = ChartTypes.Grid( Enabled=true,
LineColor=Color.LightGray,
Interval=365.0 ) )
There is also IntervalOffsetType parameter that you could set to DateTimeIntervalType.Years, but this does not seem to be working for me - so it looks like F# Charting currently only works on days.
It would be great if you could verify this, submit an issue or perhaps even look into contributing to F# Charting to get this fixed :-)

F# Set a property on ViewBag dynamic object (passing an image)

I tried to use the solution that Tomas Petricek wrote on this website but not for a string but for an image. Unfortunately, it doesn't work. This is my code:
Model:
let ChartModelCumulativePerformance =
let numMths = 60
let trackOfDates numMths = firstDate.AddMonths(numMths)
let trackHF = [for x in 0 .. 59 ->(trackOfDates x, HFReturns.[x])]
let trackBchk = [for x in 0 .. 59 ->(trackOfDates x, BchkReturns.[x])]
Chart.Line(trackHF,Name="Hedge Fund") |> ignore
Chart.Line(trackBchk,Name="Benchmark") |> ignore
let myChart = Chart.Combine(
[Chart.Line(trackHF,Name="Hedge Fund")
Chart.Line(trackBchk,Name="Benchmark")])
myChart.CopyAsBitmap()
member this.CreateCumulativePerformanceGraph() = ChartModelCumulativePerformance
Controller:
let dataChart = res.CreateCumulativePerformanceGraph()
let (?<-) (viewData:ViewDataDictionary) (name:string) (value: Image) = viewData.Add(name, value)
this.ViewData?chartCumulative <- dataChart
this.View("HFAnalysis") :> ActionResult
View
<img src =#ViewBag.chartCumulative height="80" width="80"/ alt="" />
or
<img src =#ViewData["chartCumulative"] height="80" width="80"/ alt="" />
Otherwise, do you know another methodologies? Thank in advance for your help
Ultimately you've got an HTML problem, not an F# problem here.
If you want to put image data directly into the src attribute of an img tag, you have to convert it to a base-64 string and then prefix it with the appropriate meta-data according to the Data URI standard.
I would convert your bitmap to a PNG (to shrink the file size) and then get a byte array for the image and pass it to Convert.ToBase64String. Ultimately you'll end up with something like this:
<img width="80" height="80" src="data:image/png;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7" />
Many thanks Joel !!!!
This is the code for those who would be interested:
Model:
let ChartModelCumulativePerformance =
//... code for building a Chart
let myChart = myChart.CopyAsBitmap()
let ms = new MemoryStream()
let tempVar = myChart.Save(ms,Imaging.ImageFormat.Png)
let imageData = ms.ToArray()
let imageBase64 = Convert.ToBase64String(imageData)
String.Format("data:image/png;base64,{0}", imageBase64)
Controller:
let dataChart = res.CreateCumulativePerformanceGraph()
let (?<-) (viewData:ViewDataDictionary) (name:string) (value: String) = viewData.Add(name, value)
this.ViewData?chartCumulative <- dataChart
this.View("HFAnalysis") :> ActionResult
View:

Resources