> ## Documentation Index
> Fetch the complete documentation index at: https://docs.graphy.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Bar & column

export const GraphEmbed = ({src, story, aspectRatio, borderRadius = '14px', args}) => {
  const STORYBOOK_BASE_URL = typeof window !== 'undefined' && window.location.hostname === 'localhost' ? 'http://localhost:6006' : 'https://storybook-sdk.vercel.app';
  function buildArgsString(args) {
    if (!args) return '';
    const encodeValue = value => {
      if (value === null) return '!null';
      if (value === undefined) return '!undefined';
      if (typeof value === 'boolean') return `!${value}`;
      if (typeof value === 'number') return String(value);
      return encodeURIComponent(String(value));
    };
    const properties = Object.entries(args).map(([key, value]) => `${key}:${encodeValue(value)}`).join(';');
    return `&args=${properties}`;
  }
  const resolvedSrc = story ? `${STORYBOOK_BASE_URL}/iframe.html?id=${story}&viewMode=story&embed=1${buildArgsString(args)}` : src;
  const resolvedAspectRatio = aspectRatio ?? (story ? '16 / 9' : '10 / 6');
  return <iframe src={resolvedSrc} loading="lazy" allowfullscreen="true" style={{
    width: '100%',
    aspectRatio: resolvedAspectRatio,
    border: 'none',
    borderRadius,
    colorScheme: 'light'
  }} />;
};

`geom.bar()` draws a rectangle per observation. In the default cartesian plane it produces **vertical columns**; add [`coord.flip()`](/sdk-next/concepts/coordinate-systems) to lay them on their side as **horizontal bars**. One geom, two orientations. Columns suit comparing categories or a value over discrete time periods; bars suit ranking and categories with long labels that wouldn't fit under a vertical axis.

## Basic example

Value on `y`, category on `x` — the default cartesian form draws vertical columns:

<GraphEmbed story="chart-types-bar-graph--simple" />

```tsx theme={null}
import { useMemo } from 'react';
import {
  GraphProvider,
  GraphRenderer,
  createSpec,
  pipe,
  geom,
  scale,
} from '@graphysdk/react';

const data = {
  columns: [
    { key: 'category', label: 'Product' },
    { key: 'revenue', label: 'Revenue' },
  ],
  rows: [
    { category: 'Product A', revenue: 1200 },
    { category: 'Product B', revenue: 1800 },
    { category: 'Product C', revenue: 2400 },
    { category: 'Product D', revenue: 1600 },
    { category: 'Product E', revenue: 3200 },
    { category: 'Product F', revenue: 2800 },
  ],
};

export function ProductRevenueChart() {
  const spec = useMemo(
    () =>
      pipe(
        createSpec({ x: 'category', y: 'revenue' }),
        geom.bar(),
        scale.x(),
        scale.y()
      ),
    []
  );

  return (
    <GraphProvider input={spec} data={data}>
      <GraphRenderer />
    </GraphProvider>
  );
}
```

## Stacked and grouped

Map a category to `color`, then choose how the bars in each band arrange with `position`. In long format, one row per `quarter` × `region`:

<GraphEmbed story="chart-types-bar-graph--stacked" />

```tsx theme={null}
const data = {
  columns: [
    { key: 'quarter', label: 'Quarter' },
    { key: 'region', label: 'Region' },
    { key: 'sales', label: 'Sales' },
  ],
  rows: [
    { quarter: 'Q1', region: 'North', sales: 350 },
    { quarter: 'Q1', region: 'South', sales: 200 },
    { quarter: 'Q1', region: 'West', sales: 500 },
    // ...
  ],
};

const spec = pipe(
  createSpec({ x: 'quarter', y: 'sales', color: 'region' }),
  geom.bar({ position: 'stack' }), // 'dodge' for grouped, 'fill' for 100% stacked
  scale.x(),
  scale.y(),
  scale.color.palette()
);
```

* `'stack'` — segments stacked into one column
* `'dodge'` — segments side by side within the band
* `'fill'` — stacked and normalised to 100%

