JuliaPlots / PlotlyJS.jl

Julia library for plotting with plotly.js
Other
418 stars 77 forks source link

relayout! does not update the layout of a fig created by make_subplots #427

Closed empet closed 2 years ago

empet commented 2 years ago

I tried to plot a a small multiple US map for daily vaccination in each state. I defined it as a subplot of 8 x 11 facets, but added traces only to 51 axes (51 is the number of locations). Unfortunately when I tried to update layout axes, to remove displaying ticklabels, I got finally the plot of a single facet, because relayout! seems to delete the initial
layout settings ("xaxis$k" domain, "yaxis$k" domain, k in vector of Int(s)), except for the facet referenced to xaxis, yaxis To realise what is going on I coded the same example in plotly.py and got this plot https://chart-studio.plotly.com/~empet/16100. Here is a minimal example that imitates the updates I need for US small multiple:

using PlotlyJS

recursive_merge(d::AbstractDict...) = merge(recursive_merge, d...)

#convert a Dict(String, Any) to Dict(Symbol, Any)
f(x) = x
f(d::Dict) = Dict(Symbol(k) => f(v) for (k, v) in d)
symbol_dict(d::Dict) = f(d)
##################
p = make_subplots(rows=3, cols=2)
add_trace!(p, scatter(x=0:2, y=10:12), row=1, col=2)
add_trace!(p, scatter(x=0:2, y=10:12), row=2, col=1)
add_trace!(p, scatter(x=0:2, y=10:12), row=2, col=2)
add_trace!(p, scatter(x=0:2, y=10:12), row=3, col=1)
axisD =[Dict("xaxis$k"=>Dict("showticklabels"=>false),
             "yaxis$k"=>Dict("showticklabels"=>false,
                             "range"=>[9,13])) for k in 2:5]
layt_axes = recursive_merge(axisD...);
relayout!(p, symbol_dict(layt_axes))  # I also tried relayout!(p.plot.layout,  symbol_dict(layt_axes))
p

print(json(p, 2)) illustrates that relayout! doesn't update p.plot.layout, because the domain for each facet is no more displayed in the json version. @sglyon I'd be grateful if you looked at the code and tell me if it's a bug or I'm doing something wrong. Thanks!

empet commented 2 years ago

I realized what was wrong. First I modified the function that converts a Dict{String, Any} to Dict{Symbol Any}:

#convert a Dict(String, Any) to Dict(Symbol, Any)
f(x) = x
f(d::Dict) = Dict{Symbol, Any}(Symbol(k) => f(v) for (k, v) in d)
symbol_dict(d::Dict) = f(d)

Then instead of relayout! I detailed merging the dict fig.plot.layout.fields with my dict that contains updates for axes as follows:

state_axes =  [Dict("xaxis$(us_states[K]["axis"])" => Dict("showticklabels"=>false), 
                     "yaxis$(us_states[K]["axis"])" => Dict("showticklabels"=>false,
                      "range"=>[0, ymax])) for K in keys(us_states) if us_states[K]["axis"] !=1]
push!(state_axes, Dict("xaxis" => Dict("showticklabels"=>false), 
                        "yaxis" => Dict("showticklabels"=>false,
                                        "range"=>[0, ymax])
                       ))

layt_axes = recursive_merge(state_axes...);
new_laytf =symbol_dict(layt_axes)
l=recursive_merge([fig.plot.layout.fields, new_laytf ]...)
update!(fig, layout=Layout(l))