Show and hide graph

Hi,

I try to display my graph only when the dropdown variables have been selected, is there any way to do it?

Welcome @Pierre
Do you have code already written up?

Sure, I show you:

ffn = pd.read_csv("/home/pierre/Documents/FFN/data.csv")
available_indicators = ffn["distance"].unique()
variable_indicators = ["spd_", "freq_", "amplitude_", "tempo_"]
app = dash.Dash()

colors = {
    'background': '#0077c0',
    'text': '#7FDBFF'
}

app.layout = html.Div(
    children=[

    html.Div([

        html.Div([
            html.Label(
                "Distance"),
            ], 
            style={"width": "20%", "display": "table-cell"}
        ),
        html.Div([
            dcc.Dropdown(
                id="distance_choice",
                options=[{"label": i, "value": i} for i in available_indicators],
                placeholder="Select distance"
            ),
        ],
        style={"width" : "40%", "display": "table-cell"}

    )]),

    html.Div([

        html.Div([
            html.Label("Style"),
            ],
            style={"width": "20%", "display": "table-cell"}
            ),
        html.Div([
            dcc.Dropdown(
                id="style_choice",
                placeholder="Select tyle"
            )
        ],
        style={"width": "40%", "display": "table-cell"}
    )]),

    html.Div([

        html.Div([
            html.Label("Variable"),
            ],
            style={"width" : "20%", "display": "table-cell"}
            ),
        html.Div([
            dcc.Dropdown(
                id="variable_choice",
                options=[{"label": i, "value": i} for i in variable_indicators],
                placeholder="Select variable"
                )
        ],
        style={"width": "40%", "display": "table-cell"}),

    ]),

    html.Div([
        dcc.Graph(id="distance_1")
    ], style={"width": "49%", "display": "inline-block", "padding": "0 20"})
])

@app.callback(
    Output('style_choice', 'options'),
    [Input('distance_choice', 'value')]
)
def update_date_dropdown(name):
    return [{'label': i, 'value': i} for i in ffn[ffn["distance"]==name]["style"].unique()]

@app.callback(
    Output("distance_1", "figure"),
    [Input("distance_choice", "value"),
     Input("style_choice", "value"),
     Input("variable_choice", "value")])

def update_graph_1(distance_name, style_name, variable_name):
    df = ffn.loc[(ffn["distance"]==distance_name) & (ffn["style"]==style_name)].dropna(axis="columns")
    tickvals = np.array(range(len([col for col in df if col.startswith(variable_name)])))
    ticktext = [col.split(str("_"))[1] for col in df if col.startswith(variable_name)]
    return {
    "data": [dict(y= df[df[col]>0][col], type= "box", marker=dict(color="#00539b")) for col in df if col.startswith(variable_name)],
    "layout": {"title": "2016", 
               "xaxis": {"title": "Distance (m)", "tickmode": "array", "tickvals": tickvals,"ticktext" : [s.lstrip("0") for s in ticktext]},
               "yaxis": {"title": "Vitesse (m/s)"}, 
               "showlegend": False,
               "plot_bgcolor": colors["background"],
               "paper_bgcolor": colors["background"]}
    }

if __name__ == '__main__':
    app.run_server(debug=True)

Simply I have a boxplot according to the selected variables and I would like the graph to be displayed only when all the variables have been selected.

You have a lot of code so it’s hard for me to figure out why it’s not working without the dataset and testing on my own. And I’m not sure why your graph is not showing anything. I recommend starting small.

What usually helps me is to write code where data from one Dropdown creates one boxplot with the callback. Then, add another Dropdown, then make it more complicated.

That way, it’s also easier to help you. If you have only one Dropdown with one figure output, it would be easier to see where the problem is.

Good luck,

Yes sorry, here’s a reproducible code that works and shows my problem simply.

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import pandas as pd
import numpy as np

app = dash.Dash()

data = {'x': [1, 2, 3, 1, 2, 3], 'y': [4, 1, 2, 6, 1, 4], 'name': ["USA", "USA", "USA", "CAN", "CAN", "CAN"]}
df= pd.DataFrame(data)
variable_indicators = df["name"].unique()

