21

I am trying to call a plotly-dash callback without the Input and the method won't fire.

This is a dashboard I am trying to build using dash. In the past when I use a callback with both the Input and Output everything works fine but when I tried using only output the result is not displayed on the dashboard.

html.Div(
    [

        html.P(
            "Tweet Count",
            className="twelve columns indicator_text"
        ),
        html.P(
            id = 'tweet_value',
            className="indicator_value"
        ),
    ],
    className="four columns indicator",

)

@app.callback(
Output("tweet_value","children")

)
def total_tweet_callback():

    return 100   
7
  • As far as my understanding goes, there is a need for at least one input, so that the callback "knows" when to fire. If there is no trigger for the callback, why use a callback? If you want total_tweet_callback() to run only once on load, simply put children=total_tweet_callback() for the P element. Commented Jan 15, 2019 at 8:07
  • @Shovalt I tried setting the children to the callback function but I am getting error. I have made some analysis and the goal of the app is to display them with being triggered by an input Commented Jan 15, 2019 at 11:18
  • I have a lot to explain here, so I'll post it as an answer and we can work from there until a solution is found. Commented Jan 15, 2019 at 12:33
  • did you manage to make it work? Commented Jan 17, 2019 at 8:37
  • 1
    @Shovalt Oh sorry. And I though I have accepted it. Right away Commented Jan 17, 2019 at 20:09

3 Answers 3

20

There is a need for at least one input or event for a callback to get called, as written inside the dash.py code:

Without Input or Event elements, this callback will never get called.

(Subscribing to input components will cause the callback to be called whenever their values change and subscribing to an event will cause the callback to be called whenever the event is fired.)

In your case - if there is no trigger for the callback, why use a callback? If you want total_tweet_callback to run only once on load, simply call it from the layout:

def total_tweet_callback():
    return 100

app.layout = lambda: html.Div(
    [
        html.P(
            "Tweet Count",
            className="twelve columns indicator_text"
        ),
        html.P(
            children=total_tweet_callback(),
            id='tweet_value',
            className="indicator_value"
        ),
    ],
    className="four columns indicator",
)

Notice that:

  1. I removed the decorator from total_tweet_callback.
  2. I gave the layout a function (lambda function in this case) that returns the Div element. This isn't necessarily required, and depends on other aspects of your code. For example, including the lambda: will cause the total_tweet_callback function get called each time the page is reloaded, while removing it will get the value only once when the app is loaded.
Sign up to request clarification or add additional context in comments.

6 Comments

I would advise against this if embedding in a Django app. It has the potential to break migrations, see stackoverflow.com/questions/69955759/…
@NickT, perhaps, but that is not the subject of the post. I tried to answer the OP's question with minimal changes to their code.
warning: the function does not get recalled when refreshing the page. verified using datetime.now()
@Kalanos - I just found the time to check this, and you are incorrect. The answer as presented here does call the function each time the page is refreshed (dash v2.0.0). It turns out that the lambda in the app.layout is essential for that, so I edited the answer to clarify that.
I don't understand how this is the accepted answer. A callback can be useful still, e.g. to execute using background callbacks for very slow operations.
|
14

All callbacks are run once when loaded, except disabled explicitly. So a simple solution is to use a dummy input, referring to anything, and just not using it.

I do not agree with the other answer. Directly calling the function would not make it triggered every 'load'. In that way the function only run once when the statement is run. The function is only triggered when the app is started, not every time you click refreshing button of your browser. If you use datetime.datetime.now() there, you can see the difference.

4 Comments

A correction: "Directly calling the function would not make it triggered every 'load'. " This claim seems not always true. There are different ways to launch a Dash app, and I can tell it is at least true in some cases. I didn't do more research though. So what I said in this answer is useful at least sometimes.
Does the input id and property must exist for the dummy input?
As long as you use a function for the layout (like the use of a lambda function in my answer), the function does get called when refreshing the page.
@Shovalt Thanks for clarification. Now I understand how to make the app layout reload when refreshing webpage. However, this may not always be possible (depending on how you structure the whole app) or desired (if only part of the layout should be refreshed). A dummy input can still be useful in some scenarios.
7

You could can use an dcc.Interval.

It works when refreshing the page.

from datetime import datetime

# within layout
dcc.Interval(
    id="load_interval", 
    n_intervals=0, 
    max_intervals=0, #<-- only run once
    interval=1
),
html.Span(
    id="spanner",
    style=dict(color="yellow") #<-- just so it's easy to see
),

# callback
@app.callback(
    Output(component_id="spanner", component_property="children"),
    Input(component_id="load_interval", component_property="n_intervals"),
)
def update_spanner(n_intervals:int):
    return datetime.now()

I need to refresh the initial data periodically anyways so its good to get familiar with Interval. n_intervals is kind of like n_clicks.

https://dash.plotly.com/dash-core-components/interval


Disclaimer; my approach above is kind of a hack and I don't know if it will hold up long term.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.