023 / RECHARTS / BAR & COLUMN

Diverging Bars

Recharts

Signed categorical bars extending above/below or left/right from a neutral reference, with symmetric scaling, direction-aware geometry, and factual deviation semantics.

SPEC
#023
ENGINE
Recharts
FAMILY
Bar & Column
RENDERER
svg
STATUS
preview

Installation

PLOTCN/REGISTRY/BAR-DIVERGING/SOURCE
pnpm dlx shadcn@latest add @plotcn/bar-diverging

Checking public registry…

View local registry JSON
REGISTRY direct URL·ENGINE Recharts·FILES 1·DEPENDENCIES 5

Copied as source into your project (requires recharts).

× 340Container width
Measuring preview...
RECHARTS · SVG · 0 × 340pxMotion enabled · ResizeObserver

Overview

Diverging Bars is Plotcn's canonical signed categorical visualization component designed specifically for comparing categorical deviations around an explicit neutral reference. It answers the fundamental analytical question:

“How does each categorical value deviate above or below a meaningful neutral reference?”

Secondary analytical questions answered by this component include:

  • “What is the direction of the deviation (above, on, or below the reference)?”
  • “How large is that deviation from the baseline?”
  • “Which categories are above, below, or exactly on the reference?”
  • “What was the original raw consumer observation before deviation was computed?”
TSX
import { DivergingBars } from "@/components/charts/recharts/bar-diverging"const regionalVariance = [  { region: "North", variance: 18 },  { region: "South", variance: -12 },  { region: "East", variance: 31 },  { region: "West", variance: -24 },  { region: "Central", variance: 0 },]export function RegionalVarianceChart() {  return (    <DivergingBars      data={regionalVariance}      categoryKey="region"      series={{        key: "variance",        label: "Variance from Plan",        valueFormatter: (v) => `${v}%`,      }}      baseline={0}      showGrid    />  )}

Governing Principle

Diverging Bars encodes signed deviation around an explicit neutral reference. Position relative to the baseline communicates direction; bar length communicates magnitude of deviation. Neither direction is automatically positive or negative in the moral or evaluative sense.

This principle governs:

  • API design and caller data immutability;
  • derivation of deviation in mathematical comparison space;
  • symmetrical quantitative domain resolution;
  • direction-aware outward corner rounding;
  • factual, non-judgmental tooltip language and accessibility narration;
  • keyboard traversal and container-aware responsive layout.

Bar-Family Positioning

The Plotcn Bar family provides six distinct analytical specializations:

Component Registry ID Primary Analytical Question Quantitative Scale
ComponentRegistry IDPrimary Analytical QuestionQuantitative Scale
Signal Bars (019)bar-signal"How do discrete categories compare on single or grouped measures?"Grounded Zero (0Max0 \to \text{Max})
Rank Bars (020)bar-rank"Which categories perform highest or lowest in top-N rank?"Grounded Zero (0Max0 \to \text{Max})
Group Compare (021)bar-group-compare"How do peer measures compare directly against each other?"Shared Grounded Zero (0Max0 \to \text{Max})
Stack Ledger (022)bar-stack-ledger"How do additive contributors compose the total magnitude?"Additive Total (0Max Total0 \to \text{Max Total})
Percent Stack (023)bar-percent-stack"How does the internal percentage composition differ across categories?"Fixed Normalized (0%100%0\% \to 100\%)
Diverging Bars (024)bar-diverging"How does each value deviate above or below a neutral reference?"Symmetric Deviation (Max0+Max-\text{Max} \to 0 \to +\text{Max})

Do not turn Diverging Bars into a generic mode of Signal Bars. Its baseline math, domain symmetry, color semantics, and directional labeling justify a dedicated component.

Diverging Model

ANALYTICAL MODELSigned Categorical Deviation

The Diverging Bar Model: Direction by Side, Magnitude by Length

Analytical model of Diverging Bars showing values compared to an explicit baseline where position relative to the reference encodes direction (above, on, below) and bar length encodes deviation magnitude.

In the Diverging Bars analytical model:

  • Baseline Spine: Represents the neutral reference (defaults to 0, but supports any finite numeric value).
  • Position Relative to Reference: Values above the reference extend outward to the positive side (right in horizontal layout, up in vertical layout). Values below extend to the negative side (left in horizontal layout, down in vertical layout).
  • Bar Length: Strictly encodes the magnitude of the derived deviation |value - baseline|.
  • Zero Deviation: Sits exactly on the reference baseline with a neutral marker and zero bar length.

Reference Baseline

CANONICAL DEFAULTZero Neutral Spine

Canonical Zero Baseline: Natural Positive and Negative Divergence

Visualization of a zero baseline where values diverge around zero with symmetrical quantitative axis extents.

Canonical Zero Baseline

When baseline = 0, the component operates in classical zero-centered signed mode:

  • value > 0 &rarr; Above reference (+ deviation)
  • value = 0 &rarr; On reference (0 deviation)
  • value < 0 &rarr; Below reference (&minus; deviation)

Explicit Non-Zero Benchmark or Target

Diverging Bars truthfully supports non-zero baselines such as service targets, SLA budgets, quarterly goals, or industry averages:

EXPLICIT BASELINETarget / SLA Centering

Non-Zero Reference Baseline: Centering Geometry in Deviation Space

Diagram showing an API latency dataset with target SLA of 250ms where deviations are centered around 0 in rendered geometry.

TSX
<DivergingBars  data={serviceLatencies}  categoryKey="service"  series={{    key: "latency",    label: "API Latency",    valueFormatter: (v) => `${v} ms`,  }}  baseline={250}  baselineLabel="Target"/>

For a raw observation of 310 ms against a baseline of 250 ms, the derived deviation is +60 ms. The bar geometry encodes the 60-unit deviation from the target, not 310 units from zero.

Negative Reference Baseline

A negative baseline reference is mathematically valid and fully supported:

EDGE CASE VERIFICATIONNegative Reference Baseline

Negative Baseline Reference: -80 is Above -100 Reference Baseline

Demonstration showing how values are compared with a negative baseline (-100), where -80 produces a positive deviation (+20) and sits above the reference line.

