[Python] Plot loads data as a standalone but not through streamlit

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

  1. Stack

    Stack Membro Participativo

    I am running the velocityanalysis.py file as a standalone file. when running it I get a nice plot for the forecast. I have everything set in a function. I am sending only the part of the function, not the whole code => ''' def generate_forecast(df_offerred, show_data_from, months_back, forecast_months): # Convert show_data_from to Timestamp if needed if isinstance(show_data_from, str): show_data_from = pd.to_datetime(show_data_from) # Make show_data_from timezone-aware (UTC) if show_data_from.tzinfo is None: show_data_from = show_data_from.tz_localize('UTC') else: show_data_from = show_data_from.tz_convert('UTC') now = datetime.now(timezone.utc) first_day_current_month = datetime(now.year, now.month, 1) end_of_prev_month = first_day_current_month - pd.Timedelta(days=1) start_of_range = first_day_current_month - pd.DateOffset(months=months_back)

    # Parse and assign 'date' column
    df_offerred['date'] = pd.to_datetime(
    df_offerred['ClosedDate'].fillna(df_offerred['ChangedDate']),
    utc=True, errors='coerce', infer_datetime_format=True
    )

    # Drop rows with NaT in 'date'
    df_offerred = df_offerred.dropna(subset=['date'])

    # Create 'month_start'
    df_offerred['month_start'] = df_offerred['date'].dt.to_period('M').dt.to_timestamp()

    # Drop NaT in 'month_start'
    df_offerred = df_offerred.dropna(subset=['month_start'])

    # Deduplicate
    df_offerred = df_offerred.sort_values(by=["date"])
    df_offerred = df_offerred.drop_duplicates(subset=['month_start', 'Id'], keep="last")

    # Filter rows with date >= show_data_from
    df_offerred = df_offerred.loc[df_offerred['date'] >= show_data_from]

    # Offered points
    points_offerred = df_offerred.groupby('month_start')['Points'].sum().reset_index()
    points_offerred = points_offerred[points_offerred['month_start'] < pd.Timestamp(first_day_current_month)]
    points_offerred['Points'] = points_offerred['Points'].fillna(0).astype(int)

    # Handled points
    df_handled = df_offerred[df_offerred["State"] == "Closed"] \
    .sort_values(by="ChangedDate", ascending=False) \
    .drop_duplicates(subset=["Id"], keep="first")
    df_handled = df_handled.loc[df_handled['date'] >= show_data_from]

    points_handled = df_handled.groupby('month_start')['Points'].sum().reset_index()
    points_handled = points_handled[points_handled['month_start'] < pd.Timestamp(first_day_current_month)]
    points_handled['Points'] = points_handled['Points'].fillna(0).astype(int)

    # Forecast helper function
    def forecast_points(points_df, forecast_months, label):
    df = points_df.rename(columns={'month_start': 'ds', 'Points': 'y'})
    df['ds'] = pd.to_datetime(df['ds']).dt.tz_localize(None)

    if len(df) < 3:
    start_date = df['ds'].min()
    if pd.isna(start_date):
    # fallback start date if min is NaT, e.g., first day of current month UTC
    now = pd.Timestamp.now(tz='UTC').normalize()
    start_date = now.replace(day=1).tz_localize(None)
    future_dates = pd.date_range(start=start_date, periods=forecast_months, freq='MS')
    empty_forecast = pd.DataFrame({
    'month_start': future_dates,
    f'forecasted_points_{label}': [0] * len(future_dates)
    })
    return empty_forecast

    model = Prophet()
    model.add_seasonality(name='monthly', period=30.5, fourier_order=5)
    model.fit(df)
    future = model.make_future_dataframe(periods=forecast_months, freq='MS')
    forecast = model.predict(future)

    forecast_result = forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']]
    forecast_result = forecast_result.rename(columns={
    'ds': 'month_start',
    'yhat': f'forecasted_points_{label}'
    })

    # Round forecast to nearest integer and convert to int
    forecast_result[f'forecasted_points_{label}'] = forecast_result[f'forecasted_points_{label}'].round().astype(
    int)

    return forecast_result

    # Get forecasts
    forecast_offerred = forecast_points(points_offerred, forecast_months, "offered")
    forecast_handled = forecast_points(points_handled, forecast_months, "handled")

    # Merge actual and forecast
    df_offerred_plot = pd.merge(points_offerred, forecast_offerred, on='month_start', how='outer').sort_values(
    'month_start')
    df_handled_plot = pd.merge(points_handled, forecast_handled, on='month_start', how='outer').sort_values(
    'month_start')
    '''


    when I run the code through streamlit I get an empty plot ''' with col7: with st.container(border=True): st.subheader(" Forecast") c1, c2 = st.columns([1, 1])

    # Add a date input for month/year selection (set day to 1 always)
    selected_date = c1.date_input(
    "Monitor Data From:",
    value=datetime.date.today().replace(day=1),
    min_value=datetime.date(2000, 1, 1),
    max_value=datetime.date.today(),
    key="forecast_date"
    )

    # Convert selected_date to the first day of that month as string
    show_data_from = selected_date.strftime("%Y-%m-%d")

    # Validate df_offerred before forecast
    df_offerred = st.session_state.get("df_offerred", None)
    if df_offerred is not None and df_offerred.dropna().shape[0] >= 2:
    if st.session_state.loading_forecast or "chart_forecast" not in st.session_state:
    with c2:
    with st.spinner("Loading Forecast Chart..."):
    try:
    st.session_state.chart_forecast = generate_forecast(
    df_offerred,
    show_data_from,
    24,
    12
    )
    except ValueError as e:
    st.warning(f"Forecast generation failed: {e}")
    st.session_state.chart_forecast = None
    st.session_state.loading_forecast = False

    fig = st.session_state.chart_forecast
    if fig:
    for trace in fig.data:
    if trace.name in ['Items Closed (Actual)', 'Story Points (Actual)']:
    trace.x = pd.to_datetime(trace.x) # Ensure datetime x-axis
    trace.mode = 'lines+markers'

    fig.update_xaxes(type='date')
    st.plotly_chart(fig, use_container_width=True, height=400)
    else:
    st.info("Forecast chart could not be generated due to lack of data.")
    else:
    st.warning("Not enough data available to generate a forecast.")
    '''


    i am using the same inputs in both cases and even when running it from the streamlit, the print for the forecasted values returns data

    Continue reading...

Compartilhe esta Página