Hi ,
i am quite new to Julia and especially Dash. So maybe there is an easy fix to my problems.
I want to plot a heatmap and then add via callback vlines to the heatmap. That is working quite well.
In another callback i want to be able to change the position of the vlines with a ranged slider. This is not working quite well, since we cant just add a trace to an existing figure. I tried a workaround with using the figure as Input in a callback and then just use addtraces! from the PlotlyJS package. This works, but the updates are quite slow, due the complexity of the origninal heatmap. There is no Dash function for just adding traces to an existing figure without recomputing the whole original figure, right?
Now to my Issue thats not working:
I want to use the slider for the visualisation of the slider values in my heatmap. Therefore i want to be able to zoom into my heatmap to increase the accuracy of my vline position. With the “relayoutData” attribute of my Heatmap i can access the current xlim and ylim positions of my Heatmap. I want to use these to update the “min” and “max” attribute of the ranged slider corresponding to my “zoom” in my Heatmap.
This should work right?
I am currently using Julia 1.5.3:
(@v1.5) pkg> st
Status `~\.julia\environments\v1.5\Project.toml`
[1b08a953] Dash v0.1.3
[1b08a953] DashCoreComponents v1.12.0
[1b08a953] DashHtmlComponents v1.1.1
[7073ff75] IJulia v1.23.0
[f0f68f2c] PlotlyJS v0.14.0
I tried to make an easy example that illustrates my Issue.
Thank you!
using Dash, DashHtmlComponents, DashCoreComponents,PlotlyJS
app = dash(external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"])
xdata= rand(1:10,3)
ydata= rand(1:10,3)
matrix= rand(1:10,3,3)
function vline(xposition,ydata)
scatter(Dict(
:mode => "lines",
:x => fill(xposition,2),
:y => [minimum(ydata),maximum(ydata)],
),
showlegend=false,
marker_line_width = 0.5,
marker_opacity = 0.8,
line_color= "#da0a72b6"
)
end
#Main layout
app.layout = html_div() do
html_div(
children=[
dcc_graph(
id="Hidden-Heatmap",
figure = (
Plot(
heatmap(
Dict(
:type => "heatmap",
:x => xdata,
:y => ydata,
:z => [matrix[i,:] for i in 1:size(matrix)[1]]
),
zmax= 10,
zmin= 0 ,
colorscale= "Viridis"
),
Layout(
uirevision = "zoom"
)
)
),style= Dict(
:display => "none"
)
),
html_div(
children =[
dcc_graph(id="Heatmap",
),
html_div(
id="Slider Div",
dcc_rangeslider(
id = "Ranged Slider",
step = 0.01,
min=0,
max=10,
value=[3,5],
persistence=true ,
allowCross=false,
)
)
]
)
],
className ="twelve columns"
)
end
# Vline into Graph from Hidden Graph figure
callback!(app,
Output("Heatmap","figure"),
Input("Ranged Slider","value"),
State("Hidden-Heatmap","figure")) do value,current_fig
@show length(value)
type = current_fig[:data][1][:type]
zmax = current_fig[:data][1][:zmax]
zmin = current_fig[:data][1][:zmin]
xdata = current_fig[:data][1][:x]
ydata = current_fig[:data][1][:y]
zdata = current_fig[:data][1][:z]
cur_plot = Plot(
heatmap(
Dict(
:type => type,
:x => xdata,
:y => ydata,
:z => zdata
),
zmax = 10,
zmin = 1,
colorscale= "Viridis",
uirevision = "zoom"
),
Layout(uirevision = "zoom"
)
)
for i in 1:length(value)
addtraces!(cur_plot,vline(value[i],ydata))
end
return figure=(cur_plot)
end
# Autosize range of ranged sliders to Zoom of Heatmap
callback!(app,
Output("Ranged Slider","min"),
Output("Ranged Slider","max"),
Input("Heatmap","relayoutData"),
State("Heatmap","figure")) do range,figure
# Set ranges of RangedSliders
## if relayoutData is at default
if (try range[:autosize] catch end !== nothing)
xdata_fig = figure[:data][1][:x]
min = minimum(xdata_fig)
max = maximum(xdata_fig)
return min,max
## changed the zoom
elseif try range[:autosize] catch end === nothing && typeof(range) == (NamedTuple{(Symbol("xaxis.range[0]"), Symbol("xaxis.range[1]"), Symbol("yaxis.range[0]"), Symbol("yaxis.range[1]")),NTuple{4,Float64}})
min = range[1]
max = range[2]
return min,max
## set back to autosize
elseif try range[:autosize] catch end === nothing && typeof(range) == (NamedTuple{(Symbol("xaxis.autorange"), Symbol("yaxis.autorange")),Tuple{Bool,Bool}})
xdata_fig = figure[:data][1][:x]
min = minimum(xdata_fig)
max = maximum(xdata_fig)
return min,max
else
return Dash.no_update(), Dash.no_update()
end
end
run_server(app, "0.0.0.0", debug=true)