For baseline = -100 and rawValue = -80, the derived deviation is +20 (-80 - (-100) = +20). The observation sits above the reference line even though the raw value is negative.

Raw Value vs Deviation

MATHEMATICAL TRUTHCanonical Derivation

Raw Consumer Value vs Derived Deviation: deviation = value - baseline

Step-by-step diagram illustrating how input raw values are preserved untouched while deviation is derived by subtracting the baseline, showing that raw sign does not dictate direction.

Below Reference• Raw value (+80) is positive, but sits 20 units below target.• Never classify direction using raw sign alone!EXAMPLE 2: Negative Baseline (Baseline = −100)Raw Value−80Baseline−100=+20Observation: Above Reference• Raw value (−80) is negative, but sits 20 units above reference.• True position: −80 − (−100) = +20 (Above).

Plotcn strictly preserves consumer raw values canonical. Caller data records are never mutated.

  1. The consumer supplies raw observations (value).
  2. Plotcn derives deviation = value - baseline.
  3. Recharts renders bars inside zero-centered deviation space.
  4. Tooltips and accessibility layers present both raw values, reference baseline, and derived deviation.

Symmetric Domain

PROPORTIONAL INTEGRITYVisual Comparability

Symmetric Domain: Why Equal Geometric Lengths Must Represent Equal Magnitudes

Visual comparison between an asymmetric domain and Plotcn symmetric domain, showing how asymmetric extents distort perception of magnitude across the baseline.

A diverging chart benefits from equal visual distance on opposite sides of the neutral baseline.

  • Default Symmetry: [-maxAbsDeviation, +maxAbsDeviation]
  • Under this model, equal geometric bar lengths on opposite sides represent equal deviation magnitudes.
  • If deviations range from -20 to +80, Plotcn scales the axis from -80 to +80 (or symmetrically niced bounds like [-100, +100]), preventing the misleading illusion that a small negative value is comparable to a large positive value.
  • All-Above & All-Below Datasets: Symmetrical domaining preserves the neutral baseline spine and opposing space, preventing the chart from silently collapsing into an ordinary one-sided bar chart.

Direction Semantics

POSITIONAL SEMANTICSThree Distinct States

Above Reference, Below Reference, and On Reference States

Three semantic cards explaining above reference, on reference, and below reference states and their visual representation.

Above Reference

deviation > 0

Observation strictly exceeds the baseline. Bar extends outward into positive/right region with outer rounded cap.

On Reference

deviation = 0

Observation exactly matches reference. Rendered as a neutral baseline tick mark without artificial bar length.

Below Reference

deviation < 0

Observation falls below the baseline. Bar extends outward into negative/left region with outer rounded cap.

Plotcn uses factual, non-judgmental directional language:

  • Above reference (deviation &gt; 0)
  • On reference (deviation = 0)
  • Below reference (deviation &lt; 0)

Direction Is Not Judgment

DESIGN INTEGRITYNeutral Color & Language

Direction Is Position, Not Moral Judgment

Callout showing that above reference is not automatically good and below is not automatically bad, warning against default red/green coloring.

Never confuse:

  • positive number or above baseline with a good outcome;
  • negative number or below baseline with a bad outcome.

For API latency, lower is better. For operational variance, zero deviation is ideal. Plotcn maintains semantic neutrality and avoids red/green moral judgment.

Installation

PLOTCN/REGISTRY/BAR-DIVERGING/SOURCE
pnpm dlx shadcn@latest add @plotcn/bar-diverging

Checking public registry…

View local registry JSON
REGISTRY direct URL·ENGINE Recharts·FILES 1·DEPENDENCIES 5

Copied as source into your project (requires recharts).

Missing vs On Reference

DATA SAFETYZero Deviation vs Missing

Missing Value vs On Reference: Never Conflate Unavailable Data with Zero

Side-by-side comparison showing that known zero deviation sits on the baseline with a tick mark, whereas missing or null data renders no bar and states unavailable in tooltips.

ON REFERENCEVALID OBSERVATION
  • • rawValue: 100
  • • baseline: 100
  • • deviation: 0
  • • position: "equal"

A real, finite metric was measured and exactly equals the baseline. Rendered with neutral tick mark.

MISSING / NULLUNAVAILABLE
  • • rawValue: null / undefined
  • • baseline: 100
  • • deviation: null
  • • position: "unavailable"

No observation recorded. Plotcn never substitutes 0. Category remains keyboard inspectable, displaying "Unavailable".

Plotcn maintains a strict distinction between known zero deviation and missing observations:

  • On Reference (deviation = 0): A valid numeric observation was measured and exactly equals the baseline. Rendered with a neutral baseline tick.
  • Missing (null / undefined): No numeric observation was recorded. Plotcn never substitutes zero. No bar is drawn, and tooltips report "Unavailable".

Orientation & Layout

LAYOUT STRATEGYHorizontal & Vertical

Orientation Layouts: Horizontal Left/Right vs Vertical Above/Below

Side-by-side diagrams of horizontal diverging layout (bars extending left and right from vertical baseline) versus vertical layout (bars rising and falling from horizontal baseline).

Diverging Bars supports both horizontal and vertical orientations:

  • Horizontal (layout="horizontal", default): Categories on vertical Y-axis, bars extend left/right from central vertical baseline spine. Optimal for signed categorical comparison and long category labels.
  • Vertical (layout="vertical"): Categories on horizontal X-axis, bars extend up/down from horizontal baseline.

Category Hit Regions

INTERACTION ERGONOMICSTouch & Cursor Safety

Category Band Hit Testing: Forgiving Interaction for Zero and Tiny Bars

Illustration showing that the interaction surface spans the full category band height and width, enabling easy targeting of tiny or zero-magnitude values on mobile and touch devices.

To ensure accessibility and touch safety:

  • Hit testing uses the full category band rather than only the visible bar rectangle.
  • Zero-deviation and tiny-deviation bars remain easily inspectable on mobile devices without artificial visible inflation.

Animation & Baseline Crossing

ANIMATION SAFETYNo Baseline Overshoot

