Plotly Dash - 添加注释以在点击它时对点进行散点图

时间:2018-02-16 00:16:56

标签: python-3.x plotly plotly-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)

1 个答案:

答案 0 :(得分: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个注释。