@@ -44,37 +44,46 @@ function timeseries_col(app, session)
44
44
end
45
45
46
46
function timeseries_cards (app, session)
47
- # we store the cards based on objid of TSPlot, otherwise overwrite with same key
48
- # leads to problems
49
- cards = OrderedDict {UInt, Bonito.Hyperscript.Node{Bonito.Hyperscript.HTMLSVG}} ()
50
- observables = OrderedDict {UInt, Vector{Observables.ObserverFunction}} ()
51
47
container = Observable {Bonito.Hyperscript.Node{Bonito.Hyperscript.HTMLSVG}} ()
52
48
49
+ # update the timeseries-sstacke based on the tsplots in appstate
53
50
on (app. tsplots; update= true ) do _tsplots
54
51
@debug " TS: app.tsplots => update timeseries cards"
55
- id_to_key = Dict (Base. objectid (val) => key for (key, val) in _tsplots)
56
- newids = Base. objectid .(values (_tsplots)) # collect to preserv order on setdiff
57
- knownids = keys (cards)
58
-
59
- for delid in setdiff (knownids, newids)
60
- Observables. off .(observables[delid]) # deactivate allobservables from card
61
- delete! (observables, delid)
62
- delete! (cards, delid)
52
+ # this cache contains all the card, the observer functions and the plotqueue
53
+ cache = app. _tsplotscache
54
+
55
+ known_tsplots = collect (keys (cache))
56
+ current_tsplots = collect (values (_tsplots))
57
+
58
+ # do nothing if the TSPlots objects themselve did not change
59
+ Set (known_tsplots) == Set (current_tsplots) && return
60
+
61
+ # del_tsplots = setdiff(known_tsplots, current_tsplots)
62
+ # new_tsplots = setdiff(current_tsplots, known_tsplots)
63
+ # FIXME : it is not possible to redisplay the same tsplot, recreate all
64
+ del_tsplots = known_tsplots
65
+ new_tsplots = current_tsplots
66
+
67
+ for del in del_tsplots
68
+ (; card, observerfunctions, plotqueue) = cache[del]
69
+ close (plotqueue) # close plotqueue
70
+ Observables. off .(observerfunctions) # disable all observer functions
71
+ delete! (cache, del) # delete from cache
63
72
end
64
- for newid in setdiff (newids, knownids)
65
- card, obsf = timeseries_card (app, id_to_key[newid], session)
66
- cards[newid] = card
67
- observables[newid] = obsf
68
- end
69
- if collect (keys (cards)) != newids
70
- @warn " The keys do not match: $(keys (cards)) vs $(newids) "
73
+ for new in new_tsplots
74
+ key = only ([key for (key, value) in _tsplots if value == new])
75
+ ntup = timeseries_card (app, key, session)
76
+ cache[new] = ntup
71
77
end
72
78
73
- container[] = DOM. div (values (cards)... ; class= " timeseries-stack" )
79
+ cards = [cache[ts]. card for ts in values (_tsplots)]
80
+ # update the display by notifying the content
81
+ container[] = DOM. div (cards; class= " timeseries-stack" )
74
82
75
83
nothing
76
84
end
77
85
86
+ # update the selected components in the graphplot when the active tsplot changes
78
87
on (app. active_tsplot; update= true ) do active
79
88
activesel = app. tsplots[][active]. selcomp[]
80
89
app. graphplot. _selcomp[] = activesel
@@ -303,6 +312,7 @@ function timeseries_card(app, key, session)
303
312
ts = Observable (collect (range (app. sol[]. t[begin ], app. sol[]. t[end ], length= 1000 )))
304
313
refined_xlims = Ref ((NaN , NaN ))
305
314
onany_delayed (ax. finallimits; delay= 0.5 ) do axlims
315
+ @debug " $key : Adapt ts vector"
306
316
sollims = (app. sol[]. t[begin ], app. sol[]. t[end ])
307
317
xlims = (axlims. origin[1 ], axlims. origin[1 ] + axlims. widths[1 ])
308
318
if xlims != refined_xlims[]
@@ -354,34 +364,37 @@ function timeseries_card(app, key, session)
354
364
355
365
replot = Observable {Nothing} (nothing )
356
366
367
+ # create queue for async plot updates
368
+ plotqueue = _plot_queue (key)
369
+
357
370
# store the idxs for which the autolmits where last set
358
371
last_autolimits = Ref ((eltype (valid_idxs)(), tsplot. rel[]))
359
372
# plot the thing
360
373
onany (data, replot; update= true ) do _dat, _
361
- task = @async begin
374
+ task = @task begin
375
+ @debug " $key : Launch plot for valid_idxs[]"
362
376
try
363
377
empty! (ax)
364
378
vlines! (ax. scene, app. t; color= :black )
365
379
for (idx, y) in zip (valid_idxs[], data[])
366
380
color = begin
367
- key = idx isa VIndex ? VIndex (idx. compidx) : EIndex (idx. compidx)
368
- getcycled (COLORS, color_cache[key ])
381
+ idxkey = idx isa VIndex ? VIndex (idx. compidx) : EIndex (idx. compidx)
382
+ getcycled (COLORS, color_cache[idxkey ])
369
383
end
370
384
linestyle = getcycled (LINESTYLES, linestyle_cache[idx. subidx])
371
385
lines! (ax. scene, ts[], y; label= string (idx), color, linestyle)
372
386
# scatterlines!(ax, ts[], y; label=string(idx), color, linestyle)
373
387
end
374
- # if last_autolimits[][1] != valid_idxs[] || last_autolimits[][2] != tsplot.rel[]
375
388
if last_autolimits[] != (valid_idxs[], tsplot. rel[])
376
389
autolimits! (ax)
377
390
xlims! (ax, (app. tmin[], app. tmax[]))
378
391
last_autolimits[] = (copy (valid_idxs[]), tsplot. rel[])
379
392
end
380
393
catch e
381
- @error " Plotting failed" e
394
+ @error " $key : Plotting failed for idx $(valid_idxs[]) " e
382
395
end
383
396
end
384
- push! (app . _plotqueue , task)
397
+ put! (plotqueue , task)
385
398
nothing
386
399
end |> track_obsf
387
400
@@ -432,8 +445,31 @@ function timeseries_card(app, key, session)
432
445
id= key
433
446
)
434
447
435
- return card, obsf
448
+ return (card, observerfunctions= obsf, plotqueue)
449
+ end
450
+ function _plot_queue (key)
451
+ ch = Channel {Task} (Inf ; spawn= true ) do ch
452
+ while isopen (ch)
453
+ t = try
454
+ fetch (ch)
455
+ catch e
456
+ if ! e isa InvalidStateException && e. msg == " Channel is closed."
457
+ @error " $key : Error while waiting for Task: $e "
458
+ end
459
+ break
460
+ end
461
+ try
462
+ wait (schedule (t))
463
+ catch e
464
+ @warn " $key : Error in task: $e "
465
+ end
466
+ rmt = take! (ch) # remove the executed task
467
+ @assert istaskdone (rmt)
468
+ end
469
+ @info " Plot queue for $key closed"
470
+ end
436
471
end
472
+
437
473
function closebutton (app, key)
438
474
button = Bonito. Button (" ×" , class= " close-button" )
439
475
on (button. value) do _
0 commit comments