XPlot


Google Line Chart

Binder

This example shows how to create scatter (point) charts and line charts using the XPlot.GoogleCharts library.

To create a line chart, use Chart.Line. To create a scatter (point) chart, use Chart.Scatter. In both cases, you can also combine multiple charts in the same chart area, simply by calling the functions with a list of lists (rather than with just a plan list of key value pairs)

A simple line chart

The following example calls Chart.Line with a list of key value pairs, created using a simple F# list comprehension:

open XPlot.GoogleCharts

let chart1 = Chart.Line [ for x in 0. .. 0.5 .. 6.3 -> x, sin x ]
Google Chart

A smooth function chart

By default, line charts use straight line segments between the points. You can add smoothing by creating Options with curveType="function" as follows:

let chart2 =
    [ for x in 0. .. 0.5 .. 6.3 -> x, sin x ]
    |> Chart.Line
    |> Chart.WithOptions(Options(curveType = "function"))
Google Chart

You can find more information about other options that you can specify in the documentation for the Options type in the API reference. Another way to explore the available configuration options is to type dot right after the value, i.e. Options(). - and see what fields (lower-case, at the end of the list) are available.

Combining line charts

Finally, you can also pass multiple series of values to both point and line charts. This creates a chart that shows multiple data sets using a different line or point color for each data set. The following example plots sales and expenses of some non-existent company in a single line chart with annotations:

let sales = [("2013", 1000); ("2014", 1170); ("2015", 660); ("2016", 1030)]
let expenses = [("2013", 400); ("2014", 460); ("2015", 1120); ("2016", 540)]

let options =
  Options
    ( title = "Company Performance", curveType = "function",
      legend = Legend(position = "bottom") )

let chart3 =
    [sales; expenses]
    |> Chart.Line
    |> Chart.WithOptions options
    |> Chart.WithLabels ["Sales"; "Expenses"]
Google Chart

Note that the two inputs are sequences of tuples with X (year) and Y (value) pairs. We then create Options object to specify the title, smooth curve and also the legend of the chart. Then we call Chart.Line followed by Chart.WithOptions and also Chart.WithLabels to provide labels for the two series. *)

(* Create a line chart with two different Y-axes (the example above has two lines plotted by only a single Y-axis). Plot values of different data types Based off of this sample: https://developers.google.com/chart/interactive/docs/gallery/linechart#dual-y-charts

open System

//Make up some fake data. Two sets of values for the same sequence of dates
let values1 = [1..7]
let values2 = [20.1..10.3..90.0] //using floats here to demonstrate that we can use a different data type on the second Y axis
let dates = [ for i in [6.0..(-1.0)..0.0] -> DateTime.Today.AddDays(-i) ]

let first = Deedle.Series(dates, values1)
let second = Deedle.Series(dates, values2)

let df = Deedle.Frame(["IntVals"; "FloatVals"], [first; second])

let dfOptions =
  Options
    ( title = "Value 1 & Value 2 by Date",
      legend = Legend(position = "bottom") ,
      series = [|Series("IntVals", targetAxisIndex = 0); Series("FloatVals", targetAxisIndex = 1)|],
      vAxes = [|Axis(title = "Foo"); Axis(title = "Bar")|])

let chart4 =
    df
    |> Chart.Line
    |> Chart.WithOptions dfOptions
Google Chart
namespace XPlot
namespace XPlot.GoogleCharts
val chart1 : GoogleChart
type Chart =
  static member Annotation : data:seq<DateTime * #value * string * string> * ?Labels:seq<string> * ?Options:Options -> GoogleChart + 1 overload
  static member Area : data:seq<#value> * ?Labels:seq<string> * ?Options:Options -> GoogleChart + 2 overloads
  static member Bar : data:seq<#value> * ?Labels:seq<string> * ?Options:Options -> GoogleChart + 2 overloads
  static member Bubble : data:seq<string * #value * #value> * ?Labels:seq<string> * ?Options:Options -> GoogleChart + 2 overloads
  static member Calendar : data:seq<DateTime * #value> * ?Labels:seq<string> * ?Options:Options -> GoogleChart
  static member Candlestick : data:seq<#key * #value * #value * #value * #value> * ?Labels:seq<string> * ?Options:Options -> GoogleChart + 1 overload
  static member Column : data:seq<#value> * ?Labels:seq<string> * ?Options:Options -> GoogleChart + 2 overloads
  static member Combo : data:seq<#seq<'K * 'V>> * ?Labels:seq<string> * ?Options:Options -> GoogleChart (requires 'K :> key and 'V :> value)
  static member private Create : data:seq<#seq<'T>> -> labels:seq<string> option -> options:Options option -> chartType:ChartGallery -> datumNew:('T -> Datum) -> GoogleChart
  static member private Create' : data:seq<#value> -> labels:seq<string> option -> options:Options option -> chartType:ChartGallery -> GoogleChart
  ...
static member Chart.Line : data:Deedle.Frame<'K,'V> * ?Options:Options -> GoogleChart (requires equality and equality)
static member Chart.Line : data:Deedle.Series<'K,#value> * ?Labels:seq<string> * ?Options:Options -> GoogleChart (requires equality and 'K :> key)
static member Chart.Line : data:seq<Deedle.Series<'K,#value>> * ?Labels:seq<string> * ?Options:Options -> GoogleChart (requires equality and 'K :> key)
static member Chart.Line : data:seq<#seq<'K * 'V>> * ?Labels:seq<string> * ?Options:Options -> GoogleChart (requires 'K :> key and 'V :> value)
static member Chart.Line : data:seq<#key * #value> * ?Labels:seq<string> * ?Options:Options -> GoogleChart
static member Chart.Line : data:seq<#value> * ?Labels:seq<string> * ?Options:Options -> GoogleChart
val x : float
val sin : value:'T -> 'T (requires member Sin)
member GoogleChart.GetHtml : unit -> string
val chart2 : GoogleChart
static member Chart.WithOptions : options:Options -> chart:GoogleChart -> GoogleChart
Multiple items
type Options =
  new : unit -> Options
  member ShouldSerializeaggregationTarget : unit -> bool
  member ShouldSerializeallValuesSuffix : unit -> bool
  member ShouldSerializeallowHtml : unit -> bool
  member ShouldSerializealternatingRowStyle : unit -> bool
  member ShouldSerializeanimation : unit -> bool
  member ShouldSerializeannotations : unit -> bool
  member ShouldSerializeannotationsWidth : unit -> bool
  member ShouldSerializeareaOpacity : unit -> bool
  member ShouldSerializeavoidOverlappingGridLines : unit -> bool
  ...

