# 📣 Dash Labs 0.2.0

**URL:** <https://community.plotly.com/t/dash-labs-0-2-0/52952>\
**Category:** Dash Python\
**Created:** [May 14, 2021, 5:03pm UTC](https://community.plotly.com/t/dash-labs-0-2-0/52952 "2021-05-14T17:03:40Z")\
**Posts on this page:** 1\
**Showing post:** 8

<div class="post-metadata">

**Author:** ![jmmease](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/jmmease/32/3706_2.png) [@jmmease](https://community.plotly.com/u/jmmease)\
**Post date:** [May 26, 2021, 1:21pm UTC](https://community.plotly.com/t/dash-labs-0-2-0/52952/8 "2021-05-26T13:21:33Z")

</div>

Thanks for the feedback all. I’m still working on digesting it, but I wanted to provide an example to answer @adamschroeder’s first question

> Let’s say I wanted to write another callback that takes the clickData of the scatter plot created in the `tpl.graph_output()` and use that data to create a line chart of the specific country clicked on. Is it possible to do that within the template layout system?

Here’s how I would go about that.

```python
import dash
import dash_labs as dl
import dash_bootstrap_components as dbc
import plotly.express as px
import plotly.graph_objects as go

# Make app and template
app = dash.Dash( __name__ , plugins=[dl.plugins.FlexibleCallbacks()])
tpl = dl.templates.DbcCard(app, "Gapminder", figure_template=True)

# Load and preprocess dataset
df = px.data.gapminder()
years = sorted(df.year.drop_duplicates())

@app.callback(
    args=tpl.slider_input(
        years[0], years[-1], step=5, value=years[-1], label="Year", id="slider",
    ),
    output=tpl.graph_output(id="gap-minder-graph"),
    template=tpl,
)
def callback(year):
    # Let parameterize infer output component
    year_df = df[df.year == year]
    title = f"Life Expectancy ({year})"
    return px.scatter(
        year_df, x="gdpPercap", y="lifeExp", size="pop", color="continent",
        hover_name="country", size_max=60, title=title, custom_data=["country"]
    ).update_layout(
        margin=dict(l=0, r=0, b=0), height=400
    ).update_traces(marker_opacity=0.8)

@app.callback(
    args=[
        dl.Input("gap-minder-graph", "clickData"),
        dl.Input("slider", "value")
    ],
    output=tpl.graph_output(),
    template=tpl,
)
def callback(click_data, year):
    if click_data:
        country = click_data['points'][0]['customdata'][0]
        country_df = df[df["country"] == country]
        return px.line(
            country_df, x="year", y="lifeExp", title=country
        ).add_vline(
            year, line_color="lightgray"
        ).update_layout(
            height=300
        ).update_yaxes(
            range=[30, 100]
        )
    else:
        return go.Figure(layout_height=300).update_yaxes(range=[30, 100])

app.layout = dbc.Container(fluid=True, children=tpl.children)

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

```

![gapminder_two_callbacks](https://us1.discourse-cdn.com/flex024/uploads/plot/original/2X/2/2311697f80ea48df086aa43655a0abd0d09de5f2.gif)

The key idea is to use the template constructor in one of the callbacks, with a fixed id string, then use a dependency object with that id string in the other callback.

I think I’m going to generally not recommend going the `template.roles` direction. Really the only reason to do this is if you want to access the full container that the templates creates (the component that contains the label).

Hope that makes sense!  
-Jon

* * *

Comment from @adamschroeder

> with the new system, I can include `template-tpl` in a callback but not the same one in other callbacks. If I create another callback, I either have to create a new template or use `tpl.add_component()` .

The example above is also an example of passing the same template to multiple callbacks.

* * *

Comment from @adamschroeder

> The callback Input and Output tend to align with the template input and output roles. But sometimes they won’t necessarily. If, for example, I want the first callback input of a dropdown to influence the callback output of a second dropdown’s options, both of these dropdowns would most likely be considered role=“input” inside the template, which is not seemingly contradicting. I initially thought that the callback output and input should align with the template roles.

If you don’t use a template constructor, and pass your own component to a dependency object, then the default role will be selected based on whether the component is enclosed in an `Input` or `Output` dependency.

e.g.

```auto
dl.Input(slider_component, "value") # is the same as:
dl.Input(slider_component, "value", role="input")

dl.Output(graph_component, "figure") # is the same as:
dl.Output(graph_component, "figure", role="output")

# Override default role to "output"
dl.Input(slider_component, "value", role="output")

```

Now, when you use a component constructor, the role defaults to the `_{role}` suffix on the constructor method.

e.g.

```auto
tpl.slider_input(...) # is the same as
tpl.slider_input(..., role="input")

tpl.graph_output(...) # is the same as
tpl.graph_output(..., role="output")

```

The main reason for including a default role in these methods is that they also include a default property, and it’s usually (though not always) pretty clear whether a property typically serves as an input or output. So the thinking is that having the role in the method name helps guide a user towards using the template constructors in the right place.

That said, these method names and their default parameters is a design decision that we can revisit if you have thoughts on alternatives.

* * *

Comment from @adamschroeder

> If accessing component IDs, that were generated in a callback with tpl, remains complicated ( `tpl.roles["output"][0].arg_component.id` ), I think we should not use automatically-created IDs and go back to defining our own IDs.

Yeah, as I mentioned above, this is not a syntax that we want people to need to use to look up ids. The paradigm I had in mind is that you wouldn’t ever look up an auto-generated id. If you care about id’s lining up between callbacks, then you should specify them yourself as an argument to the template constructor. The auto-generated feature is just there for all of the cases where you don’t care (but where Dash still needs them internally order to wire up the callback).

---

_[View the full topic](https://community.plotly.com/t/dash-labs-0-2-0/52952)._
