# Point

Visual markers that highlight specific data values on a chart. Points can be customized with different colors, sizes, and labels.

## Import

```tsx
import { Point } from '@coinbase/cds-mobile-visualization'
```

## Examples

### Basic Example

Points are visual markers that highlight specific data values on a chart. They can be used to emphasize important data points, show discrete values, or provide interactive elements.

You can add points using `points` on Line or [LineChart](/components/graphs/LineChart).

```jsx
<LineChart
  enableScrubbing
  showArea
  showYAxis
  height={200}
  points
  series={[
    {
      id: 'prices',
      data: [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58],
    },
  ]}
  xAxis={{
    /* This prevents points close to the right edge from awkward cutoff when scrubbing */
    range: ({ min, max }) => ({ min, max: max - 8 }),
  }}
  yAxis={{
    showGrid: true,
  }}
>
  <Scrubber />
</LineChart>
```

You can also add Points directly to a chart.

```jsx
function MyChart() {
  const prices = [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58];

  return (
    <CartesianChart
      height={200}
      series={[
        {
          id: 'prices',
          data: prices,
        },
      ]}
      inset={{
        // Overriding the right offset gives us more space to place this
        right: 32,
      }}
    >
      <YAxis showGrid position="left" tickLabelFormatter={(value) => `$${value}`} />
      {prices.map((price, index) => (
        <Point
          seriesId="prices"
          key={index}
          dataX={index}
          dataY={price}
          label={`$${price}`}
          labelPosition="right"
        />
      ))}
    </CartesianChart>
  );
}
```

#### Conditional

You can conditionally render points to highlight specific values in your data, such as maximum/minimum values or outliers.

```jsx
function AssetPriceWithMinMax() {
  const data = sparklineInteractiveData.hour.map((d) => d.value);

  const minPrice = Math.min(...data);
  const maxPrice = Math.max(...data);

  const formatPrice = useCallback((price: number) => {
    return new Intl.NumberFormat('en-US', {
      style: 'currency',
      currency: 'USD',
    }).format(price);
  }, []);

  return (
    <LineChart
      showArea
      areaType="dotted"
      height={200}
      points={({ dataX, dataY }: PointBaseProps) => {
        const isMin = dataY === minPrice;
        const isMax = dataY === maxPrice;

        if (isMin) {
          return { label: formatPrice(dataY), labelPosition: 'bottom' };
        }

        if (isMax) {
          return { label: formatPrice(dataY), labelPosition: 'top' };
        }
      }}
      series={[
        {
          id: 'btc',
          data: data,
          color: assets.btc.color,
        },
      ]}
    />
  );
};
```

### Styling

Points support customization through various properties including colors, sizes, and labels.

```jsx
function CustomizedPoints() {
  const theme = useTheme();
  return (
    <LineChart
      showArea
      showYAxis
      height={200}
      points={({ dataX, dataY }) => {
        const isHighPerformance = dataY >= 90;
        const isLowPerformance = dataY < 75;

        return {
          fill: isHighPerformance
            ? theme.color.bgPositive
            : isLowPerformance
              ? theme.color.bgNegative
              : theme.color.fgPrimary,
          radius: isHighPerformance ? 6 : 4,
          strokeWidth: 2,
          stroke: theme.color.bg,
          label: isHighPerformance || isLowPerformance ? `${dataY}%` : undefined,
          labelPosition: isHighPerformance ? 'top' : 'bottom',
        };
      }}
      series={[
        {
          id: 'performance',
          data: [65, 70, 72, 85, 88, 92, 78, 82, 90, 95, 91, 94],
        },
      ]}
      yAxis={{
        showGrid: true,
        label: 'Performance Score',
      }}
    />
  );
}
```

#### Labels

You can use `labelPosition`, `labelOffset`, and `labelFont` to adjust Point's label.

```jsx
function Scatterplot() {
  const dataPoints = [
    { x: 20, y: 30, label: 'A' },
    { x: 40, y: 65, label: 'B' },
    { x: 60, y: 45, label: 'C' },
    { x: 75, y: 80, label: 'D' },
  ];

  return (
    <CartesianChart
      height={250}
      xAxis={{
        domain: { min: 0, max: 100 },
      }}
      yAxis={{
        domain: { min: 0, max: 100 },
      }}
    >
      <XAxis showLine showTickMarks showGrid />
      <YAxis position="left" showLine showTickMarks showGrid />
      {dataPoints.map((point, index) => (
        <Point
          key={index}
          dataX={point.x}
          dataY={point.y}
          label={point.label}
          labelPosition="top"
          labelOffset={6}
          labelFont="title3"
        />
      ))}
    </CartesianChart>
  );
}
```

#### Custom Label Position

You can also use `LabelComponent` to create custom label components.

