> For AI agents: the complete documentation index is at [llms.txt](https://reflex.dev/docs/llms.txt). Markdown versions are available by appending `.md` or sending `Accept: text/markdown`.

---
components:
  - rx.recharts.ComposedChart
title: Composed Chart
meta_description: "Build composed charts in Python with Reflex. Combine bars, lines, and areas in a single Recharts composed chart with shared axes, tooltips, and legends — all in pure Python."
---

```python exec
import reflex as rx
```

# Composed Chart

Composed charts in Reflex are built on [Recharts](https://recharts.org/), a React charting library, and created in pure Python. A `composed_chart` (also called a combo chart) is a higher-level component chart that is composed of multiple charts, where other charts are the children of the `composed_chart`. The charts are placed on top of each other in the order they are provided in the `composed_chart` function.

```md alert info
# To learn more about individual charts, checkout: **[area_chart](/docs/library/graphing/charts/areachart)**, **[line_chart](/docs/library/graphing/charts/linechart)**, or **[bar_chart](/docs/library/graphing/charts/barchart)**.
```

```python demo graphing
data = [
    {"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400},
    {"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210},
    {"name": "Page C", "uv": 2000, "pv": 9800, "amt": 2290},
    {"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000},
    {"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181},
    {"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500},
    {"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100},
]


def composed():
    return rx.recharts.composed_chart(
        rx.recharts.area(data_key="uv", stroke="#8884d8", fill="#8884d8"),
        rx.recharts.bar(data_key="amt", bar_size=20, fill="#413ea0"),
        rx.recharts.line(data_key="pv", type_="monotone", stroke="#ff7300"),
        rx.recharts.x_axis(data_key="name"),
        rx.recharts.y_axis(),
        rx.recharts.cartesian_grid(stroke_dasharray="3 3"),
        rx.recharts.graphing_tooltip(),
        data=data,
        height=250,
        width="100%",
    )
```

## When to Use a Composed Chart

A composed chart is useful whenever a single chart type can't tell the whole story. Common combinations include overlaying a trend `line` on top of `bar` totals, drawing an `area` for a range with a `line` for the actual value, or comparing a cumulative measure against a per-period one. Because each series — `rx.recharts.bar()`, `rx.recharts.line()`, and `rx.recharts.area()` — is a child of `rx.recharts.composed_chart()`, they all share the same `data`, x-axis, tooltip, and legend. Series are drawn in the order you list them, so later children render on top of earlier ones.

## Composed Chart with a Dual Axis

When two series use very different scales (for example, a count and a dollar amount), a single y-axis makes the smaller series unreadable. Add a second y-axis and point each series at one with the `y_axis_id` prop: here the `orders` bars use the left axis and the `revenue` line uses the right axis.

```python demo graphing
data = [
    {"name": "Mon", "orders": 40, "revenue": 2400},
    {"name": "Tue", "orders": 30, "revenue": 1398},
    {"name": "Wed", "orders": 55, "revenue": 9800},
    {"name": "Thu", "orders": 27, "revenue": 3908},
    {"name": "Fri", "orders": 62, "revenue": 4800},
    {"name": "Sat", "orders": 48, "revenue": 3800},
    {"name": "Sun", "orders": 35, "revenue": 4300},
]


def composed_dual_axis():
    return rx.recharts.composed_chart(
        rx.recharts.bar(
            data_key="orders",
            bar_size=20,
            fill=rx.color("accent", 8),
            y_axis_id="left",
        ),
        rx.recharts.line(
            data_key="revenue",
            type_="monotone",
            stroke=rx.color("green", 9),
            y_axis_id="right",
        ),
        rx.recharts.x_axis(data_key="name"),
        rx.recharts.y_axis(y_axis_id="left"),
        rx.recharts.y_axis(y_axis_id="right", orientation="right"),
        rx.recharts.cartesian_grid(stroke_dasharray="3 3"),
        rx.recharts.graphing_tooltip(),
        rx.recharts.legend(),
        data=data,
        height=300,
        width="100%",
    )
```

## Related Charts

Explore more chart types you can build with Reflex and Recharts in pure Python:

- [Bar Chart](/docs/library/graphing/charts/barchart)
- [Line Chart](/docs/library/graphing/charts/linechart)
- [Area Chart](/docs/library/graphing/charts/areachart)

## API Reference

### rx.recharts.ComposedChart

A Composed chart component in Recharts.

#### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `width` | int, str | - | The width of chart container. String or Integer. |
| `height` | int, str | - | The height of chart container. |
| `data` | Sequence[dict[str, Any]] | - | The source data, in which each element is an object. |
| `margin` | dict[str, Any] | - | The sizes of whitespace around the chart, i.e. {"top": 50, "right": 30, "left": 20, "bottom": 5}. |
| `sync_id` | str | - | If any two categorical charts(rx.line_chart, rx.area_chart, rx.bar_chart, rx.composed_chart) have the same sync_id, these two charts can sync the position GraphingTooltip, and the start_index, end_index of Brush. |
| `sync_method` | Literal["index", "value"] | `"index"` | When sync_id is provided, allows customisation of how the charts will synchronize GraphingTooltips and brushes. Using 'index' (default setting), other charts will reuse current datum's index within the data array. In cases where data does not have the same length, this might yield unexpected results. In that case use 'value' which will try to match other charts values, or a fully custom function which will receive tick, data as argument and should return an index. 'index', 'value', function. |
| `layout` | Literal["vertical", "horizontal"] | `"horizontal"` | The layout of area in the chart. 'horizontal', 'vertical'. |
| `stack_offset` | Literal["expand", "none", "wiggle", "silhouette"] | - | The type of offset function used to generate the lower and upper values in the series array. The four types are built-in offsets in d3-shape. 'expand', 'none', 'wiggle', 'silhouette'. |
| `base_value` | int, Literal["dataMin", "dataMax", "auto"] | `"auto"` | The base value of area. Number, 'dataMin', 'dataMax', 'auto'. |
| `bar_category_gap` | int, str | `"10%"` | The gap between two bar categories, which can be a percent value or a fixed value. Percentage, Number. |
| `bar_gap` | int | `4` | The gap between two bars in the same category. |
| `bar_size` | int | - | The width or height of each bar. If the barSize is not specified, the size of the bar will be calculated by the barCategoryGap, barGap and the quantity of bar groups. |
| `reverse_stack_order` | bool | `False` | If false set, stacked items will be rendered left to right. If true set, stacked items will be rendered right to left. (Render direction affects SVG layering, not x position). |

#### Event Triggers

Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/
