Build a Budget App Project - Spend Chart Calculation?

Tell us what’s happening:

For the create_spend_chart section can we please get a more explicit description of the calculation we are supposed to perform?
I am currently doing a percentage calculation like this:
(single category amount spent) / (total spent across all categories)

I am trying to interpret the Console output and I think its telling me my 'o’s are in the wrong place, which would mean I’m doing the calculation wrong, but since we can’t see the test data it’s hard to debug.

Your code so far


Your browser information:

User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36

Challenge Information:

Build a Budget App Project - Build a Budget App Project

1 Like

Are you rounding down?

The height of each bar should be rounded down to the nearest 10.

Can you please share the full error output in the console?

1 Like

Thanks for the reply. Yes I am rounding down: 14% ->10%, 78%->70%, etc.

Here is the console output (image since I couldn’t figure out how to paste it in here and keep the formatting):

File “/home/pyodide/test_module.py”, line 23, in test_create_spend_char
self.assertEqual(actual, expected, ‘Expected different chart representation. Check that all spacing is exact.’)
AssertionError: 'Perc[35 chars] \n 90| \n 80| \n 70|[342 chars] t ’ != 'Perc[35 chars] \n 90| \n 80| \n 70| [339 chars] t ’

Can you share your full code please?

I did a final look over my code before copying and found a big error - I had mismatched the labels with the bars. That is fixed now, but I still get the error ‘Expected different chart representation. Check that all spacing is exact.’
Updated code below.

class Category:
    def __init__(self, category):
        self.category = category
        self.balance = 0
        self.ledger = []
    

    def check_funds(self, amount): 
        if self.balance-amount >= 0:
            return True
        else: 
            return False

    def get_balance(self):
        return self.balance


    def deposit(self, amount, description=""):
        self.ledger.append({"amount": amount, "description": description})
        self.balance += amount
        #print("Ledger: ",self.ledger)
        #print("Total Funds Available", self.balance)
        
    def withdraw(self, amount, description=""):
        if self.check_funds(amount):
            #used abs() in case user inputs a withdrawl as neg, will still work
            self.ledger.append({"amount": -abs(amount), "description": description})
            self.balance += -abs(amount)
            return True
        else:
            return False
        print("Ledger: ",self.ledger)
        print("Total Funds Available", self.balance)
        print(self.balance)
    

    def transfer(self, amount, target):
        if self.check_funds(amount):
            self.ledger.append
            self.withdraw(amount, f"Transfer to {target.category}")
            target.deposit(amount, f"Transfer from {self.category}")
            return True
        else:
            return False
    
    #This defines how instance of this class, aka a budget category, print()s
    def __str__(self):
        string = ''
        head = self.category.center(30,"*")
        string += head
        string += "\n"
        total = ""
        for line in self.ledger:
            amt = (line['amount'])
            descr = line['description']
            string += f'{descr[0:23]:23}{amt:7.2f}' +"\n" #this f inside the f-string is fixed-point number format. --> 7.2f format a float, reserving 7 spaces, 2 after the decimal point, right justfied by default.
        total = self.balance
        string += "Total: " + str(total) 
        return string
    




def create_spend_chart(categories):
    m = [str(cat.category) for cat in categories] #wrote code in another module then copied here. keeping m
    maxlen = len(max(m, key=len))

        
    for i in range(len(m)):
        m[i] += " "*maxlen
        
        
    transp = [[m[j][i] for j in range(len(m))] for i in range(maxlen)]
    
    #print("\n")
    for row in transp:
        row.insert(0,"     ")
        row.insert(2,"  ") #could make this into a loop. currently brute force. only works if <=4 categories
        row.insert(4,"  ")
        row.insert(6,"  ")
 
        
    
    chart = [None] * (maxlen + 12)
    chart[0] = "Percentage spent by category" #chart title
    chart[1] = "100|" + maxlen*" "
    for i in range (2,11):
        chart[i] = " "+str(110-10*i) + "|"
    chart[11] = "  0|" 
    chart[12] = "    "+"---"*len(categories) + "-"

    transplist = [''.join(ele) for ele in transp]
    

    

