How to turn off "interval" event?

I’m running a subprocess with its stdout piped, reading it using an interval timer, and displaying the output. I’d like to turn off the timer when the subprocess completes.

I tried creating a callback with Output(interval_id, ‘interval’) that detects if the subprocess has exited, and returns a value to reset the interval timer to something that effectively turns it off. I’ve tried values of 0, -1, and None but the timer keeps on ticking. How do I disable it? Do I have to remove it from the Div?

Thanks!

1 Like

Hi @plevin

I don’t think there is a way to disable the interval at the moment, but I’ve added this functionality to the component library and created a pull request: https://github.com/plotly/dash-core-components/pull/66

I tried setting the timer to an insanely large number but that doesn’t seem to work either so I don’t have much advice to give you in the meantime until we get that addition merged and released.

Sorry for the inconvenience.

I am simply setting the interval to 60*60*1000 for an 1 hour interval when output ends, and when output end is not found, I am returning the default interval value. That works fine.

@app.callback(Output('refreshing-output', 'value'),
              events=[Event('interval-element', 'interval')])
def refresh_output():
    # refresh (...)
    return new_value

@app.callback(Output('interval-element', 'interval'),
              [Input('refreshing-output', 'value')])
def disable_interval(content: str):
    if finished(content):
        return 60*60*1000
    else:
        return 1 * 5000
2 Likes

This should work and it looks like @radekwlsk was able to make this work with 1 hour. From SO, it looks like the maximum value for interval is 2,147,483,647 (2^31-1)) so perhaps this was being set to a number larger than that.

Hi guys,

I had this same issue… I couldn’t solve it in an extremely elegant way, however I didn’t like the idea of leaving a process running in the background.

I did this:

@app.callback(Output('tab-output', 'children'), [Input('tabs', 'value')], events=[Event("interval-component","interval")])
def display_content(value ):
# refresh (...)
return 

@app.callback(Output("interval-start", "children"), [Input("start-timer", "n_clicks"), Input("stop-timer", "n_clicks")])
def start_interval(n_clicks, stop_clicks):
    if n_clicks - stop_clicks > 1:
        n_clicks = stop_clicks + 1
    if n_clicks > 0 and stop_clicks == None :
        return dcc.Interval(id="interval-component", interval=1 * 1000)
    if stop_clicks > 0:
        return "No timer"
    else:
        return "Not yet started"

Maybe instead of using the click logic I needed you can include the completion of your subprocess.
Interested in your thoughts @chriddyp

I’m not sure what you mean by “subprocess” or “process running in the background”. Interval doesn’t start a new process, it just fires your callbacks. In either case, the solution that you provided looks good. You could also even just update the interval property of the interval-component if it was displayed in the app.layout.

This only worked, when I’ve added:

events=[Event('interval-data', 'interval')]

to the second callback, that switches off the interval. Basically it is listening to its own events.

Has there been any change in the Interval functionality since the last message above?
I’d like to be able to stop and start the Interval at will.

I have a live updating chart that I would like to have the option of suspending if the user wants to.

Thanks.

This was fixed a few months ago and has been available in dash-core-components since version 0.43.0. You can now write a callback that targets the disabled prop of your Interval.

Thanks for your reply,
Is there an example available that shows how to do this?
Thanks

@vidapura Something like this:

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

app = dash.Dash()

app.layout = html.Div(
    [
        dcc.Interval(id="interval"),
        html.P(id="output"),
        html.Button("toggle interval", id="button"),
    ]
)


@app.callback(
    Output("interval", "disabled"),
    [Input("button", "n_clicks")],
    [State("interval", "disabled")],
)
def toggle_interval(n, disabled):
    if n:
        return not disabled
    return disabled


@app.callback(Output("output", "children"), [Input("interval", "n_intervals")])
def display_count(n):
    return f"Interval has fired {n} times"


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

Hi Tom,
Thank you very much for taking the time to create this example for me.
I really appreciate it.

Thanks again

1 Like

Note - As per the dcc.Interval documentation, there are two properties that can be used to turn off dcc.Interval:
disabled ( boolean ; optional): If True, the counter will no longer update

max_intervals ( number ; default -1 ): Number of times the interval will be fired. If -1, then the interval has no limit (the default) and if 0 then the interval stops running.