diff --git a/KomaMRIPlots/src/ui/DisplayFunctions.jl b/KomaMRIPlots/src/ui/DisplayFunctions.jl index 03da8c9ba..8287ea978 100644 --- a/KomaMRIPlots/src/ui/DisplayFunctions.jl +++ b/KomaMRIPlots/src/ui/DisplayFunctions.jl @@ -1022,27 +1022,19 @@ julia> plot_phantom_map(obj2D, :ρ) julia> plot_phantom_map(obj3D, :ρ) ``` """ -function plot_phantom_map(obj::Phantom, key::Symbol; kwargs...) - plot_phantom_map(obj, key, obj.motion; kwargs...) -end - -# Plot dynamic phantom (For now, we define two different methods for static and dynamic phantoms) function plot_phantom_map( obj::Phantom, - key::Symbol, - m::MotionList; + key::Symbol; height=700, width=nothing, darkmode=false, view_2d=sum(KomaMRIBase.get_dims(obj)) < 3, colorbar=true, - max_spins=100_000, + max_spins=20_000, intermediate_time_samples=0, max_time_samples=100, - frame_duration_ms=250, kwargs..., ) - function interpolate_times(motion) t = times(motion) if length(t)>1 @@ -1080,27 +1072,37 @@ function plot_phantom_map( unit = " ms" if key == :T1 cmax_key = 2500 / factor - colors = MAT.matread(path * "/assets/T1cm.mat")["T1colormap"] + colors = MAT.matread(path * "/assets/T1cm.mat")["T1colormap"][1:70:end, :] N, _ = size(colors) idx = range(0, 1; length=N) #range(0,T,N) works in Julia 1.7 colormap = [ - [ + ( idx[n], - "rgb($(floor(Int,colors[n,1]*255)),$(floor(Int,colors[n,2]*255)),$(floor(Int,colors[n,3]*255)))", - ] for n in 1:N + string("rgb(", + floor(Int, colors[n,1] * 255), ",", + floor(Int, colors[n,2] * 255), ",", + floor(Int, colors[n,3] * 255), ")" + ) + ) + for n in 1:N ] elseif key == :T2 || key == :T2s if key == :T2 cmax_key = 250 / factor end - colors = MAT.matread(path * "/assets/T2cm.mat")["T2colormap"] + colors = MAT.matread(path * "/assets/T2cm.mat")["T2colormap"][1:70:end, :] N, _ = size(colors) idx = range(0, 1; length=N) #range(0,T,N) works in Julia 1.7 colormap = [ - [ + ( idx[n], - "rgb($(floor(Int,colors[n,1]*255)),$(floor(Int,colors[n,2]*255)),$(floor(Int,colors[n,3]*255)))", - ] for n in 1:N + string("rgb(", + floor(Int, colors[n,1] * 255), ",", + floor(Int, colors[n,2] * 255), ",", + floor(Int, colors[n,3] * 255), ")" + ) + ) + for n in 1:N ] end elseif key == :x || key == :y || key == :z @@ -1126,191 +1128,77 @@ function plot_phantom_map( x0 = -maximum(abs.([x y z])) * 1e2 xf = maximum(abs.([x y z])) * 1e2 - if view_2d - trace = [ - scatter(; - x=(x[:, 1]) * 1e2, - y=(y[:, 1]) * 1e2, - mode="markers", - marker=attr(; - color=getproperty(obj, key) * factor, - showscale=colorbar, - colorscale=colormap, - colorbar=attr(; ticksuffix=unit, title=string(key)), - cmin=cmin_key, - cmax=cmax_key, - size=4, - ), - showlegend=false, - text=round.(getproperty(obj, key) * factor, digits=4), - hovertemplate="x: %{x:.1f} cm
y: %{y:.1f} cm
$(string(key)): %{text}$unit", - ), - ] - frames = PlotlyFrame[ - frame(; - data=[ - attr(; - x=(x[:, i]) * 1e2, - y=(y[:, i]) * 1e2, - z=(z[:, i]) * 1e2, - zmin=0, - zmax=1, - ), - ], - name="frame_$i", - traces=[0], - ) for i in 1:length(t) - ] - else - trace = [ - scatter3d(; - x=(x[:, 1]) * 1e2, - y=(y[:, 1]) * 1e2, - z=(z[:, 1]) * 1e2, - mode="markers", - marker=attr(; - color=getproperty(obj, key) * factor, - showscale=colorbar, - colorscale=colormap, - colorbar=attr(; ticksuffix=unit, title=string(key)), - cmin=cmin_key, - cmax=cmax_key, - size=2, - ), - showlegend=false, - text=round.(getproperty(obj, key) * factor, digits=4), - hovertemplate="x: %{x:.1f} cm
y: %{y:.1f} cm
z: %{z:.1f} cm
$(string(key)): %{text}$unit", - ), - ] - frames = PlotlyFrame[ - frame(; - data=[ - attr(; - x=(x[:, i]) * 1e2, - y=(y[:, i]) * 1e2, - z=(z[:, i]) * 1e2, - zmin=0, - zmax=1, - ), - ], - name="frame_$i", - traces=[0], - ) for i in 1:length(t) - ] - end + traces = GenericTrace[] - sliders_attr = [ - attr(; - visible=length(t) > 1, - pad=attr(; b=10, t=60), - len=0.85, - x=0.15, - y=0.1, - t=0, - steps=[ - attr(; - label=round(t0; digits=2), - method="animate", - args=[ - ["frame_$i"], - attr(; - visible=[fill(false, i - 1); true; fill(false, length(t) - i)], - mode="immediate", - transition=attr(; duration=0), - frame=attr(; duration=5, redraw=true), - ), - ], - ) for (i, t0) in enumerate(t) - ], - currentvalue=attr(; - prefix="t = ", - suffix=" s", - xanchor="right", - font=attr(; color="#888", size=20), - ), - ), - ] - - buttons_attr = [ - attr(; - label="▶", # play symbol - method="animate", - args=[ - nothing, - attr(; - fromcurrent=true, - transition=(duration=frame_duration_ms,), - frame=attr(; duration=frame_duration_ms, redraw=true), - ), - ], - ), - attr(; - label="◼", # pause symbol - method="animate", - args=[ - [nothing], - attr(; - mode="immediate", - fromcurrent=true, - transition=attr(; duration=frame_duration_ms), - frame=attr(; duration=frame_duration_ms, redraw=true), - ), - ], - ), - ] + bgcolor, text_color, plot_bgcolor, grid_color, sep_color = theme_chooser(darkmode) - #Layout - bgcolor, text_color, plot_bgcolor, grid_color, sep_color = theme_chooser(darkmode) - l = Layout(; - title=obj.name * ": " * string(key), - xaxis_title="x", - yaxis_title="y", - xaxis_range=[x0, xf], - yaxis_range=[x0, xf], - xaxis_ticksuffix=" cm", - yaxis_ticksuffix=" cm", - plot_bgcolor=plot_bgcolor, - paper_bgcolor=bgcolor, - xaxis_gridcolor=grid_color, - yaxis_gridcolor=grid_color, - xaxis_zerolinecolor=grid_color, - yaxis_zerolinecolor=grid_color, - font_color=text_color, - updatemenus=[ - attr(; - visible=length(t) > 1, - x=0.1, - y=0.05, - yanchor="top", - xanchor="center", - showactive=true, - direction="left", - type="buttons", - pad=attr(; r=10, t=70), - buttons=buttons_attr, - ), - ], - sliders=sliders_attr, - scene=attr(; - xaxis=attr(; + l = Layout(;title=obj.name*": "*string(key)) + + if view_2d # 2D + # Layout config + l[:xaxis] = attr( + title="x", + range=[x0, xf], + ticksuffix=" cm", + backgroundcolor=plot_bgcolor, + gridcolor=grid_color, + zerolinecolor=grid_color, + scaleanchor="y" + ) + l[:yaxis] = attr( + title="y", + range=[x0, xf], + ticksuffix=" cm", + backgroundcolor=plot_bgcolor, + gridcolor=grid_color, + zerolinecolor=grid_color, + scaleratio=1 + ) + l[:autosize] = true + # Add traces + for i in 1:length(t) + push!(traces, scattergl( + x=(x[:,i])*1e2, + y=(y[:,i])*1e2, + mode="markers", + marker=attr(color=getproperty(obj,key)*factor, + showscale=colorbar, + colorscale=colormap, + colorbar=attr(ticksuffix=unit, title=string(key)), + cmin=cmin_key, + cmax=cmax_key, + size=4 + ), + visible=i==1, + showlegend=false, + text=round.(getproperty(obj,key)*factor,digits=4), + hovertemplate="x: %{x:.1f} cm
y: %{y:.1f} cm
$(string(key)): %{text}$unit")) + end + else # 3D + # Layout config + l[:scene] = attr( + xaxis=attr( title="x", range=[x0, xf], + fixedrange=true, ticksuffix=" cm", backgroundcolor=plot_bgcolor, gridcolor=grid_color, zerolinecolor=grid_color, ), - yaxis=attr(; + yaxis=attr( title="y", range=[x0, xf], + fixedrange=true, ticksuffix=" cm", backgroundcolor=plot_bgcolor, gridcolor=grid_color, zerolinecolor=grid_color, ), - zaxis=attr(; + zaxis=attr( title="z", range=[x0, xf], + fixedrange=true, ticksuffix=" cm", backgroundcolor=plot_bgcolor, gridcolor=grid_color, @@ -1318,163 +1206,64 @@ function plot_phantom_map( ), aspectmode="manual", aspectratio=attr(; x=1, y=1, z=1), - ), - margin=attr(; t=50, l=0, r=0, b=0), - modebar=attr(; - orientation="h", bgcolor=bgcolor, color=text_color, activecolor=plot_bgcolor - ), - xaxis=attr(; constrain="domain"), - yaxis=attr(; scaleanchor="x"), - hovermode="closest", - ) - - if height !== nothing - l.height = height - end - if width !== nothing - l.width = width - end - - return Plot(trace, l, frames) -end - -# Plot static phantom (For now, we define two different methods for static and dynamic phantoms) -function plot_phantom_map( - obj::Phantom, - key::Symbol, - m::NoMotion; - height=700, - width=nothing, - darkmode=false, - view_2d=sum(KomaMRIBase.get_dims(obj)) < 3, - colorbar=true, - max_spins=100_000, - kwargs..., -) - function decimate_uniform_phantom(obj, num_points::Int) - ss = Int(ceil(length(obj) / num_points)) - return obj[1:ss:end] - end - - if length(obj) > max_spins - obj = decimate_uniform_phantom(obj, max_spins) - @warn "For performance reasons, the number of displayed spins was capped to `max_spins`=$(max_spins)." + ) + # Add traces + for i in 1:length(t) + push!(traces, scatter3d( + x=(x[:,i])*1e2, + y=(y[:,i])*1e2, + z=(z[:,i])*1e2, + mode="markers", + marker=attr(color=getproperty(obj,key)*factor, + showscale=colorbar, + colorscale=colormap, + colorbar=attr(ticksuffix=unit, title=string(key)), + cmin=cmin_key, + cmax=cmax_key, + size=2 + ), + visible=i==1, + showlegend=false, + text=round.(getproperty(obj,key)*factor,digits=4), + hovertemplate="x: %{x:.1f} cm
y: %{y:.1f} cm
z: %{z:.1f} cm
$(string(key)): %{text}$unit")) + end end - path = @__DIR__ - cmin_key = minimum(getproperty(obj,key)) - cmax_key = maximum(getproperty(obj,key)) - if key == :T1 || key == :T2 || key == :T2s - cmin_key = 0 - factor = 1e3 - unit = " ms" - if key == :T1 - cmax_key = 2500/factor - colors = MAT.matread(path*"/assets/T1cm.mat")["T1colormap"] - N, _ = size(colors) - idx = range(0,1;length=N) #range(0,T,N) works in Julia 1.7 - colormap = [[idx[n], "rgb($(floor(Int,colors[n,1]*255)),$(floor(Int,colors[n,2]*255)),$(floor(Int,colors[n,3]*255)))"] for n=1:N] - elseif key == :T2 || key == :T2s - if key == :T2 - cmax_key = 250/factor - end - colors = MAT.matread(path*"/assets/T2cm.mat")["T2colormap"] - N, _ = size(colors) - idx = range(0,1;length=N) #range(0,T,N) works in Julia 1.7 - colormap = [[idx[n], "rgb($(floor(Int,colors[n,1]*255)),$(floor(Int,colors[n,2]*255)),$(floor(Int,colors[n,3]*255)))"] for n=1:N] - end - elseif key == :x || key == :y || key == :z - factor = 1e2 - unit = " cm" - colormap="Greys" - elseif key == :Δw - factor = 1/(2π) - unit = " Hz" - colormap="Greys" - else - factor = 1 - cmin_key = 0 - unit="" - colormap="Greys" - end - cmin_key = get(kwargs, :cmin, factor * cmin_key) - cmax_key = get(kwargs, :cmax, factor * cmax_key) - x0 = -maximum(abs.([obj.x obj.y obj.z]))*1e2 - xf = maximum(abs.([obj.x obj.y obj.z]))*1e2 - #Layout - bgcolor, text_color, plot_bgcolor, grid_color, sep_color = theme_chooser(darkmode) - l = Layout(; - title=obj.name*": "*string(key), - xaxis_title="x", - yaxis_title="y", - plot_bgcolor=plot_bgcolor, - paper_bgcolor=bgcolor, - xaxis_gridcolor=grid_color, - yaxis_gridcolor=grid_color, - xaxis_zerolinecolor=grid_color, - yaxis_zerolinecolor=grid_color, - font_color=text_color, - scene=attr( - xaxis=attr(title="x",range=[x0,xf],ticksuffix=" cm",backgroundcolor=plot_bgcolor,gridcolor=grid_color,zerolinecolor=grid_color), - yaxis=attr(title="y",range=[x0,xf],ticksuffix=" cm",backgroundcolor=plot_bgcolor,gridcolor=grid_color,zerolinecolor=grid_color), - zaxis=attr(title="z",range=[x0,xf],ticksuffix=" cm",backgroundcolor=plot_bgcolor,gridcolor=grid_color,zerolinecolor=grid_color), - aspectmode="manual", - aspectratio=attr(x=1,y=1,z=1)), - margin=attr(t=50,l=0,r=0), - modebar=attr(orientation="h",bgcolor=bgcolor,color=text_color,activecolor=plot_bgcolor), - xaxis=attr(constrain="domain"), - yaxis=attr(scaleanchor="x"), - hovermode="closest") - if height !== nothing - l.height = height + # Config the rest of the layout + l[:paper_bgcolor] = bgcolor + l[:plot_bgcolor] = plot_bgcolor + l[:font_color] = text_color + l[:sliders] = [attr( + visible=length(t) > 1, + pad=attr(l=30, b=30), + steps=[ + attr( + label=round(t0*1e3), + method="update", + args=[attr(visible=[fill(false, i-1); true; fill(false, length(t) - i)])] + ) + for (i, t0) in enumerate(t) + ], + currentvalue_prefix="x = ", + currentvalue_suffix="ms", + )] + l[:margin] = attr(t=50, l=0, r=0) + l[:modebar] = attr(orientation="h", bgcolor=bgcolor, color=text_color, activecolor=plot_bgcolor) + + if height !== nothing + l.height = height end if width !== nothing l.width = width end - if view_2d - h = scattergl( - x=obj.x*1e2, - y=obj.y*1e2, - mode="markers", - marker=attr( - color=getproperty(obj,key)*factor, - showscale=colorbar, - colorscale=colormap, - colorbar=attr(ticksuffix=unit, title=string(key)), - cmin=cmin_key, - cmax=cmax_key, - size=4 - ), - text=round.(getproperty(obj,key)*factor,digits=4), - hovertemplate="x: %{x:.1f} cm
y: %{y:.1f} cm
$(string(key)): %{text}$unit" - ) - else - h = scatter3d( - x=obj.x*1e2, - y=obj.y*1e2, - z=obj.z*1e2, - mode="markers", - marker=attr( - color=getproperty(obj,key)*factor, - showscale=colorbar, - colorscale=colormap, - colorbar=attr(ticksuffix=unit, title=string(key)), - cmin=cmin_key, - cmax=cmax_key, - size=2 - ), - text=round.(getproperty(obj,key)*factor,digits=4), - hovertemplate="x: %{x:.1f} cm
y: %{y:.1f} cm
z: %{z:.1f} cm
$(string(key)): %{text}$unit" - ) - end config = PlotConfig( displaylogo=false, toImageButtonOptions=attr( format="svg", # one of png, svg, jpeg, webp ).fields, - modeBarButtonsToRemove=["zoom", "pan", "tableRotation", "resetCameraLastSave3d", "orbitRotation", "resetCameraDefault3d"] + modeBarButtonsToRemove=["zoom", "pan", "resetCameraLastSave3d", "orbitRotation", "resetCameraDefault3d"] ) - return plot_koma(h, l; config) + return plot_koma(traces, l; config) end diff --git a/src/KomaUI.jl b/src/KomaUI.jl index 9c31463b1..72ec17e29 100644 --- a/src/KomaUI.jl +++ b/src/KomaUI.jl @@ -290,10 +290,10 @@ function KomaUI(; darkmode=true, frame=true, phantom_mode="2D", sim=Dict{String, on((img) -> view_ui!(img, w; type="absi", darkmode), img_ui) # Update Koma versions to tooltip - version_ui = pkgversion(@__MODULE__) - version_core = pkgversion(KomaMRICore) - version_io = pkgversion(KomaMRIFiles) - version_plots = pkgversion(KomaMRIPlots) + version_ui = string(pkgversion(@__MODULE__)) + version_core = string(pkgversion(KomaMRICore)) + version_io = string(pkgversion(KomaMRIFiles)) + version_plots = string(pkgversion(KomaMRIPlots)) @js_ w ( @var version_ui = $(version_ui); @var version_core = $(version_core);