bhola prasad
bhola prasad

Reputation: 725

some plotly dash figure stop showing after deploying the app to heroku

I just deployed a Plotly dash app on Heroku. The whole app is working perfectly fine on my local machine but some figures stop showing after I deployed it on the web. Can anyone tell me why is this happening?

This is how the app looks like on the web -

enter image description here

But working fine on my machine -

enter image description here

Some figures are working fine locally as well as on the web -

enter image description here

The code I am using to plot the figure that is not showing-

controls = dbc.Card(
    [
        # html.H4("Model Input"),
        dbc.CardHeader(
            "Model Input",
            className="bg-primary text-white",
        ),
        html.Br(style={"margin-bottom": "20px"}),
        dbc.FormGroup(
            [
                dbc.Label("Month", size="md"),
                dcc.Dropdown(
                    id="month-selector",
                    options=[{"label": col, "value": col} for col in month_cols],
                    value="Month__Sep",
                ),
            ],
        ),
        dbc.FormGroup(
            [
                dbc.Label("Visitor Type", size="md"),
                dcc.Dropdown(
                    id="visitor-type-selector",
                    options=[{"label": col, "value": col} for col in visitor_type_cols],
                    value="VisitorType__New_Visitor",
                ),
            ],
        ),
        dbc.FormGroup(
            [
                dbc.Label("Page Value", size="md"),
                # dbc.Input(
                #     id="page-value-input",
                #     value="37",
                #     type="text",  # passing numbers causing unexpected behaviour
                #     debounce=True,
                # ),
                dcc.Slider(
                    id="page-value-input",
                    min=0,
                    max=300,
                    step=1,
                    value=10,
                    marks={
                        0: "0",
                        30: "30",
                        90: "90",
                        150: "150",
                        210: "210",
                        300: "300",
                    },
                ),
                # dbc.FormText("Enter a value between $0 to $300.", color="secondary"),
            ],
        ),
        dbc.FormGroup(
            [
                dbc.Label("Exit Rate", size="md"),
                # dbc.Input(
                #     id="exit-rate-input",
                #     value="0.03",
                #     type="text",  # passing numbers causing unexpected behaviour
                #     debounce=True,
                # ),
                dcc.Slider(
                    id="exit-rate-input",
                    min=0.0,
                    max=1.0,
                    step=0.01,
                    value=0.05,
                    marks={
                        0: "0",
                        0.1: "0.1",
                        0.3: "0.3",
                        0.5: "0.5",
                        0.7: "0.7",
                        0.9: "0.9",
                        1: "1",
                    },
                ),
                # dbc.FormText("Enter a value between 0 and 1"),
            ]
        ),
        dbc.FormGroup(
            [
                dbc.Label("Bounce Rate", size="md"),
                # dbc.Input(
                #     id="bounce-rate-input",
                #     value="0",
                #     type="text",  # passing numbers causing unexpected behaviour
                #     debounce=True,
                # ),
                dcc.Slider(
                    id="bounce-rate-input",
                    min=0.0,
                    max=1.0,
                    step=0.01,
                    value=0.0,
                    marks={
                        0: "0",
                        0.1: "0.1",
                        0.3: "0.3",
                        0.5: "0.5",
                        0.7: "0.7",
                        0.9: "0.9",
                        1: "1",
                    },
                ),
                # dbc.FormText("Enter a value between 0 and 1")
            ],
        ),
        dbc.FormGroup(
            [
                dbc.Label("Product Related", size="md"),
                # dbc.Input(
                #     id="product-related-input", value="34", type="text", debounce=True
                # ),
                dcc.Slider(
                    id="product-related-input",
                    min=0,
                    max=200,
                    step=1,
                    value=18,
                    marks={
                        0: "0",
                        30: "30",
                        60: "60",
                        90: "90",
                        150: "150",
                        200: "200",
                    },
                ),
                # dbc.FormText(
                #     "Number of times user visited product related section (0-200).",
                #     color="secondary",
                # ),
            ],
        ),
        dbc.FormGroup(
            [
                dbc.Label("Product Related Duration", size="md"),
                # dbc.Input(
                #     id="product-related-duration-input",
                #     value="80",
                #     type="text",
                #     debounce=True,
                # ),
                dcc.Slider(
                    id="product-related-duration-input",
                    min=0,
                    max=100,
                    step=1,
                    value=55,
                    marks={
                        0: "0",
                        10: "10",
                        20: "20",
                        30: "30",
                        60: "60",
                        100: "100",
                    },
                ),
                # dbc.FormText(
                #     "Total Time spent in product related section (0-100 min.)"
                # ),
            ],
        ),
    ],
    body=True,
    # color="primary",
    # inverse=True,
)

# Dash app for predicting customer purchasing intention
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.MATERIA])
server = app.server

