Python Dash每60分钟更新一次数据帧



我有一个脚本,每小时收集一次数据,并用Plotly Dash将其可视化。

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
df = pd.read_csv("/home/pi/backup/data/data.csv").sort_values(by="Number")
df["Datetime"] = df["Datetime"].str.replace("T", " ").str.replace("Z", "")
df["Datetime"] = pd.to_datetime(df["Datetime"], format="%Y-%m-%d %H:%M:%S")
df["Datetime"] = df["Datetime"].dt.floor("H")
grouped = df.groupby(["Datetime", "Number", "Shop"]).min().reset_index()
app = dash.Dash(__name__)
tabs_styles = {
'height': '30px'
}
tab_style = {
'borderBottom': '1px solid #d6d6d6',
'padding': '6px',
'fontWeight': 'bold'
}
tab_selected_style = {
'borderTop': '1px solid #d6d6d6',
'borderBottom': '1px solid #d6d6d6',
'backgroundColor': '#119DFF',
'color': 'white',
'padding': '6px'
}
fig = px.line(grouped, x="Datetime", y="Price", hover_name="Price",
facet_col='Number', color="Shop", facet_col_wrap=5,
width=1900, height=850)
fig.update_yaxes(matches=None, title=None)
fig.update_xaxes(title=None)
fig.update_traces(line=dict(width=1))
fig.update_layout(transition_duration=500, hovermode="x unified")
app.layout = html.Div([
dcc.Tabs([
dcc.Tab(label ="Overview", children=[
dcc.Graph(
id='example-graph',
figure=fig
)
], style=tab_style, selected_style=tab_selected_style),
dcc.Tab(label = "Detail", children=[
dcc.Dropdown(id='Detail_Input', options=[
{'label': i, 'value': i} for i in df.sort_values(by=["Number"])["Number"].unique()
], multi=False, value=df["Number"].min()),
dcc.Graph(id="Detail_Graph"),
], style=tab_style, selected_style=tab_selected_style)
], style=tabs_styles)
])
@app.callback(
Output("Detail_Graph", "figure"),
[Input("Detail_Input", "value")])
def update_figure(input):
fig = px.line(grouped[grouped["Number"] == input], x="Datetime", y="Price", color="Shop", hover_name="Price",
width=1900, height=850)
fig.update_layout(transition_duration=500, hovermode="x unified")
return fig
if __name__ == '__main__':
app.run_server(debug=True,port=8050,host="0.0.0.0")

现在我想更新数据帧";df";每小时。或者,我可以检查文件"/home/pi/backup/data/data.csv";更新,如果是,则刷新数据。在谷歌或stackoverflow上找到了一些想法,但无法将其改编为我的剧本(我对Dash很陌生……来自R Shiny(。

我建议采用以下方法,

  • 创建一个回调(A(来更新数据。虽然您可以手动进行更新(即检查文件时间戳并根据需要进行更新(,但使用带有超时的服务器端缓存(如Flask Caching(可能会更容易。

  • 创建第二个回调(B(,当回调a中的数据发生变化时绘制图形。

如果你想要实时更新(即不刷新页面(,你应该使用Interval组件来触发回调A。下面是一个使用dash_extensions==0.0.28包的小例子,

import dash_html_components as html
import dash_core_components as dcc
from datetime import datetime
from dash_extensions.enrich import Dash, Trigger, Output, Input, ServersideOutput, FileSystemStore
# Create server side store to hold the data.
fss = FileSystemStore(cache_dir="some_dir", default_timeout=10)  # timeout in seconds, i.e. yours should be 3600
# Create an example app.
app = Dash(__name__)
app.layout = html.Div([
html.Div(id="log"),  # logging of data, a mock replacement of your graph
dcc.Store(id="store"),  # store that holds the data reference
dcc.Interval(id="trigger", interval=1000),  # trigger to invoke data refresh attempt, defaults to once per second
])

@app.callback(ServersideOutput("store", "data", session_check=False, backend=fss),
Trigger("trigger", "n_intervals"), memoize=True)
def update_data():
return datetime.now()  # put your update logic here

@app.callback(Output("log", "children"), Input("store", "data"))
def show_data(data):
return f"Data were collected at {data}, current time is {datetime.now()}"  # put your graph drawing code here

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

免责声明:我是dash_extensions的作者。

现在我找到了一个适合我的解决方案。不知道它是否是最佳实践。所以,如果有人有进步,我将不胜感激。

尽管如此,它只是一些MB的数据。性能不应该成为问题。

import dash
import dash_auth
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd

df = pd.read_csv("/home/pi/backup/lego/log.csv")
app = dash.Dash(__name__)
auth = dash_auth.BasicAuth(
app,
VALID_USERNAME_PASSWORD_PAIRS
)
tabs_styles = {
'height': '30px'
}
tab_style = {
'borderBottom': '1px solid #d6d6d6',
'padding': '6px',
'fontWeight': 'bold'
}
tab_selected_style = {
'borderTop': '1px solid #d6d6d6',
'borderBottom': '1px solid #d6d6d6',
'backgroundColor': '#119DFF',
'color': 'white',
'padding': '6px'
}
app.layout = html.Div([
dcc.Tabs([
dcc.Tab(label ="Overview", children=[
dcc.Interval(id="interval", interval=60000), dcc.Graph(id="output")
], style=tab_style, selected_style=tab_selected_style),
dcc.Tab(label = "Detail", children=[
dcc.Dropdown(id='Detail_Input', options=[
{'label': i, 'value': i} for i in df.sort_values(by=["Number"])["Number"].unique()
], multi=False, value=df["Number"].min()),
dcc.Graph(id="Detail_Graph",
config={
'displayModeBar': False
}),
], style=tab_style, selected_style=tab_selected_style)
], style=tabs_styles)
])
@app.callback(Output("output", "figure"), [Input("interval", "n_intervals")])
def display_time(n):
df = pd.read_csv("/home/pi/backup/lego/log.csv")
df["Datetime"] = df["Datetime"].str.replace("T", " ").str.replace("Z", "")
df["Datetime"] = pd.to_datetime(df["Datetime"], format="%Y-%m-%d %H:%M:%S")
df["Datetime"] = df["Datetime"].dt.floor("H")
grouped = df.groupby(["Datetime", "Number", "Shop"]).min().reset_index().sort_values(by=["Number", "Datetime"])
fig = px.line(grouped, x="Datetime", y="Price", hover_name="Price",
facet_col='Number', color="Shop", facet_col_wrap=6,
width=1900, height=850)
return fig
@app.callback(
Output("Detail_Graph", "figure"),
[Input("Detail_Input", "value")])
def update_figure(input):
df = pd.read_csv("/home/pi/backup/lego/log.csv")
df["Datetime"] = df["Datetime"].str.replace("T", " ").str.replace("Z", "")
df["Datetime"] = pd.to_datetime(df["Datetime"], format="%Y-%m-%d %H:%M:%S")
df["Datetime"] = df["Datetime"].dt.floor("H")
grouped = df.groupby(["Datetime", "Number", "Shop"]).min().reset_index().sort_values(by=["Number", "Datetime"])
fig = px.line(grouped[grouped["Number"] == input], x="Datetime", y="Price", color="Shop", hover_name="Price",
width=1900, height=850)
fig.update_layout(transition_duration=500, hovermode="x unified")
return fig
if __name__ == '__main__':
app.run_server(debug=True,port=8050,host="0.0.0.0")

最新更新