F# Charting


F# Charting: Live Animated Charts

Summary: This example shows a collection of LiveCharts, which update as data changes.

The input data comes from IObservable (or IEvent) sources. The data can be created using F# AsyncSeq, Rx, F# Event combinators or F# Observable combinators.

The samples are not yet individually documented.

In this sample, some extra event combinators are used to generate reactive data. The EventEx-0.1.fsx file can be found here.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
// On Mac OSX use FSharp.Charting.Gtk.fsx
#I "packages/FSharp.Charting"
#load "FSharp.Charting.fsx"
#load "EventEx-0.1.fsx"
#r "../../packages/FSharp.Control.AsyncSeq/lib/net45/FSharp.Control.AsyncSeq.dll"

open System
open System.Drawing
open FSharp.Charting
open FSharp.Control

The following code generates sample data - both as a list of values and as an F# event (IObservable) that can be passed to live charts:

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
let timeSeriesData = 
  [ for x in 0 .. 99 -> 
      DateTime.Now.AddDays (float x),sin(float x / 10.0) ]
let rnd = new System.Random()
let rand() = rnd.NextDouble()

let data = [ for x in 0 .. 99 -> (x,x*x) ]
let data2 = [ for x in 0 .. 99 -> (x,sin(float x / 10.0)) ]
let data3 = [ for x in 0 .. 99 -> (x,cos(float x / 10.0)) ]
let incData = Event.clock 10 |> Event.map (fun x -> (x, x.Millisecond))

You can use Event.cycle to create a simple live data source that iterates over in-memory sequence, or you can use an event as follows:

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
// Cycle through two data sets of the same type
LiveChart.Line (Event.cycle 1000 [data2; data3])

LiveChart.LineIncremental(incData,Name="MouseMove")
  .WithXAxis(Enabled=false).WithYAxis(Enabled=false)

LiveChart.FastLineIncremental(incData,Name="MouseMove")
  .WithXAxis(Enabled=false).WithYAxis(Enabled=false)
namespace System
namespace System.Drawing
Multiple items
namespace FSharp

--------------------
namespace Microsoft.FSharp
namespace FSharp.Charting
Multiple items
namespace FSharp.Control

--------------------
namespace Microsoft.FSharp.Control
val timeSeriesData : (DateTime * float) list

Full name: LiveChartSamples.timeSeriesData
val x : int
Multiple items
type DateTime =
  struct
    new : ticks:int64 -> DateTime + 10 overloads
    member Add : value:TimeSpan -> DateTime
    member AddDays : value:float -> DateTime
    member AddHours : value:float -> DateTime
    member AddMilliseconds : value:float -> DateTime
    member AddMinutes : value:float -> DateTime
    member AddMonths : months:int -> DateTime
    member AddSeconds : value:float -> DateTime
    member AddTicks : value:int64 -> DateTime
    member AddYears : value:int -> DateTime
    ...
  end

Full name: System.DateTime

--------------------
DateTime()
   (+0 other overloads)
DateTime(ticks: int64) : unit
   (+0 other overloads)
DateTime(ticks: int64, kind: DateTimeKind) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, calendar: Globalization.Calendar) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, kind: DateTimeKind) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, calendar: Globalization.Calendar) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, kind: DateTimeKind) : unit
   (+0 other overloads)
property DateTime.Now: DateTime
DateTime.AddDays(value: float) : DateTime
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 sin : value:'T -> 'T (requires member Sin)

Full name: Microsoft.FSharp.Core.Operators.sin
val rnd : Random

Full name: LiveChartSamples.rnd
Multiple items
type Random =
  new : unit -> Random + 1 overload
  member Next : unit -> int + 2 overloads
  member NextBytes : buffer:byte[] -> unit
  member NextDouble : unit -> float

Full name: System.Random

--------------------
Random() : unit
Random(Seed: int) : unit
val rand : unit -> float

Full name: LiveChartSamples.rand
Random.NextDouble() : float
val data : (int * int) list

Full name: LiveChartSamples.data
val data2 : (int * float) list

Full name: LiveChartSamples.data2
val data3 : (int * float) list

Full name: LiveChartSamples.data3
val cos : value:'T -> 'T (requires member Cos)

Full name: Microsoft.FSharp.Core.Operators.cos
val incData : IEvent<DateTime * int>

Full name: LiveChartSamples.incData
Multiple items
module Event

from Microsoft.FSharp.Control

--------------------
module Event

--------------------
type Event<'T> =
  new : unit -> Event<'T>
  member Trigger : arg:'T -> unit
  member Publish : IEvent<'T>

Full name: Microsoft.FSharp.Control.Event<_>

--------------------
type Event<'Delegate,'Args (requires delegate and 'Delegate :> Delegate)> =
  new : unit -> Event<'Delegate,'Args>
  member Trigger : sender:obj * args:'Args -> unit
  member Publish : IEvent<'Delegate,'Args>

Full name: Microsoft.FSharp.Control.Event<_,_>

--------------------
new : unit -> Event<'T>

--------------------
new : unit -> Event<'Delegate,'Args>
val clock : interval:int -> IEvent<DateTime>

Full name: Event.clock


 An event which triggers at regular intervals reporting the real world time at each trigger
val map : mapping:('T -> 'U) -> sourceEvent:IEvent<'Del,'T> -> IEvent<'U> (requires delegate and 'Del :> Delegate)

