4

我在破折号中有一个散点图,带有一些点击回调。我想在单击时显示某个点的注释。对于已单击的任何点,注释应保持可见。有谁知道这是否可能;我应该如何处理这个?我最初的搜索没有产生任何具体的例子或线索。

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)
4

1 回答 1

0

也许这有点矫枉过正,但您可以这样做:在破折号回调中重新定义散点图注释的样式。

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

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)

但是,我的实现中有一个错误:注释会显示所有单击的点,但当前点除外(因此当您单击两个点时它们开始显示)。

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

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

于 2018-04-23T20:30:03.303 回答