Python 3.x Plotly Dash-单击点时将注释添加到散点图

Python 3.x Plotly Dash-单击点时将注释添加到散点图,python-3.x,plotly,plotly-dash,Python 3.x,Plotly,Plotly Dash,我在dash中有一个散点图,有一些点击回调。我希望在单击某个点时显示该点的注释。对于已单击的任何点,注释都应保持可见。是否有人知道这是可能的;我应该如何处理这个问题?我最初的搜索没有找到任何具体的例子或线索 import json from textwrap import dedent as d import dash from dash.dependencies import Input, Output import dash_core_components as dcc import das

我在dash中有一个散点图,有一些点击回调。我希望在单击某个点时显示该点的注释。对于已单击的任何点,注释都应保持可见。是否有人知道这是可能的;我应该如何处理这个问题?我最初的搜索没有找到任何具体的例子或线索

import json
from textwrap import dedent as d
import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
import random

userSeq = []


app = dash.Dash(__name__)

styles = {
    'pre': {
        'border': 'thin lightgrey solid',
        'overflowX': 'scroll'
    }
}

app.layout = html.Div([
    dcc.Graph(
        id='basic-interactions',
        figure={
            'data': [
                {
                    'x': [random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100)],
                    'y': [random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100)],
                    'text': ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'],
                    #'customdata': ['c.a', 'c.b', 'c.c', 'c.d'],
                    'name': 'Trace 1',
                    'mode': 'markers+text', 
                    'marker': {'size': 12},
                    'textposition': 'bottom'
                }

            ]
        }
    ),

    html.Div(className='row', children=[

        html.Div([
            dcc.Markdown(d("""
                **Click Data**

                Click on points in the graph.
            """)),
            html.Pre(id='click-data', style=styles['pre']),
        ], className='three columns'),

    ])
])



@app.callback(
    Output('click-data', 'children'),
    [Input('basic-interactions', 'clickData')])
def display_click_data(clickData):
    if clickData != None:
        userSeq.append(clickData['points'][0]['x'])
        print(userSeq)
    return json.dumps(clickData, indent=2)


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

也许这有点过头了,但下面是您可以做的:在短划线回调中重新定义散点图注释的样式

据我所知,唯一的方法是重新定义
dcc.Graph
组件的
Figure

import json
from textwrap import dedent as d
import dash
import plotly.graph_objs as go
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
import random

# NOTE: this variable will be shared across users!
userSeq = []

x_coords = [random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100)]
y_coords = [random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100), random.randint(0, 100)]


app = dash.Dash(__name__)

styles = {
    'pre': {
        'border': 'thin lightgrey solid',
        'overflowX': 'scroll'
    }
}


app.layout = html.Div([
    dcc.Graph(
        id='basic-interactions',
        figure={
            'data': [
                {
                    'x': x_coords,
                    'y': y_coords,
                    'text': ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'],
                    #'customdata': ['c.a', 'c.b', 'c.c', 'c.d'],
                    'name': 'Trace 1',
                    'mode': 'markers+text',
                    'marker': {'size': 12},
                    'textposition': 'bottom'
                }

            ],
        },
    ),

    html.Div(className='row', children=[

        html.Div([
            dcc.Markdown(d("""
                **Click Data**

                Click on points in the graph.
            """)),
            html.Pre(id='click-data', style=styles['pre']),
        ], className='three columns'),

    ])
])


@app.callback(
    output=Output('click-data', 'children'),
    inputs=[Input('basic-interactions', 'clickData')])
def display_click_data(clickData):
    if clickData is not None:
        point = clickData['points'][0]
        userSeq.append({'x': point['x'], 'y': point['y']})
        print(userSeq)
    return json.dumps(clickData, indent=2)


@app.callback(
    Output('basic-interactions', 'figure'),
    [Input('basic-interactions', 'clickData')])
def update_annotation_style(clickData):
    """Redefine Figure with an updated style for the scatter plot annotations."""
    data = go.Data([
        go.Scatter(
            x=x_coords,
            y=y_coords,
            text=['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'],
            name='Trace 1',
            mode='markers+text',
            marker={'size': 12},
            textposition='bottom',
        )
    ])
    annotations = []
    for point in userSeq:
        annotation = {
            'x': point['x'],
            'y': point['y'],
            'xref': 'x',
            'yref': 'y',
            'text': '({}; {})'.format(point['x'], point['y']),
            'align': 'center',
            'ay': -15,
            'opacity': 0,
            'bgcolor': 'yellow',
        }
        annotations.append(annotation)

    if clickData is None:
        layout = go.Layout(annotations=annotations)
    else:
        updated_annotations = list(map(lambda ann: {**ann, 'opacity': 1.0}, annotations))
        layout = go.Layout(annotations=updated_annotations)
    figure = go.Figure(data=data, layout=layout)
    return figure


if __name__ == '__main__':
    app.run_server(debug=True)
不过,我的实现中存在一个bug:除了当前点之外,所有单击的点都会显示注释(因此当您单击两个点时,注释开始显示)

我认为这个问题是由两个破折号回调的运行顺序引起的:带有
输出('basic-interactions','figure')
的回调应该第二个运行

请记住,在您的应用程序中,
userSeq
是跨用户共享的,因此如果
user A
单击散点图中的3个点,
user B
单击散点图中的2个点,他们都将看到5个注释