The dashboard user function

Source code in src/main.py
def dashboard(config: Config):
    # internal parameters
    # (possibly to generalise later)

    config.expstart = 0

    config.label_path_effects = {
        "linewidth": 1,
        "foreground": config.colors.contrast,
    }

    ############# HELPERS

    config.errors = {}
    config.errors["DateColMissing"] = f"One column must be called '{config.strings.datecol}'."

    config.dotstyle = {
        "marker": config.marker,
        "markersize": config.markersize,
        "linestyle": "None",
    }

    config.projstyle = {
        "linestyle": "-",
        "marker": "None",
        "linewidth": config.linewidth / 4,
    }

    config = read_headers(config)

    ############# DATA

    alldata = pd.read_csv(config.csvdir + config.csv, header=1).fillna(0)
    alldata.columns = list(config.hdrnew.keys())
    alldata["Year"] = dates_to_years(config, alldata)

    expend_count_cols = [col+"_count" for col in config.expend_cols]
    alldata[expend_count_cols] = alldata[config.expend_cols].applymap(_expr_expend_count)
    expend_price_cols = [col+"_price" for col in config.expend_cols]
    alldata[expend_price_cols] = alldata[config.expend_cols].applymap(_expr_expend_price)

    alldata[config.expend_cols] = alldata[config.expend_cols].applymap(_expr_expend)
    alldata[config.cash_cols] = alldata[config.cash_cols].applymap(_expr)
    alldata[config.income_cols] = alldata[config.income_cols].applymap(_expr)

    config.retire_yr = config.born_yr + config.retire_age
    ahead_yr = datetime.now(timezone.utc).year + config.future_window
    config.max_yr = min(ahead_yr, config.retire_yr)

    config.since_yr = config.since_yr or min(alldata.Year)
    config.until_yr = config.until_yr or max(alldata.Year)
    config.years_until_retire = config.max_yr - config.since_yr
    config.age_at_retire = config.max_yr - config.born_yr

    alldata["Days"] = dates_to_days(config, alldata)
    alldata["totalSuper"] = alldata[config.super_cols].sum(axis=1)
    alldata["totalShares"] = alldata[config.shares_cols].sum(axis=1)
    alldata["totalCash"] = alldata[config.cash_cols].sum(axis=1)
    alldata["totalExpend"] = alldata[config.expend_cols].sum(axis=1)
    alldata["totalIncome"] = alldata[config.income_cols].sum(axis=1)
    alldata["total"] = alldata["totalShares"] + alldata["totalSuper"] + alldata["totalCash"]

    alldata = alldata.sort_values(by="Days").reset_index(drop=True)
    income_grand_tot = alldata["totalIncome"].sum()
    income_sum = alldata[config.income_cols].sum()
    config.income_minor = list(income_sum[income_sum < (1 - config.income_thresh) * income_grand_tot].keys())
    config.iminor_bool = len(config.income_minor) > 0

    ## not currently used in the cash panel but this should be generalised
    # cash_grand_tot = alldata["totalCash"].sum()
    # cash_sum = alldata[config.cash_cols].sum()
    # config.cash_minor = list(cash_sum[cash_sum < (1 - config.cash_thresh) * cash_grand_tot].keys())
    # config.cminor_bool = len(config.cash_minor) > 0

    config.years_uniq = {}
    for x in alldata["Year"]:
        if x >= config.since_yr and x <= config.until_yr:
            config.years_uniq[x] = True

    ########### CREATE FIGURE and AXES

    if isinstance(config.layout, str):
        config.layout = [config.layout]

    if "main7" in config.layout:
        create_dashboard_main7(config, alldata)

    if "plain8" in config.layout:
        create_dashboard_plain8(config, alldata)

    if "income4" in config.layout:
        create_dashboard_income4(config, alldata)

    if "cash4" in config.layout:
        create_dashboard_cash4(config, alldata)

    if "share4" in config.layout:
        create_dashboard_share4(config, alldata)

    if "ipad_1" in config.layout:
        create_dashboard_ipad1(config, alldata)

The Config class

Configuration class for networthdash.

Parameters:

Name Type Description Default
layout str

Names visual layout style. Accepts one or more of: {"main7","plain8"}

'main7'
csv str

Filename of the CSV input file. Path information should not be included.

'net-worth.csv'
csvdir str

Path to the CSV input file. Concatenated directly with the CSV filename, so should end in a "/".

'./'
savedir str

Path (ending in "/") to save PDF dashboards.

'Net worth archive/'
saveprefix str

First part of filename to save. Defaults to the CSV filename stripped of its file extension.

None
savesuffix str

Second part of the filename is a date stamp specified in standard datetime format (e.g., %Y-%m-%d). Default setting omits the day, assuming you don't need to log updates too often.

'%Y-%m'
savepdf bool

If true saves a PDF of the dashboard in the savedir folder.

True
savejpg bool

If true saves a JPG of the dashboard in the savedir folder.

