Chris Parmer — home

Mortality curve

Actuarial — qx by age and sex, log y-axis

Example from the compendium of canonical charts

Actuarial — Mortality curve (qx by age and sex, log y-axis)

Python Code

"""Actuarial — Mortality curve (qx by age and sex, log y-axis)."""


import pandas as pd
import plotly.graph_objects as go

URL = "https://vincentarelbundock.github.io/Rdatasets/csv/dslabs/death_prob.csv"


def generate():
    print("fetching death_prob from Rdatasets …")
    df = fetch_csv(URL)
    print("columns:", df.columns.tolist())
    print(df.head(3))

    df.columns = [c.strip().lower() for c in df.columns]
    # Expected cols: age, sex, prob

    male   = df[df["sex"].str.lower() == "male"].sort_values("age")
    female = df[df["sex"].str.lower() == "female"].sort_values("age")

    fig = go.Figure()

    fig.add_trace(go.Scatter(
        x=male["age"], y=male["prob"],
        mode="lines", name="Male",
        line=dict(color=VIOLET, width=2),
        hovertemplate="Age %{x}: %{y:.5f}<extra>Male</extra>",
    ))

    fig.add_trace(go.Scatter(
        x=female["age"], y=female["prob"],
        mode="lines", name="Female",
        line=dict(color=GREEN, width=2),
        hovertemplate="Age %{x}: %{y:.5f}<extra>Female</extra>",
    ))

    # Annotations — use nearest age to avoid exact-match failure on non-integer ages
    def yval(df_sex, age):
        idx = (df_sex["age"] - age).abs().idxmin()
        return float(df_sex.loc[idx, "prob"])

    male_20   = yval(male, 20)
    female_10 = yval(female, 10)
    male_75   = yval(male, 75)

    annotations = [
        dict(x=20, y=male_20,
             text="Accident hump", showarrow=True, arrowhead=2,
             ax=0, ay=-50, font=dict(size=11, color=MUTED),
             bgcolor="rgba(255,255,255,0.85)", bordercolor="#cccccc"),
        dict(x=10, y=female_10,
             text="Childhood trough", showarrow=True, arrowhead=2,
             ax=75, ay=-40, font=dict(size=11, color=MUTED),
             bgcolor="rgba(255,255,255,0.85)", bordercolor="#cccccc"),
        dict(x=75, y=male_75,
             text="Senescence rise", showarrow=True, arrowhead=2,
             ax=-75, ay=-40, font=dict(size=11, color=MUTED),
             bgcolor="rgba(255,255,255,0.85)", bordercolor="#cccccc"),
    ]

    fig.update_layout(
        xaxis=dict(title="Age"),
        yaxis=dict(title="Annual probability of death (qx)", type="log"),
        legend=dict(orientation="h", y=-0.14),
        margin=dict(t=50, b=70, l=80, r=40),
        annotations=annotations,
    )
    return fig


if __name__ == "__main__":
    generate()

Made with Plotly