Source code for kaxanuk.attribution_analysis.dashboard.components

"""
Reusable dashboard components (cards, tables, headers).
"""

import math

from dash import html, dash_table

from kaxanuk.attribution_analysis.dashboard.constants import (
    CURRENCY_KEYWORDS,
    PERCENTAGE_KEYWORDS,
    RATIO_KEYWORDS,
    DATE_KEYWORDS,
)
from kaxanuk.attribution_analysis.dashboard.styles import (
    get_data_table_style,
    get_data_table_header_style,
    get_table_container_style,
)


[docs] def format_metric_value(metric_name: str, value: object) -> str: """ Format a metric value for display based on its name and type. The formatting rule is inferred from keywords found in `metric_name`: currency (``$#,##0.00``), percentage (``0.00%``), ratio (4 decimal places), or date (``YYYY-MM-DD``). Falls back to 4 decimal places for other numeric values, or ``str(value)`` otherwise. Parameters ---------- metric_name : str Name of the metric, matched case-insensitively against `CURRENCY_KEYWORDS`, `PERCENTAGE_KEYWORDS`, `RATIO_KEYWORDS`, and `DATE_KEYWORDS` to select the formatting rule. value : object The value to format. Typically an ``int``, ``float``, date-like object (with a ``strftime`` method), or None. Returns ------- str The formatted value, or ``"N/A"`` if `value` is None or NaN. """ if value is None or (isinstance(value, float) and math.isnan(value)): return "N/A" metric_lower = metric_name.lower() if any(keyword in metric_lower for keyword in CURRENCY_KEYWORDS): if isinstance(value, (int, float)): return f"${value:,.2f}" return str(value) if any(keyword in metric_lower for keyword in PERCENTAGE_KEYWORDS): if isinstance(value, (int, float)): return f"{value:.2%}" return str(value) if any(keyword in metric_lower for keyword in RATIO_KEYWORDS): if isinstance(value, (int, float)): return f"{value:.4f}" return str(value) if any(keyword in metric_lower for keyword in DATE_KEYWORDS): if hasattr(value, 'strftime'): return value.strftime('%Y-%m-%d') return str(value) if isinstance(value, (int, float)): return f"{value:.4f}" return str(value)
[docs] def create_metric_card(title: str, value: str, card_type: str = "primary") -> html.Div: """ Build a single metric card (title + value) for the dashboard's KPI row. Parameters ---------- title : str Metric label displayed above the value (e.g. ``"Sharpe Ratio"``). value : str Pre-formatted metric value to display (e.g. ``"1.234"``). card_type : str, default "primary" Style variant appended as a CSS class to the value element (e.g. ``"success"``, ``"warning"``, ``"danger"``), used to color-code the card. Returns ------- dash.html.Div A ``Div`` containing the title (``H4``) and value (``H2``) elements, styled with the ``metric-card`` class. """ return html.Div([ html.H4(title, className="metric-title"), html.H2(value, className=f"metric-value {card_type}") ], className="metric-card")
[docs] def create_statistics_table( stats_data: list[dict], portfolio_name: str, ) -> html.Div: """ Build a sortable Dash DataTable of performance statistics. Parameters ---------- stats_data : list of dict Row data for the table, where each dict has ``"Metric"`` and ``"Value"`` keys. portfolio_name : str Portfolio name used as the header label for the value column. Returns ------- dash.html.Div A ``Div`` wrapping a ``dash_table.DataTable`` with columns ``Metric`` and `portfolio_name`, sortable natively and paginated at 25 rows per page. """ return html.Div([ dash_table.DataTable( data=stats_data, columns=[ {"name": "Metric", "id": "Metric"}, {"name": f"{portfolio_name}", "id": "Value"}, ], style_cell=get_data_table_style(), style_header=get_data_table_header_style(), style_table=get_table_container_style(), page_size=25, sort_action="native", style_as_list_view=True ) ], style={'margin': '20px 0'})