False
savepng bool

If true saves a PNG of the dashboard in the savedir folder.

False
datefmt str

The date format used in the CSV file.

'%Y/%m/%d'
since_yr int

Year to start the dashboard (default is the earliest year in the CSV file).

None
until_yr int

Year to conclude the dashboard (default is the latest year in the CSV file).

None
born_yr int

The year you were born.

required
retire_age int

The age at which you expect to retire.

67
retire_ratio float

Thw fraction of your net worth to commence drawing down from yearly in retirement (e.g., for the "4% rule" it would be 0.04).

0.04
cash_thresh float

Threshold (between 0 and 1) for identifying "major" or "minor" cash sources based on the all-time grand totals for each cash column.

required
income_thresh float

Threshold (between 0 and 1) for identifying "major" or "minor" income sources based on the all-time grand totals for each income column.

0.6
linear_window float

Number of years before the current date to linearly extrapolate from.

1.0
future_window float

The maximum number of extrapolation years to show on the graph.

8
linear_targets list[float]

"Targets" to extrapolate to linearly to gauge time until net worth milestones.

(5000, 10000, 15000, 20000, 35000, 50000, 75000, 100000, 150000, 200000, 350000, 500000, 750000, 1000000, 1500000, 2000000, 3500000, 5000000, 7500000, 10000000, 20000000, 50000000, 100000000)
anon bool

If True, hides all numerical labels.

False
colors Colors

Colors class setup for plot colours. See Colors class for defaults and options.

Colors()
strings Strings

Strings class setup for dashboard strings. Includes strings used in the CSV file. See Strings class for defaults and options.

Strings()
figw float

Plot size, horizontal width (physical size).

6
figh float

Plot size, vertical height (physical size).

12.5
linewidth float

Linewidth of scatter plots.

1.0
marker str

Marker of scatter plots.

'.'
markersize float

Markersize of scatter plots.

4.0
node_width float

Relative width of Sankey diagram nodes (ausankey parameter).

0.15
node_alpha float

Alpha (transparency) of Sankey diagram nodes (ausankey parameter).

0.8
flow_alpha float

Alpha (transparency) of Sankey diagram flow transitions between nodes (ausankey parameter).

0.5
currency_sign str

The currency sign used to display amounts.

required
sankey_sort str

The sort option to pass through to the Sankey diagrams. Valid options are "top", "bottom", "none".

'bottom'
sankey_colormaps list

Three colormaps for the panels which are automatically coloured based on breakdown of components. (I.e., not coloured using the Colors class.)

('Set3', 'Pastel1', 'Pastel2')
Source code in src/config.py
@dataclass
class Config:
    """
    Configuration class for networthdash.

    Parameters
    ----------
    layout : str
        Names visual layout style. Accepts one or more of:
        {"main7","plain8"}
    csv : str
        Filename of the CSV input file. Path information should not be included.
    csvdir : str
        Path to the CSV input file. Concatenated directly with the CSV filename, so should end in a "/".
    savedir : str
        Path (ending in "/") to save PDF dashboards.
    saveprefix : str
        First part of filename to save. Defaults to the CSV filename stripped of its file extension.
    savesuffix : str
        Second part of the filename is a date stamp specified in standard datetime format (e.g., `%Y-%m-%d`). Default setting omits the day, assuming you don't need to log updates too often.
    savepdf : bool
        If true saves a PDF of the dashboard in the `savedir` folder.
    savejpg : bool
        If true saves a JPG of the dashboard in the `savedir` folder.
    savepng : bool
        If true saves a PNG of the dashboard in the `savedir` folder.
    datefmt : str
        The date format used in the CSV file.
    since_yr : int
        Year to start the dashboard (default is the earliest year in the CSV file).
    until_yr : int
        Year to conclude the dashboard (default is the latest year in the CSV file).
    born_yr : int
        The year you were born.
    retire_age : int
        The age at which you expect to retire.
    retire_ratio : float
        Thw fraction of your net worth to commence drawing down from yearly in retirement (e.g., for the "4% rule" it would be 0.04).
    cash_thresh : float
        Threshold (between 0 and 1) for identifying "major" or "minor" cash sources based on the all-time grand totals for each cash column.
    income_thresh : float
        Threshold (between 0 and 1) for identifying "major" or "minor" income sources based on the all-time grand totals for each income column.
    linear_window : float
        Number of years before the current date to linearly extrapolate from.
    future_window : float
        The maximum number of extrapolation years to show on the graph.
    linear_targets: list[float]
        "Targets" to extrapolate to linearly to gauge time until net worth milestones.
    anon : bool
        If True, hides all numerical labels.
    colors : Colors
        Colors class setup for plot colours. See Colors class for defaults and options.
    strings : Strings
        Strings class setup for dashboard strings. Includes strings used in the CSV file. See Strings class for defaults and options.
    figw : float
        Plot size, horizontal width (physical size).
    figh : float
        Plot size, vertical height (physical size).
    linewidth : float
        Linewidth of scatter plots.
    marker : str
        Marker of scatter plots.
    markersize : float
        Markersize of scatter plots.
    node_width : float
        Relative width of Sankey diagram nodes (ausankey parameter).
    node_alpha : float
        Alpha (transparency) of Sankey diagram nodes (ausankey parameter).
    flow_alpha : float
        Alpha (transparency) of Sankey diagram flow transitions between nodes (ausankey parameter).
    currency_sign : str
        The currency sign used to display amounts.
    sankey_sort : str
        The sort option to pass through to the Sankey diagrams. Valid options are `"top"`, `"bottom"`, `"none"`.
    sankey_colormaps : list
        Three colormaps for the panels which are automatically coloured based on breakdown of components. (I.e., not coloured using the Colors class.)
    """

    born_yr: int

    layout: str = "main7"

    csv: str = "net-worth.csv"
    csvdir: str = "./"
    datefmt: str = "%Y/%m/%d"

    savedir: str = "Net worth archive/"
    saveprefix: str = None
    savesuffix: str = "%Y-%m"

    savepdf: bool = True
    savejpg: bool = False
    savepng: bool = False

    since_yr: int = None
    until_yr: int = None
    retire_age: int = 67
    retire_ratio: float = 0.04

    # cash_thresh: float = 0.6
    income_thresh: float = 0.6
    linear_window: float = 1.0
    future_window: int = 8

    anon: bool = False

    figw: float = 6
    figh: float = 12.5

    linewidth: float = 1.0
    markersize: float = 4.0
    marker: str = "."

    colors: "Colors" = field(default_factory=Colors)

    strings: "Strings" = field(default_factory=Strings)

    node_width: float = 0.15
    node_alpha: float = 0.8
    flow_alpha: float = 0.5

    currencysign = "$"

    sankey_sort: str = "bottom"
    sankey_colormaps: list = ("Set3", "Pastel1", "Pastel2")

    linear_targets: list[float] = (
        5000,
        10000,
        15000,
        20000,
        35000,
        50000,
        75000,
        100000,
        150000,
        200000,
        350000,
        500000,
        750000,
        1000000,
        1500000,
        2000000,
        3500000,
        5000000,
        7500000,
        10000000,
        20000000,
        50000000,
        100000000,
    )