```jsx
function ScatterplotWithCustomLabels() {
  const theme = useTheme();
  const dataPoints = [
    { x: 12, y: 34, label: 'A', color: theme.color.fgAccent },
    { x: 28, y: 67, label: 'B', color: theme.color.fgAccent },
    { x: 45, y: 23, label: 'C', color: theme.color.fgAccent },
    { x: 67, y: 89, label: 'D', color: theme.color.bgPositive },
    { x: 82, y: 76, label: 'E', color: theme.color.bgPositive },
    { x: 34, y: 91, label: 'F', color: theme.color.bgPositive },
    { x: 56, y: 45, label: 'G', color: theme.color.bgPositive },
    { x: 19, y: 12, label: 'H', color: theme.color.fgWarning },
    { x: 73, y: 28, label: 'I', color: theme.color.fgWarning },
    { x: 91, y: 54, label: 'J', color: theme.color.fgWarning },
    { x: 15, y: 58, label: 'K', color: theme.color.fgPrimary },
    { x: 39, y: 72, label: 'L', color: theme.color.fgPrimary },
    { x: 88, y: 15, label: 'M', color: theme.color.fgPrimary },
    { x: 52, y: 82, label: 'N', color: theme.color.fgPrimary },
  ];

  // Calculate domain based on data
  const xValues = dataPoints.map((p) => p.x);
  const yValues = dataPoints.map((p) => p.y);
  const xMin = Math.min(...xValues);
  const xMax = Math.max(...xValues);
  const yMin = Math.min(...yValues);
  const yMax = Math.max(...yValues);

  // Custom label component that places labels to the top-right
  const TopRightPointLabel = ({ x, y, offset = 0, children }) => {
    return (
      <ChartText
        horizontalAlignment="left"
        verticalAlignment="bottom"
        x={x + offset}
        y={y - offset}
      >
        {children}
      </ChartText>
    );
  };

  return (
    <CartesianChart
      height={300}
      xAxis={{
        domain: { min: xMin, max: xMax },
        domainLimit: 'nice',
      }}
      yAxis={{
        domain: { min: yMin, max: yMax },
        domainLimit: 'nice',
      }}
    >
      <XAxis showLine showTickMarks showGrid />
      <YAxis position="left" showLine showTickMarks showGrid />
      {dataPoints.map((point, index) => (
        <Point
          key={index}
          dataX={point.x}
          dataY={point.y}
          label={point.label}
          labelOffset={8}
          fill={point.color}
          radius={5}
          LabelComponent={TopRightPointLabel}
        />
      ))}
    </CartesianChart>
  );
}
```

## Props

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `dataX` | `number` | Yes | `-` | X coordinate in data space (not pixel coordinates). |
| `dataY` | `number` | Yes | `-` | Y coordinate in data space (not pixel coordinates). |
| `LabelComponent` | `ComponentClass<PointLabelProps, any> \| FunctionComponent<PointLabelProps>` | No | `DefaultPointLabel` | Custom component to render the label. |
| `animate` | `boolean` | No | `-` | When set, overrides the charts animation setting for this specific point. |
| `fill` | `string` | No | `theme.color.fgPrimary` | The fill color of the point. |
| `label` | `string \| SkParagraph \| { value: string \| SkParagraph; }` | No | `-` | Simple text label to display at the point position. If provided, a label component will be automatically rendered. |
| `labelFont` | `display1 \| display2 \| display3 \| title1 \| title2 \| title3 \| title4 \| headline \| body \| label1 \| label2 \| caption \| legal` | No | `-` | Font style for the label text. |
| `labelOffset` | `number` | No | `2 * radius` | Distance in pixels to offset the label from the point. |
| `labelPosition` | `top \| bottom \| left \| right \| center` | No | `'center'` | Position of the label relative to the point. |
| `opacity` | `number` | No | `-` | Opacity of the point. |
| `radius` | `number` | No | `5` | Radius of the point. |
| `stroke` | `string` | No | `theme.color.bg` | Color of the outer stroke around the point. |
| `strokeWidth` | `number` | No | `2` | Outer stroke width of the point. Set to  0 to remove the stroke. |
| `transition` | `{ type: timing; } & TimingConfig \| { type: spring; } & { stiffness?: number \| undefined; overshootClamping?: boolean \| undefined; restDisplacementThreshold?: number \| undefined; restSpeedThreshold?: number \| undefined; velocity?: number \| undefined; reduceMotion?: ReduceMotion \| undefined; } & { mass?: number \| undefined; damping?: number \| undefined; duration?: undefined; dampingRatio?: undefined; clamp?: undefined; } \| { type: spring; } & { stiffness?: number \| undefined; overshootClamping?: boolean \| undefined; restDisplacementThreshold?: number \| undefined; restSpeedThreshold?: number \| undefined; velocity?: number \| undefined; reduceMotion?: ReduceMotion \| undefined; } & { mass?: undefined; damping?: undefined; duration?: number \| undefined; dampingRatio?: number \| undefined; clamp?: { min?: number \| undefined; max?: number \| undefined; } \| undefined; }` | No | `-` | Transition configuration for point animations. Defines how the point transitions when position or color changes. |
| `yAxisId` | `string` | No | `first y-axis defined in chart props.` | Optional Y-axis id to specify which axis to plot along. |


