import { GroupedBarChart } from "semiotic"
GroupedBarChart displays bars side by side within each category, making it easy to compare values across groups. It wrapsStreamOrdinalFrame withtype="clusterbar". WhileStackedBarChart shows part-to-whole relationships, GroupedBarChart emphasizes direct comparison between groups.
Quick Start
Pass your data with a groupBy prop specifying which field creates side-by-side bars within each category.
import { GroupedBarChart } from "semiotic" const frameProps = { /* --- Data --- */ data: [ { category: "Q1", product: "Alpha", value: 120 }, { category: "Q1", product: "Beta", value: 90 }, { category: "Q1", product: "Gamma", value: 150 }, // ...more data points ], /* --- Layout --- */ groupBy: "product", /* --- Process --- */ valueAccessor: "value", categoryAccessor: "category", /* --- Customize --- */ categoryLabel: "Quarter", valueLabel: "Units Sold" } export default () => { return <GroupedBarChart {...frameProps} /> }
Examples
Horizontal Grouped Bars
Set orientation="horizontal" when category labels are long or you have many groups.
import { GroupedBarChart } from "semiotic" const frameProps = { /* --- Data --- */ data: sampleData, /* --- Layout --- */ groupBy: "product", orientation: "horizontal", /* --- Process --- */ valueAccessor: "value", categoryAccessor: "category", /* --- Customize --- */ categoryLabel: "Quarter", valueLabel: "Units Sold" } export default () => { return <GroupedBarChart {...frameProps} /> }
Custom Color Scheme
Pass a custom colorScheme array for brand colors.
import { GroupedBarChart } from "semiotic" const frameProps = { /* --- Data --- */ data: sampleData, /* --- Layout --- */ groupBy: "product", /* --- Process --- */ valueAccessor: "value", categoryAccessor: "category", /* --- Customize --- */ colorScheme: ["#6366f1", "#22c55e", "#f59e0b"], categoryLabel: "Quarter", valueLabel: "Units Sold" } export default () => { return <GroupedBarChart {...frameProps} /> }
Sorted Groups
Use sort to order categories by their total value. Default is false (preserves insertion order).
import { GroupedBarChart } from "semiotic" const frameProps = { /* --- Data --- */ data: sampleData, /* --- Layout --- */ groupBy: "product", sort: "desc", /* --- Process --- */ valueAccessor: "value", categoryAccessor: "category", /* --- Customize --- */ categoryLabel: "Quarter", valueLabel: "Units Sold" } export default () => { return <GroupedBarChart {...frameProps} /> }
Rounded Top Corners
Use roundedTop to round the top corners of each individual bar. For grouped bars, every bar in the cluster gets rounded.
import { GroupedBarChart } from "semiotic" const frameProps = { /* --- Data --- */ data: sampleData, /* --- Layout --- */ groupBy: "product", /* --- Process --- */ valueAccessor: "value", categoryAccessor: "category", /* --- Customize --- */ colorBy: "product", /* --- Other --- */ roundedTop: 4 } export default () => { return <GroupedBarChart {...frameProps} /> }
JSX
<GroupedBarChart data={sampleData} categoryAccessor="category" groupBy="product" valueAccessor="value" colorBy="product" roundedTop={4} />
Props
| Prop | Type | Required | Default | Description |
|---|
data | array | Yes | — | Array of data points with category, group, and value fields. |
categoryAccessor | string | function | — | "category" | Field name or function to access category values. |
groupBy | string | function | Yes | — | Field name or function to access group values. Each group becomes a side-by-side bar. |
valueAccessor | string | function | — | "value" | Field name or function to access numeric values. |
orientation | "vertical" | "horizontal" | — | "vertical" | Chart orientation. |
categoryLabel | string | — | — | Label for the category axis. |
valueLabel | string | — | — | Label for the value axis. |
valueFormat | function | — | — | Format function for value axis tick labels. |
colorBy | string | function | — | groupBy | Field name or function to determine bar color. Defaults to groupBy. |
colorScheme | string | array | — | "category10" | Color scheme name or custom colors array. |
sort | boolean | "asc" | "desc" | function | — | false | Sort categories by total value. Accepts true, "asc", "desc", or a custom comparator. Default false preserves insertion order. |
barPadding | number | — | 5 | Padding between bar groups in pixels. |
roundedTop | number | — | — | Rounded corner radius on bar tops (the end away from baseline). |
animate | boolean | object | — | false | Enable animated intro and smooth data-change transitions. `true` for defaults (300ms ease-out, intro enabled), or `{ duration, easing, intro }`. Set `{ intro: false }` to disable intro. |
enableHover | boolean | — | true | Enable hover annotations on bars. |
showGrid | boolean | — | false | Show background grid lines. |
showLegend | boolean | — | true | Show a legend for groups. |
tooltip | object | function | — | — | Tooltip configuration or render function. |
width | number | — | 600 | Chart width in pixels. |
height | number | — | 400 | Chart height in pixels. |
margin | object | — | { top: 50, bottom: 60, left: 70, right: 40 } | Margin around the chart area. |
title | string | — | — | Chart title displayed at the top. |
frameProps | object | — | — | Additional StreamOrdinalFrame props for advanced customization. |
Graduating to the Frame
For full control, useStreamOrdinalFrame directly withtype="clusterbar" and pieceIDAccessor.
Chart (simple)
JSX
import { GroupedBarChart } from "semiotic" <GroupedBarChart data={quarterlyData} categoryAccessor="quarter" groupBy="product" valueAccessor="sales" categoryLabel="Quarter" valueLabel="Sales" />
Frame (full control)
JSX
import { StreamOrdinalFrame } from "semiotic" <StreamOrdinalFrame data={quarterlyData} oAccessor="quarter" rAccessor="sales" type="clusterbar" pieceIDAccessor="product" style={d => ({ fill: colorScale(d.product) })} axes={[{ orient: "left", label: "Sales" }]} hoverAnnotation={true} size={[600, 400]} />
- StackedBarChart — for part-to-whole breakdowns instead of side-by-side comparison
- BarChart — for single-series categorical data
- StreamOrdinalFrame — the underlying Frame with full control over every rendering detail