--------------------
new : unit -> Options
val sales : (string * int) list
val expenses : (string * int) list
val options : Options
Multiple items
type Legend =
  new : unit -> Legend
  member ShouldSerializealignment : unit -> bool
  member ShouldSerializemaxLines : unit -> bool
  member ShouldSerializenumberFormat : unit -> bool
  member ShouldSerializeposition : unit -> bool
  member ShouldSerializetextStyle : unit -> bool
  member alignment : string
  member maxLines : int
  member numberFormat : string
  member position : string
  ...

--------------------
new : unit -> Legend
val chart3 : GoogleChart
static member Chart.WithLabels : labels:seq<string> -> chart:GoogleChart -> GoogleChart
namespace System
val values1 : int list
val values2 : float list
val dates : DateTime list
val i : float
Multiple items
[<Struct>]
type DateTime =
  new : year: int * month: int * day: int -> unit + 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
  ...

--------------------
DateTime ()
   (+0 other overloads)
DateTime(ticks: int64) : DateTime
   (+0 other overloads)
DateTime(ticks: int64, kind: DateTimeKind) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, calendar: Globalization.Calendar) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, kind: DateTimeKind) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, calendar: Globalization.Calendar) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, kind: DateTimeKind) : DateTime
   (+0 other overloads)
property DateTime.Today: DateTime with get
DateTime.AddDays(value: float) : DateTime
val first : Deedle.Series<DateTime,int>
Multiple items
module Deedle

from XPlot.GoogleCharts

--------------------
namespace Deedle
Multiple items
module Series

from Deedle

--------------------
type Series<'K,'V (requires equality)> =
  interface IFsiFormattable
  interface ISeries<'K>
  new : index:IIndex<'K> * vector:IVector<'V> * vectorBuilder:IVectorBuilder * indexBuilder:IIndexBuilder -> Series<'K,'V> + 3 overloads
  member After : lowerExclusive:'K -> Series<'K,'V>
  member Aggregate : aggregation:Aggregation<'K> * keySelector:Func<DataSegment<Series<'K,'V>>,'TNewKey> * valueSelector:Func<DataSegment<Series<'K,'V>>,OptionalValue<'R>> -> Series<'TNewKey,'R> (requires equality) + 1 overload
  member AsyncMaterialize : unit -> Async<Series<'K,'V>>
  member Before : upperExclusive:'K -> Series<'K,'V>
  member Between : lowerInclusive:'K * upperInclusive:'K -> Series<'K,'V>
  member Compare : another:Series<'K,'V> -> Series<'K,Diff<'V>>
  member Convert : forward:Func<'V,'R> * backward:Func<'R,'V> -> Series<'K,'R>
  ...