Full name: Microsoft.FSharp.Control.Event.map
val x : DateTime
property DateTime.Millisecond: int
type LiveChart =
  static member Area : data:IObservable<#seq<'a1 * 'a2>> * ?Name:string * ?Title:string * ?Color:Color * ?XTitle:string * ?YTitle:string -> GenericChart (requires 'a1 :> key and 'a2 :> value)
  static member Bar : data:IObservable<#seq<'a1 * 'a2>> * ?Name:string * ?Title:string * ?Color:Color * ?XTitle:string * ?YTitle:string -> GenericChart (requires 'a1 :> key and 'a2 :> value)
  static member Bubble : data:IObservable<#seq<'b * 'c * 'd>> * ?Name:string * ?Title:string * ?Color:Color * ?XTitle:string * ?YTitle:string * ?BubbleMaxSize:int * ?BubbleMinSize:int * ?BubbleScaleMax:float * ?BubbleScaleMin:float * ?UseSizeForLabel:bool -> GenericChart (requires 'b :> key and 'c :> value and 'd :> value)
  static member BubbleIncremental : data:IObservable<#key * #value * #value> * ?Name:string * ?Title:string * ?Color:Color * ?XTitle:string * ?YTitle:string * ?BubbleMaxSize:int * ?BubbleMinSize:int * ?BubbleScaleMax:float * ?BubbleScaleMin:float * ?UseSizeForLabel:bool -> GenericChart
  static member Candlestick : data:IObservable<#seq<'a1 * 'a2 * 'a3 * 'a4 * 'a5>> * ?Name:string * ?Title:string * ?Color:Color * ?XTitle:string * ?YTitle:string -> CandlestickChart (requires 'a1 :> key and 'a2 :> value and 'a3 :> value and 'a4 :> value and 'a5 :> value)
  static member Candlestick : data:IObservable<seq<#value * #value * #value * #value>> * ?Name:string * ?Title:string * ?Color:Color * ?XTitle:string * ?YTitle:string -> CandlestickChart
  static member CandlestickIncremental : data:IObservable<#key * #value * #value * #value * #value> * ?Name:string * ?Title:string * ?Color:Color * ?XTitle:string * ?YTitle:string -> CandlestickChart
  static member CandlestickIncremental : data:IObservable<'a0 * #value * #value * #value> * ?Name:string * ?Title:string * ?Color:Color * ?XTitle:string * ?YTitle:string -> CandlestickChart (requires 'a0 :> key and 'a0 :> value)
  static member Column : data:IObservable<#seq<'a1 * 'a2>> * ?Name:string * ?Title:string * ?Color:Color * ?XTitle:string * ?YTitle:string * ?ColumnWidth:float -> GenericChart (requires 'a1 :> key and 'a2 :> value)
  static member ColumnIncremental : data:IObservable<#key * #value> * ?Name:string * ?Title:string * ?Color:Color * ?XTitle:string * ?YTitle:string * ?ColumnWidth:float -> GenericChart
  ...

Full name: FSharp.Charting.LiveChart
static member LiveChart.Line : data:IObservable<#seq<'b * 'c>> * ?Name:string * ?Title:string * ?Color:Color * ?XTitle:string * ?YTitle:string -> ChartTypes.GenericChart (requires 'b :> key and 'c :> value)
val cycle : interval:int -> values:seq<'a> -> IEvent<'a>

Full name: Event.cycle


 Cycle through the values at the given interval
static member LiveChart.LineIncremental : data:IObservable<#key * #value> * ?Name:string * ?Title:string * ?Color:Color * ?XTitle:string * ?YTitle:string -> ChartTypes.GenericChart
static member LiveChart.FastLineIncremental : data:IObservable<#key * #value> * ?Name:string * ?Title:string * ?Color:Color * ?XTitle:string * ?YTitle:string -> ChartTypes.GenericChart
val incBubbleData : IEvent<float * float * float>

Full name: LiveChartSamples.incBubbleData
val evData : IEvent<(DateTime * int) []>

Full name: LiveChartSamples.evData
val windowTimeInterval : interval:int -> ev:IEvent<DateTime * 'a> -> IEvent<(DateTime * 'a) []>

Full name: Event.windowTimeInterval


 An event which triggers on every event, reporting samples from the given time window
val evData2 : IEvent<(DateTime * float) []>

Full name: LiveChartSamples.evData2
property DateTime.Ticks: int64
val evBubbleData : IEvent<(float * float * float) []>

Full name: LiveChartSamples.evBubbleData
val sampled : interval:int -> ev:IEvent<'a> -> IEvent<DateTime * 'a>

Full name: Event.sampled


 An event which triggers at regular intervals reporting the latest observed value of the given event
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 map : mapping:('T -> 'U) -> array:'T [] -> 'U []

