Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[split] Code help
#1
I created a peer-to-peer lending simulation in spyder when I run my main output I get an error in creating one of my plots and Im not sure why. The error comes up as "Unable to create Lender Funds Visualisation" in a message box

Output:
runfile('C:/Users/Emma Robinson/OneDrive/Documents/FIN3028 Python/Developer Showcase/main.py', wdir='C:/Users/Emma Robinson/OneDrive/Documents/FIN3028 Python/Developer Showcase') Lenders loaded: [{'id': 1, 'name': 'Lender A', 'available_funds': 5000, 'min_interest_rate_%': 5, 'max_risk': 2}, {'id': 2, 'name': 'Lender B', 'available_funds': 3000, 'min_interest_rate_%': 4, 'max_risk': 1}, {'id': 3, 'name': 'Lender C', 'available_funds': 7000, 'min_interest_rate_%': 6, 'max_risk': 3}] Borrowers loaded: [{'id': 1, 'name': 'Borrower X', 'amount_needed': 2000, 'interest_rate_%': 6, 'risk': 1, 'duration_years': 3}, {'id': 2, 'name': 'Borrower Y', 'amount_needed': 4000, 'interest_rate_%': 5, 'risk': 2, 'duration_years': 2}, {'id': 3, 'name': 'Borrower Z', 'amount_needed': 1500, 'interest_rate_%': 7, 'risk': 3, 'duration_years': 1}] ERROR:root:Missing 'name' of 'funds' key in lender: {'id': 1, 'name': 'Lender A', 'available_funds': 3000, 'min_interest_rate_%': 5, 'max_risk': 2} ERROR:root:Missing 'name' of 'funds' key in lender: {'id': 2, 'name': 'Lender B', 'available_funds': 3000, 'min_interest_rate_%': 4, 'max_risk': 1} ERROR:root:Missing 'name' of 'funds' key in lender: {'id': 3, 'name': 'Lender C', 'available_funds': 5500, 'min_interest_rate_%': 6, 'max_risk': 3} ERROR:root:No valid lender data available for plotting. Repayment Summary: borrower_id total_payment ... total_interest remaining_balance 0 1 2190.24 ... 190.37 0.0 1 3 1557.48 ... 57.47 0.0 [2 rows x 5 columns] Repayment summary saved as 'repayment_summary.csv'.
This is my main function :
import tkinter as tk
from tkinter import messagebox
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from input_output_data import load_json_data, select_file, validate_json_file, save_results
from matching_generator import match_lenders_borrowers
from repayment_simulator import simulate_repayment_schedule, generate_summary
from visualisation import plot_lender_funds, plot_repayment_schedules
import logging
import sys
import os

# Ensure correct working directory
script_dir = os.path.dirname(os.path.abspath(__file__))
os.chdir(script_dir)
sys.path.append(script_dir)

logging.basicConfig(level=logging.INFO)

def show_messagebox(title, message, error=False):
    """
    Display a messagebox for success or error messages.

    Parameters:
        - title (str): Title of the messagebox.
        - message (str): Message content.
        - error (bool): True for an error message, False for an info message.
    """
    if error:
        messagebox.showerror(title, message)
    else:
        messagebox.showinfo(title, message)
        
def display_plot(fig, root, title="Visualisation"):
    """
    Display a matplotlib figure in a tkinter window.

    Parameters:
        - fig: Matplotlib figure object.
        - root: Tkinter root window.
        - title: Title of the plot window.
    """
    if fig:
        canvas = FigureCanvasTkAgg(fig, master=root)
        canvas.get_tk_widget().pack()
        canvas.draw()
    else:
        show_messagebox("Error", f"Unable to generate {title}.", error=True)

