Skip to main content

Reflex Visualizations

Recharts patterns for Syntropy-Journals

Quick Reference

Chart TypeComponentBest For
PieChartrx.recharts.pie_chartProportions (macros, categories)
RadarChartrx.recharts.radar_chartMulti-axis scores (health domains)
BarChartrx.recharts.bar_chartComparisons over time
ComposedChartrx.recharts.composed_chartMixed bar + line overlays
FunnelChartrx.recharts.funnel_chartSequential drop-offs

Data Format

All charts bind to list[dict] state vars. Each dict represents one data point:
class MyState(rx.State):
    chart_data: list[dict] = [
        {"name": "Protein", "value": 65},
        {"name": "Carbs", "value": 250},
        {"name": "Fat", "value": 70},
    ]

Theme Colors

From components/theme.py — use these for consistent styling:
NameHexUsage
Teal#06B6D4Primary accent
Green#22C55EPositive / adherence
Blue#3B82F6Informational
Amber#F59E0BWarnings / streaks
Purple#8B5CF6Secondary accent
Rose#F43F5ENegative / alerts

Chart Patterns

PieChart (Donut Variant)

def macro_donut() -> rx.Component:
    return rx.recharts.pie_chart(
        rx.recharts.pie(
            data=MyState.macro_data,
            data_key="value",
            name_key="name",
            cx="50%",
            cy="50%",
            inner_radius="60%",
            outer_radius="80%",
            padding_angle=2,
            fill="#06B6D4",
        ),
        rx.recharts.graphing_tooltip(),
        rx.recharts.legend(),
        width="100%",
        height=300,
    )
Key props:
  • inner_radius + outer_radius — creates the donut hole
  • padding_angle — gap between slices
  • Use rx.recharts.cell() inside pie() for per-slice colors

RadarChart

def health_radar() -> rx.Component:
    return rx.recharts.radar_chart(
        rx.recharts.polar_grid(),
        rx.recharts.polar_angle_axis(data_key="domain"),
        rx.recharts.polar_radius_axis(angle=90, domain=[0, 100]),
        rx.recharts.radar(
            data_key="score",
            stroke="#06B6D4",
            fill="#06B6D4",
            fill_opacity=0.3,
        ),
        rx.recharts.graphing_tooltip(),
        data=MyState.radar_data,
        width="100%",
        height=300,
    )
Data format:
radar_data = [
    {"domain": "Nutrition", "score": 85},
    {"domain": "Consistency", "score": 70},
    {"domain": "Symptoms", "score": 90},
]

FunnelChart

def conversion_funnel() -> rx.Component:
    return rx.recharts.funnel_chart(
        rx.recharts.funnel(
            data=MyState.funnel_data,
            data_key="value",
            name_key="name",
        ),
        rx.recharts.graphing_tooltip(),
        width="100%",
        height=300,
    )

ComposedChart (Bar + Line)

def score_timeline() -> rx.Component:
    return rx.recharts.composed_chart(
        rx.recharts.cartesian_grid(stroke_dasharray="3 3"),
        rx.recharts.x_axis(data_key="week", type_="category"),
        rx.recharts.y_axis(domain=[0, 100]),
        rx.recharts.bar(
            data_key="score",
            fill="#06B6D4",
            bar_size=20,
            radius=[4, 4, 0, 0],
        ),
        rx.recharts.line(
            data_key="trend",
            stroke="#8B5CF6",
            type_="monotone",
            stroke_width=2,
        ),
        rx.recharts.graphing_tooltip(),
        rx.recharts.legend(),
        data=MyState.timeline_data,
        width="100%",
        height=300,
    )

BarChart

def weekly_bars() -> rx.Component:
    return rx.recharts.bar_chart(
        rx.recharts.cartesian_grid(stroke_dasharray="3 3"),
        rx.recharts.x_axis(data_key="day"),
        rx.recharts.y_axis(),
        rx.recharts.bar(data_key="calories", fill="#22C55E"),
        rx.recharts.graphing_tooltip(),
        data=MyState.weekly_data,
        width="100%",
        height=300,
    )

Common Elements

Tooltip

Always include for hover interactivity:
rx.recharts.graphing_tooltip()

Legend

Position options: "top", "bottom", "left", "right":
rx.recharts.legend(vertical_align="bottom")

Responsive Container

Wrap charts for fluid sizing:
rx.recharts.responsive_container(
    rx.recharts.pie_chart(...),
    width="100%",
    height=300,
)

Glass Morphism Card Wrapper

Standard card CSS for chart containers:
_CHART_CARD = (
    "p-5 rounded-xl bg-white/60 dark:bg-slate-800/60"
    " backdrop-blur-sm border border-white/30 dark:border-white/10"
)

def chart_card(title: str, chart: rx.Component) -> rx.Component:
    return rx.el.div(
        rx.el.h3(
            title,
            class_name="text-lg font-semibold text-slate-900 dark:text-white mb-4",
        ),
        chart,
        class_name=_CHART_CARD,
    )

Binding to State

Charts read from state vars at render time. Update the var to re-render:
class DashState(rx.State):
    macro_data: list[dict] = []

    @rx.event
    async def load_data(self):
        self.macro_data = [
            {"name": "Protein", "value": 65, "fill": "#06B6D4"},
            {"name": "Carbs", "value": 250, "fill": "#22C55E"},
            {"name": "Fat", "value": 70, "fill": "#F59E0B"},
        ]
Use rx.cond() to show a placeholder when data is empty:
rx.cond(
    MyState.chart_data.length() > 0,
    my_chart(),
    rx.el.p("No data yet.", class_name="text-sm text-slate-400 text-center py-8"),
)