File size: 3,988 Bytes
a91d88d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
"""
Human+ Chart Components
Streamlit rendering wrappers untuk semua Plotly charts.
Import dari sini di halaman mana saja.
"""

import streamlit as st
from core.chart_builder import (
    build_gauge_chart,
    build_biomarker_bar_chart,
    build_status_donut,
    get_gauge_preset,
)

# Plotly config — hide toolbar, dark bg, responsive
_PLOTLY_CONFIG = {
    "displayModeBar": False,
    "responsive": True,
    "staticPlot": False,
}

# Max gauge charts to show (avoid information overload)
_MAX_GAUGES = 6


def render_gauge_grid(biomarkers: list[dict]):
    """
    Render a responsive 2-column grid of gauge charts
    for the most important biomarkers (those with presets + non-neutral status).
    """
    # Filter to biomarkers that have gauge presets AND are non-neutral
    gaugeables = [
        b for b in biomarkers
        if b.get("raw_value") is not None
        and b.get("status") != "neutral"
        and get_gauge_preset(b["name"]) is not None
    ]

    # Sort danger → warning → optimal, cap at max
    priority = {"danger": 0, "warning": 1, "optimal": 2}
    gaugeables = sorted(gaugeables, key=lambda b: priority.get(b["status"], 3))
    gaugeables = gaugeables[:_MAX_GAUGES]

    if not gaugeables:
        st.markdown("""
        <div style="
            text-align:center; padding:20px;
            font-family:'DM Sans',sans-serif;
            font-size:0.8rem; color:#4a4a6a
        ">Tidak ada marker dengan gauge preset yang tersedia.</div>
        """, unsafe_allow_html=True)
        return

    # Render in 2-column grid
    pairs = [gaugeables[i:i+2] for i in range(0, len(gaugeables), 2)]

    for pair in pairs:
        cols = st.columns(len(pair))
        for col, b in zip(cols, pair):
            with col:
                preset = get_gauge_preset(b["name"])
                if preset is None:
                    continue

                range_lo, range_hi, opt_lo, opt_hi = preset

                try:
                    fig = build_gauge_chart(
                        name=b["name"],
                        value=float(b["raw_value"]),
                        unit=b.get("unit", ""),
                        status=b["status"],
                        range_lo=range_lo,
                        range_hi=range_hi,
                        optimal_lo=opt_lo,
                        optimal_hi=opt_hi,
                        height=210,
                    )
                    st.plotly_chart(
                        fig,
                        use_container_width=True,
                        config=_PLOTLY_CONFIG,
                        key=f"gauge_{b['name'].replace(' ', '_')}",
                    )
                except Exception as e:
                    # Graceful fallback — don't crash the whole page
                    st.caption(f"⚠️ Chart tidak tersedia: {b['name']}")


def render_biomarker_bar_chart(biomarkers: list[dict]):
    """
    Render horizontal bar chart untuk semua biomarker.
    Color-coded by status sesuai Human+ brand.
    """
    try:
        fig = build_biomarker_bar_chart(biomarkers, height=350)
        if fig is None:
            st.caption("Tidak ada data numerik untuk ditampilkan.")
            return
        st.plotly_chart(
            fig,
            use_container_width=True,
            config=_PLOTLY_CONFIG,
            key="biomarker_bar",
        )
    except Exception:
        st.caption("⚠️ Chart tidak tersedia saat ini.")


def render_status_donut(optimal: int, warning: int, danger: int):
    """
    Render donut pie chart untuk summary status biomarker.
    Small chart cocok untuk sidebar atau kolom kecil.
    """
    try:
        fig = build_status_donut(optimal, warning, danger)
        if fig is None:
            return
        st.plotly_chart(
            fig,
            use_container_width=True,
            config=_PLOTLY_CONFIG,
            key="status_donut",
        )
    except Exception:
        pass  # Non-critical — skip silently