Full name: Microsoft.FSharp.Collections.Array.map
val x : float * float * float
val constantLiveTimeSeriesData : IEvent<(DateTime * float) list>

Full name: LiveChartSamples.constantLiveTimeSeriesData
static member LiveChart.Point : data:IObservable<#seq<'b * 'c>> * ?Name:string * ?Title:string * ?Color:Color * ?XTitle:string * ?YTitle:string * ?MarkerColor:Color * ?MarkerSize:int -> ChartTypes.GenericChart (requires 'b :> key and 'c :> value)
static member LiveChart.FastPoint : data:IObservable<#seq<'b * 'c>> * ?Name:string * ?Title:string * ?Color:Color * ?XTitle:string * ?YTitle:string -> ChartTypes.GenericChart (requires 'b :> key and 'c :> value)
static member LiveChart.PointIncremental : data:IObservable<#key * #value> * ?Name:string * ?Title:string * ?Color:Color * ?XTitle:string * ?YTitle:string * ?MarkerColor:Color * ?MarkerSize:int -> ChartTypes.GenericChart
static member LiveChart.FastPointIncremental : data:IObservable<#key * #value> * ?Name:string * ?Title:string * ?Color:Color * ?XTitle:string * ?YTitle:string -> ChartTypes.GenericChart
static member LiveChart.BubbleIncremental : data:IObservable<#key * #value * #value> * ?Name:string * ?Title:string * ?Color:Color * ?XTitle:string * ?YTitle:string * ?BubbleMaxSize:int * ?BubbleMinSize:int * ?BubbleScaleMax:float * ?BubbleScaleMin:float * ?UseSizeForLabel:bool -> ChartTypes.GenericChart
static member LiveChart.Bubble : data:IObservable<#seq<'b * 'c * 'd>> * ?Name:string * ?Title:string * ?Color:Color * ?XTitle:string * ?YTitle:string * ?BubbleMaxSize:int * ?BubbleMinSize:int * ?BubbleScaleMax:float * ?BubbleScaleMin:float * ?UseSizeForLabel:bool -> ChartTypes.GenericChart (requires 'b :> key and 'c :> value and 'd :> value)
val asyncSeq : AsyncSeq.AsyncSeqBuilder

Full name: FSharp.Control.AsyncSeqExtensions.asyncSeq
val i : int
Multiple items
type Async
static member AsBeginEnd : computation:('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit)
static member AwaitEvent : event:IEvent<'Del,'T> * ?cancelAction:(unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate)
static member AwaitIAsyncResult : iar:IAsyncResult * ?millisecondsTimeout:int -> Async<bool>
static member AwaitTask : task:Task -> Async<unit>
static member AwaitTask : task:Task<'T> -> Async<'T>
static member AwaitWaitHandle : waitHandle:WaitHandle * ?millisecondsTimeout:int -> Async<bool>
static member CancelDefaultToken : unit -> unit
static member Catch : computation:Async<'T> -> Async<Choice<'T,exn>>
static member FromBeginEnd : beginAction:(AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg:'Arg1 * beginAction:('Arg1 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * beginAction:('Arg1 * 'Arg2 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * arg3:'Arg3 * beginAction:('Arg1 * 'Arg2 * 'Arg3 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromContinuations : callback:(('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T>
static member Ignore : computation:Async<'T> -> Async<unit>
static member OnCancel : interruption:(unit -> unit) -> Async<IDisposable>
static member Parallel : computations:seq<Async<'T>> -> Async<'T []>
static member RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:CancellationToken -> 'T
static member Sleep : millisecondsDueTime:int -> Async<unit>
static member Start : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions * ?cancellationToken:CancellationToken -> Task<'T>
static member StartChild : computation:Async<'T> * ?millisecondsTimeout:int -> Async<Async<'T>>
static member StartChildAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions -> Async<Task<'T>>
static member StartImmediate : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartWithContinuations : computation:Async<'T> * continuation:('T -> unit) * exceptionContinuation:(exn -> unit) * cancellationContinuation:(OperationCanceledException -> unit) * ?cancellationToken:CancellationToken -> unit
static member SwitchToContext : syncContext:SynchronizationContext -> Async<unit>
static member SwitchToNewThread : unit -> Async<unit>
static member SwitchToThreadPool : unit -> Async<unit>
static member TryCancelled : computation:Async<'T> * compensation:(OperationCanceledException -> unit) -> Async<'T>
static member CancellationToken : Async<CancellationToken>
static member DefaultCancellationToken : CancellationToken

Full name: Microsoft.FSharp.Control.Async

--------------------
type Async<'T>

Full name: Microsoft.FSharp.Control.Async<_>
static member Async.Sleep : millisecondsDueTime:int -> Async<unit>
Multiple items
module AsyncSeq

from FSharp.Control

--------------------
type AsyncSeq<'T> = IAsyncEnumerable<'T>

Full name: FSharp.Control.AsyncSeq<_>
val toObservable : source:AsyncSeq<'T> -> IObservable<'T>

Full name: FSharp.Control.AsyncSeq.toObservable
Fork me on GitHub