Baseline Crossing Animation: Contraction and Expansion Without Teleportation

Step-by-step animation lifecycle showing a bar transitioning from positive (+20) to negative (-10) by contracting toward the baseline and expanding into negative space.

  • Bars originate at the neutral baseline and grow outward.
  • Data updates transitioning across the baseline contract toward zero before expanding into the opposing direction, preventing teleportation or overshoot.
  • Fully honors prefers-reduced-motion.

Rendering Architecture

SYSTEM PIPELINEEnd-to-End Architecture

DivergingBars Rendering Pipeline: From Raw Observations to Directional SVG

System architecture diagram detailing consumer records input, validation of finite baseline, deviation derivation, classification, symmetric domain calculation, and Recharts SVG rendering.

Data Contract

TypeScript
interface DivergingDatum {  region: string  variance: number | null}
  • Categories preserve caller order strictly without dynamic sorting or ranking.
  • Raw values must be finite numbers; NaN and Infinity are rejected as unavailable.
  • Baseline must be a finite number.

Props Reference

Prop Type Default Description
PropTypeDefaultDescription
datareadonly TData[][]Categorical data observations. Order preserved strictly.
categoryKeykeyof TData & stringProperty key identifying discrete categories.
seriesDivergingBarSeries<TData>Semantic quantitative series { key, label, valueFormatter }.
layout"horizontal" | "vertical""horizontal"Visual orientation layout.
baselinenumber0Explicit neutral reference baseline.
baselineLabelstringOptional semantic label (e.g. "Target", "SLA").
domain[number, number] | "symmetric""symmetric"Quantitative scale domain in deviation space.
aboveColorstring"var(--chart-1)"Fill color for bars above the reference baseline.
belowColorstring"var(--chart-2)"Fill color for bars below the reference baseline.
baselineColorstring"var(--chart-axis)"Stroke color for reference baseline line.
selectionColorstring"var(--chart-selection)"Stroke emphasis for active/selected bar.
heightnumber | string340Chart container height in pixels.
showGridbooleantrueWhether to render background grid lines.
showLegendbooleanfalseWhether to render directional legend.
valueLabel"none" | "value" | "deviation" | "auto""none"Inline numeric label rendering mode.
maxBarSizenumber36Maximum bar thickness in pixels.
motionboolean | { duration?: number }trueAnimation toggle honoring reduced-motion preferences.

Accessibility

  • Screen readers receive a descriptive analytical summary detailing categories above, below, and on reference.
  • Offscreen HTML table includes Category, Raw Value, Reference Baseline, Deviation, and Position columns.
  • Single chart tab stop with keyboard navigation:
    • Horizontal: ArrowUp / ArrowDown
    • Vertical: ArrowLeft / ArrowRight
    • Home / End to jump to first / last category.
03 / Component API & Styling

Props Reference & Interactive Prop Explorer

Inspect every component property, customize semantic color roles live with instant visual feedback, and copy production-ready code with active prop configurations.

Colors & Appearance Configuration

Customize primary, reference, or annotation series colors. Defaults derive from Plotcn theme tokens.

Generated Usage Code (Live Props):
<DivergingBars
  data={data}
  categoryKey="region"
  series={{ key: "variance", label: "Variance from Plan" }}
  baseline={0}
/>
Interactive Prop Preview Lab
baselinenumber

Explicit neutral reference baseline against which deviation is derived (value - baseline).

Select value to preview live:
Active: baseline={0}Default: 0
layout"horizontal" | "vertical"

Visual layout: 'horizontal' (categories on Y) or 'vertical' (categories on X).

Select value to preview live:
Active: layout="horizontal"Default: "horizontal"
domain[number, number] | "symmetric"

Quantitative scale domain in deviation space. 'symmetric' scales [-maxAbs, +maxAbs].

Select value to preview live:
Active: domain="symmetric"Default: "symmetric"
showGridboolean

Whether to render subtle background gridlines.

Select value to preview live:
Active: showGrid={true}Default: true
showLegendboolean

Whether to display the directional legend.

Select value to preview live:
Active: showLegend={false}Default: false
valueLabel"none" | "value" | "deviation" | "auto"

Policy for rendering inline numeric labels at outward bar ends.

Select value to preview live:
Active: valueLabel="none"Default: "none"
All Properties (17)
Component properties
PropertyTypeDefaultRequiredDescription
dataReq
readonly TData[][]Yes

Array of categorical data records. Order is strictly preserved.

keyof TData & stringYes

Key on data records representing the discrete category.

DivergingBarSeries<TData>Yes

Quantitative series definition containing key, label, and optional valueFormatter.

number0No

Explicit neutral reference baseline against which deviation is derived (value - baseline).

stringundefinedNo

Optional label for the baseline (e.g. 'Target', 'Plan', 'SLA').

"horizontal" | "vertical""horizontal"No

Visual layout: 'horizontal' (categories on Y) or 'vertical' (categories on X).

[number, number] | "symmetric""symmetric"No

Quantitative scale domain in deviation space. 'symmetric' scales [-maxAbs, +maxAbs].

string"var(--chart-1)"No

Fill color for bars deviating above the neutral baseline reference.

string"var(--chart-2)"No

Fill color for bars deviating below the neutral baseline reference.

string"var(--chart-axis)"No

Stroke color for the structural baseline reference line.

string"var(--chart-selection)"No

Accent stroke color for the currently inspected category bar.

booleantrueNo

Whether to render subtle background gridlines.

booleanfalseNo

Whether to display the directional legend.

"none" | "value" | "deviation" | "auto""none"No

Policy for rendering inline numeric labels at outward bar ends.

number | string340No

Container height in pixels or CSS dimension string.

number36No

Maximum bar thickness in pixels.

boolean | { duration?: number }trueNo

Animation toggle honoring reduced-motion preferences.

04 / Cookbook & States

Component Variants & Edge States

Production cookbooks showcasing configuration variants alongside verified handling of loading, empty data, and network error states.

Variance from Plan (Zero Baseline)

Regional performance variance around a zero neutral reference baseline.

