Skip to content

Commit e8bc121

Browse files
Day 3 added. Day 4 almost finished
1 parent 502d43e commit e8bc121

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+8345
-32
lines changed

.gitignore

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ package.json
1717
vendor/
1818

1919
# Ignore folders for mermaid diagrams
20-
.assets/
20+
assets/
2121

2222
# Environment files
23-
.venv
23+
.venv
24+
.env

_python_code/Day2/car_factory.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
class Car:
2+
# This is the blueprint for a Car
3+
4+
def __init__(self, color, brand, num_wheels=4):
5+
# This is a special method called the "constructor".
6+
# It's like the initial assembly line for a new car.
7+
# 'self' refers to the specific car object being created.
8+
self.color = color # Set the color attribute for this car
9+
self.brand = brand # Set the brand attribute for this car
10+
self.num_wheels = num_wheels # Set the number of wheels (default to 4)
11+
12+
def accelerate(self):
13+
# This is a method (behavior) for a Car object
14+
print(f"The {self.color} {self.brand} car is accelerating!")
15+
16+
def brake(self):
17+
# Another method
18+
print(f"The {self.color} {self.brand} car is braking.")
19+
20+
# Creating an object (a specific car) from the Car class
21+
my_red_car = Car("red", "Toyota")
22+
johns_blue_car = Car("blue", "Honda")
23+
my_red_car.accelerate()
24+
my_red_car.brake()
25+
26+
# Accessing attributes
27+
print(f"My car's color: {my_red_car.color}")
28+
print(f"John's car's brand: {johns_blue_car.brand}")
29+
30+
# Setting (modifying) an attribute
31+
my_red_car.color = "yellow"
32+
print(f"My car's new color: {my_red_car.color}")

