import pandas as pd
import numpy as np
import matplotlib.pyplot as pltIntro to Pandas and Matplotlib
UBDS 2026: Basic Python
Day 4 : Pandas & Matplotlib
Topics covered
- Learn to handle large datasets using Pandas. / Вивчимо як працювати з великими датасетами використовуючи пандас
- Perform basic numerical analyses with NumPy. / Проведемо базовий стат аналіз викорстовуючи numpy
- Visualise data using Matplotlib. / Візуалізуємо дані використовуючи matplotlib
- Explore real-world biological data from the AnAge database. / Дослідимо реальні біологічна данні використовуючи AnAge датасет
Resources
Pandas documentation: https://pandas.pydata.org/docs/user_guide/index.html
Graph examples: https://python-graph-gallery.com
We will use the AnAge dataset (‘anage_data.tsv’); a curated database of ageing and life history in animals, including extensive longevity records / Ми будемо використовувати датасет AnAge, що є очищеною базою даних про старіння і довголіття у тварин.
Step 0: Import the tools we need
pandashelps us work with tables of data, given the alias; pd / допомогає нам працювати з таблицями, коротка назва pdnumpyis needed to work with numerical data, given the alias; np / потрібенн для роботи з числовими данними, коротка назва npmatplotlibhelps us make plots, given the alias; plt / потрібен для роботи з графіками, коротка назва plt
Step 1: Load the Dataset
- Make sure the file is in the same folder as your notebook / Перевірте що файл знаходиться в потрібній папці
# Read in the dataframe - use separator=tab as we have a tab separated file / Читаємо файл вказуючи що розділовий знак це Tab
df = pd.read_csv("anage_data.tsv", sep='\t')
# Filter the dataframe columns to the ones we are interested in / Фільтруємо потрібні колонки
df = df[['Class', 'Order', 'Family', 'Genus', 'Species', 'Common name', 'Female maturity (days)', 'Male maturity (days)', 'Gestation/Incubation (days)', 'Weaning (days)', 'Litter/Clutch size', 'Litters/Clutches per year', 'Inter-litter/Interbirth interval', 'Birth weight (g)', 'Weaning weight (g)', 'Adult weight (g)', 'Growth rate (1/days)', 'Maximum longevity (yrs)', 'Source', 'Specimen origin', 'Sample size', 'Data quality', 'IMR (per yr)', 'MRDT (yrs)', 'Metabolic rate (W)', 'Body mass (g)', 'Temperature (K)']]
df.head(5) # Show first 5 rowsEXERCISE 1
- What happens if you forget to specify sep=‘ when reading a tab delimited dataset? / Перевірте що буде якщо не вкажете sep=’
- As well as the head() method there is a tail() method. What do you think it does? / Що робить метод tail?
- Both methods accept a single numeric parameter. What do you think it does? / Обидва методи приймають параметр, що він робить?
# Your code hereStep 2: Explore the Dataset
- Get basic information about the dataset / Дослідіть базову інформацію про датасет
# How many rows?
print("Dataset length: ", len(df))
# How many rows and columns?
print("Dataset shape:", df.shape)
# How many cells in the table?
print("Dataset size: ", df.size)
# Column names
print("Columns:", df.columns.tolist())
# What are the data types of the columns?
print("Column data types: ", df.dtypes)
# Quick statistics of numeric columns
df.describe()
# Check how many Species are available in the dataset
Species = df['Common name'].to_list()
print("Number of species: ", len(set(Species)))
# Check how many Orders are available in the dataset
Order = df['Order'].to_list()
print("Number of orders: ", len(set(Order)))
# Longest lived species
print(df.loc[df['Maximum longevity (yrs)'].idxmax()])EXERCISE 2
- Name the species with the largest body mass. / Назвіть вид з найбільшою масою тіла
- What is the largest litter size? / А тепер з найбільшою кількістю потомства
- What is the shortest lived species? / А тепер найбільш короткоживучий вид
# Your code hereStep 3: Accessing the data
- Selecting columns and rows / Вибираємо колонки та строчки
# Select one column
lifespan = df['Maximum longevity (yrs)']
print(lifespan.head())
# Select multiple columns
subset = df[['Common name', 'Maximum longevity (yrs)', 'Body mass (g)']]
subset.head()
# Select rows by index
print(df.iloc[0:5])
# Select rows by condition (species with max longevity > 100)
long_lived = df[df['Maximum longevity (yrs)'] > 100]
long_lived[['Common name', 'Maximum longevity (yrs)']]EXERCISE 3: What happens if you:
- List the columns you want out of order from the way they appear in the file? / Спробуйте отримати доступ до колонок перелічивши їх в іншому порядку.
- Put the same column name in twice? / Якщо ви вкажете ім’я колонки двічі
- Put in a non-existing column name? (a.k.a Typo) / Якщо ви вкажете неіснуючу колонку
# Your code hereStep 4: Filtering data
- Filter the rows of the dataframe
- Print the values to get the answer for each filter
# Filter by the index of each row - the range is from ro 1 to row 5
df_filtered = df[1:5]
# Using a criteria to filter rows
df_old = df[df['Maximum longevity (yrs)'] > 30]
# We can filter by more than one attribute
df_old_and_fat = df[(df['Maximum longevity (yrs)'] > 30) & (df['Body mass (g)'] > 30000)]EXERCISE 4
- What happens if we ask for a single row instead of a range? / Що станеться якщо ви попросите одну колонку, а не ряд
- What species have a temperature greater than 300K and a metabolic rate greater than 200W? /Який вид має температуру більше 300К і метаболічну активність більше 200 Ват
# Your code hereStep 5: Handling missing data
- Filter out rows with missing data in the specified columns
- print the values to get the answers
# Check for missing values
missing = df.isna().sum()
# Drop rows with missing MaxLongevity or BodyWeight
df_clean = df.dropna(subset=['Maximum longevity (yrs)', 'Body mass (g)'])
print("Rows after cleaning:", df_clean.shape)EXERCISE 5
- How many missing values are there in each column? Скільки відсутніх значень у кожній колонці
- How many rows remain after removing missing values? / Скільки лишається строчок після прибирання відсутніх значень
- What happens if you drop rows based only on one column instead of two? / Що буде якщо ви приберете відсутні значення лише в одній колонці замість двох
# Your code hereStep 6: Working with large amounts of data with groupby
- When we want summary statistics for different groups in our dataframe
- For example calculating the mean lifespan per taxonomic class
Tip:
- GroupBy is very powerful in Pandas for summarizing data by categories.
# Group by Class and calculate mean MaxLongevity
mean_lifespan = df_clean.groupby('Class')['Maximum longevity (yrs)'].mean()
print(mean_lifespan)EXERCISE 6: GroupBy
- Which class has the highest average lifespan? / У якого класу найдовщий час життя
- How many species are in each class? / Скільки видів в кожному класі
- What is the average body mass per class? / Якою є середня маса в кожному класі
# Your code hereStep 7: Simple Numerical Operations with NumPy
- NumPy allows us to query our data with mathematical functions
- Convert lifespan to a NumPy array for calculations
# Convert lifespan to a NumPy array for calculations
lifespan_array = df_clean['Maximum longevity (yrs)'].to_numpy()
print("Mean lifespan:", np.mean(lifespan_array))
print("Median lifespan:", np.median(lifespan_array))
print("Standard deviation:", np.std(lifespan_array))EXERCISE 7: Numpy operations
- What is the mean lifespan of the dataset? / Якою є середня тривалість життя в усьому датасеті
- Is the median higher or lower than the mean? What does this suggest? / Чи є медіана вище чи нижче за середнє? Що це значить?
- What happens to the standard deviation if you remove extreme values? Use row filtering to remove the longest lived and shortest lived species. / Що стається зі стандартним відхиленням якщо ми приберемо екстримальні значення? Спробуйте пофільтрувати строчки щоб прибрати найдовші та найкоротші тривалості життя.
# Your code hereStep 8: Visualizing Data with Matplotlib
- The histogram is a simple yet useful plot for understanding the distribution of values in a column.
# Histogram of maximum lifespans
plt.figure(figsize=(10,6))
plt.hist(df_clean['Maximum longevity (yrs)'], bins=30, color='skyblue', edgecolor='black')
plt.title("Distribution of Maximum Longevity Across Species")
plt.xlabel("Max Longevity (years)")
plt.ylabel("Number of Species")
plt.show()EXERCISE 8: Histogram (Matplotlib)
- What does the shape of the distribution look like (e.g. skewed or normal)? / Як виглядає форма розподілу даних?
- What happens if you increase or decrease the number of bins? / Що стається якщо ви збільшуєте або зменшуєте кількість стовпців?
- Which lifespan range contains the most species? / Який діапазон тривалості життя включає в себе більшість видів?
# Your code hereStep 9: Scatter Plot
- Scatter plots allow us to compare values from two columns against each other.
# Scatter Plot - Body Weight vs Max Longevity
plt.figure(figsize=(10,6))
plt.scatter(df_clean['Body mass (g)'], df_clean['Maximum longevity (yrs)'], alpha=0.6, color='green')
plt.title("Body Weight vs Max Longevity")
plt.xlabel("Body Weight (kg)")
plt.ylabel("Max Longevity (years)")
plt.show()EXERCISE 9.1: Simple Scatter
Create a scatter plot for each of the following questions to find the answers. / Створіть діаграму розсіювання для кожного з наступних питань, щоб знайти відповіді. 1. Do larger animals tend to live longer? / Чи живуть більші тварини довше? 2. Are there any obvious outliers? / Чи є якість очевидні аутлаєри? 3. What happens if you change the transparency (alpha)? / Що стається якщо ви змінюєте прозорість точок?
# Your code hereImproving our figures
- Adding annotations with colour and labelling certain datapoints makes our figures more informative
- Visualising points on the log scale can help by separating our data and making it more understandable
# Step 8.2: Scatter Plot - colored by Order and label longest-lived species
plt.figure(figsize=(12,8))
# Get unique orders and assign colors <- Colour each point by the phylogenetic tree
orders = df_clean['Order'].unique()
colors = plt.cm.tab20(np.linspace(0, 1, len(orders)))
order_color_map = dict(zip(orders, colors))
# Plot each point with color based on Order
for idx, row in df_clean.iterrows():
plt.scatter(row['Body mass (g)'], row['Maximum longevity (yrs)'],
color=order_color_map[row['Order']], alpha=0.6)
# Label the top 5 longest-lived species
top_longest = df_clean.nlargest(5, 'Maximum longevity (yrs)')
for idx, row in top_longest.iterrows():
plt.text(row['Body mass (g)'], row['Maximum longevity (yrs)'],
row['Common name'], fontsize=9, ha='right', va='bottom')
# Plot the layers for the Matplotlib figure - Title & Axis
plt.xscale('log') # log scale for better visualization
plt.title("Body Weight vs Max Longevity")
plt.xlabel("Body Weight (g, log scale)")
plt.ylabel("Maximum Longevity (yrs)")
# Create a legend for Orders
from matplotlib.patches import Patch
legend_elements = [Patch(facecolor=color, label=order) for order, color in order_color_map.items()]
plt.legend(handles=legend_elements, bbox_to_anchor=(1.05, 1), loc='upper left', fontsize=8)
plt.show()EXERCISE 9.2: Annotated scatter plot
- Which order contains the longest-lived species? / В якому порядку найбільш довгоживучі види?
- Why is a log scale useful for body weight? / Чому логарифмічна шкала для маси є зручною?
- What happens if you label more than 5 species? / Що буде якщо ви додасте підписи до більш ніж 5 видів?
- Can you identify any clusters of related species? / Чи ви бачите якісь кластери пов’язаних видів?
# Your code hereStep 10: Do heavier animals really live longer?
- We can add a regression live to out plots to calculate the correlation between two variables.
correlation = df_clean['Body mass (g)'].corr(df_clean['Maximum longevity (yrs)'])
print(f"Correlation between body weight and longevity: {correlation:.2f}")
# Prepare x and y
x = df_clean['Body mass (g)']
y = df_clean['Maximum longevity (yrs)']
# Take log of x for fitting (because x-axis is log scale)
log_x = np.log10(x)
# Linear regression in log space: y = slope * log10(x) + intercept
slope, intercept = np.polyfit(log_x, y, 1)
# Create points for the regression line
x_fit = np.linspace(x.min(), x.max(), 100)
y_fit = slope * np.log10(x_fit) + intercept
# --- Plot ---
plt.figure(figsize=(12,8))
# Scatter points colored by Order
for idx, row in df_clean.iterrows():
plt.scatter(row['Body mass (g)'], row['Maximum longevity (yrs)'],
color=order_color_map[row['Order']], alpha=0.6)
# Label the top 5 longest-lived species
top_longest = df_clean.nlargest(5, 'Maximum longevity (yrs)')
for idx, row in top_longest.iterrows():
plt.text(row['Body mass (g)'], row['Maximum longevity (yrs)'],
row['Common name'], fontsize=9, ha='right', va='bottom')
# Plot the regression line
plt.plot(x_fit, y_fit, color='red', linewidth=2, label=f'Linear fit (log x)')
plt.xscale('log') # log scale for better visualization
plt.title("Body Weight vs Max Longevity (colored by Order) with correlation line")
plt.xlabel("Body Weight (g, log scale)")
plt.ylabel("Maximum Longevity (yrs)")
# Legend for both orders and regression line
from matplotlib.patches import Patch
legend_elements = [Patch(facecolor=color, label=order) for order, color in order_color_map.items()]
plt.legend(handles=legend_elements + [plt.Line2D([0], [0], color='red', lw=2, label='Linear fit (log x)')],
bbox_to_anchor=(1.05, 1), loc='upper left', fontsize=8)
plt.show()Step 11: What is the distribution of birth weights for animals which live longer than 5 years?
- Group the distribution by taxonomic class.
# Filter for species with longevity > 5 years
long_lived = df_clean[df_clean['Maximum longevity (yrs)'] > 5]
# Prepare data for each Class
classes = long_lived['Class'].unique()
data = []
filtered_classes = []
for cls in classes:
birth_weights = long_lived[long_lived['Class'] == cls]['Birth weight (g)'].dropna()
if len(birth_weights) > 0: # Only keep non-empty arrays
data.append(birth_weights)
filtered_classes.append(cls)
# Create the violin plot
plt.figure(figsize=(12,6))
plt.violinplot(data, showmeans=True, showmedians=True)
# Set x-ticks to class names
plt.xticks(ticks=np.arange(1, len(filtered_classes)+1), labels=filtered_classes, rotation=45)
plt.yscale('log')
plt.ylabel("Birth weight (g)")
plt.title("Distribution of Birth Weight Across Classes (Species > 10 yrs longevity)")
plt.tight_layout()
plt.show()Step 11: Challenge for Students
For each of the following visualise the answer and summarise the results in 2-3 sentences.
- Which Class of animals has the highest average longevity? / В якому класі тварини найбілш довгоживучі?
- Does litter size correlate with longevity? / Чи пов’язана кількість потомства з тривалістю життя?
- Which Order of animals has the highest average longevity? / В якому порядку тварин найбільша середня тривалість життя?
- Create a scatter plot of Body Mass vs Maximum Longevity only for mammals. What is the correlation? / Побудуйте графік розкиду масси тіла проти максимальної тривалості життя тільки дял ссавців. Якою є кореляція?
- Identify species with unexpected lifespans (e.g., small animals that live unusually long). / Визначте види з незвичайною тривалістю життя
- Compare birds and mammals in terms of average lifespan using a bar chart. / Порівняйте птахів та ссавців за їх середньою тривалістю життя використовуючи стовпчастий графік
- Does longevity always correlate with Female (or Male) maturity (days)? Identify species who grow up fast despite being long lived. / Чи тривалість життя корелює з дозріванням для самців чи самок? Визначте види які дорослішають швидше.