Simple BMI calculator in python but while loop does not execute for incorrect input - python-3.8

# Welcoming message
print('Welcome to the bmi calculator')
user = str(input("What's your name?:"))
print('\n')
# Declaring unit as empty
unit = ''
while not unit:
unit = str(input("Chose 1 for imperial and 2 for metric units(1/2):"))
if unit in ("12"):
if unit == "1":
print('You have chosen imperial units')
heighti = float(input('Please enter your height in inches:'))
weighti = float(input('Now please enter your weight in lbs:'))
bmi = ((weighti / (heighti**2) * 703))
elif unit == "2":
print('You have chosen metric units')
heightm = float(input('Please enter your height in metres:'))
weightm = float(input('Please enter your weight in kg:'))
bmi = (weightm / (heightm**2))
else:
unit = ''
print(f'Your BMI is {bmi}')
print('\n')
print('your bmi results show that you are:')
if bmi > 24:
print('Overweight')
elif bmi < 19:
print('Underweight')
else:
print('In The ideal range for human')
else:
pass
else:
print('Sorry,invalid choice,must be either 1 for imperial or 2 for metric')
Project runs smoothly once 1 or 2 is typed by the user, however if an input like 3 is put, the error is:
Sorry,invalid choice,must be either 1 for imperial or 2 for metric
***Repl Closed***
I have edited the code such that the 3rd if statement encapsulates the rest of the code. My situation is that the program works well if 1 or 2 is inputted by the user, however does not start over to ask for user's input if the first input is not 1 or 2.

Your IF statement if unit in ("12"): needs an additional else statement.
It will accept 1 or 2 but without an else case to catch numbers outside of that scope, you're code wont move to the nested if statements.
ie:
while not unit:
unit = str(input("Chose 1 for imperial and 2 for metric units(1/2):"))
if unit in ("12"):
if unit == "1":
print('You have chosen imperial units')
heighti = float(input('Please enter your height in inches:'))
weighti = float(input('Now please enter your weight in lbs:'))
bmi = ((weighti / (heighti**2) * 703), 5)
elif unit == "2":
print('You have chosen metric units')
heightm = float(input('Please enter your height in metres:'))
weightm = float(input('Please enter your weight in kg:'))
bmi = (weightm / (heightm**2), 2)
else:
unit = ''
print(f'Your BMI is {bmi}')
print('\n')
print('your bmi results show that you are:')
if bmi > 24:
print('Overweight')
elif bmi < 19:
print('Underweight')
else:
print('In The ideal range for human')
else:
print('Please choose either 1 for imperial or 2 for metric')

Related

Pigs counting when crossing a line using OpenCV

