Skip to content

Commit 29f5db7

Browse files
committed
resample t accoring to zoom
1 parent fd51c5a commit 29f5db7

File tree

4 files changed

+111
-35
lines changed

4 files changed

+111
-35
lines changed

NetworkDynamicsInspector/assets/app.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,9 @@ html, body {
104104
color: #066f00;
105105
font-weight: bolder;
106106
}
107+
108+
button{
109+
font-size: 12px !important;
110+
font-weight: normal !important;
111+
font-family: sans-serif !important;;
112+
}

NetworkDynamicsInspector/src/NetworkDynamicsInspector.jl

Lines changed: 91 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ function apptheme()
3636
linestyle = [:solid, :dot, :dash, :dashdot, :dashdotdot],
3737
),
3838
Lines = (;
39-
cycle = Cycle([:color, :linestyle], covary=true)
39+
cycle = Cycle([:color, :linestyle], covary=true),
40+
linewidth = 3,
4041
)
4142
)
4243
end
@@ -518,19 +519,22 @@ function timeseries_card(app, key, session)
518519
T=Symbol,
519520
id=gendomid("statesel"))
520521

521-
reset_button = Bonito.Button("Reset Color", style=Styles("margin-left"=>"10px"))
522-
on(reset_button.value) do _
522+
reset_color_button = Bonito.Button("Reset Color", style=Styles("margin-left"=>"10px"))
523+
on(reset_color_button.value) do _
523524
empty!(color_cache)
524525
empty!(linestyle_cache)
525526
notify(tsplot.selcomp)
526527
notify(tsplot.states)
527528
end
528529

530+
reset_axis_button = Bonito.Button("Reset Axis", style=Styles("margin-left"=>"10px"))
531+
529532
rel_toggle = ToggleSwitch(value=tsplot.rel, label="Rel to u0")
530533