<DivergingBars
  data={[
    { region: "North", variance: 18 },
    { region: "South", variance: -12 },
    { region: "East", variance: 31 },
    { region: "West", variance: -24 },
    { region: "Central", variance: 0 },
  ]}
  categoryKey="region"
  series={{ key: "variance", label: "Variance from Plan" }}
  baseline={0}
/>

API Latency vs Target SLA (Non-Zero Baseline)

Service latencies compared against a 250ms target benchmark, rendered in deviation space.

<DivergingBars
  data={[
    { service: "Auth", latency: 210 },
    { service: "Search", latency: 290 },
    { service: "Billing", latency: 250 },
    { service: "Reports", latency: 340 },
    { service: "Profile", latency: 190 },
  ]}
  categoryKey="service"
  series={{ key: "latency", label: "Latency", valueFormatter: (v) => `${v} ms` }}
  baseline={250}
  baselineLabel="Target SLA"
/>
Lifecycle & Exception States
01. Loading State

Skeletons indicate runtime fetch or pending data queries.

02. Empty Data State

Handles empty collections ([]) gracefully without crashing.

03. Error State

Graceful failure banner when data source or script fails.

05 / Responsive Lab

Container-Driven Breakpoints

Diverging Bars fluidly adapts from ultra-wide enterprise monitoring down to narrow 320px mobile displays. Symmetric domain scaling guarantees balanced visual anchor on both sides of the reference line at all widths and heights.

Desktop
>= 1024px

Full categorical tick labels, outward value callouts, and spacious analytical tooltips with raw measurements and derived deviations.

Tablet
640px - 1023px

Compact category labels, preserved symmetric domain bounds, and responsive tooltip clamping within container bounds.

Mobile
< 640px

Horizontal layout recommended to afford long category names, strict touch-action pan-y preservation, and compact card tooltips with auto-adjustment.

Tablet Preview (768px Container Constraint)
Mobile Preview (390px Container Constraint)
06 / Assistive Technology

Accessibility & Navigation Standards

Semantic figure region with single tab stop, arrow-key navigation (Left/Right for vertical layout, Up/Down for horizontal layout), Home/End traversal, polite ARIA live announcements, and an offscreen structured HTML table for screen readers.

Semantic Role & Landmark

Container mounts as region with explicit assistive label.

Color-Independent Legibility

Spatial direction relative to the baseline unambiguously conveys sign even under complete monochromatic rendering. Explicit table columns and legend indicators ensure color is never the sole information carrier.

Screen Reader Summary

Embeds visually hidden summary (.sr-only) declaring: “Announces category name, raw value, baseline reference, and signed deviation. Factual accessibility summary details counts above, below, and on reference.

Reduced Motion Support

All initial entrance animations are bypassed immediately when prefers-reduced-motion is detected.

Keyboard Interaction Model
Keyboard interaction model
KeyAction
ArrowDown / ArrowRightMove focus to the next category
ArrowUp / ArrowLeftMove focus to the previous category
HomeJump focus to the first category
EndJump focus to the last category
EscapeClear active category inspection
07 / Source Anatomy

Internal Architecture & File Dependencies

Source-first ownership model. Inspect the exact component call tree, dependencies, and full implementation below.

Component Architecture Call Tree
DivergingBars(Semantic figure and keyboard navigation coordinator)
└──ChartContainer[Container query wrapper]

Provides responsive container sizing and design tokens

