python 中的 Plotly-Dash 股票应用程序,带有客户端回调(xaxis 缩放上的 yaxis 自动缩放) [英] Plotly-Dash stock app in python, with clientside callback (yaxis autoscale on xaxis zoom)

查看:81
本文介绍了python 中的 Plotly-Dash 股票应用程序,带有客户端回调(xaxis 缩放上的 yaxis 自动缩放)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用带 xaxis 滑块的 dash-plotly (python) 创建一个简单的股票图表应用程序.滑动 xaxis 时,我希望 yaxis 动态重新缩放到视图.我想我已经设法在通过relayoutData"钩子滑动 xaxis 比例时触发回调函数.但不是更新 yaxis,脚本会引发错误.我不确定从回调函数更新布局的正确语法.有什么想法吗?

I'm creating a simple stock chart app in dash-plotly (python) whith an xaxis slider. When sliding the xaxis, I want the yaxis to dynamically rescale to the view. I think I have managed to get the callback function to trigger when sliding the xaxis scale through the 'relayoutData' hook. But instead of updating the yaxis the script throws errors. I'm not sure of the proper syntax to update layout from a callback function. Any ideas?

到目前为止,这是我的代码.它会运行,但 yaxis 是在运行时设置的,并且不会更新.

Here is my code so far. It runs, but yaxis is set at run time, and doesn't update.

非常感谢您的帮助 =)

Thanks a lot for any help =)

import dash
from dash.dependencies import Output, Input
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
import numpy as np
import datetime

#some random values
a = datetime.datetime.today()
numdays = 100
dateList = []
for x in range (0, numdays):
    dateList.append(a - datetime.timedelta(days = x))
xy = [dateList,np.random.rand(100)]

app = dash.Dash()

app.title = 'Random'
dataS = go.Scatter(
        x = xy[0],
        y = xy[1],
        name = 'Rand',
        mode = 'lines'
    )
layoutS = go.Layout(
    title="Rand",
    xaxis=dict(
        rangeslider_visible=True,
        rangeselector=dict(
            buttons=list([
                dict(count=1, label="1m", step="month", stepmode="backward"),
                dict(count=6, label="6m", step="month", stepmode="backward"),
                dict(count=1, label="YTD", step="year", stepmode="todate"),
                dict(count=1, label="1y", step="year", stepmode="backward"),
                dict(count=5, label="5y", step="year", stepmode="backward"),
                dict(step="all")
            ])
        )
    )
)

app.layout = html.Div(
    html.Div([
        html.H1(children='Random nums'),
        html.Div(children='''
            Rand rand rand.
        '''),

        dcc.Graph(id='RandGraph', animate=True, figure=go.FigureWidget(data=dataS,layout=layoutS))
    ])
)

@app.callback(Output('RandGraph','figure'),[Input('RandGraph','relayoutData')])
def update_graph(relOut):
    layout = go.Layout(
        yaxis=dict(range=[min(y),max(y)])
    )
    return {'layout':layout}

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

推荐答案

这是结果.我首先尝试了服务器端实现,结果非常慢(我保留它以供参考).客户端实现的响应速度更快,速度更快.使用起来很愉快.我只需要学习一些 javascript 就可以了 =) 当我尝试进行数组过滤时,我肯定错过了 Pandas!

Here is the result. It I tried a serverside implementation first, which ended up being really slow (I kept it for reference). The clientside impletation is a lot more responsive and faster. A joy to use. I just needed to learn a bit of javascript to make if work =) I sure was missing pandas when I was trying to do the array filtering!

这是工作代码.享受!

import dash
from dash.dependencies import Output, Input, State
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
import numpy as np
import pandas as pd
import datetime

#some random values
a = datetime.datetime.today()
numdays = 100
dateList = []
for x in range (0, numdays):
    dateList.append(a - datetime.timedelta(days = x))
xy = [dateList,np.random.rand(100)]
df = pd.DataFrame(data=xy[1],columns=["y"],index=xy[0])


