Multiple Outputs for gauge chart with data from other module

I have a daq.Gauge chart and want to update the ‘value’ and ‘max’ based on data from external module.

html.Div([
        daq.Gauge(
            id='gauge-chart',
            color={"gradient": True, "ranges": {
                "green": [0, 6], "yellow":[6, 8], "red":[8, 10]}},
            value=2,
            max=10,
            min=0,
            units="MPH",
        )
    ], className='row', style={'textAlign': 'center'}),

Now I have a second module streamer.py, which creates a random number. This random number should be displayed as ‘value’ in the gauge. The ‘max’ value for the gauge must be set dynamically as well, because the random number could be any number bigger then max=10.

@app.callback(
    Output('gauge-chart', 'value'),
    Output('gauge-chart', 'max'),
    [Input(***<SOURCE FROM STRAMER.PY>***)]
)
def update_gauge(value):
    **CODE HERE**
    return value, max

QUESTION 1:
How could I access the data from streamer.py in the Input?

QUESTION 2:
For simplicity, I’ve tested with a separate dcc.input:
dcc.Input(id='test_input', value='5', type='number'),

@app.callback(
    Output('gauge-chart', 'value'),
    # Output('gauge-chart', 'max'),
    [Input('test_input', 'value')]
)
def update_gauge(value):
    max = 12
    return value, max

This gives me an error:TypeError: ‘Output’ object is not iterable

Regarding Question 1: I am not aware of the ability for an Input to directly reference the output of a .py file/function. You would need this .py file/function to update a web component that your @app.callbackwould then trigger on.

For Question 2: Not sure if it’s a copy/paste typo but you have one output but are returning 2 values (value and max). However, for multiple outputs, you are missing [] around your Output block:

The following should work for you.

@app.callback(
    output = [Output('gauge-chart', 'value'),
              Output('gauge-chart', 'max')],
    inputs = [Input('test_input', 'value')]
)
def update_gauge(value):
    max = 12
    return value, max

Thanks @flyingcujo, question 2 was indeed the problem of missing [].

Regarding Question 1:

You would need this .py file/function to update a web component that your @app.callback would then trigger on.

Exactly my thoughts. The only way I see to do this via a hidden input field which is updated by the second .py file.

The problem is that I do not want to paste all the code from the second .py file (streamer file) in the callback function of the main file, because then the file structur will be a mess.

Shouldn’t need to paste it. The callback can reference the functions in the streamer file (or any other file) as long as you include an import statement at the top. Many of my callback functions do this in order to keep the code clean and reusable.

How do I have to do that?

if your streamer file is called streamer.py and a function within is named streamit, then the following will work:

from streamer import streamit

Or, if you want to import all the functions, use (replace streamer correct name and sf with your desired reference) :

`import streamer as sf`

Then in your code, invoke the function streamit via sf.streamit(arg1, arg2, etc)

I appologize; Importing in python is clear, but what confuses me is how to acces the data from this streamer.py file and pass it into the callback.

@app.callback([
    Output('gauge-chart', 'value'),
    Output('gauge-chart', 'max'),
],  [Input(VALUE FROM .py FILE), ]

I have to find a solution for: VALUE FROM .py FILE I could not do:

@app.callback([
    Output('gauge-chart', 'value'),
    Output('gauge-chart', 'max'),
],  [Input(streamer.streamit), ]

Hopefully now it is more clear.

The problem is, acces the data from the .py file and pass it into the callback. Maybe I do not need the Input and only do something like this:

@app.callback([
    Output('gauge-chart', 'value'),
    Output('gauge-chart', 'max'),
])
def update_gauge(streamer.streamit):
    max = 12
    value = streamer.streamit
    return value, max

Gotcha. Sorry I misunderstood your question…hopefully the pseudo code shown is ok - could be old hat for you but just in case…

You do need an Input otherwise the @app.callback will never get invoked.

The question is how will the streamer.py functions be invoked. Off the top of my head, it could be as simple as a user pressing a button on your app (or any other user-action…changing a slider, using a toggle, etc) or it could be done via periodic page updates (read about this feature on Dash How-to’s but never implemented it - suspect a callback will still be requried). Regardless, in order for the streamer functions to be invoked, some action must be done on the app in order for the callback to be invoked.

Assuming you have a button:

@app.callback(
[Output('somehiddendiv', 'children')],
[Input('yourButton', 'n_clicks')])
def getStreamerData(numClicks):
    value = streamer.streamit()
    return value

Then, when the somehiddendiv children data changes, the following callback will be automatically invoked:

@app.callback(
[Output('gauge-chart', 'value'),
Output('gauge-chart', 'max')],
[Input('somehiddendiv', 'children')])
def update_gauge( streamer_data ):
    max = 12
    value = streamer_data
    return value, max

Hope this helps!

Yes, got that.

When I start my app.py, the streamer.py runs automatically and produces, lets say just a simple counter. This counter value should be displayed in the gauge ‘value’.

I have to check, if there is a possibility to page update in the Dash How-to’s or as you mentioned, a hidden div to invoke the callback. But that somehiddendivor invoke-issue is really my problem.

@app.callback(
[Output('gauge-chart', 'value'),
Output('gauge-chart', 'max')],
[Input('somehiddendiv', 'children')])
def update_gauge( streamer_data ):
    max = 12
    value = streamer_data
    return value, max

@flyingcujo I guess I have found the solution:

From: https://dash.plot.ly/live-updates

....
  dcc.Interval(
        id='interval-component',
        interval=1*1000,  # in milliseconds
        n_intervals=0
    ),
....

@app.callback(
[Output('gauge-chart', 'value'),
Output('gauge-chart', 'max')],
[Input('interval-component', 'n_intervals')])
def update_gauge( n_intervals ):
    max = 12
    value = streamer.streamit.py
    return value, max

The hidden.div could be replaced with interval-component for frequently updating data.

Awesome! Glad you found a solution that works!