Plotly Dash的日期滑块不起作用

9

我正在构建一个带有日期时间滑块的Dash应用程序,但下面的代码无法正常工作——url显示“Error loading layout”。我是在做一些愚蠢的事情,还是构建日期时间对象的滑块需要一些技巧?以下是可重现的代码:

import dash
import dash_core_components as dcc
import dash_html_components as html
import datetime

base = datetime.datetime.today()
date_list = [base - datetime.timedelta(days=x) for x in range(0, 10)]

app = dash.Dash()

app.layout = html.Div([
    html.Label('Slider'),
    dcc.RangeSlider(min=min(date_list), 
                    max=max(date_list), 
                    value=min(date_list))
    ])

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

2
如果您能解释一下为什么要给它投反对票,那就太好了 - 谢谢。 - famargar
5个回答

15

Plotly-Dash 目前不支持日期时间对象

解决方法可以在我回答的另一个问题中找到Plotly datetime


一种可能的解决方案是在初始化时使用两个不同的参数:

  • value
  • marks

使用 pandas 生成时间戳的示例:

所需导入项:

import pandas as pd
import time

一些必要的功能:

daterange = pd.date_range(start='2017',end='2018',freq='W')

def unixTimeMillis(dt):
    ''' Convert datetime to unix timestamp '''
    return int(time.mktime(dt.timetuple()))

def unixToDatetime(unix):
    ''' Convert unix timestamp to datetime. '''
    return pd.to_datetime(unix,unit='s')

def getMarks(start, end, Nth=100):
    ''' Returns the marks for labeling. 
        Every Nth value will be used.
    '''

    result = {}
    for i, date in enumerate(daterange):
        if(i%Nth == 1):
            # Append value to dict
            result[unixTimeMillis(date)] = str(date.strftime('%Y-%m-%d'))

    return result

对于 RangeSlider 对象,您可以像这样进行初始化:

dcc.RangeSlider(
                id='year_slider',
                min = unixTimeMillis(daterange.min()),
                max = unixTimeMillis(daterange.max()),
                value = [unixTimeMillis(daterange.min()),
                         unixTimeMillis(daterange.max())],
                marks=getMarks(daterange.min(),
                            daterange.max())
            )

1
奇怪的是,键也必须被转换为整数,而不是浮点数。干得好。https://github.com/plotly/dash-core-components/issues/159 - Sean McCarthy

2

这肯定可以运行,并且比其他任何解决方案都要简单。

marks = {int(i):str(j) for i,j in zip(range(len(df.years)), df[“years”])}

然后你可以在功能回调中模仿相同的操作,通过字典键更新值。


0

看看文档,为什么不尝试使用常规滑块dcc.Slider。您可以在文档底部检查示例:https://dash.plot.ly/getting-started#dash-app-layout

编辑:从文档中添加了代码示例。

您可以将此作为元素添加到您的列表中。 hmtl.Div .
html.Label('Slider'),
    dcc.Slider(
        min=0,
        max=9,
        marks={i: 'Label {}'.format(i) if i == 1 else str(i) for i in range(1, 6)},
        value=5,
    ),

尝试使用dcc.Slider,但没有任何改变。问题似乎出在其他地方。 - famargar

0
你使用的是什么索引单位?是Pandas的日期时间还是简单的数字?
我尝试进行了一些调试:
app.layout = html.Div([dcc.RangeSlider(id='my-slider',
                                       min=1,
                                       max=5,
                                       step=1,
                                       # value=2,
                                       ),
                       html.H1(id='product')])

原来,如果我设置值(因此取消注释value=2),它会出错。 如果您可以尝试不使用value参数,那就太好了。
编辑: value参数需要是一个列表range...)。设置value=[2,3]可以解决问题。这可能会解决您的问题。

我编辑了数字以提供可重现的日期时间。拥有值列表并没有什么区别。看起来问题与使用日期时间而不是浮点数/整数相关? - famargar
是的,我认为问题出在您使用日期时间而不是整数/浮点数上。请参见https://community.plot.ly/t/solved-has-anyone-made-a-date-range-slider/6531/8 - Dummy101
1
我很惊讶他们还没有支持这个功能,因为他们已经支持了图表的范围滑块。 - Dummy101
1
的确。Plotly论坛明显不如StackOverflow好 - 那个示例很难复制。不过我会尝试。 - famargar

0

只需添加即可。

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
from datetime import datetime, timedelta, datetime, date

dates = ['03-02-2021', '03-03-2021', '03-04-2021', '03-05-2021', '03-06-2021', '03-07-2021']
mytotaldates = {i:datetime.strptime(x, "%m-%d-%Y").date() for i,x in enumerate(dates)}


a = (list(mytotaldates.keys()))

app = dash.Dash()

app.layout = html.Div(children=[   
    dcc.Slider(
        id='Dateslider',
        min=a[0],
        max=a[-1],
        marks=mytotaldates,
        value=a[-1],
    ),
    html.Div(id='OutputContainer')
])


@app.callback(
    Output('OutputContainer', 'children'),
    [Input('Dateslider', 'value')])
def rangerselection(val):
    val = mytotaldates[val]
    return f'Selected Date: {val}'


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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接