Chart(Fsharp.Charting) not respond

344 views Asked by At

Having this code:

let errorChanged = new Event<(int * float)>()

let learn error data w w_ iter =
    let rec learning error data w w_ i icount =
        //recursive(loop) fire event
        errorChanged.Trigger(i, e) //trigger event for chart update
        if (/**/) then
            learning /*params*/
        else
            /*do else*/

    let plot = LiveChart.PointIncremental(errorChanged.Publish |> Event.every 5)
    plot.ShowChart()
    learning error data w w_ 0 iter

when i run it, i see Point Chart window, which is not respond (and not updating). According to code samples this should works well, but... How can i fix this?

UPD:

if i do:

let rec learning error data w w_ i icount = async {
            let e = Seq.fold (fun s x ->
                                         s + errorPart w w_ x x) 0.0 data
            errorChanged.Trigger(i, e)
            if (e > error && i <= iter) then
                printfn "[iter] = %d of %d. [e] = %f" i icount e
                let (w, w_) = Seq.fold (fun (w, w_) x -> 
                                                learnPart w w_ x x) (w, w_) data
                return! learning error data (normalize w) (normalize w_) (i + 1) icount
            else
                let resultData = Seq.map (fun x -> calculatePart w w_ x) data
                let y = resultData
                        |> Seq.map (fun (y, _) -> y) 
                        |> Seq.concat
                let x_ = resultData
                        |> Seq.map (fun (_, x_) -> x_) 
                        |> Seq.concat
                return (w, w_, e, y, x_) }

        let plot = LiveChart.PointIncremental(errorChanged.Publish |> Event.every 5)
        plot.ShowChart()
        async { return! learning error data w w_ 0 iter}
        |> Async.RunSynchronously

i get exception: Cross-thread operation not valid. Seems like i need something like Dispatcher.

2

There are 2 answers

1
Tomas Petricek On BEST ANSWER

The problem with your code snippet is that it creates the chart, but then it runs the learning function on the current thread and so it blocks the main thread (which never gets a chance to update the chart).

You can wrap the learning function in async { .. } block and run it using Async.Start. Then it will run in the background and the chart will be able to update.

You did not post complete code, so I was not able to test, but I think the following should work:

let rec learning error data w w_ i icount = async { // Async block here!
    (* omitted *)
    errorChanged.Trigger(i, e) //trigger event for chart update
    if (e > error && i <= iter) then
        (* omitted *) 
        // Here, we now need to run the recursive call using 'return!' of async
        return! learning error data (normalize w) (normalize w_) (i + 1) icount
    else
        (* omitted *)
        return (w, w_, e, y, x_) }

let plot = LiveChart.PointIncremental(errorChanged.Publish |> Event.every 5)
plot.ShowChart()

// Create workflow that will run 'learning' and then print the result
// (this needs to return unit, so that we can use 'Async.Start')
async { let! res = learning error data w w_ 0 iter 
        printfn "Finished: %A" res } 
|> Async.Start
0
Maslow On

it's probably a lack of an WinForms event loop.

Try this simple code to see if it hangs first, then apply it to your plot

use form = new Form(Width=400, Height=300, Visible=true, Text="Hello charting")
Chart.Line([for x in 0 ..10 -> x, x+x]).ShowChart()
System.Windows.Forms.Application.Run(form)