# Fun with F# Charting. Factoring out FSharpChart

FSharpChart wraps .NET 4.0 charting control. Here is Don’s entry about it to get started and download the assembly with examples.

However, FSharpChart is still a control that needs WinForms or WPF to work. What about some Matlab-esque type of functionality, where a simple function call would do the job without having to worry about much wiring?

An example (full sources available here) is a simple risk minimization model, where given a portfolio of assets and their expected performance, we must choose the weights for each asset so that standard deviation (risk) of the portfolio is minimal. The model and its solution are described, for instance, here. It is easy enough to implement it using Math.Net package.

```module RiskMinimizationFormulation =

open System
open MathNet.Numerics.FSharp
open MathNet.Numerics.LinearAlgebra.Double
open modelling.shared

type RiskMinimization(expected : Vector, correlations : Matrix, stdDeviations : Vector) =
do
if correlations.RowCount <> correlations.ColumnCount
then
invalidArg "variances" "expected square matrix"

if expected.Count <> correlations.RowCount
then
invalidArg "expected" "expectations vector must have the same length as variance matrix dimensions"

let variances =
correlations
|> Matrix.mapi
(fun i j value ->
let mutable v = value
if correlations.[i,j] = 0.0
then
v <- correlations.[j, i]
stdDeviations.[i] * stdDeviations.[j] * v)
let n = expected.Count
let i = vector (List.init n (fun i -> 1.))

let variancesInv = variances.Inverse()
let a = i * variancesInv * i
let b = i * variancesInv * expected
let c = expected * variancesInv * expected
let denom = 1. / (a * c - b*b)
let g = denom * (variancesInv * (c * i - b * expected))
let h = denom * (variancesInv * (a * expected - b * i))

member rm.ComputeOptimal (expectation : float) =
g + h * expectation
```

We compute all the auxiliary values at instantiation and the function of interest is ComputeOptimal, that given an expectation produces a vector of weights.

Suppose we were to chart weights of our portfolio for a range of expectations. Let’s say expectations are values 0.05..0.12..0.05 ([5%, 12%], with a step of 0.5%). Our charting function could look something like this:

```        member rm.ChartOptimalWeights (expectations : float list) (names : string seq) =
let data = matrix(expectations |> List.map (fun v -> (rm.ComputeOptimal v |> Vector.toList)))

let plotData =  seq {for i in 0 .. data.ColumnCount - 1 -> data.Column(i).ToArray() |> Array.toList}

Charting.Plot(
"Line",
plotData,
plotX = (expectations |> List.map(fun v -> v * 100.)),
xTitle = "Expected Return",
yTitle = "Asset Weight",
xLimits = (5., 12.),
yLimits = (-2.0, 3.0),
seriesNames = names,
title = "Risk Minimization Model")
```

We call ComputeOptimal for each of the values in range and get a vector in return. We then construct a matrix out of these vectors, making each vector a row of the new matrix. Then our series are in the columns of the resulting matrix. For instance, for a test case with the range of expectations described above and a portfolio of four assets, we get a 4 x 24 matrix, where each row represents a portfolio. We want to chart the dynamic of each asset weight as function of expectation, so our series actually are in the columns of this matrix.

The function of interest is Charting.Plot. This function wraps the necessary functionality of FSharpChart in a general way to produce a chart of given type:

```    type Charting () =

static member private createChartOfType ((chartType : string), name, (y : seq<#IConvertible * #IConvertible>))  =
let innerTps = FSharpType.GetTupleElements(y.GetType().GetGenericArguments().)
findAndCreateChart chartType innerTps name y

static member private createChartOfType ((chartType : string), name, (y : seq<#IConvertible>))  =
let innerTp = y.GetType().GetGenericArguments().
findAndCreateChart chartType [|innerTp|] name y

static member Plot
(
chartType : string,
plotY : #seq<#IConvertible> seq,
? plotX : #seq<#IConvertible>,
? seriesNames : string seq,
? title : string,
? xTitle : string,
? yTitle : string,
? xLimits : float * float,
? yLimits : float * float,
? margin : float32 * float32 * float32 * float32) =

let marg = defaultArg margin (4.0f, 12.0f, 4.0f, 4.0f)
let chartTitle = defaultArg title "Chart"
let xTitle = defaultArg xTitle String.Empty
let yTitle = defaultArg yTitle String.Empty
let chartNames = defaultArg seriesNames (plotY |> Seq.mapi(fun i v -> "Series " + i.ToString()))
if (chartNames |> Seq.length) <> (plotY |> Seq.length) then invalidArg "names" "not of the right length"

// zip up the relevant information together
// x-values go with every y-series values in a tuple
// series names gets zipped with every sequence of (x, y) tuples: (name, seq(x, seq(y)))
let mutable chart =
match plotX with
|Some plotX ->
let plot = plotY |> Seq.map(fun s -> List.zip plotX s) |> Seq.zip chartNames
FSharpChart.Combine ([for p in plot -> Charting.createChartOfType (chartType, (fst p), (snd p))])

| None ->
let plot = plotY |> Seq.zip chartNames
FSharpChart.Combine ([for p in plot -> Charting.createChartOfType (chartType, (fst p), (snd p))])

//add x and y limits
chart <-
match xLimits with
| Some (xMin, xMax) -> FSharpChart.WithArea.AxisX(Minimum = xMin, Maximum= xMax, MajorGrid = Grid(LineColor = Color.LightGray)) chart
| None -> FSharpChart.WithArea.AxisX(MajorGrid = Grid(LineColor = Color.LightGray)) chart

chart <-
match yLimits with
| Some (yMin, yMax) -> FSharpChart.WithArea.AxisY(Minimum = yMin, Maximum= yMax, MajorGrid = Grid(LineColor = Color.LightGray)) chart
| None -> FSharpChart.WithArea.AxisY(MajorGrid = Grid(LineColor = Color.LightGray)) chart
//... and margin
|> FSharpChart.WithMargin marg

//set the titles
chart.Area.AxisX.Title <- xTitle
chart.Area.AxisY.Title <- yTitle

chart <-
FSharpChart.WithLegend(InsideArea = false, Alignment = StringAlignment.Center, Docking = Docking.Top) chart

chart.Title <- StyleHelper.Title(chartTitle, FontSize = 10.0f, FontStyle = FontStyle.Bold)

//create the form
createForm chart
```