app.layout = html.Div(children=[
    html.H1(children='Hello Dash'),

    html.Div(children='''
        Dash: A web application framework for Python.
    '''),

	dcc.Dropdown(
		id="variable_choice",
		options=[{"label": i, "value": i} for i in variable_indicators]
		),

    dcc.Graph(
        id='example-graph'
    )
])

@app.callback(
    Output("example-graph", "figure"),
    [Input("variable_choice", "value")])

def update_graph_1(variable_name):
	dff = df[df["name"]==variable_name]
	return {
    "data": [dict(x=dff.x, y=dff.y, type="bar")]
    }

if __name__ == '__main__':
    app.run_server(debug=True)

Currently I have an empty board:

And I’d just like to show an empty area instead until I select the dropdown

oh ok. That’s because you have

    dcc.Graph(
        id='example-graph'
    )

inside your app.layout. If you want a graph to appear only once callback is activated, you will have to create an empty html.Div inside the app.layout, and use the callback to Output the dcc.graph as the Children of that Div.
And don’t forget to add this line of code

app.config.suppress_callback_exceptions = True

right after “app = dash.Dash()”.

This post might help you more with this.

3 Likes

Thanks you,
I managed to adapt the code to my case. Here’s what I’ve found if it helps anyone else:

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import pandas as pd


app = dash.Dash()
app.config.suppress_callback_exceptions = True

data = {'x': [1, 2, 3, 1, 2, 3], 'y': [4, 1, 2, 6, 1, 4], 'name': ["USA", "USA", "USA", "CAN", "CAN", "CAN"]}
df= pd.DataFrame(data)
variable_indicators = df["name"].unique()

app.layout = html.Div([
 	dcc.Dropdown(
		id="variable_choice",
		options=[{"label": i, "value": i} for i in variable_indicators]
		),

	html.Div([

		], id="example-graph")
])

@app.callback(
    Output("example-graph", "children"),
    [Input("variable_choice", "value")],
    [State("example-graph", "children")])

def update_graph_1(variable_name, children):
	dff = df[df["name"]==variable_name]
	if variable_name:
		if children:
			children[0]["props"]["figure"] = {"data": [dict(x=dff.x, y=dff.y, type="bar")]}
		else:
			children.append(
				dcc.Graph(
					figure={"data": [dict(x=dff.x, y=dff.y, type="bar")]})
						)
	return children

if __name__ == '__main__':
    app.run_server(debug=True)
4 Likes

@Pierre : This was extremely helpful for me. I used it for my code but do you know how can we add the return for multiple graphs?

This is useful, as I’m experiencing the same issue.

However, when I implement as recommended, the graph doesn’t show after the callback is activated.

Here are the relevant parts of my code:


app = Dash(__name__, external_stylesheets=[dbc.themes.LUX])
app.config.suppress_callback_exceptions = True

# in layout
html.Div([], id = 'results-comparison'),

@app.callback(
    Output('results-comparison', 'figure'),
    Input('prediction', 'data'),
    Input('test-data', 'data'),
)
def plot_results(y_hat, test):
    test = pd.DataFrame(test)
    test['ds'] = pd.to_datetime(test['ds'])
    y_hat = pd.DataFrame(y_hat)
    ......

