2 people like it.
Like the snippet!
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
More information