Closed
Description
Description of the issue
- I have an app with a callback that uses a dcc.Input (type='number') as Input and recreates the figure property of two dcc.Graphs using the input value as the
facet_row_spacing
argument. - Both graphs use
facet_col
,facet_col_wrap
andfacet_row_spacing
. - The recreation works fine for the facetted scatterplot but not for the facetted heatmap/imshow; that is, the
facet_row_spacing
gets adjusted for the scatterplot but always remains the same (the initial value) for the imshow. - The figure dict gets updated correctly in both cases, as shown in the div under each figure - I know this because the difference between the domain end of the first row and the domain start of the second row is equal to the value specified in the dcc.Input.
- The subplot titles also get moved to their correct (new) position.
- However, if we use the plotly crowbar instead to retrieve the figure dict, the values for yaxis domains show a value that matches the spacing we see on the screen, that is: always the initial facet_row_spacing value for the facetted imshow [this is not shown in the video].
JS code to copy in the console to get the plotly crowbar:
javascript:document.querySelectorAll(".js-plotly-plot").forEach(function(gd){ const txt = document.createElement("textarea"); txt.appendChild(document.createTextNode(JSON.stringify({data: gd.data, layout: gd.layout})));txt.style.position='absolute';txt.style.zIndex=9999; gd.appendChild(txt);})
Screen.Recording.2024-10-11.at.13.56.32.mov
Things I have not tested
- If it happens with
facet_row
+facet_col_spacing
too.
MRE
Python 3.10
plotly==5.24.1
dash==2.18.1
plotlyjs==2.35.2 (according to the modebar)
from dash import Dash, html, dcc, callback, Input, Output
import plotly
import json
# https://community.plotly.com/t/facet-row-and-facet-row-labels-when-using-imshow/85905
print(plotly.__version__)
app = Dash(__name__)
import numpy as np
import plotly.express as px
def generate_fig1(row_spacing):
fig1 = px.imshow(
np.random.uniform(0, 1, size = (18, 28, 28)),
facet_col = 0, facet_col_wrap = 6, facet_row_spacing=row_spacing,
)
return fig1
df=px.data.gapminder().query("continent == 'Americas'")
def generate_fig2(row_spacing):
fig2 = px.line(
df, x="year", y="lifeExp",
facet_col="country", facet_col_wrap=8, facet_row_spacing=row_spacing,
)
return fig2
app.layout=html.Div([
dcc.Input(value=0.3, min=0, max=0.3, step=0.05, id='spacing', type='number'),
dcc.Graph(id='fig1'),
html.H3('fig1'),
html.Div(id='div1'),
dcc.Graph(id='fig2'),
html.H3('fig2'),
html.Div(id='div2'),
])
@callback(
Output('fig1', 'figure'),
Output('div1', 'children'),
Output('fig2', 'figure'),
Output('div2', 'children'),
Input('spacing', 'value'),
)
def update_outputs(spacing):
fig1 = generate_fig1(spacing)
fig2 = generate_fig2(spacing)
text1 = {}
for i in range (1,19):
if i == 1:
i = ""
text1[f'yaxis{i}']= fig1.layout[f'yaxis{i}']['domain']
text2 = {}
for i in range (1,26):
if i == 1:
i = ""
text2[f'yaxis{i}']= fig2.layout[f'yaxis{i}']['domain']
return fig1, str(text1), fig2, str(text2)
if __name__ == "__main__":
app.run_server(debug=True)