Involved Source Files & Registry Assets
registry/recharts/bar-diverging.tsx
Complete DivergingBars component with deviation derivation, symmetric domain resolution, direction-aware corner caps, and accessible table.
registry/recharts/bar-diverging.tsx
"use client"import * as React from "react"import {  ResponsiveContainer,  BarChart,  Bar,  XAxis,  YAxis,  Tooltip,  CartesianGrid,  ReferenceLine,  LabelList,} from "recharts"import { useChartReducedMotion } from "../shared/use-chart-reduced-motion"import { ChartContainer } from "../shared/chart-container"import {  ChartEmptyState,  ChartErrorState,  ChartLoadingState,  ChartUnavailableState,} from "../shared/chart-state"import { cn } from "@/lib/utils"/* -------------------------------------------------------------------------- *//*  Type Definitions & Contracts                                              *//* -------------------------------------------------------------------------- */export type NumericKeyOf<TData> = [keyof TData] extends [never]  ? string  : {      [K in keyof TData]: TData[K] extends number | null | undefined ? K : never    }[keyof TData] extends never  ? string  : {      [K in keyof TData]: TData[K] extends number | null | undefined ? K : never    }[keyof TData] & stringexport type DivergingBarLayout = "horizontal" | "vertical"export type DivergingValueLabel = "none" | "value" | "deviation" | "auto"export type DivergingPosition = "above" | "below" | "equal" | "unavailable"export interface DivergingBarSeries<TData extends Record<string, unknown> = Record<string, unknown>> {  /** Property key on data records representing the primary quantitative measure */  key: NumericKeyOf<TData>  /** Human-readable display label for tooltips, legend, and accessibility */  label: string  /** Optional custom numeric formatter for tooltip, axis ticks, and labels */  valueFormatter?: (value: number) => string}export interface PreparedDivergingDatum<TData = Record<string, unknown>> {  __category: string | number  __index: number  __raw: TData  __rawValue: number | null  __deviation: number | null  __position: DivergingPosition  [key: string]: unknown}export interface DivergingBarsProps<TData extends Record<string, unknown> = Record<string, unknown>> {  /** Readonly array of categorical observations. Order is strictly caller-preserved. */  data: readonly TData[]  /** Property key defining the discrete category domain */  categoryKey: keyof TData & string  /** Semantic quantitative series definition */  series: DivergingBarSeries<TData>  /**   * Orientation layout:   * - "horizontal": Categories on vertical Y-axis, bars extend left/right from central vertical baseline (default).   * - "vertical": Categories on horizontal X-axis, bars extend above/below from central horizontal baseline.   */  layout?: DivergingBarLayout  /** Chart container height in pixels or CSS dimension string (default: 340) */  height?: number | string  /**   * Explicit neutral numeric reference baseline (default: 0).   * Deviation is computed as `value - baseline`. Finite numbers only.   */  baseline?: number  /** Optional semantic label for the baseline (e.g. "Target", "Plan", "Budget", "SLA") */  baselineLabel?: string  /**   * Quantitative scale domain policy:   * - "symmetric": Extends equally on both sides of zero deviation `[-maxAbs, +maxAbs]` (default).   * - `[min, max]`: Explicit custom deviation domain bounds.   */  domain?: [number, number] | "symmetric"  /** Fill color for bars deviating above the reference (default: "var(--chart-1)") */  aboveColor?: string  /** Fill color for bars deviating below the reference (default: "var(--chart-2)") */  belowColor?: string  /** Stroke color for the reference baseline line (default: "var(--chart-axis)") */  baselineColor?: string  /** Accent outline color for the active/selected bar (default: "var(--chart-selection)") */  selectionColor?: string  /** Maximum width/thickness for individual bars in pixels (default: 36) */  maxBarSize?: number  /** Whether to render subtle background grid lines (default: true) */  showGrid?: boolean  /** Whether to render the directional legend (default: false) */  showLegend?: boolean  /** Inline numeric label policy (default: "none") */  valueLabel?: DivergingValueLabel  /** Optional motion configuration or toggle. Honors prefers-reduced-motion. (default: true) */  motion?: boolean | { duration?: number }  /** Accessible chart title for assistive technologies */  title?: string  /** Accessible description of the chart semantics */  description?: string  /** Explicit loading state */  loading?: boolean  /** Explicit error state or message */  error?: Error | string | null  /** Explicit unavailable state notice */  unavailable?: boolean | string | null  /** Additional CSS class for the root figure wrapper */  className?: string}/* -------------------------------------------------------------------------- *//*  Pure Mathematical & Classification Helpers                                *//* -------------------------------------------------------------------------- */export function isFiniteNumber(val: unknown): val is number {  return typeof val === "number" && Number.isFinite(val) && !Number.isNaN(val)}/** * Derives deviation from explicit baseline: `deviation = value - baseline`. * Preserves raw input values canonical while producing comparison space. */export function computeDeviation(value: number, baseline: number): number {  return value - baseline}/** * Classifies an observed value strictly relative to the baseline. * Never conflates raw positive/negative sign with above/below baseline position. */export function classifyAgainstBaseline(  value: number,  baseline: number): "above" | "below" | "equal" {  const diff = value - baseline  if (Math.abs(diff) < 1e-9) return "equal"  return diff > 0 ? "above" : "below"}/** * Resolves a safe numeric domain in deviation space. * Default "symmetric" mode scales symmetrically `[-maxAbs, +maxAbs]` around zero deviation. */export function resolveSymmetricDomain(  deviations: (number | null)[],  explicitDomain?: [number, number] | "symmetric"): [number, number] {  if (    Array.isArray(explicitDomain) &&    explicitDomain.length === 2 &&    isFiniteNumber(explicitDomain[0]) &&    isFiniteNumber(explicitDomain[1]) &&    explicitDomain[0] < explicitDomain[1]  ) {    return [explicitDomain[0], explicitDomain[1]]  }  const finiteDevs: number[] = []  for (const d of deviations) {    if (d !== null && isFiniteNumber(d)) {      finiteDevs.push(d)    }  }  if (finiteDevs.length === 0) {    return [-10, 10]  }  const maxAbs = Math.max(...finiteDevs.map((d) => Math.abs(d)))  if (maxAbs === 0) {    return [-1, 1]  }  // Symmetrical margin padding (10% headroom, rounded nicely)  const padded = maxAbs * 1.15  const magnitude = Math.pow(10, Math.floor(Math.log10(padded)))  const normalized = padded / magnitude  let niceFactor = 10  if (normalized <= 1) niceFactor = 1  else if (normalized <= 2) niceFactor = 2  else if (normalized <= 2.5) niceFactor = 2.5  else if (normalized <= 5) niceFactor = 5  const niceMax = Math.ceil(niceFactor * magnitude)  return [-niceMax, niceMax]}/* -------------------------------------------------------------------------- *//*  Direction-Aware Bar Shape with Outward Rounded Corners                    *//* -------------------------------------------------------------------------- */interface DivergingBarShapeProps {  x?: number  y?: number  width?: number  height?: number  payload?: PreparedDivergingDatum  layout: DivergingBarLayout  aboveColor: string  belowColor: string  selectionColor: string  isActive?: boolean}function DivergingBarShape(props: DivergingBarShapeProps) {  const {    x = 0,    y = 0,    width = 0,    height = 0,    payload,    layout,    aboveColor,    belowColor,    selectionColor,    isActive = false,  } = props  if (!payload || payload.__deviation === null) {    return null  }  const dev = payload.__deviation  const isZero = Math.abs(dev) < 1e-9  const isAbove = dev > 0  const fill = isAbove ? aboveColor : belowColor  const radius = 4  // For zero deviations, render a tiny neutral baseline tick mark without falsifying magnitude  if (isZero) {    if (layout === "horizontal") {      const markHeight = Math.max(height * 0.6, 6)      const markY = y + (height - markHeight) / 2      return (        <line          x1={x}          x2={x}          y1={markY}          y2={markY + markHeight}          stroke="var(--chart-axis-emphasis, #a1a1aa)"          strokeWidth={2}          strokeLinecap="round"        />      )    } else {      const markWidth = Math.max(width * 0.6, 6)      const markX = x + (width - markWidth) / 2      return (        <line          x1={markX}          x2={markX + markWidth}          y1={y}          y2={y}          stroke="var(--chart-axis-emphasis, #a1a1aa)"          strokeWidth={2}          strokeLinecap="round"        />      )    }  }  // Draw direction-aware rectangle with outward rounded corners  // Baseline-contact edge remains structurally flat  let pathD = ""  const w = Math.max(Math.abs(width), 0)  const h = Math.max(Math.abs(height), 0)  const actualX = width < 0 ? x + width : x  const actualY = height < 0 ? y + height : y  if (layout === "horizontal") {    const r = Math.min(radius, w / 2, h / 2)    if (isAbove) {      // Bar extends to the right: top-right & bottom-right rounded      pathD = `        M ${actualX},${actualY}        H ${actualX + w - r}        Q ${actualX + w},${actualY} ${actualX + w},${actualY + r}        V ${actualY + h - r}        Q ${actualX + w},${actualY + h} ${actualX + w - r},${actualY + h}        H ${actualX}        Z      `    } else {      // Bar extends to the left: top-left & bottom-left rounded      pathD = `        M ${actualX + r},${actualY}        H ${actualX + w}        V ${actualY + h}        H ${actualX + r}        Q ${actualX},${actualY + h} ${actualX},${actualY + h - r}        V ${actualY + r}        Q ${actualX},${actualY} ${actualX + r},${actualY}        Z      `    }  } else {    const r = Math.min(radius, w / 2, h / 2)    if (isAbove) {      // Bar rises upward: top-left & top-right rounded      pathD = `        M ${actualX},${actualY + h}        V ${actualY + r}        Q ${actualX},${actualY} ${actualX + r},${actualY}        H ${actualX + w - r}        Q ${actualX + w},${actualY} ${actualX + w},${actualY + r}        V ${actualY + h}        Z      `    } else {      // Bar extends downward: bottom-left & bottom-right rounded      pathD = `        M ${actualX},${actualY}        H ${actualX + w}        V ${actualY + h - r}        Q ${actualX + w},${actualY + h} ${actualX + w - r},${actualY + h}        H ${actualX + r}        Q ${actualX},${actualY + h} ${actualX},${actualY + h - r}        Z      `    }  }  return (    <g>      <path        d={pathD.trim()}        fill={fill}        opacity={isActive ? 1 : 0.9}        stroke={isActive ? selectionColor : "none"}        strokeWidth={isActive ? 2 : 0}        className="transition-all duration-150"      />    </g>  )}/* -------------------------------------------------------------------------- *//*  Main Component                                                            *//* -------------------------------------------------------------------------- */export function DivergingBars<TData extends Record<string, unknown> = Record<string, unknown>>({  data = [],  categoryKey,  series,  layout = "horizontal",  height = 340,  baseline = 0,  baselineLabel,  domain = "symmetric",  aboveColor = "var(--chart-1)",  belowColor = "var(--chart-2)",  baselineColor = "var(--chart-axis)",  selectionColor = "var(--chart-selection)",  maxBarSize = 36,  showGrid = true,  showLegend = false,  valueLabel = "none",  motion = true,  title = "Diverging Bars",  description,  loading = false,  error = null,  unavailable = null,  className,}: DivergingBarsProps<TData>) {  const reducedMotion = useChartReducedMotion()  const isAnimated = motion !== false && !reducedMotion  const animDuration =    typeof motion === "object" && typeof motion?.duration === "number"      ? motion.duration * 1000      : 300  // Validate finite baseline  const isBaselineValid = isFiniteNumber(baseline)  const safeBaseline = isBaselineValid ? baseline : 0  // Keyboard exploration active category index  const [activeIndex, setActiveIndex] = React.useState<number | null>(null)  const rootRef = React.useRef<HTMLDivElement>(null)  // Normalize data immutably into deviation space  const preparedData: PreparedDivergingDatum<TData>[] = React.useMemo(() => {    if (!Array.isArray(data)) return []    return data.map((item, index) => {      const rawCat = item?.[categoryKey]      const category =        typeof rawCat === "string" || typeof rawCat === "number" ? rawCat : `Category ${index + 1}`      const rawVal = item?.[series.key]      const finiteVal = isFiniteNumber(rawVal) ? rawVal : null      const deviation =        finiteVal !== null && isBaselineValid ? computeDeviation(finiteVal, safeBaseline) : null      const position: DivergingPosition =        finiteVal === null || !isBaselineValid          ? "unavailable"          : classifyAgainstBaseline(finiteVal, safeBaseline)      return {        ...item,        __category: category,        __index: index,        __raw: item,        __rawValue: finiteVal,        __deviation: deviation,        __position: position,      }    })  }, [data, categoryKey, series.key, isBaselineValid, safeBaseline])  // Resolve symmetric quantitative axis domain  const deviations = React.useMemo(    () => preparedData.map((d) => d.__deviation),    [preparedData]  )  const resolvedDomain = React.useMemo(    () => resolveSymmetricDomain(deviations, domain),    [deviations, domain]  )  // Keyboard navigation handler  const handleKeyDown = (e: React.KeyboardEvent) => {    if (preparedData.length === 0) return    const isHorizontal = layout === "horizontal"    const prevKey = isHorizontal ? "ArrowUp" : "ArrowLeft"    const nextKey = isHorizontal ? "ArrowDown" : "ArrowRight"    if (e.key === prevKey) {      e.preventDefault()      setActiveIndex((prev) => (prev === null || prev <= 0 ? preparedData.length - 1 : prev - 1))    } else if (e.key === nextKey) {      e.preventDefault()      setActiveIndex((prev) => (prev === null || prev >= preparedData.length - 1 ? 0 : prev + 1))    } else if (e.key === "Home") {      e.preventDefault()      setActiveIndex(0)    } else if (e.key === "End") {      e.preventDefault()      setActiveIndex(preparedData.length - 1)    } else if (e.key === "Escape") {      e.preventDefault()      setActiveIndex(null)    }  }  // Formatters  const formatValue = React.useCallback(    (v: number | null) => {      if (v === null) return "—"      if (series.valueFormatter) return series.valueFormatter(v)      return v.toLocaleString()    },    [series]  )  const formatDeviation = React.useCallback(    (d: number | null) => {      if (d === null) return "—"      const sign = d > 0 ? "+" : d < 0 ? "−" : ""      const absVal = Math.abs(d)      if (series.valueFormatter) {        return `${sign}${series.valueFormatter(absVal)}`      }      return `${sign}${absVal.toLocaleString()}`    },    [series]  )  // Deterministic state precedence  if (error || !isBaselineValid) {    return (      <figure        ref={rootRef}        className={cn("w-full", className)}        style={{ minHeight: typeof height === "number" ? height : 340 }}      >        <ChartErrorState          title="Invalid baseline reference"          description={            !isBaselineValid              ? "The baseline parameter must be a finite numeric value (NaN, Infinity, and -Infinity are rejected)."              : typeof error === "string"              ? error              : error?.message || "Failed to render diverging bars."          }        />      </figure>    )  }  if (unavailable) {    return (      <figure        ref={rootRef}        className={cn("w-full", className)}        style={{ minHeight: typeof height === "number" ? height : 340 }}      >        <ChartUnavailableState          title="Diverging data unavailable"          description={typeof unavailable === "string" ? unavailable : undefined}        />      </figure>    )  }  if (loading) {    return (      <figure        ref={rootRef}        className={cn("w-full", className)}        style={{ minHeight: typeof height === "number" ? height : 340 }}      >        <ChartLoadingState title="Loading diverging bars..." />      </figure>    )  }  if (!preparedData.length) {    return (      <figure        ref={rootRef}        className={cn("w-full", className)}        style={{ minHeight: typeof height === "number" ? height : 340 }}      >        <ChartEmptyState          title="No observations provided"          description="Provide categorical data to inspect signed deviations around the neutral reference."        />      </figure>    )  }  // Factual screen-reader accessibility summary  const aboveCount = preparedData.filter((d) => d.__position === "above").length  const belowCount = preparedData.filter((d) => d.__position === "below").length  const equalCount = preparedData.filter((d) => d.__position === "equal").length  const missingCount = preparedData.filter((d) => d.__position === "unavailable").length  const a11ySummary = `${title}. Signed categorical comparison of ${series.label} relative to neutral reference ${safeBaseline}${    baselineLabel ? ` (${baselineLabel})` : ""  } across ${preparedData.length} categories. ${aboveCount} above reference, ${belowCount} below reference, ${equalCount} on reference${    missingCount > 0 ? `, and ${missingCount} unavailable` : ""  }.`  const isHorizontal = layout === "horizontal"  return (    <figure      ref={rootRef}      role="region"      aria-label={title}      tabIndex={0}      onKeyDown={handleKeyDown}      className={cn(        "group relative flex flex-col w-full focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--chart-focus,#2563eb)] focus-visible:ring-offset-2 rounded-xl",        className      )}      style={{ height, minHeight: typeof height === "number" ? height : 340 }}    >      {/* Screen Reader Offscreen Analytical Summary & Data Table */}      <div className="sr-only">        <h2>{title}</h2>        <p>{description || a11ySummary}</p>        <table>          <caption>{title} — Structured Observations</caption>          <thead>            <tr>              <th scope="col">Category</th>              <th scope="col">Raw Value</th>              <th scope="col">Reference Baseline</th>              <th scope="col">Deviation</th>              <th scope="col">Position</th>            </tr>          </thead>          <tbody>            {preparedData.map((d) => (              <tr key={String(d.__category)}>                <th scope="row">{String(d.__category)}</th>                <td>{formatValue(d.__rawValue)}</td>                <td>{safeBaseline}</td>                <td>{formatDeviation(d.__deviation)}</td>                <td>                  {d.__position === "above"                    ? "Above reference"                    : d.__position === "below"                    ? "Below reference"                    : d.__position === "equal"                    ? "On reference"                    : "Unavailable"}                </td>              </tr>            ))}          </tbody>        </table>      </div>      {/* Structural Directional Legend (Neutral) */}      {showLegend && (        <div          aria-hidden="true"          className="flex flex-wrap items-center justify-end gap-5 px-3 py-1.5 text-xs text-muted-foreground font-medium"        >          <div className="flex items-center gap-1.5">            <span              className="size-2.5 rounded-sm shrink-0"              style={{ backgroundColor: aboveColor }}            />            <span>Above reference</span>          </div>          <div className="flex items-center gap-1.5">            <span              className="size-2.5 rounded-sm shrink-0"              style={{ backgroundColor: belowColor }}            />            <span>Below reference</span>          </div>          {baselineLabel && (            <div className="flex items-center gap-1.5">              <span                className="w-3 h-0.5 bg-[var(--chart-axis,#71717a)] shrink-0"              />              <span>                {baselineLabel} · {safeBaseline}              </span>            </div>          )}        </div>      )}      {/* Core Chart Canvas */}      <div className="flex-1 w-full h-full min-w-0 min-h-0">        <ChartContainer className="w-full h-full">          <ResponsiveContainer            width="100%"            height="100%"            minWidth={0}            minHeight={0}            initialDimension={{ width: 320, height: typeof height === "number" ? height : 340 }}          >            <BarChart              data={preparedData}              layout={isHorizontal ? "vertical" : "horizontal"}              margin={{                top: 16,                right: 24,                left: isHorizontal ? 20 : -10,                bottom: 12,              }}              onMouseMove={(state) => {                if (state?.activeTooltipIndex !== undefined && state.activeTooltipIndex !== null) {                  const idx = Number(state.activeTooltipIndex)                  if (!Number.isNaN(idx)) {                    setActiveIndex(idx)                  }                }              }}              onMouseLeave={() => setActiveIndex(null)}            >              {showGrid && (                <CartesianGrid                  strokeDasharray="3 3"                  horizontal={isHorizontal ? false : true}                  vertical={isHorizontal ? true : false}                  stroke="var(--chart-grid, rgba(255,255,255,0.06))"                />              )}              {/* Categorical & Quantitative Axes */}              {isHorizontal ? (                <>                  <XAxis                    type="number"                    domain={resolvedDomain}                    stroke="var(--chart-axis, #71717a)"                    fontSize={11}                    tickLine={false}                    axisLine={false}                    tickFormatter={(v: number) => (v === 0 ? "0" : v > 0 ? `+${v}` : `−${Math.abs(v)}`)}                  />                  <YAxis                    type="category"                    dataKey="__category"                    stroke="var(--chart-axis, #71717a)"                    fontSize={11}                    tickLine={false}                    axisLine={false}                    width={75}                  />                  {/* Structural Reference Line at zero deviation */}                  <ReferenceLine                    x={0}                    stroke={baselineColor}                    strokeWidth={1.5}                    label={                      baselineLabel                        ? {                            value: `${baselineLabel} (${safeBaseline})`,                            position: "top",                            fill: "var(--chart-axis-emphasis, #d4d4d8)",                            fontSize: 10,                            offset: 8,                          }                        : undefined                    }                  />                </>              ) : (                <>                  <XAxis                    dataKey="__category"                    stroke="var(--chart-axis, #71717a)"                    fontSize={11}                    tickLine={false}                    axisLine={false}                  />                  <YAxis                    type="number"                    domain={resolvedDomain}                    stroke="var(--chart-axis, #71717a)"                    fontSize={11}                    tickLine={false}                    axisLine={false}                    tickFormatter={(v: number) => (v === 0 ? "0" : v > 0 ? `+${v}` : `−${Math.abs(v)}`)}                  />                  {/* Structural Reference Line at zero deviation */}                  <ReferenceLine                    y={0}                    stroke={baselineColor}                    strokeWidth={1.5}                    label={                      baselineLabel                        ? {                            value: `${baselineLabel} (${safeBaseline})`,                            position: "right",                            fill: "var(--chart-axis-emphasis, #d4d4d8)",                            fontSize: 10,                            offset: 8,                          }                        : undefined                    }                  />                </>              )}              {/* Synchronized Analytical Tooltip */}              <Tooltip                isAnimationActive={false}                allowEscapeViewBox={{ x: false, y: false }}                cursor={{                  fill: "var(--chart-grid, rgba(255, 255, 255, 0.04))",                }}                content={({ active, payload }) => {                  if (!active || !payload || !payload.length) return null                  const row = payload[0]?.payload as PreparedDivergingDatum<TData> | undefined                  if (!row) return null                  const isMissing = row.__position === "unavailable"                  const isZero = row.__position === "equal"                  const isAbove = row.__position === "above"                  const markerColor = isMissing                    ? "var(--muted, #71717a)"                    : isZero                    ? "var(--chart-axis-emphasis, #d4d4d8)"                    : isAbove                    ? aboveColor                    : belowColor                  return (                    <div                      role="tooltip"                      className="plotcn-chart-tooltip rounded-xl border border-white/[0.12] bg-zinc-950/95 p-3.5 shadow-2xl backdrop-blur-md min-w-[min(200px,calc(100cqw-16px))] max-w-[min(300px,calc(100cqw-16px))] max-h-[calc(100cqh-16px)] overflow-y-auto text-xs font-sans not-prose space-y-2.5"                    >                      {/* Header */}                      <div className="flex items-center justify-between border-b border-white/[0.08] pb-1.5 gap-2">                        <span className="font-semibold text-zinc-100 text-sm tracking-tight truncate">                          {String(row.__category)}                        </span>                        <span                          className={cn(                            "px-1.5 py-0.5 rounded text-[10px] font-mono font-semibold tracking-wider uppercase",                            isMissing                              ? "bg-zinc-800/80 text-zinc-400 border border-zinc-700/50"                              : isZero                              ? "bg-zinc-800/80 text-zinc-300 border border-zinc-700/50"                              : isAbove                              ? "bg-blue-500/10 text-blue-400 border border-blue-500/20"                              : "bg-amber-500/10 text-amber-400 border border-amber-500/20"                          )}                        >                          {isMissing                            ? "Unavailable"                            : isZero                            ? "On Reference"                            : isAbove                            ? "Above Reference"                            : "Below Reference"}                        </span>                      </div>                      {/* Values & Deviation Summary */}                      <div className="space-y-1.5 font-mono text-xs">                        <div className="flex items-center justify-between gap-4">                          <span className="text-zinc-400">Value</span>                          <span className="font-semibold text-zinc-100 tabular-nums">                            {formatValue(row.__rawValue)}                          </span>                        </div>                        <div className="flex items-center justify-between gap-4">                          <span className="text-zinc-400">                            {baselineLabel ? baselineLabel : "Reference"}                          </span>                          <span className="text-zinc-300 tabular-nums">                            {series.valueFormatter ? series.valueFormatter(safeBaseline) : safeBaseline}                          </span>                        </div>                        <div className="flex items-center justify-between gap-4 pt-1 border-t border-white/[0.06]">                          <div className="flex items-center gap-1.5">                            <span                              className="size-2 rounded-full shrink-0"                              style={{ backgroundColor: markerColor }}                            />                            <span className="text-zinc-300">Deviation</span>                          </div>                          <span                            className={cn(                              "font-bold tabular-nums",                              isZero                                ? "text-zinc-300"                                : isAbove                                ? "text-blue-400"                                : "text-amber-400"                            )}                          >                            {formatDeviation(row.__deviation)}                          </span>                        </div>                      </div>                    </div>                  )                }}              />              {/* The Diverging Bar with Custom Direction-Aware Geometry */}              <Bar                dataKey="__deviation"                maxBarSize={maxBarSize}                isAnimationActive={isAnimated}                animationDuration={animDuration}                shape={(props: unknown) => (                  <DivergingBarShape                    {...(props as DivergingBarShapeProps)}                    layout={layout}                    aboveColor={aboveColor}                    belowColor={belowColor}                    selectionColor={selectionColor}                    isActive={activeIndex === (props as DivergingBarShapeProps)?.payload?.__index}                  />                )}              >                {/* Optional Outward Value Labels */}                {valueLabel !== "none" && (                  <LabelList                    dataKey="__deviation"                    position={isHorizontal ? "right" : "top"}                    formatter={(val: unknown) => {                      if (typeof val !== "number") return ""                      if (valueLabel === "value") {                        // Locate matching raw value                        const matching = preparedData.find((d) => d.__deviation === val)                        return matching ? formatValue(matching.__rawValue) : ""                      }                      return formatDeviation(val)                    }}                    style={{                      fill: "var(--chart-foreground, #fafafa)",                      fontSize: 10,                      fontFamily: "monospace",                      fontWeight: 600,                    }}                  />                )}              </Bar>            </BarChart>          </ResponsiveContainer>        </ChartContainer>      </div>    </figure>  )}