open Dash.NET
open Plotly.NET
open FSharp.Data

let df = CsvFile.Load("https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv").Rows |> List.ofSeq

let dslLayout = 
    Html.div [
        Attr.children [
            Graph.graph "graph-with-slider" []
            Slider.slider "year-slider" [
                Slider.Attr.min (df |> List.map (fun r -> r.Item "year" |> int) |> List.min)
                Slider.Attr.max (df |> List.map (fun r -> r.Item "year" |> int) |> List.max)
                Slider.Attr.value (df |> List.map (fun r -> r.Item "year" |> int) |> List.min)
                Slider.Attr.marks (
                    df 
                    |> List.map (fun r -> r.Item "year") 
                    |> List.distinct 
                    |> List.map (fun y -> (y, Slider.MarkValue.String y))
                    |> Map.ofList
                    |> Slider.MarksType
               )
            ]
        ]
    ]

let updateFigureCallback =
    Callback.singleOut (
        "year-slider" @. Value,
        "graph-with-slider" @. (CustomProperty "figure"),
        fun (inputValue:string) -> 
            let inputYear = inputValue |> int
            let filteredDf = df |> List.filter (fun r -> r.Item "year" |> int = inputYear)

            let xData = filteredDf |> List.map (fun r -> r.Item "gdpPercap")
            let yData = filteredDf |> List.map (fun r -> r.Item "lifeExp")
            let sizeLabels = filteredDf |> List.map (fun r -> r.Item "pop")
            let sizeData = sizeLabels |> List.map (fun s -> (double s / 10000000.))
            let countryData = filteredDf |> List.map (fun r -> r.Item "country")
            let contData = filteredDf |> List.map (fun r -> r.Item "continent")

            let labels = 
                List.zip3 countryData contData sizeLabels
                |> List.map (fun (cty, cnt, sz) -> sprintf "%s, %s, Population %s" cty cnt sz)

            let fig = 
                Chart.Bubble(
                    xData, 
                    yData, 
                    sizeData,
                    Showlegend = true,
                    Labels = labels
                )
                |> Chart.withX_Axis(
                    Axis.LinearAxis.init(
                        AxisType = StyleParam.AxisType.Log,
                        Title = "GDP Per Capita"
                    )
                )
                |> Chart.withY_Axis(
                    Axis.LinearAxis.init(
                        Title = "Life Expectancy"
                    )
                )
                |> GenericChart.toFigure

            "graph-with-slider" @. (CustomProperty "figure") => fig
    )

[<EntryPoint>]
let main args =
    DashApp.initDefault()
    |> DashApp.withLayout dslLayout
    |> DashApp.addCallback updateFigureCallback
    |> DashApp.run args