app.layout = dbc.Container(
    [
        ### first row
        html.Br(),
        dbc.Row(
            [
                dbc.Col(
                    html.H1(
                        "Online Shoppers Purchasing Intension Prediction",
                        className="text-center text-primary mb-4",
                    ),
                )
            ],
            # style={"margin": "20px"},
        ),
        html.Br(),
        ### second row
        dbc.Row(
            [
                dbc.Col(
                    [
                        html.H4("By Bhola Prasad"),
                        html.Div(
                            [
                                html.Div(
                                    [
                                        html.A(
                                            "Website",
                                            href="https://www.lifewithdata.com/",
                                            target="_blank",
                                        )
                                    ]
                                ),
                                html.Div(
                                    [
                                        html.A(
                                            "LinkedIn",
                                            href="https://www.linkedin.com/in/bhola-prasad-0065834b/",
                                            target="_blank",
                                        )
                                    ]
                                ),
                                html.Div(
                                    [
                                        html.A(
                                            "GitHub",
                                            href="https://github.com/bprasad26/predict-online-shoppers-purchasing-intention",
                                            target="_blank",
                                        )
                                    ]
                                ),
                            ]
                        )
                        # dcc.Markdown(
                        #     "##### Website - [Life With Data](https://www.lifewithdata.com/)",
                        #     className="mb-4",
                        # ),
                    ],
                )
            ],
            justify="start",
        ),
        html.Br(style={"margin-bottom": "50px"}),
        ### Third row
        dbc.Row(
            [
                dbc.Col(controls, md=4),
                dbc.Col(
                    [class_output_card, dcc.Graph(id="shap-waterfall-plot")],
                    md=8,
                ),
            ],
            # align="center",
        ),
        ### Fourth Row
        html.Br(style={"margin-bottom": "50px"}),
        dbc.Row([dbc.Col(decision_tree_card)]),
        ### Fifth Row
        html.Br(style={"margin-bottom": "50px"}),
        dbc.Row(
            [dbc.Col(permutation_imp_card, md=5), dbc.Col(feature_imp_card, md=5)],
            justify="between",
        ),  # 'start', 'center', 'end', 'around' and 'between'.
    ],
    fluid=True,
)


@app.callback(
    Output("shap-waterfall-plot", "figure"),
    [
        Input("page-value-input", "value"),
        Input("exit-rate-input", "value"),
        Input("product-related-input", "value"),
        Input("product-related-duration-input", "value"),
        Input("bounce-rate-input", "value"),
        Input("visitor-type-selector", "value"),
        Input("month-selector", "value"),
    ],
)
def shap_waterfall_plot(
    PageValues,
    ExitRates,
    ProductRelated,
    ProductRelated_Duration,
    BounceRates,
    VisitorType,
    Month,
):

    # load model

    model_path = os.path.join(os.getcwd(), "models", "rf_rnd_search1.joblib")
    model = joblib.load(open(model_path, "rb"))

    visitor_type_index = np.where(X_train_sel.columns == VisitorType)[0][0]
    month_index = np.where(X_train_sel.columns == Month)[0][0]

    x = np.zeros(len(X_train_sel.columns))
    x[0] = float(PageValues)
    x[1] = float(ExitRates)
    x[2] = float(ProductRelated)
    x[3] = float(ProductRelated_Duration)
    x[4] = float(BounceRates)
    x[visitor_type_index] = 1
    x[month_index] = 1
    x_series = pd.Series(x, index=cols_to_use)

    # create a tree explainer object
    explainer = shap.TreeExplainer(model)
    # calculate shap values
    shap_values = explainer.shap_values(x_series)

    fill_color = ["#ff0051" if val >= 0 else "#008bfb" for val in shap_values[1]]
    fig = go.Figure()
    fig.add_trace(
        go.Bar(
            x=shap_values[1],
            y=cols_to_use,
            text=np.round(shap_values[1], 3),
            orientation="h",
            marker_color=fill_color,
        )
    )
    fig.update_traces(textposition="outside")
    fig.update_layout(
        yaxis=dict(autorange="reversed"),
        xaxis=dict(
            title=f"""P(Buy= {np.round(model.predict_proba([x_series])[0][1],2)})  
            E(Buy= {np.round(explainer.expected_value[1],3)})"""
        ),
        height=600,
        template="simple_white",
    )

    return fig


if __name__ == "__main__":
    app.run_server()

The app can be seen on this link - https://customer-purchase-prediction.herokuapp.com/

For reproducing the plots, all the data sets and models can be found in this Github repo - https://github.com/bprasad26/predict-online-shoppers-purchasing-intention

Upvotes: 4

Views: 699

Answers (1)

Sebin Sunny
Sebin Sunny

Reputation: 1803

The graphs are not loaded because of following issues.

  • Numpy issue with shap
  • Graphviz binary was missing, which loads the Decision tree graphs

Steps

  • Create a runtime.txt file in the root folder add python-3.8.10

  • Install all the necessary binaries for the Dash Application

    heroku buildpacks:add --index 1 heroku/python heroku buildpacks:add --index 2 https://github.com/weibeld/heroku-buildpack-graphviz.git

  • Remove both numpy and shap version from the requirements file so it will install the latest version and fix the dependency issues with shap

numpy
shap

heroku logs --tail output streams of all of its running processes, helps in debugging.

Check out the dashboard https://machine-learning-customer.herokuapp.com/

Upvotes: 4

Related Questions