def eval_results(
        df,
        dcon=None, 
        target_mos = 'mos', 
        target_ci = 'mos_ci',
        pred = 'mos_pred',
        mapping = None,
        do_print = False,
        do_plot = False
        ):
    '''
    Evaluates a trained model on given dataset.
    '''            
    # Loop through databases
    db_results_df = []
    df['y_hat_map'] = np.nan
    
    for db_name in df.db.astype("category").cat.categories:

        df_db = df.loc[df.db==db_name]
        if dcon is not None:
            dcon_db = dcon.loc[dcon.db==db_name]
        else:
            dcon_db = None
        
        # per file -----------------------------------------------------------        
        y = df_db[target_mos].to_numpy()
        if np.isnan(y).any():
            r = {'r_p': np.nan,'r_s': np.nan,'rmse': np.nan,'r_p_map': np.nan,
                 'r_s_map': np.nan,'rmse_map': np.nan}
        else:
            y_hat = df_db[pred].to_numpy()      
            
            b, d = calc_mapping(
                df_db,
                mapping=mapping,
                target_mos=target_mos,
                target_ci=target_ci,
                pred=pred
                )
            y_hat_map = calc_mapped(y_hat, b)
            
            r = calc_eval_metrics(y, y_hat, y_hat_map=y_hat_map, d=d)
            r.pop('rmse_star_map')
        r = {f'{k}_file': v for k, v in r.items()}
            
        # per con ------------------------------------------------------------
        r_con = {'r_p': np.nan,'r_s': np.nan,'rmse': np.nan,'r_p_map': np.nan,
             'r_s_map': np.nan,'rmse_map': np.nan,'rmse_star_map': np.nan}
        
        if (dcon_db is not None) and ('con' in df_db):
            
            y_con = dcon_db[target_mos].to_numpy()
            y_con_hat = df_db.groupby('con').mean().get(pred).to_numpy()

            if not np.isnan(y_con).any():
                
                if target_ci in dcon_db:
                    ci_con = dcon_db[target_ci].to_numpy()   
                else:
                    ci_con = None            
    
                b_con, d = calc_mapping(
                    df_db,
                    dcon_db=dcon_db,
                    mapping=mapping,
                    target_mos=target_mos,
                    target_ci=target_ci,
                    pred=pred
                    )            
                
                df_db['y_hat_map'] = calc_mapped(y_hat, b_con)  
                df['y_hat_map'].loc[df.db==db_name] = df_db['y_hat_map'] 
                
                y_con_hat_map = df_db.groupby('con').mean().get('y_hat_map').to_numpy()
                r_con = calc_eval_metrics(y_con, y_con_hat, y_hat_map=y_con_hat_map, d=d, ci=ci_con)
                
        r_con = {f'{k}_con': v for k, v in r_con.items()}
        r = {**r, **r_con}
            
        # ---------------------------------------------------------------------
        db_results_df.append({'db': db_name, **r})
        # Plot  ------------------------------------------------------------------
        if do_plot and (not np.isnan(y).any()):
            xx = np.arange(0, 6, 0.01)
            yy = calc_mapped(xx, b)            
        
            plt.figure(figsize=(3.0, 3.0), dpi=300)
            plt.clf()
            plt.plot(y_hat, y, 'o', label='Original data', markersize=2)
            plt.plot([0, 5], [0, 5], 'gray')
            plt.plot(xx, yy, 'r', label='Fitted line')
            plt.axis([1, 5, 1, 5])
            plt.gca().set_aspect('equal', adjustable='box')
            plt.grid(True)
            plt.xticks(np.arange(1, 6))
            plt.yticks(np.arange(1, 6))
            plt.title(db_name + ' per file')
            plt.ylabel('Subjective ' + target_mos.upper())
            plt.xlabel('Predicted ' + target_mos.upper())
            # plt.savefig('corr_diagram_fr_' + db_name + '.pdf', dpi=300, bbox_inches="tight")
            plt.show()

                
            if (dcon_db is not None) and ('con' in df_db):
                
                xx = np.arange(0, 6, 0.01)
                yy = calc_mapped(xx, b_con)     
                
                plt.figure(figsize=(3.0, 3.0), dpi=300)
                plt.clf()
                plt.plot(y_con_hat, y_con, 'o', label='Original data', markersize=3)
                plt.plot([0, 5], [0, 5], 'gray')
                plt.plot(xx, yy, 'r', label='Fitted line')
                plt.axis([1, 5, 1, 5])
                plt.gca().set_aspect('equal', adjustable='box')
                plt.grid(True)
                plt.xticks(np.arange(1, 6))
                plt.yticks(np.arange(1, 6))
                plt.title(db_name + ' per con')
                plt.ylabel('Sub ' + target_mos.upper())
                plt.xlabel('Pred ' + target_mos.upper())
                # plt.savefig(db_name + '.pdf', dpi=300, bbox_inches="tight")
                plt.show()            
            
        # Print ------------------------------------------------------------------
        if do_print and (not np.isnan(y).any()):
            if (dcon_db is not None) and ('con' in df_db):
                print('%-30s r_p_file: %0.2f, rmse_map_file: %0.2f, r_p_con: %0.2f, rmse_map_con: %0.2f, rmse_star_map_con: %0.2f'
                      % (db_name+':', r['r_p_file'], r['rmse_map_file'], r['r_p_con'], r['rmse_map_con'], r['rmse_star_map_con']))
            else:
                print('%-30s r_p_file: %0.2f, rmse_map_file: %0.2f'
                      % (db_name+':', r['r_p_file'], r['rmse_map_file']))

    # Save individual database results in DataFrame
    db_results_df = pd.DataFrame(db_results_df)
    
    r_average = {}
    r_average['r_p_mean_file'] = db_results_df.r_p_file.mean()
    r_average['rmse_mean_file'] = db_results_df.rmse_file.mean()
    r_average['rmse_map_mean_file'] = db_results_df.rmse_map_file.mean()
    
    if dcon_db is not None:
        r_average['r_p_mean_con'] = db_results_df.r_p_con.mean()
        r_average['rmse_mean_con'] = db_results_df.rmse_con.mean()
        r_average['rmse_map_mean_con'] = db_results_df.rmse_map_con.mean()
        r_average['rmse_star_map_mean_con'] = db_results_df.rmse_star_map_con.mean()    
    else:        
        r_average['r_p_mean_con'] = np.nan
        r_average['rmse_mean_con'] = np.nan
        r_average['rmse_map_mean_con'] = np.nan
        r_average['rmse_star_map_mean_con'] = np.nan

    # Get overall per file results      
    y = df[target_mos].to_numpy()
    y_hat = df[pred].to_numpy()
            
    r_total_file = calc_eval_metrics(y, y_hat)
    r_total_file = {'r_p_all': r_total_file['r_p'], 'rmse_all': r_total_file['rmse']} 
    
    overall_results = {
        **r_total_file,
        **r_average
        }
    
    return db_results_df, overall_results

    Evaluates a trained model on given dataset.
    
speechscore/scores/nisqa/NISQA_lib.py