import pandas as pd
import matplotlib.pyplot as plt
import pyodbc

def brinson(portfolioID, beginDate, endDate, analyst=None, industry=None):

    # Setup connection to the database
    conn_str = r"DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=C:\Users\LIQI\Documents\portfolio.accdb"
    conn = pyodbc.connect(conn_str)
    
    # Define the portfolio-benchmark mapping dictionary
    portfolio_benchmark_mapping = {
        '300Active': 'CSI300',
        '300Standard': 'CSI300',
        '500Active': 'CSI500',
        '500Standard':'CSI500'
        }
    
    # Get the corresponding benchID for the given portfolioID
    if portfolioID not in portfolio_benchmark_mapping:
        print(f"No benchmark found for portfolioID: {portfolioID}")
        conn.close()
        return
    
    benchID = portfolio_benchmark_mapping[portfolioID]
   
    # Query the portfolio table
    portfolio_query = f"SELECT * FROM Mockportfolio WHERE ID = {portfolioID} AND TRADEDATE >= '{beginDate}' AND tradedate <= '{endDate}'"
    portfolio_data = pd.read_sql(portfolio_query, conn)
    portfolio_data['CONTRIBUTION'] = portfolio_data['WEIGHT']*portfolio_data['RETURN']        

    # Query the benchmark table
    benchmark_query = f"SELECT * FROM benchmark WHERE BenchID = {benchID} AND TRADEDATE >= '{beginDate}' AND tradedate <= '{endDate}'"
    benchmark_data = pd.read_sql(benchmark_query, conn)
    benchmark_data['CONTRIBUTION'] = benchmark_data['WEIGHT']*benchmark_data['RETURN']
    
    conn.close()
    
    if analyst is not None:
        # Filter portfolio data for the specified analyst
        portfolio_data = portfolio_data[portfolio_data['Analyst'] == analyst]
        benchmark_data = benchmark_data[benchmark_data['Analyst'] == analyst]
              
    # Group by industry and calculate the necessary values
    benchmark_data_grouped = benchmark_data.groupby(['TRADEDATE', 'INDUSTRY']).sum()
    portfolio_data_grouped = portfolio_data.groupby(['TRADEDATE', 'INDUSTRY']).sum()

    benchmark_data_grouped['RETURN'] =benchmark_data_grouped['CONTRIBUTION'] / benchmark_data_grouped['WEIGHT'] 
    portfolio_data_grouped['RETURN'] =portfolio_data_grouped['CONTRIBUTION'] / portfolio_data_grouped['WEIGHT'] 
    
    portfolio_df = pd.merge(portfolio_data_grouped, benchmark_data_grouped, on=['TRADEDATE', 'INDUSTRY'], suffixes=('_P', '_B'))
    
    portfolio_df['Q1_daily'] = portfolio_df['WEIGHT_B'] * portfolio_df['RETURN_B']
    portfolio_df['Q2_daily'] = portfolio_df['WEIGHT_P'] * portfolio_df['RETURN_B']
    portfolio_df['Q3_daily'] = portfolio_df['WEIGHT_B'] * portfolio_df['RETURN_P']
    portfolio_df['Q4_daily'] = portfolio_df['WEIGHT_P'] * portfolio_df['RETURN_P']
    
    portfolio_df['excess_return_daily'] = portfolio_df['Q4_daily'] - portfolio_df['Q1_daily']
    portfolio_df['allocation_effect_daily'] = portfolio_df['Q2_daily'] - portfolio_df['Q1_daily']
    portfolio_df['selection_effect_daily'] = portfolio_df['Q3_daily'] - portfolio_df['Q1_daily']
    portfolio_df['interaction_effect_daily'] = portfolio_df['Q4_daily'] - portfolio_df['Q3_daily'] - portfolio_df['Q2_daily'] + portfolio_df['Q1_daily']
    
    # Calculate the compounded excess return of each industry
    portfolio_df['Q1_compound']=(1 + portfolio_df['Q1_daily']).groupby(['INDUSTRY']).cumprod()-1
    portfolio_df['Q2_compound']=(1 + portfolio_df['Q2_daily']).groupby(['INDUSTRY']).cumprod()-1
    portfolio_df['Q3_compound']=(1 + portfolio_df['Q3_daily']).groupby(['INDUSTRY']).cumprod()-1
    portfolio_df['Q4_compound']=(1 + portfolio_df['Q4_daily']).groupby(['INDUSTRY']).cumprod()-1
    portfolio_df['excess_return_compound'] = portfolio_df['Q4_compound'] - portfolio_df['Q1_compound']
    portfolio_df['allocation_effect_compound'] = portfolio_df['Q2_compound'] - portfolio_df['Q1_compound']
    portfolio_df['selection_effect_compound'] = portfolio_df['Q3_compound'] - portfolio_df['Q1_compound']
    portfolio_df['interaction_effect_compound'] = portfolio_df['Q4_compound'] - portfolio_df['Q3_compound'] - portfolio_df['Q2_compound'] + portfolio_df['Q1_compound']
    portfolio_df=portfolio_df.reset_index()
    
    # Calculate the compounded excess return of the entire portfolio
    excess_return_compound = portfolio_df.groupby('TRADEDATE')['excess_return_compound'].sum().reset_index()
    allocation_effect_compound = portfolio_df.groupby('TRADEDATE')['allocation_effect_compound'].sum().reset_index()
    selection_effect_compound = portfolio_df.groupby('TRADEDATE')['selection_effect_compound'].sum().reset_index()
    interaction_effect_compound = portfolio_df.groupby('TRADEDATE')['interaction_effect_compound'].sum().reset_index()
    
    
    # Plot the chart for certain industry
    if industry is not None:
        # Filter portfolio data for the specified analyst
        industry_data = portfolio_df[portfolio_df['INDUSTRY'] == industry]
        plt.plot(industry_data['TRADEDATE'], industry_data['excess_return_compound'])
        plt.plot(industry_data['TRADEDATE'], industry_data['allocation_effect_compound'])
        plt.plot(industry_data['TRADEDATE'], industry_data['selection_effect_compound'])
        plt.plot(industry_data['TRADEDATE'], industry_data['interaction_effect_compound'])
        plt.xticks(rotation=45)
        plt.title(f"Excess Return in {industry}")
        plt.xlabel('TRADEDATE')
        plt.ylabel('excess_return_compound')
        plt.legend()
        # Show the plot
        plt.show()
        
        
    # Plot the chart for portoflio
    excess_return_compound = portfolio_df.groupby('TRADEDATE')['excess_return_compound'].sum().reset_index()
    allocation_effect_compound = portfolio_df.groupby('TRADEDATE')['allocation_effect_compound'].sum().reset_index()
    selection_effect_compound = portfolio_df.groupby('TRADEDATE')['selection_effect_compound'].sum().reset_index()
    interaction_effect_compound = portfolio_df.groupby('TRADEDATE')['interaction_effect_compound'].sum().reset_index()
    
    plt.plot(excess_return_compound['TRADEDATE'], excess_return_compound['excess_return_compound'],label='Excess Return')
    plt.plot(allocation_effect_compound['TRADEDATE'], allocation_effect_compound['allocation_effect_compound'],label='Allocation Effect')
    plt.plot(selection_effect_compound['TRADEDATE'], selection_effect_compound['selection_effect_compound'],label='Selection Effect')
    plt.plot(interaction_effect_compound['TRADEDATE'], interaction_effect_compound['interaction_effect_compound'],label='Interaction Effect')
    plt.xticks(rotation=45)
    plt.title("Entire Portfolio Compound Excess Return")
    plt.xlabel("Trade Date")
    plt.ylabel("Excess Return")
    plt.legend()
    plt.show()
Please go throught this code and see if there exist any bug?  thanks.