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...