531534
comp_state_sel_dom = Grid(
532-
DOM.span("Components"), comp_sel, reset_button,
533-
DOM.span("States"), state_sel, rel_toggle;
535+
DOM.span("Components"), comp_sel,
536+
DOM.div(reset_color_button, reset_axis_button, rel_toggle; style=Styles("grid-row"=>"1/3", "grid-column"=>"3")),
537+
DOM.span("States"), state_sel;
534538
columns = "min-content auto min-content",
535539
align_items = "center",
536540
class = "comp-state-sel-grid"
@@ -548,7 +552,7 @@ function timeseries_card(app, key, session)
548552
####
549553
COLORS = Makie.wong_colors()
550554
LINESTYLES = [:solid, :dot, :dash, :dashdot, :dashdotdot]
551-
LINESTYLES = ["", "", "--", "-⋅-", "-⋅⋅"]
555+
LINESTYLES_STR = ["", "", "--", "-⋅-", "-⋅⋅"]
552556
color_cache = Dict{Union{EIndex{Int,Nothing},VIndex{Int,Nothing}}, Int}()
553557
linestyle_cache = Dict{Symbol,Int}()
554558

@@ -578,7 +582,7 @@ function timeseries_card(app, key, session)
578582
i = _smallest_free(linestyle_cache)
579583
linestyle_cache[new] = i
580584
end
581-
lstylepairs[] = [(; title=repr(s), linestyle=getcycled(LINESTYLES, i))
585+
lstylepairs[] = [(; title=repr(s), linestyle=getcycled(LINESTYLES_STR, i))
582586
for (s,i) in linestyle_cache]
583587
nothing
584588
end
@@ -606,7 +610,7 @@ function timeseries_card(app, key, session)
606610
styleContent += `#$(comp_ms_id) +span li[title='${title}']::after {
607611
content: 'xx';
608612
display: inline-block;
609-
padding: 0px 4px;
613+
padding: 0px 1px;
610614
background-color: ${color} !important;
611615
color: ${color} !important;
612616
border-left: 1px solid #aaa;
@@ -644,7 +648,7 @@ function timeseries_card(app, key, session)
644648
styleContent += `#$(state_ms_id) +span li[title='${title}']::after {
645649
content: '${linestyle}';
646650
display: inline-block;
647-
padding: 0px 4px;
651+
padding: 0px 1px;
648652
color: inherit;
649653
border-left: 1px solid #aaa;
650654
font-size: smaller;
@@ -676,27 +680,18 @@ function timeseries_card(app, key, session)
676680
nothing
677681
end
678682

679-
ts = Observable(range(app.sol[].t[begin], app.sol[].t[end], length=1000))
680-
# last update of ts range
681-
lastupdate = Ref(time())
682-
on(ax.finallimits) do lims
683-
lastupdate[] = time()
683+
ts = Observable(collect(range(app.sol[].t[begin], app.sol[].t[end], length=1000)))
684+
refined_xlims = Ref((NaN, NaN))
685+
onany_delayed(ax.finallimits; delay=0.5) do axlims
686+
sollims = (app.sol[].t[begin], app.sol[].t[end])
687+
xlims = (axlims.origin[1], axlims.origin[1] + axlims.widths[1])
688+
if xlims != refined_xlims[]
689+
refined_xlims[] = xlims
690+
refine_time_limits!(ts[], sollims, xlims)
691+
notify(ts)
692+
end
684693
nothing
685694
end
686-
# every 0.5 seconds trigger resampling
687-
# timer = Timer(.5; interval=.5) do _
688-
# if time() > lastupdate[] + 0.5
689-
# lims = ax.finallimits[]
690-
# tmin = max(app.sol[].t[begin], lims.origin[1])
691-
# tmax = min(app.sol[].t[end], tmin + lims.widths[1])
692-
# ts[] = range(tmin, tmax, length=1000)
693-
# lastupdate[] = Inf
694-
# end
695-
# end
696-
# on(session.on_close) do _
697-
# @info "Session closed, time to clean up"
698-
# # close(timer)
699-
# end
700695

701696
# collect all the states wie might want to plot
702697
valid_idxs = Observable(
@@ -731,19 +726,29 @@ function timeseries_card(app, key, session)
731726
notify(data)
732727
end
733728

729+
replot = Observable{Nothing}(nothing)
730+
731+
# store the idxs for which the autolmits where last set
732+
last_autolimits = Ref((eltype(valid_idxs)(), tsplot.rel[]))
734733
# plot the thing
735-
on(data; update=true) do _dat
734+
onany(data, replot) do _dat, _
736735
@async begin
737736
try
738737
empty!(ax)
739-
vlines!(ax, app.t; color=:black)
738+
vlines!(ax.scene, app.t; color=:black)
740739
for (idx, y) in zip(valid_idxs[], data[])
741740
color = begin
742741
key = idx isa VIndex ? VIndex(idx.compidx) : EIndex(idx.compidx)
743-
Cycled(color_cache[key])
742+
getcycled(COLORS, color_cache[key])
744743
end
745-
linestyle = Cycled(linestyle_cache[idx.subidx])
746-
lines!(ax, ts[], y; label=string(idx), color, linestyle)
744+
linestyle = getcycled(LINESTYLES, linestyle_cache[idx.subidx])
745+
lines!(ax.scene, ts[], y; label=string(idx), color, linestyle)
746+
# scatterlines!(ax, ts[], y; label=string(idx), color, linestyle)
747+
end
748+
# if last_autolimits[][1] != valid_idxs[] || last_autolimits[][2] != tsplot.rel[]
749+
if last_autolimits[] != (valid_idxs[], tsplot.rel[])
750+
autolimits!(ax)
751+
last_autolimits[] = (copy(valid_idxs[]), tsplot.rel[])
747752
end
748753
catch e
749754
@error "Plotting failed" e
@@ -752,6 +757,10 @@ function timeseries_card(app, key, session)
752757
nothing
753758
end
754759

760+
on(reset_axis_button.value) do _
761+
autolimits!(ax)
762+
end
763+
755764
####
756765
#### Click interaction to set time
757766
####
@@ -780,8 +789,20 @@ function timeseries_card(app, key, session)
780789
class=cardclass
781790
)
782791

792+
793+
# trigger plot on document ready
794+
jqdocument = Bonito.JSString(raw"$(document)")
795+
trigger_plot = js"""
796+
$(jqdocument).ready(function(){
797+
console.log("Document ready, trigger plot");
798+
// $(data).notify();
799+
$(replot).notify();
800+
});
801+
"""
802+
Bonito.evaljs(session, trigger_plot)
803+
783804
# on click set active-tseries class
784-
click = js"""
805+
onload_js = js"""
785806
(card) => {
786807
card.addEventListener("click", function(event) {
787808
$(app.active_tsplot).notify($(key));
@@ -795,11 +816,46 @@ function timeseries_card(app, key, session)
795816
}, { capture: true });
796817
}
797818
"""
798-
Bonito.onload(session, card, click)
819+
Bonito.onload(session, card, onload_js)
799820

800821
return card
801822
end
802823

824+
function refine_time_limits!(ts, sollims, axlims)
825+
FOCUS = 900
826+
UNFOCUS = 100
827+
if length(ts) !== FOCUS + UNFOCUS
828+
@warn "Resize ts, lenght $(length(ts)) != $(FOCUS + UNFOCUS)"
829+
resize!(ts, FOCUS + UNFOCUS)
830+
end
831+
# never plot outside of solution
832+
axlims = (max(axlims[1], sollims[1]), min(axlims[2], sollims[2]))
833+
834+
axrange = range(axlims[1], axlims[2], length=FOCUS)
835+
outer_low = max(0, axlims[1] - sollims[1])
836+
outer_high = max(0, sollims[2] - axlims[2])
837+
838+
if outer_low == 0
839+
high_range = range(sollims[2], axlims[2], length=UNFOCUS+1)[2:end]
840+
ts[1:FOCUS] .= axrange
841+
ts[FOCUS+1:end] .= high_range
842+
elseif outer_high == 0
843+
low_range = range(axlims[1], sollims[1], length=UNFOCUS+1)[1:end-1]
844+
ts[1:UNFOCUS] .= low_range
845+
ts[UNFOCUS+1:end] .= axrange
846+
else
847+
N_LOW = round(Int, outer_low/(outer_low + outer_high) *UNFOCUS)
848+
N_HIGH = UNFOCUS - N_LOW
849+
low_range = range(sollims[1], axlims[1], length=N_LOW+1)[1:end-1]
850+
high_range = range(axlims[2], sollims[2], length=N_HIGH+1)[2:end]
851+
ts[1:N_LOW] .= low_range
852+
ts[N_LOW+1:N_LOW+FOCUS] .= axrange
853+
ts[N_LOW+FOCUS+1:end] .= high_range
854+
end
855+
# ts .= range(axlims[1], axlims[2], length=1000)
856+
nothing
857+
end
858+
803859
function _sidx_to_str(s, app)
804860
if s isa VIndex
805861
"v$(s.compidx)"

NetworkDynamicsInspector/src/utils.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,16 @@ function onany_throttled(f, obs...; update=false, delay)
109109
tr(args...)
110110
end
111111
end
112+
113+
function onany_delayed(f, obs...; delay)
114+
future = nothing
115+
116+
onany(obs...) do args...
117+
if !isnothing(future)
118+
close(future)
119+
end
120+
future = Timer(delay) do _
121+
f(args...)
122+
end
123+
end
124+
end

NetworkDynamicsInspector/src/widgets.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,7 @@ function Bonito.jsrender(session::Session, toggle::ToggleSwitch)
586586
"position" => "relative",
587587
"display" => "inline-block",
588588
"cursor" => "pointer",
589+
"margin" => "0.25rem",
589590
)
590591

591592
input_style = Styles(

0 commit comments

Comments
 (0)