[Python] Empty plotly line plot in shiny express app being fed by a @reactive.calc dataframe

Discussão em 'Python' iniciado por Stack, Maio 21, 2025.

  1. Stack

    Stack Membro Participativo

    I have a shiny express app which first pulls a dataframe from a saved pin, does some data manipulation, then outputs it to a plotly plot along with a few summary info cards. The filters and cards work correctly, as well as an outputted rendered dataframe showing the filtered data, but my plot is blank with the x-axis ('tran_date') showing default year 2000 dates.

    There is a @reactive.calc section at the bottom which looks like this where the filtered dataframe is generated:

    import plotly.express as px
    import pandas as pd
    import datetime as dt
    from shiny import reactive
    from shiny.express import ui, input, render
    from shinywidgets import render_widget
    import plotly

    columns = ["tran_date", "Card_Type", "Entity", "tran_amt", "fee", "fee_pct"]

    data = [
    ["2025-04-10", "Test", "HF", 39.77, -1.39, 3.5]
    ["2025-04-10", "Test2", "1", 156722.44, -2133.43, 1.36]
    ["2025-04-10", "Test2", "3", 7026.4, -91.81, 1.31]
    ["2025-04-10", "Test2", "HF", 19326.39, -257.04, 1.33]
    ["2025-04-10", "Test3", "1", 537720.57, -17150.55, 3.19]
    ["2025-04-10", "Test3", "3", 51286.76, -1616.46, 3.15]
    ["2025-04-10", "Test3", "HF", 3610.66, -121.13, 3.35]
    ["2025-04-10", "Test4", "1", 769.76, -21.17, 2.75]
    ["2025-04-10", "Test4", "HF", 398.01, -5.77, 1.45]
    ["2025-04-10", "Test5", "1", 456447.03, -5058.61, 1.11]
    ["2025-04-10", "Test5", "3", 27686.38, -325.47, 1.18]
    ["2025-04-10", "Test5", "HF", 37173.72, -439.91, 1.18]
    ["2025-04-10", "Test6", "1", 1005795.05, -23607.7, 2.35]
    ["2025-04-10", "Test6", "3", 301824.57, -7086.06, 2.35]
    ["2025-04-10", "Test6", "HF", 24651.23, -579.0, 2.35]

    df2 = pd.dataFrame(data, columns = columns)

    # Define filter elements

    accts = df2['Card_Type'].unique().tolist()
    mindate = df2['tran_date'].min()
    maxdate = df2['tran_date'].max()

    # Define the UI

    ui.page_opts(title='Settlement Fee Tracking', fillable = True)
    with ui.sidebar(title='Filter Controls'):
    ui.input_select(
    'acct',
    'Select an Account',
    choices=accts
    )
    ui.input_date_range(
    "date",
    "Date Range",
    min=mindate,
    max=maxdate,
    start=mindate,
    end=maxdate
    )
    with ui.navset_pill(id = "tab"):
    with ui.nav_panel("Fee Percentage by Card Type - Entity Split"):
    # Graph
    with ui.layout_columns():
    with ui.card(full_screen = True):
    ui.card_header("Card Fee Percentage Tracking")

    @render_widget
    def feelp():
    df = fee_df().copy()
    df['tran_date'] = pd.to_datetime(df['tran_date'])
    df = df.dropna(subset=['tran_date'])

    fig = px.line(
    data_frame = df,
    x = 'tran_date',
    y = 'fee_pct',
    color = 'Entity',
    color_discrete_map = {'1': 'blue', '3': 'red'},
    line_shape = 'spline',
    markers = True,
    labels = {
    "tran_date": "Transaction Date",
    "fee_pct": "Fee Percentage"
    },
    custom_data = 'Entity'
    )
    fig.update_traces(
    line = dict(width = 3),
    hovertemplate =
    'Entity %{customdata[0]}<br>' +
    '%{y:,.2f}%<br>' +
    '<extra></extra>'
    )
    fig.update_layout(
    xaxis = dict(type='date'),
    hovermode = 'x unified',
    font=dict(family="Calibri Black",size=18),
    hoverlabel=dict(font_size=18, font_weight='bold')
    )
    return fig

    @reactive.calc
    def fee_df():
    drange = input.date()
    start_date, end_date = drange[0], drange[1]

    filtered_df = df2[
    (df2['tran_date'] >= (start_date)) &
    (df2['tran_date'] <= (end_date))
    ]

    inacct = input.acct()
    idx = filtered_df.Card_Type.str.contains(inacct)
    filtered_df = filtered_df[idx]

    return filtered_df



    I suspect this could be an issue with the date format of 'tran_date' but haven't been able to figure it out. It's strange that the individual cards and dataframe all react and work with the filters, but not the plot. Possibly the plot is trying to render before fee_df() is ready from the @reactive.calc?

    I had a previous version of this shiny app without filters, just pulling from the same pin and segmenting the DF into many smaller dfs including all available dates with their own individual plotly plots for each segment which works fine. The plotly code is the same between the two aside from referencing fee_df() instead of the segmented static DFs. I've tried many different date conversions for 'tran_date' without any working, they either show a blank graph or cause the whole app to crash on startup. I've tried a simplified version of the plot with no luck.

    Continue reading...

Compartilhe esta Página