The Colors class

Color class for networthdash.

Parameters:

Name Type Description Default
bg str

Background colour of the figure.

'#272727'
axis str

Background colour of the axes.

'#4e4e4e'
text str

Colour of generic text.

'white'
contrast str

Colour of contrast text (e.g., overlaid percentages on Sankey plots).

'black'
label str

Colour of text labels.

'white'
title str

Colour of axis titles.

'white'
tick str

Colour of axis ticks.

'white'
dashes str

Colour of dashed lines.

'white'
frame str

Colour of axis frames.

'white'
grid str

Colour of axis grids.

'#b5b5b5'
target str

Colour of extrapolated target intersection lines.

'#b5b5b5'
super str

Colour of Super lines/labels.

'#ffbf80'
total str

Colour of total net worth lines/labels.

'#8ec6ff'
shares str

Colour of Shares lines/labels.

'#5eff86'
cash str

Colour of Cash lines/labels.

'#ffa1a1'
expend str

Colour of lines/labels for expenditure on shares investments.

'#e9a8ff'
Source code in src/colors.py
@dataclass
class Colors:
    """
    Color class for networthdash.

    Parameters
    ----------
    bg : str
        Background colour of the figure.
    axis : str
        Background colour of the axes.
    text : str
        Colour of generic text.
    contrast : str
        Colour of contrast text (e.g., overlaid percentages on Sankey plots).
    label : str
        Colour of text labels.
    title : str
        Colour of axis titles.
    tick : str
        Colour of axis ticks.
    dashes : str
        Colour of dashed lines.
    frame : str
        Colour of axis frames.
    grid : str
        Colour of axis grids.
    target : str
        Colour of extrapolated target intersection lines.
    super : str
        Colour of Super lines/labels.
    total : str
        Colour of total net worth lines/labels.
    shares : str
        Colour of Shares lines/labels.
    cash : str
        Colour of Cash lines/labels.
    expend : str
        Colour of lines/labels for expenditure on shares investments.
    """

    bg: str = "#272727"
    axis: str = "#4e4e4e"
    text: str = "white"
    contrast: str = "black"
    label: str = "white"
    title: str = "white"
    tick: str = "white"
    dashes: str = "white"
    frame: str = "white"
    grid: str = "#b5b5b5"
    target: str = "#b5b5b5"
    super: str = "#ffbf80"
    total: str = "#8ec6ff"
    shares: str = "#5eff86"
    cash: str = "#ffa1a1"
    expend: str = "#e9a8ff"
    income: str = "#e3a3aa"

    def __getitem__(self, key: str) -> str:
        return getattr(self, key)