1 estrella en GitHub = 1 componente nuevo.

Dar una estrella
Gráficos y Estadísticaschartsvgzero-dependencypyramiddemographicsbutterflycomparison

Population Pyramid

Barras horizontales enfrentadas que comparan dos grupos en franjas ordenadas como edades.

Vista Previa en Vivo

Audience by age

Share of users per age band

  • Women
  • Men
2.1%
65+
1.7%
4.8%
55–64
4.1%
8.2%
45–54
7.4%
12.6%
35–44
11.8%
15.4%
25–34
16.2%
7.9%
18–24
8.8%
View data
BandWomenMen
65+2.1%1.7%
55–644.8%4.1%
45–548.2%7.4%
35–4412.6%11.8%
25–3415.4%16.2%
18–247.9%8.8%

Uso

Copia y pega este código directamente en tu componente React:

tsx
import { PopulationPyramid } from 'react-component-kit-ui/charts';

<PopulationPyramid bands={['35–44', '25–34', '18–24']} left={[12.6, 15.4, 7.9]} right={[11.8, 16.2, 8.8]} leftLabel="Women" rightLabel="Men" />

Instalación Manual

Si no estás usando el paquete npm, crea un archivo nuevo y pega el siguiente código: src/components/PopulationPyramid.tsx + PopulationPyramid.css:

PopulationPyramid.tsx
'use client';

import type { CSSProperties } from 'react';
import ChartFrame from './ChartFrame';
import { formatValue, colorAt } from './chart-utils';
import './PopulationPyramid.css';

/** "a: b; --c: d" → style object */
function st(css: string | undefined): CSSProperties {
  const o: Record<string, string> = {};
  for (const decl of String(css ?? '').split(';')) {
    const i = decl.indexOf(':');
    if (i < 0) continue;
    const k = decl.slice(0, i).trim();
    if (k) o[k.startsWith('--') ? k : k.replace(/-([a-z])/g, (_, c) => c.toUpperCase())] = decl.slice(i + 1).trim();
  }
  return o as CSSProperties;
}

/**
 * PopulationPyramid — Back-to-back horizontal bars comparing two groups across
 * ordered bands (age groups, tiers, price brackets).
 *
 * @param {string[]} bands - Row labels, top to bottom.
 * @param {number[]} left - Values for the left group.
 * @param {number[]} right - Values for the right group.
 * @param {string} leftLabel - Left group name.
 * @param {string} rightLabel - Right group name.
 * @param {string} suffix - Value suffix.
 * @param {string} variant - Card style (glass|solid|ghost).
 * @param {string} size - Density (sm|md|lg).
 */
export interface PopulationPyramidProps {
  title?: string;
  subtitle?: string;
  bands?: string[];
  left?: number[];
  right?: number[];
  leftLabel?: string;
  rightLabel?: string;
  prefix?: string;
  suffix?: string;
  colors?: string[];
  variant?: 'glass' | 'solid' | 'ghost';
  size?: 'sm' | 'md' | 'lg';
  className?: string;
}

export function PopulationPyramid({
  title = 'Audience by age',
  subtitle = 'Share of users per age band',
  bands = ['65+', '55–64', '45–54', '35–44', '25–34', '18–24'],
  left = [2.1, 4.8, 8.2, 12.6, 15.4, 7.9],
  right = [1.7, 4.1, 7.4, 11.8, 16.2, 8.8],
  leftLabel = 'Women',
  rightLabel = 'Men',
  prefix = '',
  suffix = '%',
  colors,
  variant = 'glass',
  size = 'md',
  className = '',
}: PopulationPyramidProps) {
  const max = Math.max(...left, ...right) || 1;
  const cl = colorAt(0, colors);
  const cr = colorAt(1, colors);
  const fmt = (v: number) => formatValue(v, prefix, suffix);
  return (
    <>
      <ChartFrame title={title} subtitle={subtitle} variant={variant} size={size} className={className} legend={[{ label: leftLabel, color: cl }, { label: rightLabel, color: cr }]} table={{ headers: ['Band', leftLabel, rightLabel], rows: bands.map((b, i) => [b, fmt(left[i]), fmt(right[i])]) }}>
        <div className="pp" role="list" data-rk-b22a54="">
          {bands.map((b, i) => (
            <div key={i} className="pp__row" role="listitem" data-rk-b22a54="">
              <div className="pp__side pp__side--l" data-rk-b22a54="">
                <span className="pp__val" data-rk-b22a54="">{fmt(left[i])}</span>
                <span className="pp__bar cf-mark" tabIndex={0} style={st(`width:${(left[i] / max) * 100}%; background:${cl}`)} aria-label={`${b}, ${leftLabel}: ${fmt(left[i])}`} data-tip-title={`${b} · ${leftLabel}`} data-tip={`${cl}::${fmt(left[i])}`} data-rk-b22a54=""></span>
              </div>
              <span className="pp__band" data-rk-b22a54="">{b}</span>
              <div className="pp__side pp__side--r" data-rk-b22a54="">
                <span className="pp__bar cf-mark" tabIndex={0} style={st(`width:${(right[i] / max) * 100}%; background:${cr}`)} aria-label={`${b}, ${rightLabel}: ${fmt(right[i])}`} data-tip-title={`${b} · ${rightLabel}`} data-tip={`${cr}::${fmt(right[i])}`} data-rk-b22a54=""></span>
                <span className="pp__val" data-rk-b22a54="">{fmt(right[i])}</span>
              </div>
            </div>
          ))}
        </div>
      </ChartFrame>
    </>
  );
}

export default PopulationPyramid;
PopulationPyramid.css
/* PopulationPyramid — ported from astro-component-kit (charts/PopulationPyramid.astro) */

.pp:where([data-rk-b22a54]) { display: grid; gap: 4px; }
.pp__row:where([data-rk-b22a54]) {
  display: grid;
  grid-template-columns: 1fr 4rem 1fr;
  align-items: center;
  gap: 0.5rem;
}
.pp__side:where([data-rk-b22a54]) {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  height: 24px;
}
.pp__side--l:where([data-rk-b22a54]) { justify-content: flex-end; }
.pp__bar:where([data-rk-b22a54]) {
  height: 100%;
  min-width: 2px;
  max-width: calc(100% - 3rem);
  transition: opacity 0.2s ease;
}
.pp__side--l:where([data-rk-b22a54]) .pp__bar:where([data-rk-b22a54]) { border-radius: 4px 0 0 4px; }
.pp__side--r:where([data-rk-b22a54]) .pp__bar:where([data-rk-b22a54]) { border-radius: 0 4px 4px 0; }
.pp__bar:hover:where([data-rk-b22a54]) { opacity: 0.85; }
.pp__bar:focus-visible:where([data-rk-b22a54]) { outline: 2px solid var(--c-text-1, #fff); outline-offset: 1px; }
.pp__band:where([data-rk-b22a54]) {
  text-align: center;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--c-text-1, #fff);
}
.pp__val:where([data-rk-b22a54]) {
  font-size: 0.75rem;
  color: var(--c-text-2, #a3a3a3);
  font-variant-numeric: tabular-nums;
  min-width: 2.5rem;
}
.pp__side--l:where([data-rk-b22a54]) .pp__val:where([data-rk-b22a54]) { text-align: right; }

Información Rápida

Categoría
Gráficos y Estadísticas
Nombre de archivo
PopulationPyramid.tsx
Dependencias
Ninguna — React + CSS puro
Etiquetas
chartsvgzero-dependencypyramiddemographicsbutterflycomparison