首页 > 解决方案 > 单击带有破折号的条形图时创建模式

问题描述

我有一个条形图,我想在单击它们时创建一个模态图。你知道我该怎么处理吗?我尝试了一些东西,但没有出现。

在此处输入图像描述

我知道如何使用数据表来做到这一点。但是这里我有一个条形图,我在设计的最后添加了一个模态对象,但我无法让它出现。

这是一个最小的可重现示例:

import dash
import dash_core_components as dcc
import dash_bootstrap_components as dbc
import dash_html_components as html
import plotly.graph_objs as go
import pandas as pd
from dash.dependencies import Input, Output

df = pd.read_excel("https://github.com/chris1610/pbpython/blob/master/data/salesfunnel.xlsx?raw=True")
pv = pd.pivot_table(df, index=['Name'], columns=["Status"], values=['Quantity'], aggfunc=sum, fill_value=0)

trace1 = go.Bar(x=pv.index, y=pv[('Quantity', 'declined')], name='Declined')
trace2 = go.Bar(x=pv.index, y=pv[('Quantity', 'pending')], name='Pending')
trace3 = go.Bar(x=pv.index, y=pv[('Quantity', 'presented')], name='Presented')
trace4 = go.Bar(x=pv.index, y=pv[('Quantity', 'won')], name='Won')

app = dash.Dash()

app.layout = html.Div(children=[
    html.H1(children='Sales Funnel Report'),
    html.Div(children='''National Sales Funnel Report.'''),
    dcc.Graph(
        id='graph',
        figure={
            'data': [trace1, trace2, trace3, trace4],
            'layout':
                go.Layout(title='Order Status by Customer', barmode='stack')
        }),
    dbc.Modal(
        [
            dbc.ModalHeader("Header"),
            dbc.ModalBody("This is the content of the modal"),
            dbc.ModalFooter(
                dbc.Button("Close", id="close", className="ml-auto")
            ),
        ],
        size="xl",
        id="modal",
    )
])


@app.callback(
    Output('modal', 'children'),
    [Input('graph', 'clickData')])
def display_click_data(clickData):
    print("clickData: ", clickData)
    return [
        dbc.ModalHeader("Test"),
        dbc.ModalBody(
            html.Div([
                html.Div([
                    html.H6('Sales', style={'textAlign': 'center', 'padding': 10}),
                    html.P("Bitch", id="sales_stocks", style={'textAlign': 'center', 'padding': 10})
                ], className='pretty_container four columns'),
                html.Div([
                    html.H5('Current ratio', style={'textAlign': 'center', 'padding': 10})
                ], className='pretty_container seven columns')
            ])),
        dbc.ModalFooter(dbc.Button("Close", id="close"))
    ]


# Press the green button in the gutter to run the script.
if __name__ == '__main__':
    app.run_server(debug=True)

标签: python-3.xmodal-dialogplotly-dash

解决方案


我遇到了一个类似的问题,但在概念上是相同的:单击 plotly/dash-object 中的某些内容,然后显示一个模态。研究这个问题,我也在plotly论坛上发现了这个帖子,它遇到了非常相似的问题。那里提出的解决方案给了我如何解决的想法。

如果我复制您的代码,手头有两个问题。

  1. 它缺少指向引导程序“外部样式表”的链接,该链接可以轻松添加到上面的示例中,替换app = dash.Dash()app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
  2. 回调现在只改变模态的孩子。但是,要显示,它的属性open应该设置为True. 当id=close按下按钮时,打开变为False

我把你的代码剪掉了一些有用的东西。希望这对您也有帮助!

import dash_core_components as dcc
import dash_bootstrap_components as dbc
import dash_html_components as html
import plotly.graph_objs as go
import pandas as pd
# added State to be used in callbacks
from dash.dependencies import Input, Output, State

# using #type: ignore to suppress warnings in my editor (vs code). 
df = pd.read_excel("https://github.com/chris1610/pbpython/blob/master/data/salesfunnel.xlsx?raw=True")
pv = pd.pivot_table(df, index=['Name'], columns=["Status"], values=['Quantity'], aggfunc=sum, fill_value=0)#type: ignore

trace1 = go.Bar(x=pv.index, y=pv[('Quantity', 'declined')], name='Declined') #type: ignore
trace2 = go.Bar(x=pv.index, y=pv[('Quantity', 'pending')], name='Pending')#type: ignore
trace3 = go.Bar(x=pv.index, y=pv[('Quantity', 'presented')], name='Presented')#type: ignore
trace4 = go.Bar(x=pv.index, y=pv[('Quantity', 'won')], name='Won')#type: ignore

app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])

app.layout = html.Div(children=[
    html.H1(children='Sales Funnel Report'),
    html.Div(children='''National Sales Funnel Report.'''),
    dcc.Graph(
        id='graph',
        figure={
            'data': [trace1, trace2, trace3, trace4],
            'layout':
                go.Layout(title='Order Status by Customer', barmode='stack')#type: ignore
        }),
    dbc.Button("toggle", id="open"),
    dbc.Modal(
        [
            dbc.ModalHeader("Header",id = 'modalheader'),
            dbc.ModalBody("This is the content of the modal"),
            dbc.ModalFooter(
                dbc.Button("Close", id="close", className="ml-auto")
            ),
        ],
        size="xl",
        id="modal",
    )
])

@app.callback([Output("modal", "children"),
               Output("modal", "is_open")],
              [Input("graph", "clickData"),
               Input("close", "n_clicks")],
              [State("modal", "is_open"),
               State("modal", "children")])
def set_content(value,clicked,is_open,children):
    ctx = dash.callback_context

    if ctx.triggered[0]['prop_id'] == 'close.n_clicks':
        # you pressed the closed button, keeping the modal children as is, and 
        # close the model itself. 
        return children, False 
    elif ctx.triggered[0]['prop_id'] == 'graph.clickData':
        # you clicked in the graph, returning the modal children and opening it
        return [dbc.ModalHeader("Test"),
                dbc.ModalBody(
                html.Div([
                    html.Div([
                        html.H6('Sales', style={'textAlign': 'center', 'padding': 10}),
                        html.P("Bitch", id="sales_stocks", style={'textAlign': 'center', 'padding': 10})
                    ], className='pretty_container four columns'),
                    html.Div([
                        html.H5('Current ratio', style={'textAlign': 'center', 'padding': 10}),
                        html.P(str(value),style = {'fontFamily':'monospace'})
                    ], className='pretty_container seven columns')
                ])),
                dbc.ModalFooter(dbc.Button("Close", id="close"))
                ], True
    else:
        raise dash.exceptions.PreventUpdate

# Press the green button in the gutter to run the script.
if __name__ == '__main__':
    app.run_server(debug=True)

推荐阅读