There is not much going on – just setting some chart parameters. There are only two things of interest:

```FSharpChart.Combine ([for p in plot -> Charting.createChartOfType (chartType, (fst p), (snd p))])
```

This call will create a combined chart (if necessary – the combination of only one series) of any type, by calling one of two createChartType overrides. One override looks for chart with X and Y series, the other – for just Y series. For instance:

```static member private createChartOfType ((chartType : string), name, (y : seq<#IConvertible * #IConvertible>))  =
let innerTps = FSharpType.GetTupleElements(y.GetType().GetGenericArguments().)
findAndCreateChart chartType innerTps name y
```

This version of the function will look for something like

```ChartTypes.type name<TX, TY>(IEnumerable<TX> xvalues, IEnumerable<TY> yvalues) where TX: IConvertible where TY: IConvertible
```

in FSharpType and then attempt to create it:

```    let (|FindChartOfType|_|) numGenericArgs chartType =
let mi =
(typeof<FSharpChart>.GetMethods()
|> Array.filter(
fun v ->
v.Name = chartType && v.GetParameters().Length = 1 && v.GetGenericArguments().Length = numGenericArgs)).
match mi with
| x when x = Unchecked.defaultof<MethodInfo> -> None
|_ -> Some mi

let findAndCreateChart chartType (genericArgs : Type []) name y =
let mi =
match chartType with
| FindChartOfType genericArgs.Length mi -> mi
| _ -> invalidArg "chartType " ("Chart of type " + chartType + " not found")

let chart = mi.GetGenericMethodDefinition().MakeGenericMethod(genericArgs).Invoke(null, [|y|]) :?> ChartTypes.GenericChart
chart.Name <- name
chart

```

Another function of interest is the one that puts it all together and displays the chart:

```    let createForm (chart : ChartTypes.CombinedChart) =
let chartForm = new ChartForm<ChartData.DataSourceCombined>(chart)
chartForm.Text <- "Chart"
chartForm.ClientSize <- new Size(600, 600)
Application.EnableVisualStyles()
Application.Run(chartForm :> Form)
```

MSDN.FSharp.Charting namespace ChartExtensions module provides the ChartForm class that is used to host the chart control and display the chart.

My test data represents a hypothetical portfolio, taken from a Frank Fabozzi’s book:

```        [TestMethod]
public void ChartWeights()
{
Vector expected =  new DenseVector (new double [] { 0.079, 0.079, 0.09, 0.071 });

Matrix correlations = new DenseMatrix(new double[,] { { 1.0, 0F, 0F, 0F }, { 0.24, 1.0, 0F, 0F }, { 0.25, 0.47, 1.0, 0F }, { 0.22, 0.14, 0.25, 1.0 } });

Vector stdDeviations = new DenseVector(new double[] { 0.195, 0.182, 0.183, 0.165 });
RiskMinimizationFormulation.RiskMinimization model = new RiskMinimizationFormulation.RiskMinimization(expected, correlations, stdDeviations);

var range = ListModule.OfSeq(Enumerable.Range(50, 120).Where(e => e % 5 == 0).Select(e => (double)e / 1000D));

model.ChartOptimalWeights(range, new string [] {"Australia", "Austria", "Belgium", "Canada"});
}
```

## One thought on “Fun with F# Charting. Factoring out FSharpChart”

1. Don Syme (@dsyme) says:

If it is possible, could you update this sample to use the new Fsharp.Charting (the next evolution of FSharpChart)? http://fsharp.github.io/FSharp.Charting/

Thanks
Don and Tomas

This site uses Akismet to reduce spam. Learn how your comment data is processed.