【问题标题】:Plotly Dash - Add annotation to scatter plot for a point when it is clicked-onPlotly Dash - 单击时为散点图添加注释
【发布时间】:2018-02-16 00:16:55
【问题描述】:

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

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)

【问题讨论】:

    标签: python-3.x plotly plotly-dash


    【解决方案1】:

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

    据我所知,唯一的办法就是重新定义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)
    

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-28
      • 2021-11-04
      • 2019-01-27
      • 2018-11-11
      • 1970-01-01
      • 2017-01-17
      • 2022-01-02
      相关资源
      最近更新 更多