Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
07b12f5
scenario file
PempheroM Nov 13, 2025
cb095e3
Merge branch 'master' into pemphero/nurses_scenario
thewati Nov 13, 2025
6617d49
changes_yearmode,hr scaling
PempheroM Nov 20, 2025
f586244
added default function
PempheroM Nov 21, 2025
94a9b35
reformat
PempheroM Nov 21, 2025
7f24781
Merge remote-tracking branch 'origin/pemphero/nurses_scenario' into p…
PempheroM Nov 21, 2025
ec05b17
remove unused input
PempheroM Nov 21, 2025
97c63a9
Merge branch 'master' into pemphero/nurses_scenario
PempheroM Nov 21, 2025
7994ed8
added files for improved and worse case scenarios
PempheroM Nov 27, 2025
9cb86db
Merge remote-tracking branch 'origin/pemphero/nurses_scenario' into p…
PempheroM Nov 27, 2025
40406ef
addressing comments
PempheroM Dec 8, 2025
6657544
.
thewati Dec 9, 2025
0a95a42
Merge remote-tracking branch 'origin/master'
thewati Dec 9, 2025
6e84902
Merge remote-tracking branch 'origin/master'
thewati Dec 28, 2025
f6cd794
Merge remote-tracking branch 'origin/master'
thewati Jan 12, 2026
660f2a0
Merge remote-tracking branch 'origin/master'
thewati Jan 19, 2026
74e7486
Merge remote-tracking branch 'origin/master'
thewati Jan 23, 2026
e3d3c41
Merge remote-tracking branch 'origin/master'
thewati Jan 27, 2026
992984a
Merge remote-tracking branch 'origin/master'
thewati Feb 3, 2026
7ef22f1
Merge branch 'master' into pemphero/nurses_scenario
thewati Feb 3, 2026
45174af
Merge remote-tracking branch 'origin/pemphero/nurses_scenario' into p…
thewati Feb 3, 2026
cc60285
setup analyses for qs
thewati Feb 3, 2026
95f4020
isort
thewati Feb 3, 2026
6d2ba99
change start and end years
thewati Feb 4, 2026
af3261e
Merge remote-tracking branch 'origin/master'
thewati Feb 4, 2026
55f31fd
Merge branch 'master' into pemphero/nurses_scenario
thewati Feb 4, 2026
b789b7a
Merge branch 'master' into pemphero/nurses_scenario
tbhallett Feb 5, 2026
9fa9a29
Merge branch 'master' into pemphero/nurses_scenario
tbhallett Feb 6, 2026
d5def29
TH suggestions
tbhallett Feb 6, 2026
beadfee
linting!
tbhallett Feb 6, 2026
8c0a02d
Merge remote-tracking branch 'origin/master'
thewati Feb 9, 2026
541555d
Merge remote-tracking branch 'origin/master'
thewati Feb 11, 2026
685d91c
Merge remote-tracking branch 'origin/master'
thewati Feb 12, 2026
481e2bf
plots of draws
thewati Feb 16, 2026
f48c011
Merge remote-tracking branch 'origin/master'
thewati Feb 16, 2026
0687ecc
Merge branch 'master' into pemphero/nurses_scenario
thewati Feb 16, 2026
29f3a3d
Merge remote-tracking branch 'origin/master'
thewati Feb 19, 2026
f8a393d
Merge branch 'master' into pemphero/nurses_scenario
thewati Feb 20, 2026
417503d
from LFS to Git
thewati Feb 20, 2026
e7c2568
Label plots with names and not numbers
thewati Feb 20, 2026
0b139b2
detailed plots
thewati Feb 24, 2026
ea79f95
plots for nurse cadre counts and appointments over time
thewati Feb 25, 2026
5436c6f
Merge remote-tracking branch 'origin/master'
thewati Feb 25, 2026
f3d65f8
Merge remote-tracking branch 'origin/master'
thewati Mar 11, 2026
6b96607
staff num more
thewati Mar 11, 2026
7d92e23
Merge remote-tracking branch 'origin/master'
thewati Mar 12, 2026
05aba63
Merge remote-tracking branch 'origin/master'
thewati Mar 19, 2026
dc00df5
Merge remote-tracking branch 'origin/master'
thewati Mar 30, 2026
dfb7ff1
Merge remote-tracking branch 'origin/master'
thewati Apr 20, 2026
2aab2a4
Merge branch 'master' into pemphero/nurses_scenario
thewati Apr 20, 2026
0b7c8a4
update for next run
thewati Apr 20, 2026
2befeab
comment out unused
thewati Apr 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Officer_Category,L0_factor,L1a_factor,L1b_factor,L2_factor,L3_factor,L4_factor,L5_factor
Clinical,1,1,1,1,1,1,1
DCSA,1,1,1,1,1,1,1
Dental,1,1,1,1,1,1,1
Laboratory,1,1,1,1,1,1,1
Mental,1,1,1,1,1,1,1
Nursing_and_Midwifery,0.85,0.85,0.85,0.85,0.85,0.85,0.85
Nutrition,1,1,1,1,1,1,1
Pharmacy,1,1,1,1,1,1,1
Radiography,1,1,1,1,1,1,1
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Officer_Category,L0_factor,L1a_factor,L1b_factor,L2_factor,L3_factor,L4_factor,L5_factor
Clinical,1,1,1,1,1,1,1
DCSA,1,1,1,1,1,1,1
Dental,1,1,1,1,1,1,1
Laboratory,1,1,1,1,1,1,1
Mental,1,1,1,1,1,1,1
Nursing_and_Midwifery,1.455,1.455,1.455,1.455,1.455,1.455,1.455
Nutrition,1,1,1,1,1,1,1
Pharmacy,1,1,1,1,1,1,1
Radiography,1,1,1,1,1,1,1
197 changes: 197 additions & 0 deletions src/scripts/nurses_analyses/analysis_nurses_scenario.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
"""This file uses the results of the results of running `nurse_analyses/nurses_scenario_analyses.py` to make some summary
graphs."""

