【问题标题】:plotly dash range slider with datetime and scatterplot interaction具有日期时间和散点图交互的绘图破折号范围滑块
【发布时间】:2021-10-30 15:30:50
【问题描述】:

我想在我的下拉列表中添加一个范围滑块,并将范围滑块设置为“Wallclock”日期时间以及允许范围滑块根据下拉值选择该胶囊的日期时间的交互。我设法找到了其他人这样做的几种方法,但似乎没有一种方法适合我的情况,尤其是回调和图表更新。谢谢!

数据看起来像这样。

Dash 看起来像这样。

代码如下所示。

import pandas as pd
import plotly.express as px  # (version 4.7.0)
import plotly.graph_objects as go
import numpy as np

import openpyxl
import dash  # (version 1.12.0) pip install dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
from dash.exceptions import PreventUpdate

app = dash.Dash(__name__)
server = app.server

df = pd.read_excel("tcd vs rh 2.xlsx")
print(df)

capsuleID = df['Capsule_ID'].unique()
print(capsuleID)

capsuleID_names = sorted(list(capsuleID))
print(capsuleID_names)

capsuleID_names_1 = [{'label': k, 'value': k} for k in sorted(capsuleID)]
capsuleID_names_2 = [{'label': '(Select All)', 'value': 'All'}]
capsuleID_names_all = capsuleID_names_1 + capsuleID_names_2

app.layout = html.Div([

    html.H1("Relative Humidity vs TCD", style={'text-align': 'center'}),

    dcc.Dropdown(id="capsule_select",
                 options=capsuleID_names_all,
                 optionHeight=25,
                 multi=True,
                 searchable=True,
                 placeholder='Please select...',
                 clearable=True,
                 value=['All'],
                 style={'width': "100%"}
                 ),

    dcc.RangeSlider(id='slider',
                    min=df['Wallclock'].min(),
                    max=df['Wallclock'].max(),
                    value=[df.iloc[-101]['Wallclock'].timestamp(), df.iloc[-1]['Wallclock'].timestamp()]
                    ),

    html.Div([
        dcc.Graph(id="the_graph"),
    ]),

])

# -----------------------------------------------------------
@app.callback(
    Output('the_graph', 'figure'),
    Output('capsule_select', 'value'),
    Input('capsule_select', 'value'),
    Input('slider', 'value'),
)
def update_graph(capsule_chosen):
    lBound = pd.to_datetime(value[0], unit='s')
    uBound = pd.to_datetime(value[1], unit='s')
    filteredData = df.loc[(df['date'] >= lBound) & (df['date'] <= uBound)]

    dropdown_values = capsule_chosen

    if "All" in capsule_chosen:
        dropdown_values = capsuleID_names
        dff = df
    else:
        dff = df[df['Capsule_ID'].isin(capsule_chosen)]  # filter all rows where capsule ID is the capsule ID selected

    scatterplot = px.scatter(
        data_frame=dff,
        x="tcd",
        y="humidity",
        hover_name="Wallclock",
    )

    scatterplot.update_traces(textposition='top center')

    return scatterplot, dropdown_values


# ------------------------------------------------------------------------------

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

