Python
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import urllib.request
import os
from io import StringIO

url = "https://data.techforpalestine.org/api/v2/killed-in-gaza.csv"
filename = "killed-in-gaza.csv"

if not os.path.exists(filename):
    urllib.request.urlretrieve(url, filename)

df = pd.read_csv(filename)

# International Database (IDB) of US Census
# Gaza age tables
# https://www.census.gov/data-tools/demo/idb/
gaza_age_table = '''Country/Area Name,Year,GROUP,GENC,Population,% of Population,Male Population,% of Males,Female Population,% of Females,Sex Ratio of the Population
Gaza Strip,2023,0 - 4,XG,278511,13.3,143109,13.4,135402,13.1,1.06
Gaza Strip,2023,5 - 9,XG,279047,13.3,143583,13.5,135464,13.1,1.06
Gaza Strip,2023,10 - 14,XG,274493,13.1,140861,13.2,133632,12.9,1.05
Gaza Strip,2023,15 - 19,XG,255642,12.2,130586,12.3,125056,12.1,1.04
Gaza Strip,2023,20 - 24,XG,211361,10.1,107887,10.1,103474,10.0,1.04
Gaza Strip,2023,25 - 29,XG,180167,8.6,90837,8.5,8933,8.6,1.02
Gaza Strip,2023,30 - 34,XG,154037,7.3,7669,7.2,77347,7.5,0.99
Gaza Strip,2023,35 - 39,XG,109552,5.2,53884,5.1,55668,5.4,0.97
Gaza Strip,2023,40 - 44,XG,90302,4.3,44106,4.1,46196,4.5,0.95
Gaza Strip,2023,45 - 49,XG,69733,3.3,34025,3.2,35708,3.5,0.95
Gaza Strip,2023,50 - 54,XG,55364,2.6,27103,2.5,28261,2.7,0.96
Gaza Strip,2023,55 - 59,XG,45962,2.2,23303,2.2,22659,2.2,1.03
Gaza Strip,2023,60 - 64,XG,35604,1.7,1843,1.7,17174,1.7,1.07
Gaza Strip,2023,65 - 69,XG,24244,1.2,12596,1.2,11648,1.1,1.08
Gaza Strip,2023,70 - 74,XG,16471,0.8,8758,0.8,7713,0.7,1.14
Gaza Strip,2023,75 - 79,XG,9523,0.5,4844,0.5,4679,0.5,1.04
Gaza Strip,2023,80 - 84,XG,4947,0.2,2321,0.2,2626,0.3,0.88'''

csvStringIO = StringIO(gaza_age_table)
dfAgeTable = pd.read_csv(csvStringIO)
maleAgeTable = dfAgeTable["% of Males"]
femaleAgeTable = dfAgeTable["% of Females"]
AgeTable = dfAgeTable["% of Population"]

# Gendered cohorts
male_ages = df[df["sex"] == "m"]["age"]
female_ages = df[df["sex"] == "f"]["age"]

# Calculate histogram per sex
bins = np.arange(0, 90, 5)
male_hist, _ = np.histogram(male_ages, bins=bins)
female_hist, _ = np.histogram(female_ages, bins=bins)

# Calculate sum and difference per bin
diff = male_hist - female_hist
total = male_hist + female_hist

# Calculate general statistics
print("General Statistics")
print(f"Total number of deaths: {total.sum()}")
print(f"Number of male deaths: {male_hist.sum()}")
print(f"Number of female deaths: {female_hist.sum()}")
print(f"Excess male deaths (male - female): {diff.sum()} ({np.round(diff.sum()/total.sum()*100,2)}% of total deaths)")
# male age bins death frequency / male general population bin %
print("male age bins death frequency / male general population bin %\n",np.round(male_hist/male_hist.sum()*100/maleAgeTable.to_numpy(dtype="float"),1))
# female age bins death frequency / female general population bin %
print("female age bins death frequency / female general population bin %\n",np.round(female_hist/female_hist.sum()*100/femaleAgeTable.to_numpy(dtype="float"),1))
# age bins death frequency / general population %
print("age bins death frequency / general population bin %\n",np.round(total/total.sum()*100/AgeTable.to_numpy(dtype="float"),1))

plt.figure(figsize=(12, 8))
bin_centers = (bins[:-1] + bins[1:]) / 2

# First subplot: original histograms
plt.subplot(2, 1, 1)

plt.bar(bin_centers-1.25, male_hist, width=2, label="Male", color="dodgerblue", edgecolor="black")
plt.bar(bin_centers+1.25, female_hist, width=2, label="Female", color="hotpink", edgecolor="black")
plt.locator_params(axis='x', nbins=19)
plt.xlabel("Age Range")
plt.ylabel("Count")
plt.title("Age Distribution of male and female death count")
plt.legend()

# Second subplot: difference and sum
plt.subplot(2, 1, 2)

plt.bar(bin_centers, total, width=4, label="Male + Female", color="white", edgecolor="black")
plt.bar(bin_centers, diff, width=4, label="Male - Female", color="purple", edgecolor="black")
plt.locator_params(axis='x', nbins=19)
plt.xlabel("Age Range")
plt.ylabel("Count")
plt.title("Difference and Sum of male and female death count by age bin")
plt.legend()

plt.tight_layout()
plt.show()
General Statistics
Total number of deaths: 58186
Number of male deaths: 39567
Number of female deaths: 18619
Excess male deaths (male - female): 20948 (36.0% of total deaths)
male age bins death frequency / male general population bin %
 [0.5 0.5 0.6 0.9 1.1 1.4 1.7 1.8 1.5 1.4 1.4 1.3 1.4 1.4 1.7 1.5 1.9]
female age bins death frequency / female general population bin %
 [0.9 0.9 0.9 0.8 0.8 1.  1.1 1.1 1.  1.2 1.3 1.5 1.7 1.8 2.2 2.  2.7]
age bins death frequency / general population bin %
 [0.6 0.6 0.7 0.9 1.  1.3 1.5 1.6 1.3 1.3 1.3 1.4 1.5 1.5 1.8 1.6 2.6]