import argparse
from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

from scripts.nurses_analyses.nurses_scenario_analyses import StaffingScenario
from tlo.analysis.utils import (
extract_results,
get_scenario_info,
load_pickled_dataframes,
make_age_grp_lookup,
make_age_grp_types,
summarize,
)


# Rename draw numbers to scenario names
def set_param_names_as_column_index_level_0(_df, param_names):
"""Set column index level 0 (draw numbers) to scenario names."""
ordered_param_names = {i: x for i, x in enumerate(param_names)}
names_of_cols_level0 = [
ordered_param_names.get(col)
for col in _df.columns.levels[0]
]
_df.columns = _df.columns.set_levels(names_of_cols_level0, level=0)
return _df


def extract_total_deaths(results_folder):
def extract_deaths_total(df: pd.DataFrame) -> pd.Series:
return pd.Series({"Total": len(df)})

return extract_results(
results_folder,
module="tlo.methods.demography",
key="death",
custom_generate_series=extract_deaths_total,
do_scaling=True
)


def plot_summarized_total_deaths(summarized_total_deaths):
fig, ax = plt.subplots()

scenario_names = summarized_total_deaths.columns.get_level_values(0).unique()

means = np.array([
summarized_total_deaths[(s, "mean")].values[0]
for s in scenario_names
])
lowers = np.array([
summarized_total_deaths[(s, "lower")].values[0]
for s in scenario_names
])
uppers = np.array([
summarized_total_deaths[(s, "upper")].values[0]
for s in scenario_names
])

ax.bar(
scenario_names,
means,
yerr=[means - lowers, uppers - means],
capsize=5
)

ax.set_ylabel("Total number of deaths")
ax.set_xticklabels(scenario_names, rotation=45, ha="right")
fig.tight_layout()

return fig, ax


def compute_difference_in_deaths_across_runs(total_deaths, scenario_info):
deaths_difference_by_run = [
total_deaths[0][run_number]["Total"] - total_deaths[1][run_number]["Total"]
for run_number in range(scenario_info["runs_per_draw"])
]
return np.mean(deaths_difference_by_run)


def extract_deaths_by_age(results_folder):
def extract_deaths_by_age_group(df: pd.DataFrame) -> pd.Series:
_, age_group_lookup = make_age_grp_lookup()
df["Age_Grp"] = df["age"].map(age_group_lookup).astype(make_age_grp_types())
df = df.rename(columns={"sex": "Sex"})
return df.groupby(["Age_Grp"])["person_id"].count()

return extract_results(
results_folder,
module="tlo.methods.demography",
key="death",
custom_generate_series=extract_deaths_by_age_group,
do_scaling=True
)


def plot_summarized_deaths_by_age(deaths_summarized_by_age):
fig, ax = plt.subplots()

scenario_names = deaths_summarized_by_age.columns.get_level_values(0).unique()

for i, scenario in enumerate(scenario_names):
central_values = deaths_summarized_by_age[(scenario, "mean")].values
lower_values = deaths_summarized_by_age[(scenario, "lower")].values
upper_values = deaths_summarized_by_age[(scenario, "upper")].values

ax.plot(
deaths_summarized_by_age.index,
central_values,
label=scenario
)

ax.fill_between(
deaths_summarized_by_age.index,
lower_values,
upper_values,
alpha=0.3
)

ax.set(xlabel="Age-Group", ylabel="Total deaths")
ax.set_xticks(deaths_summarized_by_age.index)
ax.set_xticklabels(deaths_summarized_by_age.index, rotation=90)
ax.legend()
fig.tight_layout()
return fig, ax


if __name__ == "__main__":

parser = argparse.ArgumentParser(
"Analyse scenario results for nurses scenario"
)
parser.add_argument(
"--scenario-outputs-folder",
type=Path,
required=True,
help="Path to folder containing scenario outputs",
)
parser.add_argument(
"--show-figures",
action="store_true",
help="Whether to interactively show figures",
)
parser.add_argument(
"--save-figures",
action="store_true",
help="Whether to save figures to results folder",
)
args = parser.parse_args()

# results_folder = args.scenario_outputs_folder

results_folder = Path(
'./outputs/wamulwafu@kuhes.ac.mw/nurses_scenario_outputs-2026-02-09T110530Z'
)

# Load log (optional, but useful)
log = load_pickled_dataframes(results_folder)

scenario_info = get_scenario_info(results_folder)

# Get scenario names directly from Scenario class

param_names = tuple(StaffingScenario()._scenarios.keys())

# Total deaths
total_deaths = extract_total_deaths(results_folder).pipe(
set_param_names_as_column_index_level_0,
param_names=param_names
)

summarized_total_deaths = summarize(total_deaths)

fig_1, ax_1 = plot_summarized_total_deaths(summarized_total_deaths)

# Deaths by age
deaths_by_age = extract_deaths_by_age(results_folder).pipe(
set_param_names_as_column_index_level_0,
param_names=param_names
)

summarized_deaths_by_age = summarize(deaths_by_age)

fig_2, ax_2 = plot_summarized_deaths_by_age(summarized_deaths_by_age)

if args.show_figures:
plt.show()

if args.save_figures:
fig_1.savefig(results_folder / "total_deaths_across_scenarios.pdf")
fig_2.savefig(results_folder / "deaths_by_age_across_scenarios.pdf")
Loading
Loading