I'm trying to count the number of piglets that enter and leave a zone. This is important because, in my project, there is a balance underneath the zone that computes the weight of the animals. My goal is to find the pig's weight, so, to achieve that, I will count the number of piglets that enter the zone, and if this number is zero, I have the pig's weight, and according to the number of piglets that get in I will calculate the weight of each as well.
But the weight history is for the future. Currently, I need help in the counting process.
The video can be seen here. The entrance occurs from the minute 00:40 until 02:00 and the exit starts on the minute 03:54 and goes all the way through the video because the piglets start, at this point, to enter and exit the zone.
I've successfully counted the entrance with the code below. I defined a region of interest, very small, and filter the pigs according to their colors. It works fine until the piglets start to move around and get very active, leaving and entering the zone all the time.
I'm out of ideas to proceed with this challenge. If you have any suggestions, please, tell me!
Thanks!!
import cv2
FULL_VIDEO_PATH = "PATH TO THE FULL VIDEO"
MAX_COLOR = (225, 215, 219)
MIN_COLOR = (158, 141, 148)
def get_centroid(x, y, w, h):
x1 = int(w / 2)
y1 = int(h / 2)
cx = x + x1
cy = y + y1
return cx, cy
def filter_mask(frame):
# create a copy from the ROI to be filtered
ROI = (frame[80:310, 615:620]).copy()
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
# create a green rectangle on the structure that creates noise
thicker_line_filtered = cv2.rectangle(ROI, (400, 135), (0, 165), (20, 200, 20), -1)
closing = cv2.morphologyEx(thicker_line_filtered, cv2.MORPH_CLOSE, kernel)
opening = cv2.morphologyEx(closing, cv2.MORPH_OPEN, kernel)
dilation = cv2.dilate(opening, kernel, iterations=2)
# Filter the image according to the colors
segmented_line = cv2.inRange(dilation, MIN_COLOR, MAX_COLOR)
# Resize segmented line only for plot
copy = cv2.resize(segmented_line, (200, 400))
cv2.imshow('ROI', copy)
return segmented_line
def count_pigs():
cap = cv2.VideoCapture(FULL_VIDEO_PATH)
ret, frame = cap.read()
total_pigs = 0
frames_not_seen = 0
last_center = 0
is_position_ok = False
is_size_ok = False
total_size = 0
already_counted = False
while ret:
# Window interval used for counting
count_window_interval = (615, 0, 620, 400)
# Filter frame
fg_mask = filter_mask(frame)
# Draw a line on the frame, which represents when the pigs will be counted
frame_with_line = cv2.line(frame, count_window_interval[0:2], count_window_interval[2:4],(0,0,255), 1)
contours, _ = cv2.findContours(fg_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# If no contour is found, increments the variable
if len(contours) == 0:
frames_not_seen += 1
# If no contours are found within 5 frames, set last_center to 0 to generate the position difference when
# a new counter is found.
if frames_not_seen > 5:
last_center = 0
for c in contours:
frames_not_seen = 0
# Find the contour coordinates
(x, y, w, h) = cv2.boundingRect(c)
# Calculate the rectangle's center
centroid = get_centroid(x, y, w, h)
# Get the moments from the contour to calculate its size
moments = cv2.moments(c)
# Get contour's size
size = moments['m00']
# Sum the size until count the current pig
if not already_counted:
total_size += size
# If the difference between the last center and the current one is bigger than 80 - which means a new pig
# enter the counting zone - set the position ok and set the already_counted to False to mitigate noises
# with significant differences to be counted
if abs(last_center - centroid[1]) > 80:
is_position_ok = True
already_counted = False
# Imposes limits to the size to evaluate if the contour is consistent
# Min and Max value determined experimentally
if 1300 < total_size < 5500:
is_size_ok = True
# If all conditions are True, count the pig and reset all of them.
if is_position_ok and is_size_ok and not already_counted:
is_position_ok = False
is_size_ok = False
already_counted = True
total_size = 0
total_pigs += 1
last_center = centroid[1]
frame_with_line = cv2.putText(frame_with_line, f'Pigs: {total_pigs}', (100, 370) , cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0,0,0), 2)
cv2.imshow('Frame', frame_with_line)
cv2.moveWindow('ROI', 1130, 0)
cv2.moveWindow('Frame', 0, 0)
k = cv2.waitKey(15) & 0xff
if k == 27:
break
elif k == 32:
cv2.waitKey() & 0xff
ret, frame = cap.read()
cv2.destroyAllWindows()
cap.release()
if __name__ == '__main__':
count_pigs()

Metrics Calculation for Multilabel Classification Problem