#adding the 'o' for percentage
    totspent=0
    for cat in categories:
        j=0
        totdep=0
        spent=0
        for item in cat.ledger: #calc total spent
            if ('Transfer' not in item["description"]) and (item["amount"]<0):
                spent += abs(item["amount"])
                
        for item in cat.ledger:
            if ('Transfer' not in item["description"]) and (item["amount"]>0):
                totdep += item["amount"]
        totspent+=spent
        cat.spent = spent
        print(cat.category, "spent: ",cat.spent)

    totspent+=spent
    print("totspent: ", totspent)
    for cat in categories:
            cat.percent=cat.spent/totspent
    for cat in categories:
            print(cat.category,' ',cat.percent)
    



    for i in range(11):
        row=11-i
        for cat in categories:
            if (cat.percent*10)>=(i):
                chart[row]+=' o '
            else:
                chart[row]+="   "

    chart[13:] = transplist
    #for line in chart:
    #   print(line)

    for i in range(0,12):
            chart[i] += " " * (len(chart[11]) - len(chart[i])+1)
    print("length 100 line: ", len(chart[11]))
    print('\n'.join(chart))        
    return '\n'.join(chart)

An assertion error gives you a lot of information to track down a problem. For example:

AssertionError: 'Year' != 'Years'
- Year
+ Years
?     +

Your output comes first, and the output that the test expects is second.

AssertionError: ‘Year’ != ‘Years’

Your output: Year does not equal what’s expected: Years

The next part is a diff, it shows the difference between two files

- Year
+ Years
?     +

- Dash indicates the incorrect output
+ Plus shows what it should be
? The Question mark line indicates the place of the character that’s different between the two lines. Here a + is placed under the missing s .

I hope this helps interpret your error!

1 Like

Here is your assertion error:

AssertionError: 
'Perc[35 chars]                 \n 90|          \n 80|       [351 chars] t  ' != 
'Perc[35 chars]     \n 90|          \n 80|          \n 70|   [339 chars] t  '

Looks like you have too many spaces before \n 90. You can start with that and see where you get to.

1 Like

I did a quick test:

food = Category("Food")
food.deposit(1000, "deposit")
food.withdraw(10.15, "groceries")
food.withdraw(15.89, "restaurant and more food for dessert")
clothing = Category("Clothing")
food.transfer(50, clothing)
print(food)

print(create_spend_chart([food, clothing]))

The output has a stray o:

Percentage spent by category
100|         o    
 90| o     
 80| o     
 70| o     
 60| o     
 50| o     
 40| o     
 30| o     
 20| o     
 10| o     
  0| o  o  
    -------
     F  C    
     o  l    
     o  o    
     d  t    
        h    
        i    
        n    
        g    
1 Like

Thank you. It’s very helpful to get how to read the console output.
Your test input was helpful too - I realized I hadn’t tested a case where the spending was nearly 100% in a category.
I have fixed that, but still get an assertion error. My number of characters now matches though, so my guess is some characters are in the wrong place.

'Perc[77 chars]| \n 60| \n 50| o \n [297 chars] t ’ !=
'Perc[77 chars]| o \n 60| o \n 50| o \n [297 chars] t ’

Based on the console output of the chart representation:

console2

my interpretation is that the middle column is actually a higher spending percentage than what my code calculates, and there should be more o’s there.
What does the ^ symbol mean in this case?

I’m having a hard time debugging when I’m not sure what the input data is, since my chart representation is correct now based on the various input tests I have tried.

the caret points to a difference

are you sure you are calculating correctly the percentages?

1 Like
'Perc[77 chars]| \n 60| \n 50| o \n [297 chars] t ’ !=
'Perc[77 chars]| o \n 60| o \n 50| o \n [297 chars] t ’

[77 chars] just shows that it’s skipping 77 characters where it’s all the same, so it can focus on showing you the parts where it’s different.

I would do some of your own tests, and ensure it’s calculating percentages correctly

1 Like

Thank you! Since the example above used a + to show the difference I thought ^ might mean something else.

I have found my error. I was almost doing the calculation correctly, but had a line which added the total spent for the last category twice. Fixed and passed.

2 Likes

Got it, thank you!

In case it helps anyone else:
I did a lot more tests, and eventually found my error by creating three spending categories then making the spending 0%, and then 100% in each category one by one.

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.