dash-core-components
dash-core-components copied to clipboard
Dash objects reset their height to 450px after changing tabs
This problem started after I upgraded to dash 1.19.0 (possibly a dash-core-components 1.15.0 issue??)
I have an app with multiple tabs, with dash components on them like charts and indicators. I set the component heights using update_layout. When I first load the page, everything looks fine. But when I click on a different tab, and then go back to the previous tab, all the dash charts and indicators change their height to 450px. The indicators are set in my code to be 200px, and when they snap to 450px after changing tabs, the indicators components themselves stretch outside of their containing DIVs.
Can confirm this was not an issue in Dash 1.16 and was recently introduced.
As well as getting this on a backlog for a fix in future release, I'm also interested if anyone has a clever workaround to prevent this right now while using the current dash version.
Thanks, Nathan
Thanks for the report @gtg489p - can you make a self-contained example app that shows the problem? There are a number of ways to set sizes so it's important that we're talking about the same thing.
I can try for a full fledged example when time allows, but for the time being - to address your specific concern, here is how I set the height of the figures in my python code
fig.update_layout(height=200)
It is set once at initialization, and no callbacks ever touch it again.
Thanks, Nathan
Here is a small app that shows the problem. It's a new issue in 1.19.0. It works fine in 1.18.1
import dash
import dash_html_components as html
import dash_core_components as dcc
import plotly.express as px
import pandas as pd
external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
df = pd.DataFrame(
{
"Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"],
"Amount": [4, 1, 2, 2, 4, 5],
"City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"],
}
)
fig = px.bar(df, x="Fruit", y="Amount", color="City", barmode="group")
fig.update_layout(height=200)
tab1 = html.Div([html.H3("Tab content 1"), dcc.Graph(id="example-graph1", figure=fig)])
tab2 = html.Div([html.H3("Tab content 2"), dcc.Graph(id="example-graph2", figure=fig)])
app.layout = html.Div(
[
dcc.Tabs(
id="tabs",
value="tab-1",
children=[
dcc.Tab(label="Tab one", value="tab-1", children=tab1),
dcc.Tab(label="Tab two", value="tab-2", children=tab2),
],
),
]
)
if __name__ == "__main__":
app.run_server(debug=True)

