2 people like it.

Factoring out FSharpChart

Using FSharpChart control. Just call Charting.Plot() to chart series or collections of series. No need to create forms, etc.

  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: 
108: 
109: 
110: 
111: 
namespace modelling.shared

[<AutoOpen>]
module Plotting =

    open System.Drawing
    open System.Windows.Forms
    open System.Windows.Forms.DataVisualization.Charting
    open Microsoft.FSharp.Reflection
    open System.Reflection
    open MSDN.FSharp.Charting
    open MSDN.FSharp.Charting.ChartStyleExtensions
    open System

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

    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)

    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

    type Charting () =  

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

        static member private createChartOfType ((chartType : string), name, (y : seq<#IConvertible>))  =
            let innerTp = y.GetType().GetGenericArguments().[0]
            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, (x, 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

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

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

            //create the form
            createForm chart
Multiple items
type AutoOpenAttribute =
  inherit Attribute
  new : unit -> AutoOpenAttribute
  new : path:string -> AutoOpenAttribute
  member Path : string

Full name: Microsoft.FSharp.Core.AutoOpenAttribute

--------------------
new : unit -> AutoOpenAttribute
new : path:string -> AutoOpenAttribute
module Plotting

from modelling.shared
namespace System
namespace System.Drawing
namespace System.Windows
namespace System.Windows.Forms
namespace Microsoft
namespace Microsoft.FSharp
namespace Microsoft.FSharp.Reflection
namespace System.Reflection
val numGenericArgs : 'a (requires equality)
val chartType : 'b (requires equality)
val mi : MethodInfo
val typeof<'T> : Type

Full name: Microsoft.FSharp.Core.Operators.typeof
type Array =
  member Clone : unit -> obj
  member CopyTo : array:Array * index:int -> unit + 1 overload
  member GetEnumerator : unit -> IEnumerator
  member GetLength : dimension:int -> int
  member GetLongLength : dimension:int -> int64
  member GetLowerBound : dimension:int -> int
  member GetUpperBound : dimension:int -> int
  member GetValue : [<ParamArray>] indices:int[] -> obj + 7 overloads
  member Initialize : unit -> unit
  member IsFixedSize : bool
  ...

Full name: System.Array
val filter : predicate:('T -> bool) -> array:'T [] -> 'T []

Full name: Microsoft.FSharp.Collections.Array.filter
val v : MethodInfo
property MemberInfo.Name: string
MethodBase.GetParameters() : ParameterInfo []
MethodInfo.GetGenericArguments() : Type []
val x : MethodInfo
module Unchecked

from Microsoft.FSharp.Core.Operators
val defaultof<'T> : 'T

Full name: Microsoft.FSharp.Core.Operators.Unchecked.defaultof
type MethodInfo =
  inherit MethodBase
  member Equals : obj:obj -> bool
  member GetBaseDefinition : unit -> MethodInfo
  member GetGenericArguments : unit -> Type[]
  member GetGenericMethodDefinition : unit -> MethodInfo
  member GetHashCode : unit -> int
  member MakeGenericMethod : [<ParamArray>] typeArguments:Type[] -> MethodInfo
  member MemberType : MemberTypes
  member ReturnParameter : ParameterInfo
  member ReturnType : Type
  member ReturnTypeCustomAttributes : ICustomAttributeProvider

Full name: System.Reflection.MethodInfo
union case Option.None: Option<'T>
union case Option.Some: Value: 'T -> Option<'T>
val createForm : chart:'a -> unit

Full name: modelling.shared.Plotting.createForm
val chart : 'a
val chartForm : Form
property Form.Text: string
property Form.ClientSize: Size
Multiple items
type Size =
  struct
    new : pt:Point -> Size + 1 overload
    member Equals : obj:obj -> bool
    member GetHashCode : unit -> int
    member Height : int with get, set
    member IsEmpty : bool
    member ToString : unit -> string
    member Width : int with get, set
    static val Empty : Size
    static member Add : sz1:Size * sz2:Size -> Size
    static member Ceiling : value:SizeF -> Size
    ...
  end

Full name: System.Drawing.Size

--------------------
Size()
Size(pt: Point) : unit
Size(width: int, height: int) : unit
type Application =
  static member AddMessageFilter : value:IMessageFilter -> unit
  static member AllowQuit : bool
  static member CommonAppDataPath : string
  static member CommonAppDataRegistry : RegistryKey
  static member CompanyName : string
  static member CurrentCulture : CultureInfo with get, set
  static member CurrentInputLanguage : InputLanguage with get, set
  static member DoEvents : unit -> unit
  static member EnableVisualStyles : unit -> unit
  static member ExecutablePath : string
  ...
  nested type MessageLoopCallback

Full name: System.Windows.Forms.Application
Application.EnableVisualStyles() : unit
Application.Run() : unit
Application.Run(context: ApplicationContext) : unit
Application.Run(mainForm: Form) : unit
Multiple items
type Form =
  inherit ContainerControl
  new : unit -> Form
  member AcceptButton : IButtonControl with get, set
  member Activate : unit -> unit
  member ActiveMdiChild : Form
  member AddOwnedForm : ownedForm:Form -> unit
  member AllowTransparency : bool with get, set
  member AutoScale : bool with get, set
  member AutoScaleBaseSize : Size with get, set
  member AutoScroll : bool with get, set
  member AutoSize : bool with get, set
  ...
  nested type ControlCollection

Full name: System.Windows.Forms.Form

--------------------
Form() : unit
val findAndCreateChart : chartType:string -> genericArgs:Type [] -> name:'a -> y:'b -> 'c

Full name: modelling.shared.Plotting.findAndCreateChart
val chartType : string
val genericArgs : Type []
type Type =
  inherit MemberInfo
  member Assembly : Assembly
  member AssemblyQualifiedName : string
  member Attributes : TypeAttributes
  member BaseType : Type
  member ContainsGenericParameters : bool
  member DeclaringMethod : MethodBase
  member DeclaringType : Type
  member Equals : o:obj -> bool + 1 overload
  member FindInterfaces : filter:TypeFilter * filterCriteria:obj -> Type[]
  member FindMembers : memberType:MemberTypes * bindingAttr:BindingFlags * filter:MemberFilter * filterCriteria:obj -> MemberInfo[]
  ...

Full name: System.Type
val name : 'a
val y : 'b
active recognizer FindChartOfType: 'a -> 'b -> MethodInfo option

Full name: modelling.shared.Plotting.( |FindChartOfType|_| )
property Array.Length: int
val invalidArg : argumentName:string -> message:string -> 'T

Full name: Microsoft.FSharp.Core.Operators.invalidArg
val chart : 'c
MethodInfo.GetGenericMethodDefinition() : MethodInfo
Multiple items
type Charting =
  new : unit -> Charting
  static member Plot : chartType:string * plotY:seq<#IConvertible list> * ?plotX:#IConvertible list * ?seriesNames:seq<string> * ?title:string * ?xTitle:string * ?yTitle:string * ?xLimits:(float * float) * ?yLimits:(float * float) * ?margin:(float32 * float32 * float32 * float32) -> unit
  static member private createChartOfType : chartType:string * name:'f * y:seq<#IConvertible * #IConvertible> -> 'i
  static member private createChartOfType : chartType:string * name:'c * y:seq<#IConvertible> -> 'e

Full name: modelling.shared.Plotting.Charting

--------------------
new : unit -> Charting
static member private Charting.createChartOfType : chartType:string * name:'f * y:seq<#IConvertible * #IConvertible> -> 'i

Full name: modelling.shared.Plotting.Charting.createChartOfType
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = String

Full name: Microsoft.FSharp.Core.string
val name : 'f
val y : seq<#IConvertible * #IConvertible>
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Core.Operators.seq

--------------------
type seq<'T> = Collections.Generic.IEnumerable<'T>

Full name: Microsoft.FSharp.Collections.seq<_>
type IConvertible =
  member GetTypeCode : unit -> TypeCode
  member ToBoolean : provider:IFormatProvider -> bool
  member ToByte : provider:IFormatProvider -> byte
  member ToChar : provider:IFormatProvider -> char
  member ToDateTime : provider:IFormatProvider -> DateTime
  member ToDecimal : provider:IFormatProvider -> decimal
  member ToDouble : provider:IFormatProvider -> float
  member ToInt16 : provider:IFormatProvider -> int16
  member ToInt32 : provider:IFormatProvider -> int
  member ToInt64 : provider:IFormatProvider -> int64
  ...

Full name: System.IConvertible
val innerTps : Type []
type FSharpType =
  static member GetExceptionFields : exceptionType:Type * ?bindingFlags:BindingFlags -> PropertyInfo []
  static member GetFunctionElements : functionType:Type -> Type * Type
  static member GetRecordFields : recordType:Type * ?bindingFlags:BindingFlags -> PropertyInfo []
  static member GetTupleElements : tupleType:Type -> Type []
  static member GetUnionCases : unionType:Type * ?bindingFlags:BindingFlags -> UnionCaseInfo []
  static member IsExceptionRepresentation : exceptionType:Type * ?bindingFlags:BindingFlags -> bool
  static member IsFunction : typ:Type -> bool
  static member IsModule : typ:Type -> bool
  static member IsRecord : typ:Type * ?bindingFlags:BindingFlags -> bool
  static member IsTuple : typ:Type -> bool
  ...

Full name: Microsoft.FSharp.Reflection.FSharpType
static member FSharpType.GetTupleElements : tupleType:Type -> Type []
Object.GetType() : Type
static member private Charting.createChartOfType : chartType:string * name:'c * y:seq<#IConvertible> -> 'e

Full name: modelling.shared.Plotting.Charting.createChartOfType
val name : 'c
val y : seq<#IConvertible>
val innerTp : Type
static member Charting.Plot : chartType:string * plotY:seq<#IConvertible list> * ?plotX:#IConvertible list * ?seriesNames:seq<string> * ?title:string * ?xTitle:string * ?yTitle:string * ?xLimits:(float * float) * ?yLimits:(float * float) * ?margin:(float32 * float32 * float32 * float32) -> unit

Full name: modelling.shared.Plotting.Charting.Plot
val plotY : seq<#IConvertible list>
val plotX : #IConvertible list option
val seriesNames : seq<string> option
val title : string option
val xTitle : string option
val yTitle : string option
val xLimits : (float * float) option
Multiple items
val float : value:'T -> float (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.float

--------------------
type float = Double

Full name: Microsoft.FSharp.Core.float

--------------------
type float<'Measure> = float

Full name: Microsoft.FSharp.Core.float<_>
val yLimits : (float * float) option
val margin : (float32 * float32 * float32 * float32) option
Multiple items
val float32 : value:'T -> float32 (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.float32

--------------------
type float32 = Single

Full name: Microsoft.FSharp.Core.float32

--------------------
type float32<'Measure> = float32

Full name: Microsoft.FSharp.Core.float32<_>
val marg : float32 * float32 * float32 * float32
val defaultArg : arg:'T option -> defaultValue:'T -> 'T

Full name: Microsoft.FSharp.Core.Operators.defaultArg
val chartTitle : string
val xTitle : string
Multiple items
type String =
  new : value:char -> string + 7 overloads
  member Chars : int -> char
  member Clone : unit -> obj
  member CompareTo : value:obj -> int + 1 overload
  member Contains : value:string -> bool
  member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
  member EndsWith : value:string -> bool + 2 overloads
  member Equals : obj:obj -> bool + 2 overloads
  member GetEnumerator : unit -> CharEnumerator
  member GetHashCode : unit -> int
  ...

Full name: System.String

--------------------
String(value: nativeptr<char>) : unit
String(value: nativeptr<sbyte>) : unit
String(value: char []) : unit
String(c: char, count: int) : unit
String(value: nativeptr<char>, startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int) : unit
String(value: char [], startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Text.Encoding) : unit
field string.Empty
val yTitle : string
val chartNames : seq<string>
module Seq

from Microsoft.FSharp.Collections
val mapi : mapping:(int -> 'T -> 'U) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.mapi
val i : int
val v : #IConvertible list
Int32.ToString() : string
Int32.ToString(provider: IFormatProvider) : string
Int32.ToString(format: string) : string
Int32.ToString(format: string, provider: IFormatProvider) : string
val length : source:seq<'T> -> int

Full name: Microsoft.FSharp.Collections.Seq.length
val mutable chart : obj
val plotX : #IConvertible list
val plot : seq<string * (#IConvertible * #IConvertible) list>
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.map
val s : #IConvertible list
Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  member Head : 'T
  member IsEmpty : bool
  member Item : index:int -> 'T with get
  member Length : int
  member Tail : 'T list
  static member Cons : head:'T * tail:'T list -> 'T list
  static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
val zip : list1:'T1 list -> list2:'T2 list -> ('T1 * 'T2) list

Full name: Microsoft.FSharp.Collections.List.zip
val zip : source1:seq<'T1> -> source2:seq<'T2> -> seq<'T1 * 'T2>

Full name: Microsoft.FSharp.Collections.Seq.zip
static member private Charting.createChartOfType : chartType:string * name:'f * y:seq<#IConvertible * #IConvertible> -> 'i
static member private Charting.createChartOfType : chartType:string * name:'c * y:seq<#IConvertible> -> 'e
val fst : tuple:('T1 * 'T2) -> 'T1

Full name: Microsoft.FSharp.Core.Operators.fst
val snd : tuple:('T1 * 'T2) -> 'T2

Full name: Microsoft.FSharp.Core.Operators.snd
val plot : seq<string * #IConvertible list>
val xMin : float
val xMax : float
type Color =
  struct
    member A : byte
    member B : byte
    member Equals : obj:obj -> bool
    member G : byte
    member GetBrightness : unit -> float32
    member GetHashCode : unit -> int
    member GetHue : unit -> float32
    member GetSaturation : unit -> float32
    member IsEmpty : bool
    member IsKnownColor : bool
    ...
  end

Full name: System.Drawing.Color
property Color.LightGray: Color
val yMin : float
val yMax : float
type StringAlignment =
  | Near = 0
  | Center = 1
  | Far = 2

Full name: System.Drawing.StringAlignment
field StringAlignment.Center = 1
Multiple items
type DockingAttribute =
  inherit Attribute
  new : unit -> DockingAttribute + 1 overload
  member DockingBehavior : DockingBehavior
  member Equals : obj:obj -> bool
  member GetHashCode : unit -> int
  member IsDefaultAttribute : unit -> bool
  static val Default : DockingAttribute

Full name: System.Windows.Forms.DockingAttribute

--------------------
DockingAttribute() : unit
DockingAttribute(dockingBehavior: DockingBehavior) : unit
type FontStyle =
  | Regular = 0
  | Bold = 1
  | Italic = 2
  | Underline = 4
  | Strikeout = 8

Full name: System.Drawing.FontStyle
field FontStyle.Bold = 1
Raw view Test code New version

More information

Link:http://fssnip.net/aK
Posted:12 years ago
Author:Boris Kogan
Tags: fsharpchart , reflection , charting , active patterns