This should be common functionality but I cannot see this asked elsewhere or in the docs?
How can my call back call a function that is within a class?
from dash import Dash, html, dcc, callback, Output, Input
import plotly.express as px
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminder_unfiltered.csv')
class S:
def __init__(self) -> None:
pass
@callback(
Output('graph-content', 'figure'),
[Input('dropdown-selection', 'value')]
)
def update_graph(self, value):
dff = df[df.country==value]
return px.line(dff, x='year', y='pop')
app = Dash(__name__)
app.layout = html.Div([
html.H1(children='Title of Dash App', style={'textAlign':'center'}),
dcc.Dropdown(df.country.unique(), 'Canada', id='dropdown-selection'),
dcc.Graph(id='graph-content')
])
if __name__ == '__main__':
app.run(debug=True)
This gives the error TypeError: S.update_graph() missing 1 required positional argument: 'value'
which is typical if a class function is missing the self
arg.
AIMPED
September 1, 2023, 12:22pm
2
Hi @this_josh , not sure, but in this example your function could be a @staticmethod , try deleting the self
parameter.
Hi, in my actual use case, the plots require object properties, e.g.
def update_graph(self, value):
plot(value, self.name)
This is not possible with staticmethod
It seems strange for dash
not to support this
Hello @this_josh ,
Hmm, have you looked into the documentation for AIO components?
It may shed some light on this.
Thank you for highlighting this, the docs do shed some light, although it seems needlessly complex.
Here is a working example, the aio I replaced with just pattern-matching callbacks:
from dash import Dash, html, dcc, callback, Output, Input, MATCH
import plotly.express as px
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminder_unfiltered.csv')
class S(html.Div):
class ids:
graph = lambda id: {"index": id, 'type': 'graph'}
dropdown = lambda id: {"index": id, 'type': 'dropdown'}
ids = ids
def __init__(self, id, dropdownData, dropdownValue = None):
super().__init__([
dcc.Dropdown(dropdownData, dropdownValue, id=self.ids.dropdown(id)),
dcc.Graph(id=self.ids.graph(id))
])
@callback(
Output(ids.graph(MATCH), 'figure'),
Input(ids.dropdown(MATCH), 'value')
)
def updateGraph(value):
dff = df[df.country == value]
return px.line(dff, x='year', y='pop')
app = Dash(__name__)
mygraph = S('graph-content', df.country.unique())
app.layout = html.Div([
html.H1(children='Title of Dash App', style={'textAlign':'center'}),
mygraph
])
if __name__ == '__main__':
app.run(debug=True)
1 Like
You got me going, haha, check out the more watered down version without using pattern-matching:
from dash import Dash, html, dcc, callback, Output, Input, MATCH
import plotly.express as px
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminder_unfiltered.csv')
class S(html.Div):
def update_graph(self, value, charttype):
dff = df[df.country == value]
if charttype == 'scatter':
fig = px.scatter(dff, x='year', y='pop')
elif charttype == 'bar':
fig = px.bar(dff, x='year', y='pop')
else:
fig = px.line(dff, x='year', y='pop')
return fig
def __init__(self, id, dropdown, charttype=None):
@callback(
Output(id, 'figure'),
Input(dropdown, 'value')
)
def updateGraph(value):
return self.update_graph(value, charttype)
super().__init__([
dcc.Graph(id=id)
])
app = Dash(__name__)
dropdown = dcc.Dropdown(df.country.unique(), id='dropdowns')
app.layout = html.Div([
html.H1(children='Title of Dash App', style={'textAlign':'center'}),
dropdown,
S('graph-content', 'dropdowns', 'scatter'),
S('graph-content2', 'dropdowns'),
S('graph-content3', 'dropdowns', 'bar')
])
if __name__ == '__main__':
app.run(debug=True)
3 Likes
That’s nice, thanks, I particularly like the second method.
Cheers
1 Like