#Graph data
dataS = [dict(
    x = df.index,
    y = df['y'],
    name = 'meter',
    mode = 'lines'
)]

#Graph layout
layoutS = go.Layout(
    title="Meter",
    xaxis=dict(
        rangeslider_visible=True,
        rangeselector=dict(
            buttons=list([
                dict(count=1, label="1m", step="month", stepmode="backward"),
                dict(count=6, label="6m", step="month", stepmode="backward"),
                dict(count=1, label="YTD", step="year", stepmode="todate"),
                dict(count=1, label="1y", step="year", stepmode="backward"),
                dict(count=5, label="5y", step="year", stepmode="backward"),
                dict(step="all")
            ])
        )
    ),
    yaxis=dict(range=[0,2])
)

#Dash app layout
app = dash.Dash()
app.title = 'Random'

app.layout = html.Div(
    html.Div([
        html.H1(children='Random nums'),
        html.Div(children='''
            Rand rand rand.
        '''),

        dcc.Input(
            id='input-y',
            placeholder='Insert y value',
            type='number',
            value='',
        ),
        html.Div(id='result'),

        dcc.Graph(id='RandGraph',figure=dict(data=dataS,layout=layoutS))
    ])
)

#client side implementation
app.clientside_callback(
    """
    function(relOut, Figure) {
        if (typeof relOut !== 'undefined') {
            if (typeof relOut["xaxis.range"] !== 'undefined') {
                //get active filter from graph
                fromS = new Date(relOut["xaxis.range"][0]).getTime()
                toS = new Date(relOut["xaxis.range"][1]).getTime()

                xD = Figure.data[0].x
                yD = Figure.data[0].y

                //filter y data with graph display
                yFilt = xD.reduce(function (pV,cV,cI){
                    sec = new Date(cV).getTime()
                    if (sec >= fromS && sec <= toS) {
                        pV.push(yD[cI])
                    }
                    return pV
                }, [])

                yMax = Math.max.apply(Math, yFilt)
                yMin = Math.min.apply(Math, yFilt)
            } else { 
                yMin = Math.min.apply(Math, Figure.data[0].y)
                yMax = Math.max.apply(Math, Figure.data[0].y) 
            }
        } else { 
            yMin = Math.min.apply(Math, Figure.data[0].y)
            yMax = Math.max.apply(Math, Figure.data[0].y) 
        }
        Figure.layout.yaxis = {
            'range': [yMin,yMax],
            'type': 'linear'
        }
        return {'data': Figure.data, 'layout': Figure.layout};
    }
    """,
    Output('RandGraph','figure'),
    [Input('RandGraph','relayoutData')],[State('RandGraph', 'figure')]
)

#Server side implementation (slow)
#@app.callback(
#    Output('RandGraph','figure'),
#    [Input('RandGraph','relayoutData')],[State('RandGraph', 'figure')]
#)
#def update_result(relOut,Fig):
#    ymin = df.loc[relOut['xaxis.range'][1]:relOut['xaxis.range'][0],'y'].min()
#    ymax = df.loc[relOut['xaxis.range'][1]:relOut['xaxis.range'][0],'y'].max()
#    newLayout = go.Layout(
#        title="OL Meter",
#        xaxis=dict(
#            rangeslider_visible=True,
#            rangeselector=dict(
#                buttons=list([
#                    dict(count=0, label="1m", step="month", stepmode="backward"),
#                    dict(count=6, label="6m", step="month", stepmode="backward"),
#                    dict(count=1, label="YTD", step="year", stepmode="todate"),
#                    dict(count=1, label="1y", step="year", stepmode="backward"),
#                    dict(count=5, label="5y", step="year", stepmode="backward"),
#                    dict(step="all")
#                ])
#            ),
#            range=relOut['xaxis.range']
#        ),
#        yaxis=dict(range=[ymin,ymax])
#    )
#    
#    
#    Fig['layout']=newLayout
#    return Fig

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

这篇关于python 中的 Plotly-Dash 股票应用程序,带有客户端回调(xaxis 缩放上的 yaxis 自动缩放)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