If I substitute the html.Div line with the following, it works (but shows the empty axes upon app-loading, which is what I’m trying to avoid:

dbc.Row(dcc.Graph(id='results-comparison', figure={})),

hi @matsuobasho
Output('results-comparison', 'figure') This is incorrect because figure is not a component property of the html.div.

Your second solution should work, but you need to assign the plot that you built to the figure property. Let’s assum you created a scatter plot inside the callback function and you called id my_plot:

def plot_results(y_hat, test):
    ...
    my_plot = px.scatter(test, x=...)
    return dbc.Row(dcc.Graph(id='results-comparison', figure=my_plot))

Thanks @adamschroeder .

I’m not exactly following your proposed solution. If we have id='results-comparison' within the function, then what is the Output of the callback? The way I have it below seems off.

import dash_bootstrap_components as dbc
from dash import Dash

app = Dash(__name__, external_stylesheets=[dbc.themes.LUX])

app.Layout = dbc.Container([
                          dbc.Row(dcc.Graph(id='results-comparison', figure={})),
                          ])

@app.callback(
    Output('results-comparison', 'figure'),
    Input('prediction', 'data'),
    Input('test-data', 'data'),
)
def plot_results(y_hat, test):
    test = pd.DataFrame(test)
    test['ds'] = pd.to_datetime(test['ds'])
    y_hat = pd.DataFrame(y_hat)
    ....
    res = px.line(comb_res)
    return dbc.Row(dcc.Graph(id='results-comparison', figure=res))

Hi @matsuobasho
Take a look at the code you just pasted above.

An output has a component_id and a component_property.
Output(component_id='results-comparison', component_property='figure'),.

In this case, whatever object you return in the callback function will be assigned to the figure property of the dcc.Graph.

Your function returns a Row: dbc.Row(dcc.Graph(id='results-comparison', figure=res)). That is not a figure. Remember that the figure property of dcc.Graph must be assigned a plotly figure. So instead of returning a whole row, you can return only the px.line(comb_res).
So, this should work:

 return res

Thanks @adamschroeder

Here is how I have it as per your guidance:

app.Layout = dbc.Container([
                          dbc.Row(dcc.Graph(id='results-comparison', figure={})),
                          ])

@app.callback(
    Output('results-comparison', 'figure'),
    Input('prediction', 'data'),
    Input('test-data', 'data'),
)
def plot_results(y_hat, test):
    test = pd.DataFrame(test)
    test['ds'] = pd.to_datetime(test['ds'])
    y_hat = pd.DataFrame(y_hat)
    ....
    res = px.line(comb_res)
    return res

I still see the empty graph axes like this when I launch the app, which is what I’m trying to get rid of:

Does this help?

HI @matsuobasho
To build on @AIMPED 's helpful tip, try this code:

app.Layout = dbc.Container([
                          dbc.Row(html.Div(id='results-comparison')),
                          ])

@app.callback(
    Output('results-comparison', 'children'),
    Input('prediction', 'data'),
    Input('test-data', 'data'),
)
def plot_results(y_hat, test):
    test = pd.DataFrame(test)
    test['ds'] = pd.to_datetime(test['ds'])
    y_hat = pd.DataFrame(y_hat)
    ....
    res = px.line(comb_res)
    return dcc.Graph(figure=res)

Actually, the layout in my code might be more accurate as such:

app.Layout = dbc.Container([
    dbc.Row([
        dbc.Col([html.Div(id='results-comparison')], width=12)
    ]),
])
1 Like

@adamschroeder @AIMPED neither of your solutions display the chart after the callback is called.

For @AIMPED 's solution, I tried this:

        html.Div([dcc.Graph(id='results-comparison', style={'visibility': 'hidden'}),
                 html.Div(id='dummy')]) 

Not sure what’s going on.

For reference since many combinations of dcc.Graph, html.Divhave been proposed, here is the version that works (where the axes are displayed upon loading):

dbc.Row(dcc.Graph(id='results-comparison', figure={}))

hi @matsuobasho
What error do you get when you try this code? Make sure not to put dcc.Graph inside the app.layout.

app.Layout = dbc.Container([
                          dbc.Row(html.Div(id='results-comparison')),
                          ])

@app.callback(
    Output('results-comparison', 'children'),
    Input('prediction', 'data'),
    Input('test-data', 'data'),
)
def plot_results(y_hat, test):
    test = pd.DataFrame(test)
    test['ds'] = pd.to_datetime(test['ds'])
    y_hat = pd.DataFrame(y_hat)
    ....
    res = px.line(comb_res)
    return dcc.Graph(figure=res)

If you use this approach, you’ll have to update the style of your graph via callback.

an example:

from dash import Dash, html, dcc, Input, Output
import plotly.graph_objects as go

app = Dash()
app.layout = html.Div(
    id='container',
    children=[
        html.Button('click', id='btn'),
        dcc.Graph(
            id='graph',
            figure={},
            style={'visibility': 'hidden'}
        )
    ]
)


@app.callback(
    Output('graph', 'figure'),
    Output('graph', 'style'),
    Input('btn', 'n_clicks'),
    prevent_initial_call=True
)
def show(_):
    figure = go.Figure(go.Scatter(x=[1, 2], y=[3, 4]))
    style = {}

    return figure, style


if __name__ == '__main__':
    app.run(debug=True)
1 Like

@adamschroeder , my error, I forgot to switch the component_property of the output in the callback to children from figure. That works, thanks so much!