将特定颜色映射设置给带有回调的柱状图 – Dash Plotly

huangapple go评论62阅读模式
英文:

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']ColorCategory等。

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)

将特定颜色映射设置给带有回调的柱状图 – Dash Plotly

huangapple
  • 本文由 发表于 2023年2月16日 07:53:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/75466520.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定