""" 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("""
Tidak ada marker dengan gauge preset yang tersedia.
""", 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