【问题讨论】:

    标签: python plotly plotly-dash dashboard rangeslider


    【解决方案1】:
    • 显然我无权访问您的 Excel 电子表格,因此生成了一个形状相同的数据框
    • 采取的方法是使用带有 rangeslider 的第二个图形来实现滑块功能
    • 更新了回调以将此数字用作日期范围的输入
    • 使用 jupyter dash inline,这可以改回您的设置(注释行)

    生成一些样本数据

    import pandas as pd
    import numpy as np
    df = pd.DataFrame(
        {
            "Wallclock": pd.date_range(
                "22-dec-2020 00:01:36", freq="5min", periods=2000
            ),
            "tcd": np.linspace(3434, 3505, 2000) *np.random.uniform(.9,1.1, 2000),
            "humidity": np.linspace(63, 96, 2000),
        }
    ).pipe(lambda d: d.assign(Capsule_ID=(d.index // (len(d)//16))+2100015))
    
    

    滑块是一个带有rangeslider的图形

    import pandas as pd
    import plotly.express as px  # (version 4.7.0)
    import plotly.graph_objects as go
    import numpy as np
    
    import openpyxl
    import dash  # (version 1.12.0) pip install dash
    import dash_core_components as dcc
    import dash_html_components as html
    from dash.dependencies import Input, Output, State
    from dash.exceptions import PreventUpdate
    from jupyter_dash import JupyterDash
    
    # app = dash.Dash(__name__)
    # server = app.server
    app = JupyterDash(__name__)
    
    
    # df = pd.read_excel("tcd vs rh 2.xlsx")
    # print(df)
    
    capsuleID = df["Capsule_ID"].unique()
    # print(capsuleID)
    
    capsuleID_names = sorted(list(capsuleID))
    # print(capsuleID_names)
    
    capsuleID_names_1 = [{"label": k, "value": k} for k in sorted(capsuleID)]
    capsuleID_names_2 = [{"label": "(Select All)", "value": "All"}]
    capsuleID_names_all = capsuleID_names_1 + capsuleID_names_2
    
    def slider_fig(df):
        return px.scatter(
                    df.groupby("Wallclock", as_index=False).size(), x="Wallclock", y="size"
                ).update_layout(
                    xaxis={"rangeslider": {"visible": True}, "title":None},
                    height=125,
                    yaxis={"tickmode": "array", "tickvals": [], "title": None},
                    margin={"l": 0, "r": 0, "t": 0, "b": 0},
                )
    
    app.layout = html.Div(
        [
            html.H1("Relative Humidity vs TCD", style={"text-align": "center"}),
            dcc.Dropdown(
                id="capsule_select",
                options=capsuleID_names_all,
                optionHeight=25,
                multi=True,
                searchable=True,
                placeholder="Please select...",
                clearable=True,
                value=["All"],
                style={"width": "100%"},
            ),
            dcc.Graph(
                id="slider",
                figure=slider_fig(df),
            ),
            html.Div(
                [
                    dcc.Graph(id="the_graph"),
                ]
            ),
        ]
    )
    
    # -----------------------------------------------------------
    @app.callback(
        Output("the_graph", "figure"),
        Output("capsule_select", "value"),
        Output("slider", "figure"),
        Input("capsule_select", "value"),
        Input('slider', 'relayoutData'),
        State("slider", "figure")
    )
    def update_graph(capsule_chosen, slider, sfig):
        dropdown_values = capsule_chosen
    
        if "All" in capsule_chosen:
            dropdown_values = capsuleID_names
            dff = df
        else:
            dff = df[
                df["Capsule_ID"].isin(capsule_chosen)
            ]  # filter all rows where capsule ID is the capsule ID selected
    
        
        if slider and "xaxis.range" in slider.keys():
            dff = dff.loc[dff["Wallclock"].between(*slider["xaxis.range"])]
        else:
            # update slider based on selected capsules
            sfig = slider_fig(dff)
            
        scatterplot = px.scatter(
            data_frame=dff,
            x="tcd",
            y="humidity",
            hover_name="Wallclock",
        )
    
        scatterplot.update_traces(textposition="top center")
    
        return scatterplot, dropdown_values, sfig
    
    
    # ------------------------------------------------------------------------------
    
    if __name__ == "__main__":
        #     app.run_server(debug=True)
        app.run_server(mode="inline")
    

    【讨论】:

    • 嗨,罗伯!感谢您的回复,这种方法是一个非常好的方法。可以根据胶囊调整日期范围滑块。例如,仅选择胶囊 2100015 会将范围滑块值更改为 22Dec20 到 26Dec20,而不是显示所有胶囊的整个日期范围。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多