Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
What is going on?
#1
What it needs to do....
Quote:2. InputExpenseNames
First create an empty list for expense items. Next, enter a loop that iterates for as long as the user
responds that there are more item names to enter. In the loop, display a message asking the user to
input the name of an expense item, then input the name and append it to the list. Then input a
response to the question whether there are more item names.
After the loop ends, return the expense items list.
3. InputExpenseAmounts
Create an empty list for expense amounts. Enter a loop that uses the size (you may use the len
function) of the expense items list to determine number of iterations. For each iteration, display a
message that says:
How much was spent on xxxxxxxxxx expense item?
where xxxxxxxxxx is replaced by the name from the expense_items_list corresponding to the current
iteration. The amount should then be input and appended to the expense amounts list. Input
validation should be done including using try … except … to ensure a number was entered.
After the loop ends, return the expense amounts list.


What I have...
def InputExpenseNames():
    expenseItems = []    
    name = input("Enter expense name (q for quit):")    
    while name != "q" :    
        expenseItems.append(name)    
        name = input("Enter expense name (q for quit):")    
    return expenseItems
        
#expense amounts expenseAmounts
def InputExpenseAmounts(expenseItems):
    expenseAmounts = []
    print('How much was spent on ')
    for i in expenseItems:
        amount = int(input(i + 'expense items?'))
        expenceAmount.append(amount)
   return expenseAmounts
What I am getting is it goes back to the main_menu and not allowing me to input. Recommendations on how to fix this so I can input into the expenseItems list.


This is what I have def in main...
while choice != quitOp:
        main_menu()
        choice = int(input('Enter expense report option: '))

        if choice == nameOp:
            InputExpenseNames()

        elif choice == amountOp:
            InputExpenseAmounts(expenseItems)

        elif choice == reportOp:
            displayExpenseReport(expenseItems, expenseAmounts)
             
        else:
            print('Thank you, goodbye')
Reply
#2
Your posted code does not do what you describe. It contains errors that prevent running the code at all. After I fix the errors I cannot call amountOp or reportOp because your main function does not save the list returned by InputExpenseNames. I can call InputExpenseNames, and that does not do what you describe. Next time post the actual code.

Your functions don't work with your main. Main ignores the list returned by InputExpenseNames. Maybe this is what you are talking about. Calling InputExpenseNames creates a new list and adds expense names to this list. Your main loop ignores this list, and the list returned by InputExpenseAmounts, so when you call InputExpenseAmounts, it must be passing an empty list that you initialized in some code you did not post (more reason to include all code in post). These two expenseItems lists are completely different lists.
expenseItems = []
def InputExpenseNames():
    expenseItems = []
It doesn't matter that they have the same name. Assignment inside a function creates a variable that is local to the function, even if there is a global variable that has the same name. Your main needs to assign the list returned by InputExpenseNames. Like this:
        if choice == nameOp:
            expenseItems = InputExpenseNames()
This loop is wrong.
while choice != quitOp:
        main_menu()
        choice = int(input('Enter expense report option: '))
 
        if choice == nameOp:
            expenseItems = InputExpenseNames()  # Fixed this
 
        elif choice == amountOp:
            expenseAmounts = InputExpenseAmounts(expenseItems)  # Fixed this
 
        elif choice == reportOp:
            displayExpenseReport(expenseItems, expenseAmounts)
              
        else:
            print('Thank you, goodbye')
If the user enters something that is not nameOp, amountOp, reportOp or quitOp, your program prints "Thank you. goodbye" and asks for the next menu option. You need to test your code by providing invalid inputs to see what happens.

Why are you doing this?
choice = int(input('Enter expense report option: '))
Do you do math with choice? Is it an index into a list? If you don't use something as an int, don't make it an int. You can check if user input is "1" without worrying about the user entering "a" and crashing the program. Entering an int is dangerous and should be avoided when possible.

Why does this code have two inputs?
def InputExpenseNames():
    expenseItems = []    
    name = input("Enter expense name (q for quit):")    
    while name != "q" :    
        expenseItems.append(name)    
        name = input("Enter expense name (q for quit):")    
    return expenseItems
Repeating code, even if it is one line of code, should make your skin crawl. You should only have one input and break out of the loop if the user inputs "q".