I need to learn how this function works for multilabel problems.
I try to calculate accuracy for to reach same result but i couldnt.
How does it work?
4 labels in this dataset, y_array is real, y_pred is predicted array.
y is like this;
[0,1,1,1], [1,0,0,0] ...
tp = 0
tn = 0
fn = 0
fp = 0
for i in range(len(y_array)):
for j in range(4) :
#True
if ( y_array[i][j] == 1 ) and (y_pred[i][j] == 1 ) :
tp = tp + 1
elif ( y_array[i][j] == 0 ) and (y_pred[i][j] == 0 ) :
tn = tn + 1
#False
elif ( y_array[i][j] == 0 ) and (y_pred[i][j] == 1 ) :
fn = fn + 1
elif ( y_array[i][j] == 1 ) and (y_pred[i][j] == 0 ) :
fp = fp + 1
ac = (tp+tn)/(tp+tn+fp+fn)
print("Accuracy", ac)
print('Accuracy: {0}'.format(accuracy_score(y_array, y_pred)))
They are different from each other, How can i calculate accuracy or other metrics for this multilabel problem?
Is it wrong to use sklearn accuracy metric?
Accuracy 0.9068711367973193
Accuracy: 0.7134998676125521
As per scikit-learn documentation for accuracy_score:
for multilabel classification, this function computes subset accuracy:
the set of labels predicted for a sample must exactly match the
corresponding set of labels in y_true.
This means that each label will look something like [0,0,1,0] and will need identical match for a single Positive (so y_pred will need to be [0,0,1,0] as well), and anything that isn't [0,0,1,0] will result in a single Negative.
In your manual function, you count each partial match separately:
if y_true is [0,0,1,0] and y_pred is [0,1,0,0], you count this as 2 True Negatives (in position 0 and 3), 1 False Positive (position 1) and 1 False Negative (position 2). With the formula you use for accuracy, this results in ac = (0+2)/(0+2+1+1), which gives 50% accuracy, while sklearn.metrics.accuracy_score will be 0%.
If you want to replicate scikit-learn accuracy_score manually, you would need to first check each member of y_array[i], and only then label it as one of the TP,TN,FP,FN.
However seeing as you're dealign with multilabel classification, as per link above, you might want to check out sklearn.metrics.jaccard_score, sklearn.metrics.hamming_loss or sklearn.metrics.zero_one_loss

Need help iterating through a nested list but

'''
patients = [[175.8, 73.4], [180.2, 59.5], [165.4, 70.2], [193.5, 120]]
def calculate_bmi(height, weight):
return weight / ((height / 100 )**2)
def get_bmi_category(bmi):
if bmi < 18.5:
return "underweight"
elif bmi < 25.0:
return "normal weight"
elif bmi < 30:
return "overweighting"
else:
return "obesity"
for patient in patients:
height, weight = patients[0]
bmi = calculate_bmi(height, weight)
bmi_category = get_bmi_category(bmi)
print("Patient's BMI is: {} ({})".format(bmi, bmi_category))
'''
When I print, I only get the results of the first nested list four times, when I want the results of all the nested loops. What else can i do?
problem is with the following line of code
height, weight = patients[0]
above would only assign values of [175.8, 73.4] to height and weight.
update it as follows
height, weight = patient
or
for height, weight in patients:
#in this case you'll have to remove, height, weight = patients[0]
Change height, weight = patients[0] to height, weight = patient.

How do I add the BMI calculation to the following code?

So heres my code below:
def inForm():
name = requestString("What is your name?")
age = requestInteger("What is your age?")
height = requestInteger("What is your height?")
weight = requestInteger("What is your weight?")
print "Hello", name, "!", "You are", age,"years old!", "Your height
is", height, "cm", "and you weigh", weight, "kg"
I need to add the BMI calculation to this code, this is my formula, BMI =weight/(height*height)
With these messages displayed depending on BMI:
You are very severely underweight less than 15
Your are severely underweight from 15.0 to 16.0
You are underweight from 16.0 to 18.5
Your weight is normal from 18.5 to 25
You are overweight from 25 to 30
You are moderately obese from 30 to 35
You are severely obese from 35 to 40
You are very severely obese over 40
I can't seem to figure it out, how would i go by this?
Thanks in Advance!
Instead of converting from cm to m why don't you use requestNumber for the height and weight. Also, the print statement could be shorter like I have demonstrated below. Also, I use %s %d %r this is called String Formatting Operations.
def inForm():
name = requestString("Please enter your name")
age = requestInteger("How old are you?")
height = requestNumber("How tall are you? (Meters)")
weight = requestNumber("How heavy are you? (Kilograms)")
bmi = weight/(height*height)
print "Hello, %s! I see that you are %r years old, %r meters tall, weight %r kgs and your BMI is %d." % (name, age, height, weight, bmi)
n = bmi
if n<15:
print "You are very severely underweight"
elif 15<=n<=16:
print "You are severely underweight"
elif 16<n<=18.5:
print "You are underweight"
elif 18.5<n<=25:
print "Your weight is normal"
elif 25<n<=30:
print "You are overweight"
elif 30<n<=35:
print "You are moderately obese"
elif 35<n<=40:
print "You are severely obese"
elif n>40:
print "You are very severely obese"
For calculating the bmi, you normally use the height in meters (instead of cm). This means you need to adjust twice for the conversion from cm to m in your formula:
bmi = 10000 * weight / (height*height)
print bmi
You can use an if-elif-...-else statement for the text part:
if bmi < 15:
message = "very severely underweight"
elif bmi <= 16:
message = "severely underweight"
# Add more elif parts here...
else:
message = "very severely obese"
print "You are", message

