英文:
Set specific colour map to Bar-chart with callback - dash Plotly
问题
我有一个交互式的条形图,显示了一周中每天的计数。我试图设置颜色映射,使每周的每一天保持相同的颜色。目前,如果我移除任何一天,颜色会改变。
另外,是否可能保持一周中的相同下拉值,并映射相同的颜色顺序,但绘制DATES
而不是一周的天数?
html.Label('星期几:', style={'paddingTop': '2rem'}),
dcc.Dropdown(
id='DOW',
options=[
{'label': x, 'value': x} for x in df['DOW'].unique()
],
value=['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'],
multi=True
),
@app.callback(
Output('date-bar-chart', 'figure'),
[Input("DOW", "value"),
])
def date_chart(dow):
dff = df[df['DOW'].isin(dow)]
count = dff['DOW'].value_counts()
dff['Color'] = dff['DOW'].map(dict(zip(dff['DOW'].unique(),
px.colors.qualitative.Plotly[:len(dff['DOW'].unique())])))
Color = dff['Color'].unique()
Category = dff['DOW'].unique()
cats = dict(zip(Color, Category))
data = px.bar(x = count.index,
y = count.values,
color = count.index,
color_discrete_map = cats,
)
layout = go.Layout(title = '日期')
fig = go.Figure(data = data, layout = layout)
return fig
英文:
I've got an interactive bar chart that displays counts from days of the week. I'm trying to set the color map so each day of the week maintains the same color. At the moment, if I remove any days, the color changes.
Separately, is it possible to keep the same dropdown values for days of the week and map the same color sequence but plot DATES
instead of days of the week?
from dash import dcc
from dash import html
import dash_bootstrap_components as dbc
import dash
from dash.dependencies import Input, Output, State
from datetime import datetime
import plotly.graph_objs as go
import plotly.express as px
import pandas as pd
import numpy as np
from datetime import datetime as dt
df = pd.DataFrame({
'Type': ['A','B','B','B','C','C','D','E','E','E','E','F','F','F'],
})
N = 30
df = pd.concat([df] * N, ignore_index=True)
df['TIMESTAMP'] = pd.date_range(start='2022/01/01 07:30', end='2022/01/30 08:30', periods=len(df))
df['TIMESTAMP'] = pd.to_datetime(df['TIMESTAMP'], dayfirst = True).sort_values()
df['TIMESTAMP'] = df['TIMESTAMP'].dt.floor('1min')
df['DATE'], df['TIME'] = zip(*[(d.date(), d.time()) for d in df['TIMESTAMP']])
df['DATE'] = pd.to_datetime(df['DATE'])
df['YEAR'] = df['DATE'].dt.year
df = df.sort_values(by = 'DATE')
df['DOW'] = df['DATE'].dt.weekday
df = df.sort_values('DOW').reset_index(drop=True)
df['DOW'] = df['DATE'].dt.day_name()
external_stylesheets = [dbc.themes.SPACELAB, dbc.icons.BOOTSTRAP]
app = dash.Dash(__name__, external_stylesheets = external_stylesheets)
filter_box = html.Div(children=[
################### Filter box ######################
html.Div(children=[
html.Label('Day of the week:', style={'paddingTop': '2rem'}),
dcc.Dropdown(
id='DOW',
options=[
{'label': x, 'value': x} for x in df['DOW'].unique()
],
value=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday','Sunday'],
multi=True
),
], className="four columns",
style={'padding':'2rem', 'margin':'1rem'} )
])
app.layout = dbc.Container([
dbc.Row([
dbc.Col(html.Div(filter_box, className="bg-secondary h-100"), width=2),
dbc.Col([
dbc.Row([
dbc.Col(),
]),
dbc.Row([
dbc.Col(dcc.Graph(id = 'date-bar-chart'), style={
"padding-bottom": "10px",
},),
]),
dbc.Row([
]),
], width=5),
dbc.Col([
dbc.Row([
dbc.Col(),
]),
], width=5),
])
], fluid=True)
@app.callback(
Output('date-bar-chart', 'figure'),
[Input("DOW", "value"),
])
def date_chart(dow):
dff = df[df['DOW'].isin(dow)]
count = dff['DOW'].value_counts()
dff['Color'] = dff['DOW'].map(dict(zip(dff['DOW'].unique(),
px.colors.qualitative.Plotly[:len(dff['DOW'].unique())])))
Color = dff['Color'].unique()
Category = dff['DOW'].unique()
cats = dict(zip(Color, Category))
data = px.bar(x = count.index,
y = count.values,
color = count.index,
color_discrete_map = cats,
)
layout = go.Layout(title = 'Date')
fig = go.Figure(data = data, layout = layout)
return fig
if __name__ == '__main__':
app.run_server(debug=True, port = 8051)
答案1
得分: 3
接受的答案过于复杂,没有回答第二个问题。
对于color_discrete_map
参数的第一个问题,您应该像这样定义一个合适的字典,其中键是星期几的名称,值是颜色。您不需要df['Color']
,Color
,Category
等。
import pandas as pd
...
color_map = {
pd.Timestamp(2023, 2, 13+i).day_name(): # 2-13是星期一。
px.colors.qualitative.Plotly[i]
for i in range(7)
}
...
def date_chart(dow):
dff = df[df['DOW'].isin(dow)]
count = dff['DOW'].value_counts()
data = px.bar(x = count.index,
y = count.values,
color = count.index,
color_discrete_map = color_map,
)
...
对于第二个问题,您需要选择与给定星期几匹配的行的逻辑。以下是一个选择第一行的示例(这使用了group_by()
,所以不需要value_counts()
)。
def date_chart(dow):
dff = df[df['DOW'].isin(dow)]
g = dff.groupby('DOW', as_index=False)
g_df = g.head(1).merge(g.size())
data = px.bar(x = g_df['DATE'],
y = g_df['size'],
color = g_df['DOW'],
color_discrete_map = color_map,
)
...
英文:
The accepted answer is too complicated and doesn't answer the second question.
For the first question on the color_discrete_map
parameter, you should define a proper dictionary with keys as week day names and values as colors like this. You don't need df['Color']
, Color
, Category
, etc.
import pandas as pd
...
color_map = {
pd.Timestamp(2023, 2, 13+i).day_name(): # 2-13 was monday.
px.colors.qualitative.Plotly[i]
for i in range(7)
}
...
def date_chart(dow):
dff = df[df['DOW'].isin(dow)]
count = dff['DOW'].value_counts()
data = px.bar(x = count.index,
y = count.values,
color = count.index,
color_discrete_map = color_map,
)
...
For the second question, you need a logic to choose one of the rows matching a given week day. The following is one example which chooses the first one.(This uses the group_by()
, so the value_counts()
is not necessary.)
def date_chart(dow):
dff = df[df['DOW'].isin(dow)]
g = dff.groupby('DOW', as_index=False)
g_df = g.head(1).merge(g.size())
data = px.bar(x = g_df['DATE'],
y = g_df['size'],
color = g_df['DOW'],
color_discrete_map = color_map,
)
...
答案2
得分: 2
因为您在回调函数中设置了cats
,所以每次根据筛选更改您的dff
,您的字典都会被更改。所以我认为您应该使用df
而不是dff
来定义您的color_discrete_map
。而且,我认为您应该将cats
更改为cats = dict(zip(Category, Color))
。
from dash import dcc
from dash import html
import dash_bootstrap_components as dbc
import dash
from dash.dependencies import Input, Output, State
from datetime import datetime
import plotly.graph_objs as go
import plotly.express as px
import pandas as pd
import numpy as np
from datetime import datetime as dt
df = pd.DataFrame({
'Type': ['A', 'B', 'B', 'B', 'C', 'C', 'D', 'E', 'E', 'E', 'E', 'F', 'F', 'F'],
})
N = 30
df = pd.concat([df] * N, ignore_index=True)
df['TIMESTAMP'] = pd.date_range(start='2022/01/01 07:30', end='2022/01/30 08:30', periods=len(df))
df['TIMESTAMP'] = pd.to_datetime(df['TIMESTAMP'], dayfirst=True).sort_values()
df['TIMESTAMP'] = df['TIMESTAMP'].dt.floor('1min')
df['DATE'], df['TIME'] = zip(*[(d.date(), d.time()) for d in df['TIMESTAMP']])
df['DATE'] = pd.to_datetime(df['DATE'])
df['YEAR'] = df['DATE'].dt.year
df = df.sort_values(by='DATE')
df['DOW'] = df['DATE'].dt.weekday
df = df.sort_values('DOW').reset_index(drop=True)
df['DOW'] = df['DATE'].dt.day_name()
df['Color'] = df['DOW'].map(dict(zip(df['DOW'].unique(), px.colors.qualitative.Plotly[:len(df['DOW'].unique())]))
Color = df['Color'].unique()
Category = df['DOW'].unique()
cats = dict(zip(Category, Color))
external_stylesheets = [dbc.themes.SPACELAB, dbc.icons.BOOTSTRAP]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
filter_box = html.Div(children=[
################### Filter box ######################
html.Div(children=[
html.Label('Day of the week:', style={'paddingTop': '2rem'}),
dcc.Dropdown(
id='DOW',
options=[
{'label': x, 'value': x} for x in df['DOW'].unique()
],
value=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
multi=True
),
], className="four columns",
style={'padding': '2rem', 'margin': '1rem'})
])
app.layout = dbc.Container([
dbc.Row([
dbc.Col(html.Div(filter_box, className="bg-secondary h-100"), width=2),
dbc.Col([
dbc.Row([
dbc.Col(),
]),
dbc.Row([
dbc.Col(dcc.Graph(id='date-bar-chart'), style={
"padding-bottom": "10px",
},),
]),
dbc.Row([
]),
], width=5),
dbc.Col([
dbc.Row([
dbc.Col(),
]),
], width=5),
])
], fluid=True)
@app.callback(
Output('date-bar-chart', 'figure'),
[Input("DOW", "value"),
])
def date_chart(dow):
dff = df[df['DOW'].isin(dow)]
count = dff['DOW'].value_counts()
data = px.bar(x=count.index,
y=count.values,
color=count.index,
color_discrete_map=cats,
)
return data
if __name__ == '__main__':
app.run_server(debug=False, port=8051)
上述代码是您提供的代码,只翻译了您要修改的部分。如果您有其他问题或需要更多帮助,请随时提出。
英文:
Because you are setting cats
in your callback so each time your dff change based on filter, your dict will be changed. So that I think you should define your color_discrete_map
with df, not dff. And I think you should change your cats to cats = dict(zip(Category,Color))
from dash import dcc
from dash import html
import dash_bootstrap_components as dbc
import dash
from dash.dependencies import Input, Output, State
from datetime import datetime
import plotly.graph_objs as go
import plotly.express as px
import pandas as pd
import numpy as np
from datetime import datetime as dt
df = pd.DataFrame({
'Type': ['A','B','B','B','C','C','D','E','E','E','E','F','F','F'],
})
N = 30
df = pd.concat([df] * N, ignore_index=True)
df['TIMESTAMP'] = pd.date_range(start='2022/01/01 07:30', end='2022/01/30 08:30', periods=len(df))
df['TIMESTAMP'] = pd.to_datetime(df['TIMESTAMP'], dayfirst = True).sort_values()
df['TIMESTAMP'] = df['TIMESTAMP'].dt.floor('1min')
df['DATE'], df['TIME'] = zip(*[(d.date(), d.time()) for d in df['TIMESTAMP']])
df['DATE'] = pd.to_datetime(df['DATE'])
df['YEAR'] = df['DATE'].dt.year
df = df.sort_values(by = 'DATE')
df['DOW'] = df['DATE'].dt.weekday
df = df.sort_values('DOW').reset_index(drop=True)
df['DOW'] = df['DATE'].dt.day_name()
df['Color'] = df['DOW'].map(dict(zip(df['DOW'].unique(),
px.colors.qualitative.Plotly[:len(df['DOW'].unique())])))
Color = df['Color'].unique()
Category = df['DOW'].unique()
cats = dict(zip(Category,Color))
external_stylesheets = [dbc.themes.SPACELAB, dbc.icons.BOOTSTRAP]
app = dash.Dash(__name__, external_stylesheets = external_stylesheets)
filter_box = html.Div(children=[
################### Filter box ######################
html.Div(children=[
html.Label('Day of the week:', style={'paddingTop': '2rem'}),
dcc.Dropdown(
id='DOW',
options=[
{'label': x, 'value': x} for x in df['DOW'].unique()
],
value=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday','Sunday'],
multi=True
),
], className="four columns",
style={'padding':'2rem', 'margin':'1rem'} )
])
app.layout = dbc.Container([
dbc.Row([
dbc.Col(html.Div(filter_box, className="bg-secondary h-100"), width=2),
dbc.Col([
dbc.Row([
dbc.Col(),
]),
dbc.Row([
dbc.Col(dcc.Graph(id = 'date-bar-chart'), style={
"padding-bottom": "10px",
},),
]),
dbc.Row([
]),
], width=5),
dbc.Col([
dbc.Row([
dbc.Col(),
]),
], width=5),
])
], fluid=True)
@app.callback(
Output('date-bar-chart', 'figure'),
[Input("DOW", "value"),
])
def date_chart(dow):
dff = df[df['DOW'].isin(dow)]
count = dff['DOW'].value_counts()
data = px.bar(x = count.index,
y = count.values,
color = count.index,
color_discrete_map = cats,
)
return data
if __name__ == '__main__':
app.run_server(debug=False, port = 8051)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论