There is a python naming convention that function and variable names don't contain capital letters. Instead of InputExpenseNames the convention is to use underscores: input_expense_names. May as well follow coding conventions while learning coding. You won't learn any bad habits.

It may be a matter of omission, like you posted code, but the instructions you posted make no mention of having a menu. Is the menu required? If a menu is required, do you need an option to input expense names and another to input expense amounts? It seems odd that you would not do them at the same time. Maybe a menu option for entering expenses that would call your funciton to input names and then call the function to enter amounts. Make sure you are solving the correct problem. Most coding errors are not writing code that matches the requirements, and the hardest part of coding is understanding what your customer needs. Once you understand the requirments the coding is fairly easy.

As an exmaple, your code does not address this requirement:
Quote: Input validation should be done including using try … except … to ensure a number was entered.
Reply
#3
Thank you for the input...but understand...I have been doing this for one month. This is homework, which means I am learning.

In some moment, the code does not look pretty, but it works.

I did not post the 5 page pdf of what is expected for this project, I just wanted help on getting the list made in one function and using it in another. If I have it in the code...it has to be there.

Quote:PROJECT 4 INTRODUCTION

The goal of this programming project is to enable students practice solving a problem that uses the Python features of functions and lists.

PROBLEM

Write a program that inputs names of personal expenses and a corresponding amount for each expense. The program should store all input data in lists. The program should present the user with a main menu to select options to:

1. Input personal expense names

2. Input personal expense amounts

3. Display the expenses (names and amounts)

4. Exit the program

The program should then allow the user to select how the information will be displayed from the list of:

(a) pie chart

(b) bar chart

© table.

The program should achieve this in functions described below. To ensure good programming and modularity, none of the functions should call itself and the only function calls should be in the main function. Functions should not be defined inside other functions. At the bottom, there should be a statement that calls the main function.

Here are the descriptions of what should be in the functions:

1. main

This function will have statements to call the other functions and display the main menu. The first function called will input names of the expenses into a list and assign the list to a list object. The second call will pass the expense items list to a function that inputs expense amounts into a second list that is then assigned to a list object. The third call passes the two lists to a function that will display the contents on the two lists.

Here are the Python statements:

expenseItems = InputExpenseNames()
expenseAmounts = InputExpenseAmounts(expenseItems)
DisplayExpenseReport(expenseItems, expenseAmounts)

2. InputExpenseNames First create an empty list for expense items. Next, enter a loop that iterates for as long as the user responds that there are more item names to enter. In the loop, display a message asking the user to input the name of an expense item, then input the name and append it to the list. Then input a response to the question whether there are more item names.

After the loop ends, return the expense items list.

3. InputExpenseAmounts

Create an empty list for expense amounts. Enter a loop that uses the size (you may use the len function) of the expense items list to determine number of iterations. For each iteration, display a message that says:

How much was spent on xxxxxxxxxx expense item?

where xxxxxxxxxx is replaced by the name from the expense_items_list corresponding to the current iteration. The amount should then be input and appended to the expense amounts list. Input validation should be done including using try ... except ... to ensure a number was entered.

After the loop ends, return the expense amounts list.

4. DisplayExpenseReport

Parameters to this function will be the expense items and expense amounts lists. Your program should offer the user the menu of (a) table display (b) pie chart © bar chart. When the user selects option (a), the program should output column headings and then enters a loop that iterates as many times as the size of the expense items list and outputs the contents of the lists. The program should output some type of delineation that expenses are done and output the total of the amounts in the expense amounts list. After exiting the loop, the program should display the totals line of the report. Use the format function and format strings. Here is an example of what the output may look like.

EXPENSE ITEM AMOUNT
------------------- ------------
Rent 450.00
Car loan payment 375.50
Food and groceries 250.00
Electricity 75.00
Water 35.68
=========== ========
TOTALS 1,186.18

When the user selects option (b), the program should output a pie chart of the data in the lists using matplotlib.

When the user selects option ©, the program should output a bar chart of the data in the lists using matplotlib.

Hint

In plotting a pie chart the following did not work for me:

• plt.pie(expenseAmounts, expenseNames)

It required creating and adding a parameter between amounts and names called explode: explodes = [] # create an explodes array for the chart