Learning Python 3.3 - TypeError: 'int' object is not callable

I was trying to solve Challenge 2 at the end of the classes chapter (Chapter 8) in "Python Programming for the Absolute Beginner" which is stated as:
Write a program that simulates a television by creating it as an object. The user should be able to enter a channel number and raise or lower the volume. Make sure that the channel number and the volume level stay within valid ranges.
I keep getting: TypeError: 'int' object is not callable, which at this stage just isn't very helpful.
I'm a beginner but I've seen something really similar working (see at the bottom right below my code) and nearly went as far as nearly copying that code. Could somebody maybe explain what's wrong with this and how I can get it to work?
Here's the complete error:
Traceback (most recent call last):
File "Untitled 3.py", line 59, in <module>
main()
File "Untitled 3.py", line 50, in main
tv.channel(newchannel = int(input("What channel would you like to set the TV to?")))
TypeError: 'int' object is not callable
My code is below,
Thanks
class Television(object):
"""a TV"""
def __init__(self, channel = 0, volume = 0):
self.channel = channel
self.volume = volume
def channel(self, newchannel = 0):
if newchannel <= 0 or newchannel >9:
print("No negative numbers or numbers higher than 9. Start again from the menu")
else:
self.channel = newchannel
print("You set the TV on channel", self.channel)
def volume(self, newvolume = 0):
if newvolume <= 0 or newvolume >9:
print("No negative numbers or numbers higher than 9. Start again from the menu")
else:
self.volume = newvolume
print("You set the TV on volume", self.volume)
def watch(self):
print("You are watching channel", self.channel, "at volume", self.volume)
def main():
tv = Television()
choice = None
while choice != "0":
print \
("""
TV
0 - Quit
1 - Watch the TV
2 - Change channel
3 - Set the volume
""")
choice = input("Choice: ")
print()
# exit
if choice == "0":
print("Good-bye.")
elif choice == "1":
tv.watching()
elif choice == "2":
tv.channel(newchannel = int(input("What channel would you like to set the TV to?")))
elif choice == "3":
tv.volume(newvolume = int(input("What channel would you like to set the TV to?")))
# some unknown choice
else:
print("\nSorry, but", choice, "isn't a valid choice.")
main()
("\n\nPress the enter key to exit.")
Why does the following work instead? To me, it looks pretty similar to what I've done.
class Critter(object):
"""A virtual pet"""
def __init__(self, hunger = 0, boredom = 0):
self.hunger = hunger
self.boredom = boredom
def eat(self, food = 4):
print("Brruppp. Thank you.")
self.hunger += food
if self.hunger < 0:
self.hunger = 0
crit = Critter()
print(crit.hunger)
crit.eat(food = int(input("how much do you want to feed him?")))
print(crit.hunger)
The problem is you are defining a method with the same name as a property. That is, you're saying Television.channel is an int, but later you are binding a method to that name.