# Main function
def main():
    """
    Main function to orchestrate the Peer-to-Peer Lending Simulator.
    """
   
    # Set up tkinter root window for file dialogs and plots
    #file:///C:/Users/Emma%20Robinson/Downloads/FIN3028_Companion_Notes.pdf
    root = tk.Tk()
    root.title("Peer-to-Peer Lending Simulator")
    root.geometry("800x600") #Set window size
    
    logging.info("Starting Peer-to-Peer Lending Simulator.")
    
    # File selection
    lenders_file = select_file("Lenders")
    borrowers_file = select_file("Borrowers")
    
    if not lenders_file or not borrowers_file:
        show_messagebox("Error", "Both lenders and borrowers files are required.", error=True)
        return
    
    try:
        validate_json_file(lenders_file)
        validate_json_file(borrowers_file)
    except ValueError as e:
        show_messagebox("Error", str(e), error=True)
        return
    
    # Load data
    lenders = load_json_data(lenders_file)
    borrowers = load_json_data(borrowers_file)
    
    if not lenders:
        show_messagebox("Error", "Lenders data is empty or invalid.", error = True)
        return
    if not borrowers:
        show_messagebox("Error", "Borrowers data is empty or invalid.", error = True)
        return
    
    # Debug prints to verify structure
    print("Lenders loaded:", lenders)
    print("Borrowers loaded:", borrowers)

    # Process matches
    matches, unmatched_borrowers = match_lenders_borrowers(lenders, borrowers)
    if not matches:
        logging.info(f"Lenders: {lenders}")
        logging.info(f"Borrowers: {borrowers}")
        show_messagebox("Info", "No matches were found. Check logs for details.")
        return
    
    # Simulate repayment schedules
    repayment_schedule = simulate_repayment_schedule(matches, borrowers)
    if not repayment_schedule:
        show_messagebox("Error", "Failed to generate repayment schedule.", error=True)
        return
    
    # Save results
    save_results(matches, repayment_schedule)
    
    # Generate and display summary
    summary = generate_summary(repayment_schedule)
    if not summary.empty:
        print("\nRepayment Summary:\n")
        print(summary)

        # Optional: Save the summary to a CSV file
        summary.to_csv("repayment_summary.csv")
        print("Repayment summary saved as 'repayment_summary.csv'.")
    
    #Visualise lender funds and repayment schedules
    fig1 = plot_lender_funds(lenders)
    display_plot(fig1, root, title="Lender Funds Visualisation")

    fig2 = plot_repayment_schedules(repayment_schedule)
    display_plot(fig2, root, title="Repayment Schedules Visualisation")

    root.mainloop()  # Keep the plots open

if __name__ == "__main__":
    main()
This is my visualisation code

import matplotlib.pyplot as plt
import logging
import matplotlib.ticker as mticker
import os

logging.basicConfig(level=logging.ERROR)

#Plot amount of funds lenders have remaining after matching loans
def plot_lender_funds(lenders, save_path = None):
    
    """
    Creates a bar chart showing remaining funds each lender has
    
    Parameters:
        - lenders (list of dict): List of lender details
        
    Returns:
        - matplotlib.figure.Figure: The figure object containing the bar chart.
    """
    
    if not lenders:
        logging.error("No lender data available to plot.")
        return None
    
    filtered_lenders = []
    for lender in lenders:
        if 'name' not in lender or 'funds' not in lender:
            logging.error(f"Missing 'name'  of 'funds' key in lender: {lender}")
            continue
        filtered_lenders.append(lender)
        
    if not filtered_lenders:
        logging.error("No valid lender data available for plotting.")
        return None
    
    # Sort and limit to top 10 lenders for large datasets
    filtered_lenders = sorted(filtered_lenders, key=lambda x: x['available_funds'], reverse=True)[:10]
    
    lender_names = [lender['name'] for lender in lenders]
    funds_remaining = [lender['funds'] for lender in lenders]
    
    fig, ax = plt.subplots(figsize = (8,6))
    ax.bar(lender_names, funds_remaining)
    ax.set_title("Lender Funds Remaining")
    ax.set_xlabel("Lender")
    ax.set_ylabel("Funds Remaining (GBP)")
    
    #Format Y-axis for currency
    ax.yaxis.set_major_formatter(mticker.StrMethodFormatter('£{x:,.0f}'))
    plt.xticks(rotation = 45)
    plt.tight_layout()
    
    if save_path:
        save_path = os.path.abspath(save_path)
        os.makedirs(os.path.dirname(save_path), exist_ok=True)  # Ensure directory exists
        fig.savefig(save_path)
        
    return fig

#Plot repayment schedules over time for each borrower - line plot  
def plot_repayment_schedules(repayment_schedule, save_path = None):
    
    """
    Plots repayment schedules for loan over time for each borrower
    
    Parameters:
        - repayment_schdeule (list of dict): The repayment schedule
        
    Returns:
        - matplotlib.figure.Figure: The figure object containing the repayment schedule plot.
    """
    if not repayment_schedule:
        logging.error("No repayment schedule data to plot.")
        return None
    
    #Group repayments by borrower
    borrowers = {entry['borrower_id'] for entry in repayment_schedule}
    
    fig, ax = plt.subplots(figsize = (10, 6))
    
    #Loop through each borrower - extract monthly payments and months
    for borrower_id in borrowers:
        
        borrower_payments = [entry['payment'] for entry in repayment_schedule if entry['borrower_id'] == borrower_id]
        
        months = [entry['month'] for entry in repayment_schedule if entry['borrower_id'] == borrower_id]
        
        ax.plot(months, borrower_payments, label = f"Borrower {borrower_id}")
        
    ax.set_title("Repayment Schedules")
    ax.set_xlabel("Month")
    ax.set_ylabel("Monthly Payment (GBP)")
    ax.legend(title="Borrower ID")
    ax.grid(True)
    plt.tight_layout()
    
    if save_path:
        save_path = os.path.abspath(save_path)
        os.makedirs(os.path.dirname(save_path), exist_ok=True)  # Ensure directory exists
        fig.savefig(save_path)

    return fig
This is my borrower data and lender data i used to test:

Output:
[ { "id": 1, "name": "Lender A", "available_funds": 5000, "min_interest_rate_%": 5, "max_risk": 2 }, { "id": 2, "name": "Lender B", "available_funds": 3000, "min_interest_rate_%": 4, "max_risk": 1 }, { "id": 3, "name": "Lender C", "available_funds": 7000, "min_interest_rate_%": 6, "max_risk": 3 } ] [ { "id": 1, "name": "Borrower X", "amount_needed": 2000, "interest_rate_%": 6, "risk": 1, "duration_years": 3 }, { "id": 2, "name": "Borrower Y", "amount_needed": 4000, "interest_rate_%": 5, "risk": 2, "duration_years": 2 }, { "id": 3, "name": "Borrower Z", "amount_needed": 1500, "interest_rate_%": 7, "risk": 3, "duration_years": 1 } ]
Not sure if my mistake is easy found, just have been looking for ages and would appreciate any help. Thanks
buran write Dec-12-2024, 11:58 AM:
Please, use proper tags when post code, traceback, output, etc. This time I have added tags for you.
See BBcode help for more info.
Reply
#2
Tthere is error:

ERROR:root:Missing 'name'  of 'funds' key in lender: {'id': 1, 'name': 'Lender A', 'available_funds': 3000, 'min_interest_rate_%': 5, 'max_risk': 2}
There is code which causes it:

 if 'name' not in lender or 'funds' not in lender:
            logging.error(f"Missing 'name'  of 'funds' key in lender: {lender}")
There is no key 'funds' in lender:

>>> lender = {'available_funds': 7000}
>>> 'funds' in lender
False
>>> for key in lender:
...     if 'funds' in key:
...         print(key)
...
available_funds
I'm not 'in'-sane. Indeed, I am so far 'out' of sane that you appear a tiny blip on the distant coast of sanity. Bucky Katt, Get Fuzzy

Da Bishop: There's a dead bishop on the landing. I don't know who keeps bringing them in here. ....but society is to blame.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [split] How to continue code after .show() in matplotlib? pythonnewbie62 1 218 Apr-28-2025, 04:02 PM
Last Post: deanhystad
  [split] another problem with code blakeusherremix68 0 433 Dec-23-2024, 11:36 PM
Last Post: blakeusherremix68
  [split] Explain the python code in this definition Led_Zeppelin 1 1,337 Jan-13-2023, 10:20 PM
Last Post: deanhystad
  [split] Kera Getting errors when following code example Image classification from scratch hobbyist 3 5,619 Apr-13-2021, 01:26 PM
Last Post: amirian
  [split] Python code help sairam17519 3 3,722 Sep-10-2020, 01:44 PM
Last Post: sairam17519
  How to Split Output Audio on Text to Speech Code Base12 2 8,121 Aug-29-2020, 03:23 AM
Last Post: Base12
  How to split and combine embedded lines using less code pjfarley3 6 3,815 Aug-13-2020, 09:13 PM
Last Post: pjfarley3
  [split] SyntaxError when trying to execute code on Windows nehaya 2 2,587 Aug-04-2020, 11:18 AM
Last Post: nehaya
  [split] need help with the code CERO123 2 2,523 Feb-10-2020, 03:32 PM
Last Post: jefsummers
  [split] VS Code Editor SupaNub 5 4,055 Nov-27-2019, 03:37 PM
Last Post: snippsat

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020