> ## 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.

# Live data

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&globals=mode:readonly${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'
  }} />;
};

A chart fed by a live source updates by receiving new `data`. Keep `spec` the same object across
pushes: the provider compares it by reference, and a new one means a full compile, spec resolution
included, where a data push alone reuses the resolved spec.

<GraphEmbed story="features-live-data--rolling-line" />

This line uses the same `second` and `reading` columns as the example above. Each source message
supplies a complete data object (`columns` and `rows`) containing the current rolling window.

```tsx theme={null}
import { useEffect, useMemo, useState } from 'react';
import { GraphProvider, GraphRenderer } from '@graphysdk/react-renderer';
import {
  createSpec,
  type Data,
  geom,
  pipe,
  scale,
} from '@graphysdk/viz-engine';

function RollingLine({ source }: { source: EventSource }) {
  // Built once. Building it inside the render would make every push a full compile.
  const spec = useMemo(
    () =>
      pipe(
        createSpec({ x: 'second', y: 'reading' }),
        geom.line(),
        scale.x.continuous({ nice: false }),
        scale.y.continuous()
      ),
    []
  );
  const [data, setData] = useState<Data>({
    columns: [{ key: 'second' }, { key: 'reading' }],
    rows: [{ second: 0, reading: 50 }],
  });

  useEffect(() => {
    source.onmessage = (event) => setData(JSON.parse(event.data));
  }, [source]);

  return (
    <GraphProvider spec={spec} data={data}>
      <GraphRenderer animation={{ transitions: false }} />
    </GraphProvider>
  );
}
```

Transitions are off here because a source that pushes faster than a spring settles has nothing for a
spring to settle towards. Above `maxAnimatedGeoms` (1500 by default, set on `animation`) the graph
plays no animation on its own, but that counts geoms, not points: a live bar chart past the ceiling
needs no such setting, while a line is one geom however many points it draws and keeps
transitioning until you turn them off.

## Related

* [Interactivity](/sdk-next/rendering/interactivity) — every `animation` setting
* [Provider and renderer](/sdk-next/rendering/provider-and-renderer) — what `spec` and `data` are