--------------------
new : pairs:seq<Collections.Generic.KeyValuePair<'K,'V>> -> Deedle.Series<'K,'V>
new : keys:seq<'K> * values:seq<'V> -> Deedle.Series<'K,'V>
new : keys:'K [] * values:'V [] -> Deedle.Series<'K,'V>
new : index:Deedle.Indices.IIndex<'K> * vector:Deedle.IVector<'V> * vectorBuilder:Deedle.Vectors.IVectorBuilder * indexBuilder:Deedle.Indices.IIndexBuilder -> Deedle.Series<'K,'V>
val second : Deedle.Series<DateTime,float>
val df : Deedle.Frame<DateTime,string>
Multiple items
module Frame

from Deedle

--------------------
type Frame =
  static member ReadCsv : location:string * hasHeaders:Nullable<bool> * inferTypes:Nullable<bool> * inferRows:Nullable<int> * schema:string * separators:string * culture:string * maxRows:Nullable<int> * missingValues:string [] * preferOptions:bool -> Frame<int,string> + 1 overload
  static member ReadReader : reader:IDataReader -> Frame<int,string>
  static member CustomExpanders : Dictionary<Type,Func<obj,seq<string * Type * obj>>>
  static member NonExpandableInterfaces : ResizeArray<Type>
  static member NonExpandableTypes : HashSet<Type>

--------------------
type Frame<'TRowKey,'TColumnKey (requires equality and equality)> =
  interface IDynamicMetaObjectProvider
  interface INotifyCollectionChanged
  interface IFsiFormattable
  interface IFrame
  new : rowIndex:IIndex<'TRowKey> * columnIndex:IIndex<'TColumnKey> * data:IVector<IVector> * indexBuilder:IIndexBuilder * vectorBuilder:IVectorBuilder -> Frame<'TRowKey,'TColumnKey> + 1 overload
  member AddColumn : column:'TColumnKey * series:seq<'V> -> unit + 3 overloads
  member AggregateRowsBy : groupBy:seq<'TColumnKey> * aggBy:seq<'TColumnKey> * aggFunc:Func<Series<'TRowKey,'a>,'b> -> Frame<int,'TColumnKey>
  member Clone : unit -> Frame<'TRowKey,'TColumnKey>
  member ColumnApply : f:Func<Series<'TRowKey,'T>,ISeries<'TRowKey>> -> Frame<'TRowKey,'TColumnKey> + 1 overload
  member DropColumn : column:'TColumnKey -> unit
  ...

--------------------
new : names:seq<'TColumnKey> * columns:seq<Deedle.ISeries<'TRowKey>> -> Deedle.Frame<'TRowKey,'TColumnKey>
new : rowIndex:Deedle.Indices.IIndex<'TRowKey> * columnIndex:Deedle.Indices.IIndex<'TColumnKey> * data:Deedle.IVector<Deedle.IVector> * indexBuilder:Deedle.Indices.IIndexBuilder * vectorBuilder:Deedle.Vectors.IVectorBuilder -> Deedle.Frame<'TRowKey,'TColumnKey>
val dfOptions : Options
Multiple items
type Series =
  new : ?type:string -> Series
  member ShouldSerializeannotations : unit -> bool
  member ShouldSerializeareaOpacity : unit -> bool
  member ShouldSerializecolor : unit -> bool
  member ShouldSerializecurveType : unit -> bool
  member ShouldSerializefallingColor : unit -> bool
  member ShouldSerializelineWidth : unit -> bool
  member ShouldSerializepointShape : unit -> bool
  member ShouldSerializepointSize : unit -> bool
  member ShouldSerializerisingColor : unit -> bool
  ...

--------------------
new : ?type:string -> Series
Multiple items
type Axis =
  new : unit -> Axis
  member ShouldSerializeallowContainerBoundaryTextCufoff : unit -> bool
  member ShouldSerializebaseline : unit -> bool
  member ShouldSerializebaselineColor : unit -> bool
  member ShouldSerializedirection : unit -> bool
  member ShouldSerializeformat : unit -> bool
  member ShouldSerializegridlines : unit -> bool
  member ShouldSerializelogScale : unit -> bool
  member ShouldSerializemaxAlternation : unit -> bool
  member ShouldSerializemaxTextLines : unit -> bool
  ...

--------------------
new : unit -> Axis
val chart4 : GoogleChart