简体   繁体   中英

Adding Control filters to Plotly Bar Chart

I'm trying to add filter selection to my Plotly Bar. Here's the working Code:

import plotly.express as px
import plotly.graph_objects as go
# from plotly.subplots import make_subplots
import plotly as py
import pandas as pd
from plotly import tools

d = {'Mkt_cd': ['Mkt1','Mkt2','Mkt3','Mkt4','Mkt5','Mkt1','Mkt2','Mkt3','Mkt4','Mkt5'],
       'Category': ['Apple','Orange','Grape','Mango','Orange','Mango','Apple','Grape','Apple','Orange'],
           'CategoryKey': ['Mkt1Apple','Mkt2Orange','Mkt3Grape','Mkt4Mango','Mkt5Orange','Mkt1Mango','Mkt2Apple','Mkt3Grape','Mkt4Apple','Mkt5Orange'],
            'Current': [15,9,20,10,20,8,10,21,18,14],
           'Goal': [50,35,21,44,20,24,14,29,28,19],
            'Q1': [30,25,11,34,10,14,4,19,8,9]
     }
dataset  = pd.DataFrame(d)

grouped = dataset.groupby('Category', as_index=False).sum()
data = grouped.to_dict(orient='list')
v_cat = grouped['Category'].tolist()
v_current = grouped['Current']
v_goal = grouped['Goal']
v_q1 = grouped['Q1']
fig = go.Figure()
fig.add_trace(go.Bar(
    x=v_current,
    y=v_cat,
    marker_color="#ff0000",
    orientation='h',
    width=0.25
    ))
for i, g in enumerate(v_goal):
    a=fig.add_shape(type="rect",
                    x0=g+0.5, y0=v_cat[i], x1=g, y1=v_cat[i],
                    line=dict(color='#636EFA', width = 58))

for i, g in enumerate(v_q1):
    b=fig.add_shape(type="rect",
                    x0=g+0.5, y0=v_cat[i], x1=g, y1=v_cat[i],
                    line=dict(color='#636EFA', width = 58))    

#Adding Buttons here, first for Mkt_cd
buttons = []
groups = dataset['Mkt_cd'].unique().tolist()
frame={}
for i in groups:
    frame[str(i)]=dataset[dataset['Mkt_cd']==i]

for k in frame.keys():
    buttons.append(dict(method='restyle',label=k,
                        args=[{'y':[frame[str(k)]['Mkt_cd'].values],
                               'type':'bar'}, [0]],
                        )
                  )
updatemenu = []
your_menu = dict()
updatemenu.append(your_menu)

updatemenu[0]['buttons'] = buttons
updatemenu[0]['direction'] = 'down'
updatemenu[0]['showactive'] = True

fig.update_layout(barmode='relative', updatemenus=updatemenu)
fig.show()

My dataset is in un-aggregated form at the Key level. I group it together at the Category level with Grouped. I want to add two filters:

1st) Mkt_Cd filter. User should be able to select their market and see how their categories are doing in their markets. This should ideally be a multi-select filter where you can add a bunch of markets and see how the numbers are looking, and it should also filter the Goals and Q1 numbers

2nd) Goals Filter. Users should be able to select which trace they want to look at when it comes to the Goals (Goal or Q1 for now but in the future, Q2, Q3 as well). Again, ideally a multiselector.

Something like this:

在此处输入图像描述

I was able to add a clunky Mkt_cd filter but as you can see it's broken:P and there's no way of resetting the view. I did not even try to attempt the Goals filter. Any help will be appreciated.

