Can't understand why my app always reload

Hi !

Hello,

I don’t understand why my app reloads when I select the selectbox. I’ve set up cache management, managed states but the result is still the same.
Do you see where the problem could be coming from?

My code :

import os
import pandas as pd
import streamlit as st
from datetime import datetime
import numpy as np
import plotly.express as px
import plotly.graph_objs as go
import chardet

st.set_page_config(page_title="Bank statement analyzer", page_icon="🐈", layout="wide")

@st.cache_data(show_spinner=False)
def get_encoding(file): #Model
    """Detect the encoding of a file."""
    result = chardet.detect(file.read())
    return result['encoding']

@st.cache_data(show_spinner=False)
def read_csv(file, delimiter, encoding): #Model
    """Read a CSV file with the specified delimiter and encoding."""
    file.seek(0)
    return pd.read_csv(file, delimiter=delimiter, encoding=encoding)

class FinancialApp:
    def __init__(self):
        self.data = None
        self.delimiter = ';'
        self.currency = '€'

    def detect_headers(self): #Model
        """Detect the headers of the CSV file."""
        return list(self.data.columns)
    
    def process_dates(self, start_date, end_date): #Model
        """Process the dates and return filtered data to display comparative graphs."""

    def process_data(self): #Model
        """Process the data in the CSV file."""
        self.show_tabs()

    def clean_number(self, num): #Model
        """Clean a number string by removing non-numeric characters and converting it to a float."""
        try:
            return float(str(num).replace(",", "."))
        except ValueError:
            return np.nan
        
    def match_columns(self, headers): #Controller
        """Match the columns in the CSV file to the required columns."""

    def display_monthly_expenses(self):
        st.header("Monthly Expense Analysis")

        # Get unique years and months from the data
        self.data['Year'] = self.data[self.date_column].dt.year
        self.data['Month'] = self.data[self.date_column].dt.month

        unique_years = sorted(self.data['Year'].unique())
        unique_months = sorted(self.data['Month'].unique())

        # Initialize session state for year, month, and category if not already set
        if 'selected_year' not in st.session_state:
            st.session_state['selected_year'] = unique_years[0]
        if 'selected_month' not in st.session_state:
            st.session_state['selected_month'] = unique_months[0]
        if 'selected_category' not in st.session_state:
            st.session_state['selected_category'] = None

        # Year and Month SelectBox
        selected_year = st.selectbox("Select Year", unique_years, index=unique_years.index(st.session_state['selected_year']), key='year_selectbox')
        selected_month = st.selectbox("Select Month", unique_months, index=unique_months.index(st.session_state['selected_month']), key='month_selectbox')

        # Update session state if the selections change
        st.session_state['selected_year'] = selected_year
        st.session_state['selected_month'] = selected_month

        filtered_data = self.data[(self.data['Year'] == st.session_state['selected_year']) & (self.data['Month'] == st.session_state['selected_month'])]

        if not filtered_data.empty:
            # Group by category
            expenses_by_category = filtered_data.groupby(self.category_column)[self.debit_column].sum().reset_index()

            st.subheader(f"Expenses for {st.session_state['selected_month']}/{st.session_state['selected_year']}")
            st.dataframe(expenses_by_category)

            # Pie chart of expenses per category
            fig = px.pie(expenses_by_category, values=self.debit_column, names=self.category_column, title="Expenses by Category")
            st.plotly_chart(fig, use_container_width=True)

            # Add click interaction for category selection
            categories = expenses_by_category[self.category_column].tolist()
            if st.session_state['selected_category'] not in categories:
                st.session_state['selected_category'] = categories[0]

            selected_category = st.selectbox("Select Category to view details", categories, index=categories.index(st.session_state['selected_category']), key='category_selectbox')

            # Update session state for selected category
            st.session_state['selected_category'] = selected_category

            if st.session_state['selected_category'] == True:
                category_expenses = filtered_data[filtered_data[self.category_column] == st.session_state['selected_category']]
                st.subheader(f"Details for category: {st.session_state['selected_category']}")
                st.dataframe(category_expenses)
        else:
            st.write(f"No data available for {st.session_state['selected_month']}/{st.session_state['selected_year']}")

    def show_summary(self): #View
        """Show a summary of the financial data."""
        st.header("Summary")

        st.subheader("CSV File")
        st.dataframe(self.data)   
    
        self.show_charts()

    def show_charts(self): #View
        """Show charts of the financial data."""

    def run(self): #Controller
        with st.sidebar:
            st.title('FinancialAnalysisApp')
            with st.expander("Settings", expanded=True):
                self.delimiter = st.text_input("Delimiter (default ';')", value=";", key="delimiter")
                self.currency = st.text_input("Currency (default '€')", value="€", key="currency")
                self.savings = st.number_input(f"How much money do you want to save every month? (default {self.currency}1000)", value=1000, key="savings")
                self.date_format = st.text_input("Date format (default '%d-%m-%Y')", value="%d-%m-%Y", key="date_format")
            self.file = st.file_uploader("Upload your CSV file", type=['csv'], key="file_uploader")

        if st.session_state.get('file_uploader') is not None:
            try:
                encoding = get_encoding(st.session_state['file_uploader'])
                self.data = read_csv(st.session_state['file_uploader'], st.session_state['delimiter'], encoding)                
                headers = self.detect_headers()
                with st.sidebar:
                    with st.expander("Match columns", expanded=True):
                        self.match_columns(headers)
                    # Initialize session state for the process button if not already set
                    if 'process' not in st.session_state:
                        st.session_state['process'] = False
                    
                    # Define the process button
                    if st.button("Process", key="process_button"):
                        st.session_state['process'] = True

                # Execute processing if the process button was clicked
                if st.session_state['process'] == True:
                    with st.spinner("Processing data..."):
                        self.process_data()
                        st.session_state['process'] = False
            except Exception as e:
                with st.sidebar:
                    st.write("Error: ", e)         

    def show_tabs(self):
        tab1, tab2 = st.tabs(["Summary", "Monthly Analysis"])

        with tab1:
            self.show_summary()
        with tab2:
            self.display_monthly_expenses()

if __name__ == "__main__":
    app = FinancialApp()
    app.run()

I seem unable to properly run your code. Anyway, your main script rerunning on each user interaction is expected behavior, if that is what you are seeing.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.