_python_code/Day2/data/meals.csv

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
date,meal_type,food,calories
2+
2025-06-01,Breakfast,Oatmeal,250
3+
2025-06-01,Lunch,Chicken Salad,500
4+
2025-06-01,Dinner,Pasta,600
5+
2025-06-02,Breakfast,Eggs,300
6+
2025-06-02,Lunch,Sandwich,450
7+
2025-06-02,Dinner,Steak,700
8+
2025-06-03,Breakfast,Smoothie,200
9+
2025-06-03,Lunch,Rice and Beans,550
10+
2025-06-03,Dinner,Grilled Fish,500
11+
2025-06-04,Breakfast,Yogurt with Granola,320
12+
2025-06-04,Lunch,Vegetable Soup,380
13+
2025-06-04,Dinner,Chicken Curry,650
14+
2025-06-05,Breakfast,Avocado Toast,400
15+
2025-06-05,Lunch,Caesar Salad,420
16+
2025-06-05,Dinner,Salmon with Vegetables,580
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
date,type,duration_minutes,calories_burned
2+
2025-06-01,Running,30,300
3+
2025-06-02,Cycling,45,400
4+
2025-06-03,Yoga,60,200
5+
2025-06-04,Swimming,30,350
6+
2025-06-05,Running,40,350
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import csv
2+
import os
3+
import pandas as pd
4+
import matplotlib.pyplot as plt
5+
from datetime import datetime
6+
from matplotlib.dates import DateFormatter
7+
8+
# ---------- CLASSES ----------
9+
10+
class LogEntry:
11+
def __init__(self, date):
12+
self.date = date
13+
14+
class Workout(LogEntry):
15+
def __init__(self, date, workout_type, duration, calories):
16+
super().__init__(date)
17+
self.workout_type = workout_type
18+
self.duration = duration
19+
self.calories = calories
20+
21+
class Meal(LogEntry):
22+
def __init__(self, date, meal_type, food, calories):
23+
super().__init__(date)
24+
self.meal_type = meal_type
25+
self.food = food
26+
self.calories = calories
27+
28+
# ---------- FILE PATHS ----------
29+
30+
DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
31+
WORKOUTS_FILE = os.path.join(DATA_DIR, 'workouts.csv')
32+
MEALS_FILE = os.path.join(DATA_DIR, 'meals.csv')
33+
34+
# ---------- READ CSV MANUALLY ----------
35+
36+
def read_workouts_manual(file_path):
37+
workouts = []
38+
with open(file_path, newline='') as csvfile:
39+
reader = csv.reader(csvfile)
40+
next(reader) # Skip header
41+
for row in reader:
42+
date = row[0].strip()
43+
workout_type = row[1].strip()
44+
duration = int(row[2].strip())
45+
calories = int(row[3].strip())
46+
workouts.append(Workout(date, workout_type, duration, calories))
47+
return workouts
48+
49+
# ---------- USING PANDAS ----------
50+
51+
def load_and_clean_data():
52+
df_workouts = pd.read_csv(WORKOUTS_FILE)
53+
df_meals = pd.read_csv(MEALS_FILE)
54+
55+
df_workouts['date'] = pd.to_datetime(df_workouts['date'])
56+
df_meals['date'] = pd.to_datetime(df_meals['date'])
57+
58+
# Fill any missing values in workout data with zeros (e.g., missing durations or calories)
59+
df_workouts.fillna(0, inplace=True)
60+
# Fill any missing values in meal data with "Unknown" (e.g., missing food descriptions)
61+
df_meals.fillna("Unknown", inplace=True)
62+
63+
return df_workouts, df_meals
64+
65+
# ---------- ANALYSIS ----------
66+
67+
def summarize_data(df_workouts, df_meals):
68+
workout_summary = df_workouts.groupby('date')['calories_burned'].sum().reset_index()
69+
meal_summary = df_meals.groupby('date')['calories'].sum().reset_index()
70+
71+
combined = pd.merge(workout_summary, meal_summary, on='date', how='outer').fillna(0)
72+
combined['net_calories'] = combined['calories'] - combined['calories_burned']
73+
return combined
74+
75+
# ---------- VISUALIZATION ----------
76+
77+
def plot_fitness_trends(combined_df):
78+
# Create a new figure with specified size (width: 16 inches, height: 10 inches)
79+
# This creates a larger plot that is easier to read and analyze
80+
plt.figure(figsize=(16, 10))
81+
82+
# Plot calories consumed with circular markers
83+
plt.plot(combined_df['date'], combined_df['calories'], label="Calories Consumed", marker='o')
84+
85+
# Plot calories burned with x markers for visual distinction
86+
plt.plot(combined_df['date'], combined_df['calories_burned'], label="Calories Burned", marker='x')
87+
88+
# Plot net calories (consumed - burned) with dashed line style
89+
# This shows the caloric balance for each day
90+
plt.plot(combined_df['date'], combined_df['net_calories'], label="Net Calories", linestyle='--')
91+
92+
# Calculate and plot a 2-day rolling average of net calories
93+
# This smooths out daily fluctuations and shows the overall trend
94+
rolling = combined_df['net_calories'].rolling(window=2).mean()
95+
plt.plot(combined_df['date'], rolling, label="Rolling Mean (Net)", linestyle='dotted')
96+
97+
# Add axis labels with increased font size for better readability
98+
plt.xlabel('Date', fontsize=14)
99+
plt.ylabel('Calories', fontsize=14)
100+
101+
# Format the x-axis to display dates in YYYY-MM-DD format
102+
# This ensures consistent date representation on the chart
103+
date_format = DateFormatter('%Y-%m-%d')
104+
plt.gca().xaxis.set_major_formatter(date_format)
105+
106+
# Rotate x-axis labels by 45 degrees to prevent overlap and increase font size
107+
plt.xticks(rotation=45, fontsize=12)
108+
plt.yticks(fontsize=12)
109+
110+
plt.title('Fitness Tracker Summary', fontsize=16) # Add a descriptive title to the chart with larger font
111+
112+
plt.legend() # Add a legend to identify each line in the plot
113+
114+
plt.grid(True) # Add a grid to make it easier to read values from the chart
115+
116+
plt.tight_layout() # Adjust layout to ensure all elements fit without overlapping
117+
118+
plt.show() # Display the completed chart
119+
120+
121+
# ---------- MAIN FUNCTION ----------
122+
123+
def main():
124+
print("Loading data...")
125+
df_workouts, df_meals = load_and_clean_data()
126+
127+
print("\nSummarizing data...")
128+
combined = summarize_data(df_workouts, df_meals)
129+
print(combined)
130+
131+
print("\nPlotting results...")
132+
plot_fitness_trends(combined)
133+
134+
if __name__ == "__main__":
135+
main()
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
class Vehicle: # General blueprint
2+
def __init__(self, num_wheels, top_speed):
3+
self.num_wheels = num_wheels
4+
self.top_speed = top_speed
5+
6+
def move(self):
7+
print("Vehicle is moving.")
8+
9+
class Car(Vehicle): # Car inherits from Vehicle
10+
def __init__(self, color, brand):
11+
super().__init__(4, 200) # Call the parent (Vehicle) constructor
12+
self.color = color
13+
self.brand = brand
14+
15+
def accelerate(self): # Car has its own specific method
16+
print(f"The {self.color} {self.brand} car is accelerating!")
17+
18+
class Motorcycle(Vehicle): # Motorcycle also inherits from Vehicle
19+
def __init__(self, engine_size):
20+
super().__init__(2, 180) # Call the parent (Vehicle) constructor
21+
self.engine_size = engine_size
22+
23+
def wheelie(self):
24+
print(f"The motorcycle is doing a wheelie!")
25+
26+
my_car = Car("green", "BMW")
27+
my_car.move() # Car can use the Vehicle's move method
28+
my_car.accelerate()
29+
30+
my_motorcycle = Motorcycle("1000cc")
31+
my_motorcycle.move()
32+
my_motorcycle.wheelie()
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
from amadeus import Client, ResponseError
2+
import os, smtplib
3+
from dotenv import load_dotenv
4+
from datetime import datetime, timedelta
5+
import json
6+
import csv
7+
8+
# Load environment variables from .env file
9+
load_dotenv()
10+
11+
12+
amadeus = Client(
13+
client_id= os.getenv("AMADEUS_API_KEY"),
14+
client_secret= os.getenv("AMADEUS_API_SECRET")
15+
)
16+
17+
# Search for flights
18+
try:
19+
response = amadeus.shopping.flight_offers_search.get(
20+
originLocationCode='LON',
21+
destinationLocationCode='SCQ',
22+
departureDate=(datetime.now() + timedelta(days=10)).strftime("%Y-%m-%d"),
23+
adults=1,
24+
currencyCode='GBP')
25+
26+
# Save response to a JSON file
27+
with open('flight_offers.json', 'w') as f:
28+
json.dump(response.data, f, indent=4)
29+
30+
# Extract flight data for CSV
31+
csv_data = []
32+
for offer in response.data:
33+
price_grand_total = offer['price']['grandTotal']
34+
35+
# Process each itinerary
36+
for itinerary in offer['itineraries']:
37+
# For each segment in the itinerary
38+
for segment in itinerary['segments']:
39+
# Get basic segment info
40+
dep_iata = segment['departure']['iataCode']
41+
dep_time = segment['departure']['at']
42+
arr_iata = segment['arrival']['iataCode']
43+
arr_time = segment['arrival']['at']
44+
carrier_code = segment['carrierCode']
45+
46+
# Get baggage info from the first traveler pricing
47+
baggage_info = {}
48+
cabin_bags_qty = None
49+
checked_bags_weight = None
50+
checked_bags_weight_unit = None
51+
52+
if 'travelerPricings' in offer:
53+
for pricing in offer['travelerPricings']:
54+
for fare_detail in pricing['fareDetailsBySegment']:
55+
if fare_detail['segmentId'] == segment['id']:
56+
if 'includedCheckedBags' in fare_detail:
57+
if 'weight' in fare_detail['includedCheckedBags']:
58+
checked_bags_weight = fare_detail['includedCheckedBags']['weight']
59+
checked_bags_weight_unit = fare_detail['includedCheckedBags'].get('weightUnit', 'N/A')
60+
elif 'quantity' in fare_detail['includedCheckedBags']:
61+
checked_bags_weight = fare_detail['includedCheckedBags']['quantity']
62+
checked_bags_weight_unit = 'PIECES'
63+
64+
if 'includedCabinBags' in fare_detail and 'quantity' in fare_detail['includedCabinBags']:
65+
cabin_bags_qty = fare_detail['includedCabinBags']['quantity']
66+
67+
# Add to CSV data
68+
csv_data.append({
69+
'departure_iatacode': dep_iata,
70+
'departure_at': dep_time,
71+
'arrival_iatacode': arr_iata,
72+
'arrival_at': arr_time,
73+
'carriercode': carrier_code,
74+
'price_grandtotal': price_grand_total,
75+
'included_checkedbags_weight': checked_bags_weight,
76+
'included_checkedbags_weightunit': checked_bags_weight_unit,
77+
'included_cabinbags_quantity': cabin_bags_qty
78+
})
79+
80+
# Write to CSV
81+
csv_fields = ['departure_iatacode', 'departure_at', 'arrival_iatacode', 'arrival_at',
82+
'carriercode', 'price_grandtotal', 'included_checkedbags_weight',
83+
'included_checkedbags_weightunit', 'included_cabinbags_quantity']
84+
with open('flight_data.csv', 'w', newline='') as csvfile:
85+
writer = csv.DictWriter(csvfile, fieldnames=csv_fields)
86+
writer.writeheader()
87+
writer.writerows(csv_data)
88+
89+
print(f"Flight data extracted and saved to flight_data.csv")
90+
91+
# Check if any flights are below price threshold
92+
for offer in response.data:
93+
price_grand_total = float(offer['price']['grandTotal'])
94+
if price_grand_total < 150:
95+
try:
96+
with smtplib.SMTP("smtp.gmail.com", 587) as connection:
97+
connection.starttls()
98+
connection.login(user=os.getenv("EMAIL_ADDRESS"), password=os.getenv("GMAIL_PASSWORD"))
99+
connection.sendmail(
100+
from_addr=os.getenv("EMAIL_ADDRESS"),
101+
to_addrs="[email protected]",
102+
msg=f"Subject:Cheap Flight Alert!\n\nOnly {price_grand_total}GBP to fly to Santiago de Compostela!\n On the {dep_time} with {offer['itineraries'][0]['segments'][0]['carrierCode']}.\n\n"
103+
)
104+
print(f"Email alert sent for flight priced at £{price_grand_total}")
105+
except Exception as e:
106+
print(f"Failed to send email alert: {e}")
107+
108+
except ResponseError as error:
109+
print(error)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import requests
2+
3+
base_url = "http://api.openweathermap.org/data/2.5/weather"
4+
params = {
5+
"q": "London",
6+
"appid": "24a16cc554ff1dd57f5586f849772f01",
7+
"units": "metric" # You can change to "imperial" for Fahrenheit
8+
}
9+
10+
response = requests.get(base_url, params=params)
11+
12+
if response.status_code == 200:
13+
data = response.json()
14+
print(f"Weather in {params['q']}: {data['weather'][0]['description']}")
15+
else:
16+
print("Error:", response.status_code, response.text)

0 commit comments

Comments
 (0)