将 x 轴更改为一年中连续的一周(WK52、WK01...)
Change x-axis to continuous week of the year (WK52,WK01...)
下午好,
我目前正在 Python 中构建 Dash 应用程序。此应用程序的目标是可视化预测并将其与过去几年的数据进行比较。
我 运行 遇到的问题是:我希望我的 x 轴在一年中的第几周(星期日开始)而不是日期。
到目前为止,我尝试创建一个周列并将其用于我的绘图。问题是 WK01 不会在 WK52 之后,它会在我的情节开始时出现,这是我不想要的。理想情况下,我希望在我的情节中有 10 周以上的时间范围和 -10 与今天的日期(例如 2019 年和 2018 年的 WK45)。
我的 df 和 actuals 布局如下:
category date store brand volume week year version
BAG 2019-09-22 LONDON LV ... 2428.0 38 2019 FCT
BAG 2019-09-29 LONDON LV ... 0.0 39 2019 FCT
BAG 2019-10-06 LONDON LV ... 0.0 40 2019 DFT
BAG 2019-10-13 LONDON LV ... 0.0 41 2019 FCT
BAG 2019-10-20 LONDON LV ... 0.0 42 2019 DFT
这是我的代码:
# Import required libraries
import pandas as pd
from flask import Flask
import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
import datetime
from datetime import datetime as dt
app = dash.Dash(__name__)
server = app.server
#Data preparation
df = pd.read_csv('Export.csv')
actuals = pd.read_csv('actuals.csv')
df['date'] = pd.to_datetime(df['date'])
df['year'] = pd.DatetimeIndex(df['date']).year
actuals['date'] = pd.to_datetime(actuals['date'])
actuals['year'] = actuals['date'].dt.year
df['week'] = pd.DatetimeIndex(df['date']).week
actuals['week'] = actuals['date'].dt.week
df = pd.concat([df, actuals])
upperdatelimit = (pd.datetime.today() + pd.to_timedelta(pd.np.ceil(10), unit="W")).strftime('%Y-%m-%d')
lowerdatelimit = (pd.datetime.today() + pd.to_timedelta(pd.np.ceil(-10), unit="W")).strftime('%Y-%m-%d')
mask = (df['date'] <= upperdatelimit) & (df['date'] >= lowerdatelimit)
df = df.loc[mask]
# Create controls
brand_options = [{'label': str(brand), 'value': str(brand)}
for brand in df['brand'].unique()]
year_options = [{'label': year,
'value': year}
for year in actuals['year'].unique()]
store_options = [{'label': str(store), 'value': str(store)}
for store in df['store'].unique()]
category_options = [{'label': str(category),
'value': str(category)}
for category in df['category'].unique()]
# Load data
app.layout = html.Div(
[
dcc.Store(id='aggregate_data'),
html.Div(
[
html.Div(
[
html.H2(
'Phantasm',
),
html.H4(
'Forecast Overview',
)
],
className='eight columns'
),
html.Img(
src="x.png",
className='two columns',
),
],
id="header",
className='row',
),
html.Div(
[
html.Div(
[
html.P(
'Actuals Comparison Year',
className="control_label"
),
dcc.Dropdown(
id='dropdown',
options=year_options,
multi=False,
value=pd.datetime.today().year - 1,
className="dcc_control"
),
html.P(
'Filter by category:',
className="control_label"
),
dcc.Dropdown(
id='category_names',
options=category_options,
multi=True,
value=list(df['category'].unique()),
className="dcc_control"
),
html.P(
'Filter by brand:',
className="control_label"
),
dcc.Dropdown(
id='brand_names',
options=brand_options,
multi=True,
value=list(df['brand'].unique()),
className="dcc_control"
),
html.P(
'Filter by store:',
className="control_label"
),
dcc.Dropdown(
id='store_names',
options=store_options,
multi=True,
value=list(df['store'].unique()),
className="dcc_control"
),
],
className="pretty_container four columns"
),
html.Div(
[
html.Div(
[
html.Div(
[
html.Div(
[
html.P("Hermes"),
html.H6(
id="brand_text",
className="info_text"
)
],
id="Hermes",
className="pretty_container"
),
html.Div(
[
html.P("LV"),
html.H6(
id="branda_text",
className="info_text"
)
],
id="LV",
className="pretty_container"
),
html.Div(
[
html.P("Valentino"),
html.H6(
id="brandb_text",
className="info_text"
)
],
id="valentino",
className="pretty_container"
),
],
id="tripleContainer",
)
],
id="infoContainer",
className="row"
),
html.Div(
[
dcc.Graph(
id='count_graph',
)
],
id="countGraphContainer",
className="pretty_container"
)
],
id="rightCol",
className="eight columns"
)
],
className="row"
),
html.Div(
[
html.Div(
[
dcc.Graph(id='main_graph')
],
className='pretty_container eight columns',
),
html.Div(
[
dcc.Graph(id='individual_graph')
],
className='pretty_container four columns',
),
],
className='row'
),
html.Div(
[
html.Div(
[
dcc.Graph(id='pie_graph')
],
className='pretty_container seven columns',
),
html.Div(
[
dcc.Graph(id='aggregate_graph')
],
className='pretty_container five columns',
),
],
className='row'
),
],
id="mainContainer",
style={
"display": "flex",
"flex-direction": "column"
}
)
# Create callbacks
@app.callback(Output('brand_text', 'children'),
[Input('store_names', 'value'),
Input('category_names', 'value')])
def update_forecast_text(store_names,category_names):
dff = df[df['store'].isin(store_names) & df['category'].isin(category_names)
& df['brand'].isin(['Hermes']) & df['version'].isin(['DFT'])]
return ""+"{:,}".format(int(dff['volume'].sum()))
@app.callback(Output('branda_text', 'children'),
[Input('store_names', 'value'),
Input('category_names', 'value')])
def update_forecast_text(store_names,category_names):
dff = df[df['store'].isin(store_names) & df['category'].isin(category_names)
& df['brand'].isin(['LV']) & df['version'].isin(['DFT'])]
return ""+"{:,}".format(int(dff['volume'].sum()))
@app.callback(Output('brandb_text', 'children'),
[Input('store_names', 'value'),
Input('category_names', 'value')])
def update_forecast_text(store_names,category_names):
dff = df[df['store'].isin(store_names) & df['category'].isin(category_names)
& df['brand'].isin(['Valentino']) & df['version'].isin(['DFT'])]
return ""+"{:,}".format(int(dff['volume'].sum()))
@app.callback(Output('main_graph', 'figure'),
[Input('dropdown', 'value'),
Input('store_names', 'value'),
Input('category_names', 'value'),
Input('brand_names','value')])
def update_graph(dropdown_value,store_names,category_names,brand_names):
actualsdf = actuals[actuals['year'] == dropdown_value]
dffdraft = df[df['store'].isin(store_names) & df['category'].isin(category_names)
& df['brand'].isin(brand_names) & df['version'].isin(['DFT','ACTUALS'])]
dfffct = df[df['store'].isin(store_names) & df['category'].isin(category_names)
& df['brand'].isin(brand_names) & df['version'].isin(['FCT','ACTUALS'])]
dffactuals = actualsdf[actualsdf['store'].isin(store_names) & actualsdf['category'].isin(category_names)
& actualsdf['brand'].isin(brand_names) & actualsdf['version'].isin(['ACTUALS'])]
dffdraft = dffdraft.groupby('date')['volume'].sum().reset_index()
dfffct = dfffct.groupby('date')['volume'].sum().reset_index()
dffactuals = dffactuals.groupby('date')['volume'].sum().reset_index()
trace1 = go.Scatter(y=dffdraft['volume'],x=dffdraft['date'],mode='lines',name='Draft')
trace2 = go.Scatter(y=dfffct['volume'], x=dfffct['date'], mode='lines', name='Forecast')
trace3 = go.Scatter(y=dffactuals['volume'], x=dffactuals['date'], mode='lines', name='Actuals')
data = [trace1,trace2,trace3]
return {"data": data}
# Main
if __name__ == '__main__':
app.server.run(debug=True, threaded=True)
非常感谢!
Goal
Current output
解决此问题的一种方法是使用日期列作为绘图的 x 值,然后设置刻度格式:
return {"data": data, "layout": {"xaxis": {"tickformat": "W%W"}}}
这里是 documentation and an example and here the date formats.
如果这不符合您的需要,您始终可以选择使用自定义刻度位置和标签。这是更多的工作,但它是完全可定制的。这是一个 example.
下午好,
我目前正在 Python 中构建 Dash 应用程序。此应用程序的目标是可视化预测并将其与过去几年的数据进行比较。
我 运行 遇到的问题是:我希望我的 x 轴在一年中的第几周(星期日开始)而不是日期。
到目前为止,我尝试创建一个周列并将其用于我的绘图。问题是 WK01 不会在 WK52 之后,它会在我的情节开始时出现,这是我不想要的。理想情况下,我希望在我的情节中有 10 周以上的时间范围和 -10 与今天的日期(例如 2019 年和 2018 年的 WK45)。
我的 df 和 actuals 布局如下:
category date store brand volume week year version
BAG 2019-09-22 LONDON LV ... 2428.0 38 2019 FCT
BAG 2019-09-29 LONDON LV ... 0.0 39 2019 FCT
BAG 2019-10-06 LONDON LV ... 0.0 40 2019 DFT
BAG 2019-10-13 LONDON LV ... 0.0 41 2019 FCT
BAG 2019-10-20 LONDON LV ... 0.0 42 2019 DFT
这是我的代码:
# Import required libraries
import pandas as pd
from flask import Flask
import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
import datetime
from datetime import datetime as dt
app = dash.Dash(__name__)
server = app.server
#Data preparation
df = pd.read_csv('Export.csv')
actuals = pd.read_csv('actuals.csv')
df['date'] = pd.to_datetime(df['date'])
df['year'] = pd.DatetimeIndex(df['date']).year
actuals['date'] = pd.to_datetime(actuals['date'])
actuals['year'] = actuals['date'].dt.year
df['week'] = pd.DatetimeIndex(df['date']).week
actuals['week'] = actuals['date'].dt.week
df = pd.concat([df, actuals])
upperdatelimit = (pd.datetime.today() + pd.to_timedelta(pd.np.ceil(10), unit="W")).strftime('%Y-%m-%d')
lowerdatelimit = (pd.datetime.today() + pd.to_timedelta(pd.np.ceil(-10), unit="W")).strftime('%Y-%m-%d')
mask = (df['date'] <= upperdatelimit) & (df['date'] >= lowerdatelimit)
df = df.loc[mask]
# Create controls
brand_options = [{'label': str(brand), 'value': str(brand)}
for brand in df['brand'].unique()]
year_options = [{'label': year,
'value': year}
for year in actuals['year'].unique()]
store_options = [{'label': str(store), 'value': str(store)}
for store in df['store'].unique()]
category_options = [{'label': str(category),
'value': str(category)}
for category in df['category'].unique()]
# Load data
app.layout = html.Div(
[
dcc.Store(id='aggregate_data'),
html.Div(
[
html.Div(
[
html.H2(
'Phantasm',
),
html.H4(
'Forecast Overview',
)
],
className='eight columns'
),
html.Img(
src="x.png",
className='two columns',
),
],
id="header",
className='row',
),
html.Div(
[
html.Div(
[
html.P(
'Actuals Comparison Year',
className="control_label"
),
dcc.Dropdown(
id='dropdown',
options=year_options,
multi=False,
value=pd.datetime.today().year - 1,
className="dcc_control"
),
html.P(
'Filter by category:',
className="control_label"
),
dcc.Dropdown(
id='category_names',
options=category_options,
multi=True,
value=list(df['category'].unique()),
className="dcc_control"
),
html.P(
'Filter by brand:',
className="control_label"
),
dcc.Dropdown(
id='brand_names',
options=brand_options,
multi=True,
value=list(df['brand'].unique()),
className="dcc_control"
),
html.P(
'Filter by store:',
className="control_label"
),
dcc.Dropdown(
id='store_names',
options=store_options,
multi=True,
value=list(df['store'].unique()),
className="dcc_control"
),
],
className="pretty_container four columns"
),
html.Div(
[
html.Div(
[
html.Div(
[
html.Div(
[
html.P("Hermes"),
html.H6(
id="brand_text",
className="info_text"
)
],
id="Hermes",
className="pretty_container"
),
html.Div(
[
html.P("LV"),
html.H6(
id="branda_text",
className="info_text"
)
],
id="LV",
className="pretty_container"
),
html.Div(
[
html.P("Valentino"),
html.H6(
id="brandb_text",
className="info_text"
)
],
id="valentino",
className="pretty_container"
),
],
id="tripleContainer",
)
],
id="infoContainer",
className="row"
),
html.Div(
[
dcc.Graph(
id='count_graph',
)
],
id="countGraphContainer",
className="pretty_container"
)
],
id="rightCol",
className="eight columns"
)
],
className="row"
),
html.Div(
[
html.Div(
[
dcc.Graph(id='main_graph')
],
className='pretty_container eight columns',
),
html.Div(
[
dcc.Graph(id='individual_graph')
],
className='pretty_container four columns',
),
],
className='row'
),
html.Div(
[
html.Div(
[
dcc.Graph(id='pie_graph')
],
className='pretty_container seven columns',
),
html.Div(
[
dcc.Graph(id='aggregate_graph')
],
className='pretty_container five columns',
),
],
className='row'
),
],
id="mainContainer",
style={
"display": "flex",
"flex-direction": "column"
}
)
# Create callbacks
@app.callback(Output('brand_text', 'children'),
[Input('store_names', 'value'),
Input('category_names', 'value')])
def update_forecast_text(store_names,category_names):
dff = df[df['store'].isin(store_names) & df['category'].isin(category_names)
& df['brand'].isin(['Hermes']) & df['version'].isin(['DFT'])]
return ""+"{:,}".format(int(dff['volume'].sum()))
@app.callback(Output('branda_text', 'children'),
[Input('store_names', 'value'),
Input('category_names', 'value')])
def update_forecast_text(store_names,category_names):
dff = df[df['store'].isin(store_names) & df['category'].isin(category_names)
& df['brand'].isin(['LV']) & df['version'].isin(['DFT'])]
return ""+"{:,}".format(int(dff['volume'].sum()))
@app.callback(Output('brandb_text', 'children'),
[Input('store_names', 'value'),
Input('category_names', 'value')])
def update_forecast_text(store_names,category_names):
dff = df[df['store'].isin(store_names) & df['category'].isin(category_names)
& df['brand'].isin(['Valentino']) & df['version'].isin(['DFT'])]
return ""+"{:,}".format(int(dff['volume'].sum()))
@app.callback(Output('main_graph', 'figure'),
[Input('dropdown', 'value'),
Input('store_names', 'value'),
Input('category_names', 'value'),
Input('brand_names','value')])
def update_graph(dropdown_value,store_names,category_names,brand_names):
actualsdf = actuals[actuals['year'] == dropdown_value]
dffdraft = df[df['store'].isin(store_names) & df['category'].isin(category_names)
& df['brand'].isin(brand_names) & df['version'].isin(['DFT','ACTUALS'])]
dfffct = df[df['store'].isin(store_names) & df['category'].isin(category_names)
& df['brand'].isin(brand_names) & df['version'].isin(['FCT','ACTUALS'])]
dffactuals = actualsdf[actualsdf['store'].isin(store_names) & actualsdf['category'].isin(category_names)
& actualsdf['brand'].isin(brand_names) & actualsdf['version'].isin(['ACTUALS'])]
dffdraft = dffdraft.groupby('date')['volume'].sum().reset_index()
dfffct = dfffct.groupby('date')['volume'].sum().reset_index()
dffactuals = dffactuals.groupby('date')['volume'].sum().reset_index()
trace1 = go.Scatter(y=dffdraft['volume'],x=dffdraft['date'],mode='lines',name='Draft')
trace2 = go.Scatter(y=dfffct['volume'], x=dfffct['date'], mode='lines', name='Forecast')
trace3 = go.Scatter(y=dffactuals['volume'], x=dffactuals['date'], mode='lines', name='Actuals')
data = [trace1,trace2,trace3]
return {"data": data}
# Main
if __name__ == '__main__':
app.server.run(debug=True, threaded=True)
非常感谢!
Goal
Current output
解决此问题的一种方法是使用日期列作为绘图的 x 值,然后设置刻度格式:
return {"data": data, "layout": {"xaxis": {"tickformat": "W%W"}}}
这里是 documentation and an example and here the date formats.
如果这不符合您的需要,您始终可以选择使用自定义刻度位置和标签。这是更多的工作,但它是完全可定制的。这是一个 example.