> 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.BarChart
  - rx.recharts.Bar
title: Bar Chart
meta_description: "Create interactive bar charts in Python with Reflex. Build grouped, stacked, and horizontal Recharts bar charts with custom colors, axes, tooltips, and legends — all in pure Python, no JavaScript."
---

# Bar Chart

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

Bar charts in Reflex are built on [Recharts](https://recharts.org/), a React charting library, and let you visualize categorical data in pure Python. A bar chart presents categorical data with rectangular bars whose heights or lengths are proportional to the values that they represent.

For a bar chart we must define an `rx.recharts.bar()` component for each set of values we wish to plot. Each `rx.recharts.bar()` component has a `data_key` which clearly states which variable in our data we are tracking. In this simple example we plot `uv` as a bar against the `name` column which we set as the `data_key` in `rx.recharts.x_axis`.

## Simple Example

```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 bar_simple():
    return rx.recharts.bar_chart(
        rx.recharts.bar(
            data_key="uv",
            stroke=rx.color("accent", 9),
            fill=rx.color("accent", 8),
        ),
        rx.recharts.x_axis(data_key="name"),
        rx.recharts.y_axis(),
        data=data,
        width="100%",
        height=250,
    )
```

## Multiple Bars

Multiple bars can be placed on the same `bar_chart`, using multiple `rx.recharts.bar()` components. Drawn side by side like this, they form a grouped (or clustered) bar chart.

```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 bar_double():
    return rx.recharts.bar_chart(
        rx.recharts.bar(
            data_key="uv",
            stroke=rx.color("accent", 9),
            fill=rx.color("accent", 8),
        ),
        rx.recharts.bar(
            data_key="pv",
            stroke=rx.color("green", 9),
            fill=rx.color("green", 8),
        ),
        rx.recharts.x_axis(data_key="name"),
        rx.recharts.y_axis(),
        data=data,
        width="100%",
        height=250,
    )
```

## Stacked Bar Chart

To build a stacked bar chart, give each `rx.recharts.bar()` the same `stack_id`. Instead of being drawn side by side, the bars are stacked on top of one another, which is ideal for showing part-to-whole composition (also called a segmented bar chart). Set `stack_offset="expand"` on the `bar_chart` to turn it into a 100% stacked bar chart.

```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 bar_stacked():
    return rx.recharts.bar_chart(
        rx.recharts.bar(
            data_key="uv",
            stack_id="1",
            fill=rx.color("accent", 8),
        ),
        rx.recharts.bar(
            data_key="pv",
            stack_id="1",
            fill=rx.color("green", 8),
        ),
        rx.recharts.x_axis(data_key="name"),
        rx.recharts.y_axis(),
        rx.recharts.legend(),
        data=data,
        width="100%",
        height=300,
    )
```

## Ranged Charts

You can also assign a range in the bar by assigning the data_key in the `rx.recharts.bar` to a list with two elements, i.e. here a range of two temperatures for each date.

```python demo graphing
range_data = [
    {"day": "05-01", "temperature": [-1, 10]},
    {"day": "05-02", "temperature": [2, 15]},
    {"day": "05-03", "temperature": [3, 12]},
    {"day": "05-04", "temperature": [4, 12]},
    {"day": "05-05", "temperature": [12, 16]},
    {"day": "05-06", "temperature": [5, 16]},
    {"day": "05-07", "temperature": [3, 12]},
    {"day": "05-08", "temperature": [0, 8]},
    {"day": "05-09", "temperature": [-3, 5]},
]


def bar_range():
    return rx.recharts.bar_chart(
        rx.recharts.bar(
            data_key="temperature",
            stroke=rx.color("accent", 9),
            fill=rx.color("accent", 8),
        ),
        rx.recharts.x_axis(data_key="day"),
        rx.recharts.y_axis(),
        data=range_data,
        width="100%",
        height=250,
    )
```

## Stateful Charts

Here is an example of a bar graph with a `State`. Here we have defined a function `randomize_data`, which randomly changes the data for both graphs when the first defined `bar` is clicked on using `on_click=BarState.randomize_data`.

```python demo exec
class BarState(rx.State):
    data = data

    @rx.event
    def randomize_data(self):
        for i in range(len(self.data)):
            self.data[i]["uv"] = random.randint(0, 10000)
            self.data[i]["pv"] = random.randint(0, 10000)
            self.data[i]["amt"] = random.randint(0, 10000)


def bar_with_state():
    return rx.recharts.bar_chart(
        rx.recharts.cartesian_grid(
            stroke_dasharray="3 3",
        ),
        rx.recharts.bar(
            data_key="uv",
            stroke=rx.color("accent", 9),
            fill=rx.color("accent", 8),
        ),
        rx.recharts.bar(
            data_key="pv",
            stroke=rx.color("green", 9),
            fill=rx.color("green", 8),
        ),
        rx.recharts.x_axis(data_key="name"),
        rx.recharts.y_axis(),
        rx.recharts.legend(),
        on_click=BarState.randomize_data,
        data=BarState.data,
        width="100%",
        height=300,
    )
```

## Click Events and Drill-Down

The `on_click` event on `rx.recharts.bar` provides no arguments, so it cannot tell you which bar was clicked. To handle clicks with data — for example, to drill down into a category — render an `rx.recharts.cell` for each data point with `rx.foreach`, so each cell binds its click data at render time from the loop variable.

In this example, clicking a bar filters the chart to that category (zoom in), and clicking the same bar again clears the filter (zoom out). An `rx.cond` on the cell's `fill` highlights the selected bar.

```python demo exec
drilldown_data = [
    {"name": "Fiction", "count": 42},
    {"name": "History", "count": 28},
    {"name": "Science", "count": 35},
    {"name": "Biography", "count": 17},
    {"name": "Fantasy", "count": 24},
]

DRILLDOWN_COLORS = ["#6366F1", "#8B5CF6", "#A855F7", "#D946EF", "#EC4899"]


class BarDrilldownState(rx.State):
    drilled_genre: str = ""

    @rx.var
    def genre_data(self) -> list[dict[str, str | int]]:
        if self.drilled_genre:
            return [d for d in drilldown_data if d["name"] == self.drilled_genre]
        return drilldown_data

    @rx.event
    def toggle_genre(self, genre_name: str):
        """Click the same bar again to zoom back out."""
        if self.drilled_genre == genre_name:
            self.drilled_genre = ""
        else:
            self.drilled_genre = genre_name


def _drilldown_cell(item: rx.Var, index: rx.Var) -> rx.Component:
    """Each bar gets its own cell with on_click bound to the item name."""
    return rx.recharts.cell(
        on_click=BarDrilldownState.toggle_genre(item["name"].to(str)),
        custom_attrs={"cursor": "pointer"},
        fill=rx.cond(
            BarDrilldownState.drilled_genre == item["name"],
            "#1D4ED8",
            rx.Var.create(DRILLDOWN_COLORS)[index % len(DRILLDOWN_COLORS)],
        ),
    )


def bar_drilldown():
    return rx.recharts.bar_chart(
        rx.recharts.cartesian_grid(stroke_dasharray="3 3", vertical=False),
        rx.recharts.x_axis(data_key="name", tick_line=False, axis_line=False),
        rx.recharts.y_axis(allow_decimals=False, axis_line=False, tick_line=False),
        rx.recharts.bar(
            rx.foreach(BarDrilldownState.genre_data, _drilldown_cell),
            data_key="count",
            radius=[4, 4, 0, 0],
        ),
        rx.recharts.graphing_tooltip(),
        data=BarDrilldownState.genre_data,
        width="100%",
        height=300,
    )
```

The key points of the pattern:

1. Define a helper function that takes `(item, index)` from `rx.foreach` and returns an `rx.recharts.cell`.
2. Bind the click with `on_click=State.handler(item["name"])` — the handler receives a plain value because it is bound at render time, not extracted from the click event.
3. Use `rx.cond` to highlight the selected item with a different `fill`.
4. Apply the drill filter to the chart's own data, so only the clicked item remains visible; clearing the filter restores all items.

The same pattern works for pie charts: place the `rx.foreach` of cells inside `rx.recharts.pie`.

## Example with Props

Here's an example demonstrates how to customize the appearance and layout of bars using the `bar_category_gap`, `bar_gap`, `bar_size`, and `max_bar_size` props. These props accept values in pixels to control the spacing and size of the bars.

```python demo graphing
data = [
    {"name": "Page A", "value": 2400},
    {"name": "Page B", "value": 1398},
    {"name": "Page C", "value": 9800},
    {"name": "Page D", "value": 3908},
    {"name": "Page E", "value": 4800},
    {"name": "Page F", "value": 3800},
]


def bar_features():
    return rx.recharts.bar_chart(
        rx.recharts.bar(
            data_key="value",
            fill=rx.color("accent", 8),
        ),
        rx.recharts.x_axis(data_key="name"),
        rx.recharts.y_axis(),
        data=data,
        bar_category_gap="15%",
        bar_gap=6,
        bar_size=100,
        max_bar_size=40,
        width="100%",
        height=300,
    )
```

## Rounded Bars

The `radius` prop on `rx.recharts.bar` rounds the corners of each bar. Pass a single number to round all four corners, or a list of four values in the order `[top-left, top-right, bottom-right, bottom-left]` — for example `[8, 8, 0, 0]` rounds only the top corners.

```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 bar_rounded():
    return rx.recharts.bar_chart(
        rx.recharts.bar(
            data_key="uv",
            fill=rx.color("accent", 8),
            radius=[8, 8, 0, 0],
        ),
        rx.recharts.x_axis(data_key="name"),
        rx.recharts.y_axis(),
        data=data,
        width="100%",
        height=250,
    )
```

## Gradient Fill

Bars can be styled with SVG linear gradients. Define one gradient per series inside an `rx.el.svg.defs` block as the first child of the chart, then reference each gradient from the bar's `fill` prop with `"url(#gradient-id)"`.

```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 create_bar_gradient(color: str, gradient_id: str) -> rx.Component:
    return rx.el.svg.linear_gradient(
        rx.el.svg.stop(offset="5%", stop_color=color, stop_opacity=0.8),
        rx.el.svg.stop(offset="95%", stop_color=color, stop_opacity=0.2),
        id=gradient_id,
        x1=0,
        y1=0,
        x2=0,
        y2=1,
    )


def bar_gradient():
    return rx.recharts.bar_chart(
        rx.el.svg.defs(
            create_bar_gradient("#8884d8", "bar_gradient_uv"),
            create_bar_gradient("#82ca9d", "bar_gradient_pv"),
        ),
        rx.recharts.bar(
            data_key="uv",
            fill="url(#bar_gradient_uv)",
            radius=[4, 4, 0, 0],
        ),
        rx.recharts.bar(
            data_key="pv",
            fill="url(#bar_gradient_pv)",
            radius=[4, 4, 0, 0],
        ),
        rx.recharts.x_axis(data_key="name"),
        rx.recharts.y_axis(),
        rx.recharts.graphing_tooltip(),
        rx.recharts.legend(),
        data=data,
        width="100%",
        height=300,
    )
```

## Vertical Example

The `layout` prop allows you to set the orientation of the graph to be vertical or horizontal, it is set horizontally by default. Setting `layout="vertical"` makes the bars run left-to-right, which is how you create a horizontal bar chart in Reflex.

```md alert info
# Include margins around your graph to ensure proper spacing and enhance readability. By default, provide margins on all sides of the chart to create a visually appealing and functional representation of your data.
```

```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 bar_vertical():
    return rx.recharts.bar_chart(
        rx.recharts.bar(
            data_key="uv",
            stroke=rx.color("accent", 8),
            fill=rx.color("accent", 3),
        ),
        rx.recharts.x_axis(type_="number"),
        rx.recharts.y_axis(data_key="name", type_="category"),
        data=data,
        layout="vertical",
        margin={"top": 20, "right": 20, "left": 20, "bottom": 20},
        width="100%",
        height=300,
    )
```

To learn how to use the `sync_id`, `stack_id`,`x_axis_id` and `y_axis_id` props check out the of the area chart [documentation](/docs/library/graphing/charts/areachart), where these props are all described with examples.

## Related Charts

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

- [Line Chart](/docs/library/graphing/charts/linechart)
- [Area Chart](/docs/library/graphing/charts/areachart)
- [Composed Chart](/docs/library/graphing/charts/composedchart)

## API Reference

### rx.recharts.BarChart

A Bar 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"] | `"none"` | 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. |
| `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, str | `4` | The gap between two bars in the same category, which can be a percent value or a fixed value. Percentage, Number. |
| `bar_size` | int | - | The width of all the bars in the chart. Number. |
| `max_bar_size` | int | - | The maximum width of all the bars in a horizontal BarChart, or maximum height in a vertical BarChart. |
| `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/

### rx.recharts.Bar

A Bar component in Recharts.

#### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `layout` | Literal["vertical", "horizontal"] | - | The layout of bar in the chart, usually inherited from parent. 'horizontal', 'vertical'. |
| `data_key` | int, str | - | The key of a group of data which should be unique in an area chart. |
| `x_axis_id` | int, str | `0` | The id of x-axis which is corresponding to the data. |
| `y_axis_id` | int, str | `0` | The id of y-axis which is corresponding to the data. |
| `legend_type` | Literal["circle", "cross", "diamond", "line", "plainline", "rect", "square", "star", "triangle", "wye", "none"] | - | The type of icon in legend. If set to 'none', no legend item will be rendered. 'line', 'plainline', 'square', 'rect'\| 'circle', 'cross', 'diamond', 'star', 'triangle', 'wye', 'none' optional. |
| `label` | dict[str, Any], bool | `False` | If false set, labels will not be drawn. If true set, labels will be drawn which have the props calculated internally. |
| `is_animation_active` | bool | `True` | If set false, animation of bar will be disabled. |
| `animation_begin` | int | `0` | Specifies when the animation should begin, the unit of this option is ms. |
| `animation_duration` | int | `1500` | Specifies the duration of animation, the unit of this option is ms. |
| `animation_easing` | Literal["ease", "ease-in", "ease-out", "ease-in-out", "linear"] | `"ease"` | The type of easing function. |
| `unit` | int, str | - | The unit of data. This option will be used in tooltip. |
| `name` | int, str | - | The name of data. This option will be used in tooltip and legend to represent a bar. If no value was set to this option, the value of dataKey will be used alternatively. |
| `stroke` | str, Color | - | The color of the line stroke. |
| `stroke_width` | str, int, float | - | The width of the line stroke. |
| `fill` | str, Color | `Color("accent", 9)` | The width of the line stroke. |
| `background` | bool | `False` | If false set, background of bars will not be drawn. If true set, background of bars will be drawn which have the props calculated internally. |
| `stack_id` | str | - | The stack id of bar, when two bars have the same value axis and same stack_id, then the two bars are stacked in order. |
| `min_point_size` | int | - | The minimal height of a bar in a horizontal BarChart, or the minimal width of a bar in a vertical BarChart. By default, 0 values are not shown. To visualize a 0 (or close to zero) point, set the minimal point size to a pixel value like 3. In stacked bar charts, minPointSize might not be respected for tightly packed values. So we strongly recommend not using this prop in stacked BarCharts. |
| `bar_size` | int | - | Size of the bar (if one bar_size is set then a bar_size must be set for all bars). |
| `max_bar_size` | int | - | Max size of the bar. |
| `radius` | int, Sequence[int] | `0` | If set a value, the option is the radius of all the rounded corners. If set a array, the option are in turn the radiuses of top-left corner, top-right corner, bottom-right corner, bottom-left corner. |

#### Event Triggers

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

Component-specific event triggers:

| Event Trigger | Description |
| --- | --- |
| `on_animation_start` | The customized event handler of animation start. |
| `on_animation_end` | The customized event handler of animation end. |
