Black Lives Matter. Please consider donating to Black Girls Code today.

Graph at 50% width on page load, goes to 100% when redrawing

Description

I’ve created the dashboard layout using Dash Bootstrap Components, and one Tab is behaving weirdly.

When I open the app for the first time, it looks like this:

And when the window is redrawn (which can be triggered by resizing the browser window, changing the zoom level, or even opening browser’s dev tools) it starts looking like this (which is what I ultimately want it to look):

Any hints on what can be done to have the figure at 100% width on page load?

Code bits

  • layout part defining the graph above:
dbc.Row(dbc.Col(width=12, children=dbc.Card(className="w-100", children=[
    dbc.CardHeader(html.H5("Predefined graphs")),
    dbc.CardBody([
        dcc.Graph(
            id='graph_predefined',
            figure={}
        )
    ]),
])))

I’m seeing the exact same behavior if I remove the Row/Col definitions and keep just the dbc.Card(...). Embedding the dbc.Card() into a html.Div(..., style={'width': '100%'}) doesn’t help either.

  • part of the callback updating the figure:
fig = make_subplots(
    rows=n_rows,
    cols=n_cols,
    shared_xaxes=True,
    shared_yaxes=False,
    vertical_spacing=0.3/n_rows,
    subplot_titles=plot_names,
    specs=[[{"secondary_y": True}, {"secondary_y": True}],
           [{"secondary_y": True}, {"secondary_y": True}]]
)

fig["layout"].update(
    height=header_margin + 250*n_rows + 250*0.3*(n_rows-1),
    autosize=True,
    showlegend=True,
    margin=go.layout.Margin(l=50, r=50, b=50, t=header_margin, pad=50),
    template="plotly_white",
)

Further on I’m only adding traces to the subplots, no layout modifications are performed.

Context

dash                              1.3.0
dash-bootstrap-components         0.7.1
dash-core-components              1.2.0
dash-html-components              1.0.1
dash-renderer                     1.1.0
dash-table                        4.3.0

@dmhv

I’ve had a similar problem and found a workaround on stackoverflow where a clientside callback is triggered with the tab that forces a window resize to make all graphs expand to the desired width.

In the python file:

app.clientside_callback(
    ClientsideFunction(namespace='clientside', function_name='resize'),
    Output('resize_output_clientside', 'children'),
    [Input('view_tabs', 'active_tab'))]
)

In the javascript file:

if (!window.dash_clientside) {
	window.dash_clientside = {};
}
window.dash_clientside.clientside = {
	resize: function(value) {
		setTimeout(function() {
			window.dispatchEvent(new Event('resize'));
		}, 500);
		return null;
	}
};

Of course this is no fix in the long term but hope it helps

1 Like

Thanks for the reply, appreciated!

I’ve found the stackoverflow post, but am having difficulty understanding the javascript file. Where should it be placed, and how do I import it? Or am I supposed to change some existing file in the Dash library?

@dmhv

You have to add a folder named assets to your project. In that folder you can put in external files such as javascript or css files.

Your project structure could look like this:

- app.py
- assets/
    |- some-js-file.js
    |- some-css-file.css
    |- etc....

For more info you could look at this official guide page:
https://dash.plot.ly/external-resources

And here the realease of clientside callbacks:

1 Like

Added the javascript file in the proper place, and it’s being used (checked with another .js script with an alert() inside).

However, I ran into even more weird behavior with it. First time I load the dash app in the browser, the graph is resized on load, but this time it’s actually much larger than the container it’s in. When I reload the page, it doesn’t seem to trigger anymore and the graph is too small.

Any ideas?

@dmhv

I never had that problem.
Is it possible that you could provide a minimal working example of code?

That would make it a lot easier to help

I tried to create a minimal example that reproduces the issue, only it doesn’t reproduce the issue, everything is working as expected.
Maybe it has to do with the fact that the “real” dashboard is served through a somewhat customized Flask server (authentication / authorization scaffolding)… I don’t see any other differences.

If you’re not able to get the stackoverflow solution to work, then you could try dynamically rendering the tab content instead. I.e. write a callback that takes the active_tab property as input, then renders content in a div below the tabs. Here’s an example of that.

The issue is that dbc.Tabs sets display: none on the non-active tabs, so Plotly is unable to figure out the container size, but changing display doesn’t trigger a redraw. There’s some more details on that here and here

1 Like