for expense in expenseAmounts: explodes.append(0.05) plt.pie(expenseAmounts, explodes, expenseNames

this is most of what is expected
Reply
#4
You did not need explode. The problem was you passed expenseItems as a positional parameter, so pie accepted this as the optional explode argument. The correct way to solve the problem is use named parameters. Like this:\
def report(items, amounts):
    plt.pie(amounts, labels=items)  # Tells pyplot.pie that items is the labels for the plot.
    plt.show()
Reply
#5
(Jun-28-2024, 08:34 PM)deanhystad Wrote: You did not need explode.

Not exploding...but you did say...make my skin crawl.

Also understand, I am a perfectionist, and this class is going to bring down my 4.0

...i am stressing...
Reply
#6
Personally, if I have the name of / reason for an expense and its value, I think they are better in a dictionary.

The teacher obviously does not like students!

from string import ascii_uppercase
from random import choices, randint
from pprint import pprint
from matplotlib import pyplot as plt
import matplotlib.colors

# make some random names, save all that inputting by hand
# unlikely to be any identical entries in a small sample
# otherwise exclude them somehow
names = [''.join(choices(ascii_uppercase, k=5)) for i in range(10)]
# if you really need the amounts as a list:
amounts_list = [randint(1, 1001) for i in range(10)]
# make a dictionary of name: amount, save all that inputting by hand
amounts = {name: randint(1, 1001) for name in names}
# show the data
pprint(amounts)

def main():
    # make some random names, save all that inputting by hand
    names = [''.join(choices(ascii_uppercase, k=5)) for i in range(10)]
    # if you really need the amounts as a list:
    amounts_list = [randint(1, 1001) for i in range(10)]
    # make a dictionary of name: amount, save all that inputting by hand
    amounts = {name: randint(1, 1001) for name in names}
    # show the data
    pprint(amounts)
    # or
    for item in amounts.items():
        print(f'We wasted {item[1]} on {item[0]}.')

# Creating a pie
fig = plt.figure(figsize=(10, 7), num="Apple pie")
plt.pie(amounts_list, labels=names)
# show plot
plt.show()
Reply
#7
There are some errors in the code:

Typo in InputExpenseAmounts function: expenceAmount.append(amount) should be expenseAmounts.append(amount).

Not storing the returned lists from InputExpenseNames and InputExpenseAmounts in the main loop.
Reply
#8
Here is a function for the bar chart exploded! (I am a terrorist!)

def pie_chart():
    colours = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red', 'tab:purple', 'tab:brown', 'tab:pink', 'tab:gray', 'tab:olive', 'tab:cyan']
    explode = (0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1)
    expense_names = ['beer', 'car', 'computers', 'flowers', 'food', 'fun', 'girlfriend', 'hotels', 'lawyer', 'mobile']
    expense_amounts = {name: randint(1, 1001) for name in expense_names}
    values = list(expense_amounts.values())
    names = list(expense_amounts.keys())
    total = sum(values)
    # Wedge properties
    wp = {'linewidth': 1, 'edgecolor': "blue"}
    # Creating autocpt arguments
    # percent values
    def func(pct, allvalues):
        absolute = int(pct / 100.*sum(allvalues))
        return "{:.1f}%\n(£{:d})".format(pct, absolute)
    # Creating plot
    fig, ax = plt.subplots(figsize=(10, 7), num="My Expenses per Week")
    # setting the axes title invokes the axes don't want to see them so hide them 
    ax.set_title(f"My Expenses Total = £{total}.00", fontsize=16)
    #hide x-axis
    ax.get_xaxis().set_visible(False)
    #hide y-axis 
    ax.get_yaxis().set_visible(False)
    wedges, texts, autotexts = ax.pie(values,
                                      autopct=lambda pct: func(pct, values),
                                      explode=explode,
                                      labels=names,
                                      shadow=True,
                                      colors=colours,
                                      startangle=90,
                                      wedgeprops=wp,
                                      textprops=dict(color="black"))

    # Adding legend
    ax.legend(wedges, names,
              title="My Expenses",
              loc="upper left",
              bbox_to_anchor=(-0.4, 0, 0.5, 1))

    plt.setp(autotexts, size=8, weight="bold")
    # show plot
    plt.show()
New, improved!
Reply


Forum Jump:

User Panel Messages

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