A bar layer defaults to `'dodge'`, so a multi-series bar chart with no `position` renders grouped. See [position modes](/sdk-next/concepts/geoms#position-modes) for the full list.

## Negative values

`'identity'` draws each bar at its raw value, so bars with a negative `y` hang below the zero baseline instead of being folded into a stack:

```tsx theme={null}
const spec = pipe(
  createSpec({ x: 'month', y: 'pnl' }), // pnl rows may be negative
  geom.bar({ position: 'identity' }),
  scale.x(),
  scale.y()
);
```

## Counting rows

Map only `x` and set the `count` [stat](/sdk-next/advanced/statistics) to get a bar per category whose height is the number of rows in it — no value column needed:

```tsx theme={null}
const spec = pipe(
  createSpec({ x: 'category' }),
  geom.bar({ stat: 'count' }),
  scale.x(),
  scale.y()
);
```

## Horizontal bars

Keep the natural mapping — category on `x`, value on `y` — and add [`coord.flip()`](/sdk-next/concepts/coordinate-systems) to swap the axes. Stacking, grouping and styling all carry over unchanged; only the orientation differs:

<GraphEmbed story="chart-types-bar-graph--simple" args={{ flipped: true }} />

```tsx theme={null}
import { createSpec, pipe, geom, scale, coord } from '@graphysdk/react';

const spec = pipe(
  createSpec({ x: 'country', y: 'users' }),
  geom.bar(),
  scale.x(),
  scale.y(),
  coord.flip() // horizontal bars
);
```

## Ranking

To order bars by value, sort the data with a [transform](/sdk-next/advanced/transforms) — most useful with horizontal bars:

```tsx theme={null}
import { transform } from '@graphysdk/react';

const spec = pipe(
  createSpec({ x: 'country', y: 'users' }),
  transform.sort({ variableName: 'users', direction: 'desc' }),
  geom.bar(),
  scale.x(),
  scale.y(),
  coord.flip()
);
```

## Bar geometry

`geom.bar()` takes one param, and it is geometry rather than paint — it sets the band envelope the compiler writes into the position variables:

<ParamField path="params.width" type="number" default="0.7">
  Bar width as a fraction of the band the discrete scale allocates to the
  category, in `(0, 1]`.
</ParamField>

```tsx theme={null}
geom.bar({ params: { width: 0.6 } });
```

A value outside `(0, 1]` draws with a substitute width and reports an `INVALID_GEOM_PARAM` warning.

## Painting the bars

Fill, opacity, corner rounding and the border come from the [stylesheet](/sdk-next/config/styling), through the `style.geom.bar` target:

```tsx theme={null}
import { createSpec, pipe, geom, scale, styles, style } from '@graphysdk/react';

const spec = pipe(
  createSpec({ x: 'category', y: 'revenue' }),
  geom.bar({ params: { width: 0.6 } }),
  scale.x(),
  scale.y(),
  styles({
    defaults: [
      style.geom.bar({
        borderRadius: 'md',
        borderColor: '#ffffff',
        borderWidth: 2,
      }),
    ],
  })
);
```

`style.geom.bar` declares `color`, `alpha`, `saturation`, `borderRadius`, `borderColor` and `borderWidth`.

### Corner rounding

`borderRadius` is a named token rather than a pixel value, so each coordinate system renders it in its own frame — a rectangle in cartesian, an arc corner in polar:

| Token                              | Effect                                                 |
| ---------------------------------- | ------------------------------------------------------ |
| `'none'`                           | Square corners                                         |
| `'xs'` `'sm'` `'md'` `'lg'` `'xl'` | Increasing rounding; `'sm'` is the built-in default    |
| `'full'`                           | Rounds to half the bar's cross-axis thickness — a pill |

```tsx theme={null}
styles({ defaults: [style.geom.bar({ borderRadius: 'full' })] });
```

A stacked column rounds only the outer corners of the whole column, so the segments inside it stay flush against each other.

### Borders

`borderWidth` is `1` by default; the border becomes visible once `borderColor` resolves to a color. A border in the chart's background color is the usual way to separate stacked segments or pie wedges:

```tsx theme={null}
styles({
  defaults: [style.geom.bar({ borderColor: '#ffffff', borderWidth: 2 })],
});
```

Scope an entry with `{ layer }` to paint one bar layer of a [combo](/sdk-next/graph-types/combo) differently, or with `{ where }` to paint by value — negative bars in a warning color, for instance.

## Related

* [Styling](/sdk-next/config/styling) — the stylesheet, its cascade and every target
* [Coordinate systems](/sdk-next/concepts/coordinate-systems) — how `coord.flip()` works
* [Geoms & layers](/sdk-next/concepts/geoms) — position modes and layering
* [Scales](/sdk-next/concepts/scales) — control the value axis range