Thanks @gtg489p and @AnnMarieW - moved to dcc as that's ultimately where the problem is. This is probably a result of https://github.com/plotly/dash-core-components/pull/905
Hey @gtg489p
A workaround is to add the height in the style parameter of dcc.Graph: This works with 1.19.0
tab1 = html.Div(
[
html.H3("Tab content 1"),
dcc.Graph(id="example-graph1", figure=fig, style={"height": 200})
]
)
Thanks @AnnMarieW , I'll see to using that in the mean time (changed 200 to "200px")
Off topic, but how did you create that gif illustrating the bug? I know there are gif maker programs out there but just wondering if there's a commonly accepted way. Thanks
@gtg489p Happy to help :-)
I'm not sure about the commonly accepted way to make a gif, but on Linux I use Peek and on Windows I used ScreenToGif. Both are pretty simple, which makes them easy to use.
Any other workaround on this? Setting the height in the dcc.Graph does not work for me as I want to have different dcc.Graph and figure heights (and using 'overflowY': 'scroll').
@ann-marie-ward thanks for this workaround. It works for me but is clunky to have to specify the height by style when my dcc.Graph objects (a plotly Table and a line_mapbox) already specify height via their height parameters.
In my case, my two tabs initially render correctly, click to the second one, good. Click back to the first, and the height changes to 450px. This is using 1.21. If I add your style parameter to both dcc.Graph objects, it works correctly.
Experiencing the same problem as ppfreitas. Having another workaround/fix would be nice!
Same problem here! The workaround works well though, thanks @AnnMarieW . But a fix would be good since now I am styling both the figure and graph in two places, when one should be enough
Is this issue solved in Dash 2.x?
No, it's still not solved
This issue happened when I changed one tab (showing a heatmap with default aspect ratio) to another tab (showing a bar chart). I tried the style parameter workaround as suggested:
Hey @gtg489p
A workaround is to add the height in the style parameter of dcc.Graph: This works with 1.19.0
tab1 = html.Div( [ html.H3("Tab content 1"), dcc.Graph(id="example-graph1", figure=fig, style={"height": 200}) ] )
but still to no avail. I noticed that this issue only happens when I changed tabs from the heatmap tab, and the tab with issue is the subsequent tab from heatmap tab (where I am using px.imshow.
So I added the aspect='auto' parameter in px.imshow so that it follows the size of plot area. Now it works fine.
I am using:
- python=3.10.5
- dash=2.6.1
- dash-bootstrap-components=1.2.1
Experiencing same bug. Switching tabs resets height of Dropdown options container, previously set by maxHeight argument.

I'm still having this issue as my charts are dynamic heights based on internal variables.
Here's a way to solve it. I used @AnnMarieW 's code for this example. Just added a Callback that uses the dcc.Tabs value as input to set the size of the graph everytime you switch tabs. It uses the current state of both graphs to transform it into a go.Figure (from plotly.graph_objects) and sets the layout's height you need.
It just causes a little blink in the chart and you can see how it changes sizes, but is only just a microsecond, so, if it's not a major problem for you, it works :)
https://user-images.githubusercontent.com/37990054/202556541-b132e93d-29d7-419b-8eff-2d950d8226b2.mp4
import dash
import dash_html_components as html
import dash_core_components as dcc
import plotly.express as px
import pandas as pd
from dash import Input, Output, State, ctx
from dash.exceptions import PreventUpdate
import plotly.graph_objects as go
external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
df = pd.DataFrame(
{
"Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"],
"Amount": [4, 1, 2, 2, 4, 5],
"City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"],
}
)
fig = px.bar(df, x="Fruit", y="Amount", color="City", barmode="group")
fig.update_layout(height=200)
tab1 = html.Div([html.H3("Tab content 1"), dcc.Graph(id="example-graph1", figure=fig)])
tab2 = html.Div([html.H3("Tab content 2"), dcc.Graph(id="example-graph2", figure=fig)])
app.layout = html.Div(
[
dcc.Tabs(
id="tabs",
value="tab-1",
children=[
dcc.Tab(label="Tab one", value="tab-1", children=tab1),
dcc.Tab(label="Tab two", value="tab-2", children=tab2),
],
),
]
)
@app.callback(
[Output('example-graph1','figure'),
Output('example-graph2','figure')],
Input('tabs','value'),
State('example-graph1','figure'),
State('example-graph2','figure')
)
def controlGraphSizes(tabValue, figure1,figure2):
if tabValue == 'tab-1':
print(type(figure1))
newFigure1 = go.Figure(figure1)
newFigure1.update_layout(height=200)
return [newFigure1,dash.no_update]
elif tabValue == 'tab-2':
print(type(figure2))
newFigure2 = go.Figure(figure1)
newFigure2.update_layout(height=200)
return [dash.no_update,newFigure2]
else:
raise PreventUpdate
if __name__ == "__main__":
app.run_server(debug=True)
Here's an example of a clientside callback for faster updating if your graph takes a while to create and specifying the height in style isn't a solution for you. Note that also specifying the height in the dcc.Graph style will likely overwrite the callback output.
The dcc.Tabs components has id='tabs', the dcc.Graph has id='plot' and the dcc.Graph is inside tab 1 with default value='tab-1'. The updated graph will have a height of 450px.
from dash import clientside_callback, Input, Output, State
clientside_callback(
"""
function adjust_height(tab_value, plot) {
if (tab_value === 'tab-1') {
var plot = Object.assign({}, plot);
plot.layout.height = 450;
return plot;
}
return plot;
}
""",
Output('plot', 'figure', allow_duplicate=True),
Input('tabs', 'value'),
State('plot', 'figure'),
prevent_initial_call=True
)
Use allow_duplicate=True in the Output if the dcc.Graph is created through another callback. Otherwise you should be okay to remove it.
The graphs on each of my tabs have a variable height that is calculated based on the len of the df in the callback. The height varies widely depending on the value selected from the dropdown. In this case, setting a fixed height is not an option. I don't think any of the proposed workarounds will work for my case.
Any ideas in this case?
Here's a way to solve it. I used @AnnMarieW 's code for this example. Just added a Callback that uses the dcc.Tabs value as input to set the size of the graph everytime you switch tabs. It uses the current state of both graphs to transform it into a go.Figure (from plotly.graph_objects) and sets the layout's height you need.
It just causes a little blink in the chart and you can see how it changes sizes, but is only just a microsecond, so, if it's not a major problem for you, it works :)
WhatsApp.Video.2022-11-17.at.17.37.49.4.mp4
import dash import dash_html_components as html import dash_core_components as dcc import plotly.express as px import pandas as pd from dash import Input, Output, State, ctx from dash.exceptions import PreventUpdate import plotly.graph_objects as go external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"] app = dash.Dash(__name__, external_stylesheets=external_stylesheets) df = pd.DataFrame( { "Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"], "Amount": [4, 1, 2, 2, 4, 5], "City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"], } ) fig = px.bar(df, x="Fruit", y="Amount", color="City", barmode="group") fig.update_layout(height=200) tab1 = html.Div([html.H3("Tab content 1"), dcc.Graph(id="example-graph1", figure=fig)]) tab2 = html.Div([html.H3("Tab content 2"), dcc.Graph(id="example-graph2", figure=fig)]) app.layout = html.Div( [ dcc.Tabs( id="tabs", value="tab-1", children=[ dcc.Tab(label="Tab one", value="tab-1", children=tab1), dcc.Tab(label="Tab two", value="tab-2", children=tab2), ], ), ] ) @app.callback( [Output('example-graph1','figure'), Output('example-graph2','figure')], Input('tabs','value'), State('example-graph1','figure'), State('example-graph2','figure') ) def controlGraphSizes(tabValue, figure1,figure2): if tabValue == 'tab-1': print(type(figure1)) newFigure1 = go.Figure(figure1) newFigure1.update_layout(height=200) return [newFigure1,dash.no_update] elif tabValue == 'tab-2': print(type(figure2)) newFigure2 = go.Figure(figure1) newFigure2.update_layout(height=200) return [dash.no_update,newFigure2] else: raise PreventUpdate if __name__ == "__main__": app.run_server(debug=True)
In case anyone else is facing the same issue, and to complete a bit this answer, I managed to avoid the blink by having the tab content outside the Tab component, as in this example: https://dash-bootstrap-components.opensource.faculty.ai/examples/graphs-in-tabs/
I have only tried it with dbc.Tabs and not with dcc.Tabs, so I don't know if it'd solve the issue. In any case I think it can be useful.
Cheers