Skip to content

facet_row_spacing modified in a callback for px.imshow changes the figure dict but not the plot #4794

Description

@celia-lm

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 and facet_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)

Metadata

Metadata

Assignees

Labels

P2considered for next cyclebugsomething brokensev-3annoyance with workaround

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions