{"id":21676888,"url":"https://github.com/rasbeetech/loan-calculator","last_synced_at":"2025-03-20T09:40:25.804Z","repository":{"id":135281803,"uuid":"341678250","full_name":"RasbeeTech/Loan-Calculator","owner":"RasbeeTech","description":"Tkinter framework application","archived":false,"fork":false,"pushed_at":"2021-04-07T15:51:39.000Z","size":164,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-25T10:26:17.951Z","etag":null,"topics":["matplotlib","numpy","python","tkinter"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RasbeeTech.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-02-23T20:15:47.000Z","updated_at":"2021-04-14T01:02:13.000Z","dependencies_parsed_at":null,"dependency_job_id":"dc220f5e-71c9-46fc-9c55-0e3491d28569","html_url":"https://github.com/RasbeeTech/Loan-Calculator","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RasbeeTech%2FLoan-Calculator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RasbeeTech%2FLoan-Calculator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RasbeeTech%2FLoan-Calculator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RasbeeTech%2FLoan-Calculator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RasbeeTech","download_url":"https://codeload.github.com/RasbeeTech/Loan-Calculator/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244589759,"owners_count":20477597,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["matplotlib","numpy","python","tkinter"],"created_at":"2024-11-25T14:16:45.261Z","updated_at":"2025-03-20T09:40:25.798Z","avatar_url":"https://github.com/RasbeeTech.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Loan-Calculator\n\n App to calculate interest and principle amounts of a loan and display's the data in an easy to read graph format.\n \n Python version: 3.8.7\n\n TkInter is used to create the graphical user interface\n \n  ## Sample:\n  \n  ![alt text](https://github.com/RasbeeTech/Loan-Calculator/blob/main/sample_image.jpeg)\n  \n  To see finished program code, click [here](https://github.com/RasbeeTech/Loan-Calculator/blob/main/loan_calculator.py)\n  \n  ## Process:\n  1. Create a class object for loan calculations\n  ```python\n  class Loan:\n  \t# defined default variables for testing\n    def __init__(interest=3.99, principle=80000.00, term=60, payment_frequency=\"monthly\"):\n        self.interest = interest\n        self.principle = principle\n        self.term = term\n        self.payment_frequency = payment_frequency\n  ```\n  \n  2. Create Loan class function to calculate interest based on payment/amortization frequency\n  ```python\n  def get_interest_percent_to_float(self):\n  \t# converts percentage(%) to a float(decimal) number \n  \treturn self.interest / 100\n  \n  def get_interest_per_period(self):\n  \t# returns the amount of interest calculated\n  \t# Use of dictionary makes for cleaner code and easy readability\n    interest = self.get_interest_percent_to_float()\n    return {\n        \"monthly\": interest / 12,\n        \"biweekly\": interest / (365 / 14),\n        \"weekly\": interest / (365 / 7),\n        \"daily\": interest / 365\n    }[self.payment_frequency]\n  ```\n  \n  3. Create function to calculate the amount to be paid per period\n  ```\n  The following formula is used: \n  \n  P = r(PV)/1-(1+r)^n\n  \n  P = Payment\n  PV = Present Value\n  r = rate per period\n  n = number of periods\n  ```\n  Code:\t\t\n  ```python\n  def get_payments_per_period(self):\n\ti = self.get_interest_per_period()\n    p = self.principle\n    t = self.term\n    # using formula to calculate payments per period\n    period_payments = p * ((i * (1 + i) ** t) / (((1 + i) ** t) - 1))\n    return period_payments\n  ```\n  \n  3. Create function to calculate the cost of borrowing (total interest to be paid on loan)\n  ```python\n  def get_total_interest_to_be_paid(self):\n  \tprinciple = self.principle\n  \tterm = list(range(self.term))\n  \t\n  \ti = self.get_interest_per_period()\n    p = self.get_payments_per_period()\n    \n    total_interest_paid = 0\n    for t in term:\n    \tinterest_paid_this_period = i * principle\n        principle -= (p - interest_paid_this_period)\n        total_interest_paid += interest_paid_this_period\n    return total_interest_paid\n  ```\n  \n  4. To calculate the total amount to be repaid on a loan you can simply get the sum of interest to be paid (using the function above) and the amount borrowed (principle).  This can be done by creating the simple function:\n  ```python\n  def get_total_to_be_paid_on_loan(self):\n  \treturn self.principle + self.get_total_interest_to_be_paid()\n  ```\n  \n  5. Now that the Loan class has been completed, Now its time to find a way to display the loan data.  To do this I used the Tkinter frameworks for python.  I started by making a Window class\n  ```python\n  class Window:\n  def __init__(self, window):\n  \tself.window = window\n    self.loan = Loan()\n\n    self.input_labels = [\"Principle ($)\", \"Interest (%)\", \"Term Length\", \"Frequency\"]\n    self.output_labels = [\"Total Interest\", \"Total repaid\", \"Pay/Period\"]\n    self.frequency_options = [\"yearly\", \"monthly\", \"biweekly\", \"weekly\", \"daily\"]\n    self.menuVar = tk.StringVar(self.window)\n    self.data_input = {}\n    self.data_output = {}\n\n    self.setup_gui()\n    self.set_gui_default_values()\n    self.graph = self.setup_graph()\n  ```\n  \tYou may notice on the last line I am planning to use a graph to display data.\n  \n  6. I start off by creating a function to setup the user interface.  I use loops to create Tkinter labels and entries to receive and display data. Included are buttons for calculating and viewing the loans payment schedule.\n  ```python\n  def setup_gui(self):\n  \t# input labels\n    input_labels = self.input_labels\n    for label in input_labels:\n    \trow = input_labels.index(label)\n        tk_label = tk.Label(text=label, font=\"Helvetica 15 bold\")\n        tk_label.grid(row=row, column=0)\n\n        if label == \"Frequency\":\n            choices = self.frequency_options\n            input = tk.OptionMenu(self.window, self.menuVar, *choices)\n            input.grid(row=row, column=1, pady=5, sticky=\"nesw\")\n        else:\n            input = tk.Entry(bd=3, width=20, justify=\"center\")\n            input.grid(row=row, column=1, pady=5)\n         self.data_input[label] = input\n\n    calculate_button = tk.Button(text=\"Calculate\", font=\"Helvetica 15 bold\", command=self.calculate_button)\n    calculate_button.grid(row=len(input_labels), column=0, columnspan=2, pady=20)\n\n    # output labels\n    output_labels = self.output_labels\n    for label in output_labels:\n    \trow = len(input_labels) + output_labels.index(label) + 1\n        tk_label = tk.Label(text=label, font=\"Helvetica 15 bold\")\n        tk_label.grid(row=row, column=0)\n\n        output = tk.Label(text=\"\", font=\"Helvetica 15 bold\", width=\"20\", bg=\"#d3d3d3\", bd=3, relief=\"ridge\")\n        output.grid(row=row, column=1, pady=5)\n        self.data_output[label] = output\n\n     view_button = tk.Button(text=\"View payment schedule\", font=\"Helvetica 15 bold\",\n                                command=self.view_payment_schedule_button)\n    view_button.grid(row=len(output_labels) + len(input_labels) + 1, column=0, columnspan=2, pady=20)\n  ```\n  \n  7. When the add first starts I would like to set some default values so the user has an example of how to enter data:\n  ```python\n  def set_gui_default_values(self):\n  \tdefault_principle = self.loan.principle\n  \tdefault_interest = self.loan.interest\n    default_term = self.loan.term\n\n    self.data_input[\"Principle ($)\"].insert(index=tk.END, string=str(default_principle))\n    self.data_input[\"Interest (%)\"].insert(index=tk.END, string=str(default_interest))\n    self.data_input[\"Term Length\"].insert(index=tk.END, string=str(default_term))\n    self.menuVar.set(self.frequency_options[1])\n\n    default_interest_to_be_paid = round(self.loan.get_total_interest_to_be_paid(), 2)\n    default_total_to_be_paid = round(self.loan.get_total_to_be_paid_on_loan(), 2)\n    default_pay_per_period = round(self.loan.get_payments_per_period(), 2)\n    self.data_output[\"Total Interest\"].config(text=\"$\" + str(default_interest_to_be_paid))\n    self.data_output[\"Total repaid\"].config(text=\"$\" + str(default_total_to_be_paid))\n    self.data_output[\"Pay/Period\"].config(text=\"$\" + str(default_pay_per_period))\n  ```\n  \n  8. The calculate button is used to recalculate loan if new data has been entered:\n  ```python\n  def calculate_button(self):\n  \tnew_principle = self.data_input[\"Principle ($)\"].get()\n    new_interest = self.data_input[\"Interest (%)\"].get()\n    new_term = self.data_input[\"Term Length\"].get()\n    new_frequency = self.menuVar.get()\n    self.loan.update(principle=float(new_principle),\n                    \tinterest=float(new_interest),\n                        term=int(new_term),\n                        payment_frequency=new_frequency)\n    self.data_output[\"Total Interest\"].config(text=\"$\" + str(round(self.loan.get_total_interest_to_be_paid(), 2)))\n    self.data_output[\"Total repaid\"].config(text=\"$\" + str(round(self.loan.get_total_to_be_paid_on_loan(), 2)))\n     self.data_output[\"Pay/Period\"].config(text=\"$\" + str(round(self.loan.get_payments_per_period(), 2)))\n    self.update_graph()\n  ```\n  \n  9. Since the main user interface may already be a little crowded, I will create a new toplevel window to view the payment schedule.\n  ```python\n  def view_payment_schedule_button(self):\n  \tschedule_window = tk.Toplevel(self.window)\n    payment_schedule = self.loan.get_payment_schedule()\n\n    header = [\"#\", \"Payment\", \"Interest\", \"Principle\"]\n    for head in header:\n        label = tk.Label(schedule_window, text=head)\n        label.grid(row=0, column=header.index(head))\n\n    data = [\"#\", \"total_payment\", \"amount_toward_interest\", \"remaining_principle\",]\n    for payment in payment_schedule:\n        row = payment.get(\"#\") + 1\n        for d in data:\n            column = data.index(d)\n            if d == \"#\":\n                label = tk.Label(schedule_window, text=payment.get(d)+1)\n            else:\n                label = tk.Label(schedule_window, text=str(round(payment.get(d) + 1, 2)))\n            label.grid(row=row, column=column)\n  ```\n  \n  10. I previously mentioned that I plan to display data in the form of a graph.  To this we need to get some plot points.\n  ```python\n  def get_plot_points(self):\n  \tpoints = self.loan.term / 12\n    x_period = list(range(1, (int(points) + 1)))\n\n    schedule = self.loan.get_payment_schedule()[11::12]\n\n    y_interest_paid = []\n    y_principle_paid = []\n    y_remaining_balance = []\n\n    for s in schedule:\n        y_interest_paid.append(s.get(\"total_interest_paid\"))\n        y_principle_paid.append(s.get(\"total_paid\"))\n        y_remaining_balance.append(s.get(\"remaining_principle\"))\n\n    return x_period, y_principle_paid, y_interest_paid, y_remaining_balance\n  ```\n  \n  11. Now i setup the graph and place graph in gui all in one function:\n  ```python\n  def setup_graph(self):\n  \tx_period, y_principle_paid, y_interest_paid, y_remaining_balance = self.get_plot_points()\n    width = 0.22\n    x = np.array(x_period)\n    y1 = np.array(y_principle_paid)\n    y2 = np.array(y_interest_paid)\n    y3 = np.array(y_remaining_balance)\n\n    figure = Figure(figsize=(9, 5))\n    fig = figure.add_subplot(111)\n\n    fig.bar(x - width, y1, width, label=\"Total paid\", color=\"orange\")\n    fig.bar(x, y2, width, label=\"Interest paid\", color=\"blue\")\n    fig.bar(x + width, y3, width, label=\"Balance remaining\", color=\"purple\")\n\n    fig.set_title(\"Loan Calculator\", fontsize=16)\n    fig.set_ylabel(\"Amount ($)\", fontsize=14)\n    fig.set_xlabel(\"Year\", fontsize=14)\n    fig.legend()\n\n    canvas = FigureCanvasTkAgg(figure, master=self.window)\n    canvas.get_tk_widget().grid(columnspan=10, rowspan=10, row=0, column=2)\n    canvas.draw()\n    return fig\n  ```\n  \n  13. A function to update graph whenever the calculate button is clicked:\n  ```python\n  def update_graph(self):\n  \tself.graph.clear()\n    self.graph = self.setup_graph()\n  ```\n  \n  14. Now that we have completed both the Loan and Window classes, the following code will allow the app to start:\n  ```python\n  root = tk.Tk()\n  start = Window(root)\n  root.mainloop()\n  ```\n  \n  To see finished program code, click [here](https://github.com/RasbeeTech/Loan-Calculator/blob/main/loan_calculator.py)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frasbeetech%2Floan-calculator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frasbeetech%2Floan-calculator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frasbeetech%2Floan-calculator/lists"}