I've put together a suggestion that builds on previous contributions of mine using JupyterLab. You may find that it's a bit messy. But if this is what you're looking for conceptually , then we can clean it up. And alswo rewrite the whole thing to use "pure" Dash and not JupyterDash. The code snippet below will produce the following figure with:

  1. a radio-item to lets you select one market, and
  2. a checklist that will let you select any and all categories I believe are your Goals: ['Goal', 'Q1 ]

Here are a few scenarios for different combinations of selections:

Plot 1

在此处输入图像描述

Plot 2

在此处输入图像描述

Plot 3

在此处输入图像描述

Complete code for JupyterDash

import plotly.express as px
import plotly.graph_objects as go
import plotly as py
import pandas as pd
from plotly import tools

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
from jupyter_dash import JupyterDash

d = {'Mkt_cd': ['Mkt1','Mkt2','Mkt3','Mkt4','Mkt5','Mkt1','Mkt2','Mkt3','Mkt4','Mkt5'],
       'Category': ['Apple','Orange','Grape','Mango','Orange','Mango','Apple','Grape','Apple','Orange'],
           'CategoryKey': ['Mkt1Apple','Mkt2Orange','Mkt3Grape','Mkt4Mango','Mkt5Orange','Mkt1Mango','Mkt2Apple','Mkt3Grape','Mkt4Apple','Mkt5Orange'],
            'Current': [15,9,20,10,20,8,10,21,18,14],
           'Goal': [50,35,21,44,20,24,14,29,28,19],
            'Q1': [30,25,11,34,10,14,4,19,8,9]
     }
dataset  = pd.DataFrame(d)

# Dash
app = JupyterDash(__name__)
app.config['suppress_callback_exceptions'] = True

app.layout = html.Div([
    
    dcc.RadioItems(
        id='market-radio',
        options=[{'label': k, 'value': k} for k in dataset['Mkt_cd'].unique()],
        value=dataset['Mkt_cd'].iloc[0]
    ),

    html.Hr(),
    html.Hr(),

        dcc.Checklist(
        id='goals-radio',
        options=[{'label': k, 'value': k} for k in ['Goal', 'Q1']],
        value=['Goal'],
    ),
    
    html.Hr(),
    
    html.Div(id='display-selected-values'),
    
    dcc.Graph(id="mkt_graph")
    
])

# Make a figure based on the selections
@app.callback( # Columns 2m_temp_prod, or....
    Output('mkt_graph', 'figure'),
    [Input('market-radio', 'value'),
     Input('goals-radio', 'value')])
def make_graph(market, levels):
    dataset  = pd.DataFrame(d)
    dataset = dataset[dataset['Mkt_cd']==market]
    grouped = dataset.groupby('Category', as_index=False).sum()
    data = grouped.to_dict(orient='list')
    v_cat = grouped['Category'].tolist()
    level_colors = px.colors.qualitative.Plotly[2:]

    fig = go.Figure()
    fig.add_trace(go.Bar(
        x= grouped['Current'],
        y=grouped['Category'].tolist(),
        marker_color="#ff0000",
        orientation='h',
        width=0.25
        ))

    for j, lev in enumerate(levels):
        for i, g in enumerate(grouped[lev]):
            fig.add_shape(type="rect",
                            x0=g+0.5, y0=v_cat[i], x1=g, y1=v_cat[i],
                            line=dict(color=level_colors[j], width = 58))
    return fig

app.run_server(mode='inline', port = 8070, dev_tools_ui=True,
          dev_tools_hot_reload =True, threaded=True)

Addendum: Controls and figures nicely organized

This could easily have been asked as a question on its own, but for the sake of completeness the complete snippet below will produce the following Dash App with controls neatly organized to the left of the figure. The only way I know how to do this reliably so far is throgh bootstrap components. That introduces a few new concepts in this context. But it's what I have to offer right now. There's still room for improvements though. Like som air between control header and options. But we can sort that out if this is in fact something you can use.

在此处输入图像描述

Complete snippet for boostrap components

import plotly as py
import pandas as pd

from plotly import tools
import plotly.express as px
import plotly.graph_objects as go

import dash
import dash_core_components as dcc
import dash_html_components as html
from jupyter_dash import JupyterDash
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output


d = {'Mkt_cd': ['Mkt1','Mkt2','Mkt3','Mkt4','Mkt5','Mkt1','Mkt2','Mkt3','Mkt4','Mkt5'],
       'Category': ['Apple','Orange','Grape','Mango','Orange','Mango','Apple','Grape','Apple','Orange'],
           'CategoryKey': ['Mkt1Apple','Mkt2Orange','Mkt3Grape','Mkt4Mango','Mkt5Orange','Mkt1Mango','Mkt2Apple','Mkt3Grape','Mkt4Apple','Mkt5Orange'],
            'Current': [15,9,20,10,20,8,10,21,18,14],
           'Goal': [50,35,21,44,20,24,14,29,28,19],
            'Q1': [30,25,11,34,10,14,4,19,8,9]
     }
dataset  = pd.DataFrame(d)

app = JupyterDash(external_stylesheets=[dbc.themes.SLATE])
template = 'plotly_dark'

controls = dbc.Card(
        [dbc.FormGroup(
            [
                dbc.Label("Market"),
     dcc.RadioItems(
        id='market-radio',
        options=[{'label': 'All', 'value': 'All'}] + [{'label': k, 'value': k} for k in dataset['Mkt_cd'].unique()],
        value='All',
        
    ),
            ],
        ),
        dbc.FormGroup(
            [
                dbc.Label("Goals"),
        dcc.Checklist(
        id='goals-radio',
        options=[{'label': k, 'value': k} for k in ['Goal', 'Q1']],
        value=['Goal'],
        style={'display': 'inline-block'}
    ),
            ], 
        ),
    ],
    body=True,
    style = {'font-size': 'large'}
)

app.layout = dbc.Container(
    [
        html.H1("Markets and goals"),
        html.Hr(),
        dbc.Row([
            dbc.Col([controls],xs = 4),
            dbc.Col([
                dbc.Row([
                    dbc.Col(dcc.Graph(id="market_graph")),
                ])
            ]),
        ]),
        html.Br(),
    ],
    fluid=True,
)

@app.callback(
    Output("market_graph", "figure"),
    [
        Input("market-radio", "value"),
        Input("goals-radio", "value"),
    ],
)
def history_graph(market, levels):

    dataset  = pd.DataFrame(d)
    
    if not market == 'All':
        dataset = dataset[dataset['Mkt_cd']==market]
    
    grouped = dataset.groupby('Category', as_index=False).sum()
    data = grouped.to_dict(orient='list')
    v_cat = grouped['Category'].tolist()
    level_colors = px.colors.qualitative.Plotly[2:]

    fig = go.Figure()
    fig.add_trace(go.Bar(
        x= grouped['Current'],
        y=grouped['Category'].tolist(),
        marker_color="#ff0000",
        orientation='h',
        width=0.25
        ))

    for j, lev in enumerate(levels):
        for i, g in enumerate(grouped[lev]):
            fig.add_shape(type="rect",
                            x0=g+0.5, y0=v_cat[i], x1=g, y1=v_cat[i],
                            line=dict(color=level_colors[j], width = 58))

    fig.update_layout(template='plotly_dark')

    
    return fig


app.run_server(mode='inline', port = 8007)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM