You can use the restyleData
prop of the Graph
to detect when the legend has been interacted with.
The thing that’s slightly complicated is that it only shows you changes, not the current state of the legend. I can’t see how you would pull that out from the figure
attribute of the Graph
, so the best I can think to do is to keep track of the current state of the legend yourself by watching for edits.
Here’s an example of that. It just displays the selected items in a list when the user clicks on a button, but you could easily adapt this to download a CSV or similar instead.
import dash
import dash_core_components as dcc
import dash_html_components as html
import numpy as np
import plotly.graph_objs as go
from dash.dependencies import Input, Output, State
FIG = go.Figure(
data=[
go.Scatter(x=np.arange(10), y=np.random.rand(10), name=f"Name {i}")
for i in range(10)
]
)
app = dash.Dash()
app.layout = html.Div(
[
# create a store which will keep track of which elements in the legend
# are currently active
dcc.Store(
id="store",
data=[
{
"name": d.name if d.name is not None else f"trace {i}",
"visible": d.visible if d.visible is not None else True,
}
for i, d in enumerate(FIG["data"])
],
),
dcc.Graph(id="graph", figure=FIG),
html.Button("Button", id="button"),
html.Div(id="output"),
]
)
# when the legend is clicked, use restyleData to update the store
@app.callback(
Output("store", "data"),
Input("graph", "restyleData"),
[State("store", "data")],
)
def update_store(restyle_data, store):
if restyle_data is not None:
edits, indices = restyle_data
try:
for visible, index in zip(edits["visible"], indices):
# visible could be the string "legend_only" which is truthy
# hence explicit comparison to True here
store[index]["visible"] = visible is True
except KeyError:
pass
return store
# when the button is clicked, use the store to populate a list (or do something
# more interesting)
@app.callback(
Output("output", "children"),
Input("button", "n_clicks"),
State("store", "data"),
)
def show_legend_items(n, store):
if n:
return html.Ul(
[html.Li(item["name"]) for item in store if item["visible"]]
)
return html.P("Select items on the legend then click on the button")
if __name__ == "__main__":
app.run_server(debug=True)