Preview Updated 2026-05-10

Ridge plot

Vertically stacked density curves across multiple groups.

Basic usage

Data is passed via props and rendered as pure SVG, with no third-party charting dependency. Colors are drawn from the --viz-1..8 tokens and are colorblind-friendly.

背景
2024 Q12024 Q22024 Q32024 Q4
src/App.vue
<script setup lang="ts">
import { CfRidgePlot } from '@chufix-design/vue';
function bell(center: number, n = 30) {
  return Array.from({ length: n }, (_, i) => {
    const x = (i - center) / 4;
    return Math.exp(-x * x);
  });
}
const rows = [
  { label: '2024 Q1', density: bell(8) },
  { label: '2024 Q2', density: bell(12) },
  { label: '2024 Q3', density: bell(15) },
  { label: '2024 Q4', density: bell(20) },
];
</script>
<template>
  <CfRidgePlot :rows="rows" />
</template>
<script setup>
import { CfRidgePlot } from '@chufix-design/vue';
function bell(center, n = 30) {
  return Array.from({ length: n }, (_, i) => {
    const x = (i - center) / 4;
    return Math.exp(-x * x);
  });
}
const rows = [
  { label: '2024 Q1', density: bell(8) },
  { label: '2024 Q2', density: bell(12) },
  { label: '2024 Q3', density: bell(15) },
  { label: '2024 Q4', density: bell(20) },
];
</script>
<template>
  <CfRidgePlot :rows="rows" />
</template>
import { CfRidgePlot } from '@chufix-design/react';

export default function Demo() {
  function bell(center: number, n = 30) {
    return Array.from({ length: n }, (_, i) => {
      const x = (i - center) / 4;
      return Math.exp(-x * x);
    });
  }
  const rows = [
    { label: '2024 Q1', density: bell(8) },
    { label: '2024 Q2', density: bell(12) },
    { label: '2024 Q3', density: bell(15) },
    { label: '2024 Q4', density: bell(20) },
  ];
  return (
    <>
      <CfRidgePlot rows={rows} />
    </>
  );
}
import { CfRidgePlot } from '@chufix-design/react';

export default function Demo() {
  function bell(center, n = 30) {
    return Array.from({ length: n }, (_, i) => {
      const x = (i - center) / 4;
      return Math.exp(-x * x);
    });
  }
  const rows = [
    { label: '2024 Q1', density: bell(8) },
    { label: '2024 Q2', density: bell(12) },
    { label: '2024 Q3', density: bell(15) },
    { label: '2024 Q4', density: bell(20) },
  ];
  return (
    <>
      <CfRidgePlot rows={rows} />
    </>
  );
}

Multimodal distributions

Stacking multiple bells produces bimodal distributions, common when crossing seasons or user cohorts with secondary peaks.

背景
src/App.vue
<script setup lang="ts">
import { CfRidgePlot } from '@chufix-design/vue';
function bell(center: number, n = 30, height = 1) {
  return Array.from({ length: n }, (_, i) => {
    const x = (i - center) / 4;
    return Math.exp(-x * x) * height;
  });
}
function combine(...waves: number[][]) {
  const out = new Array(waves[0].length).fill(0);
  for (const w of waves) for (let i = 0; i < w.length; i++) out[i] += w[i];
  return out;
}
const rows = [
  { label: '春', density: combine(bell(8, 30, 1), bell(20, 30, 0.4)) },
  { label: '夏', density: combine(bell(15, 30, 1.2)) },
  { label: '秋', density: combine(bell(10, 30, 0.6), bell(22, 30, 1.0)) },
  { label: '冬', density: combine(bell(5, 30, 0.8), bell(25, 30, 0.6)) },
];
</script>
<template>
  <CfRidgePlot :rows="rows" :height="220" :overlap="0.5" />
</template>
<script setup>
import { CfRidgePlot } from '@chufix-design/vue';
function bell(center, n = 30, height = 1) {
  return Array.from({ length: n }, (_, i) => {
    const x = (i - center) / 4;
    return Math.exp(-x * x) * height;
  });
}
function combine(...waves: number[][]) {
  const out = new Array(waves[0].length).fill(0);
  for (const w of waves) for (let i = 0; i < w.length; i++) out[i] += w[i];
  return out;
}
const rows = [
  { label: '春', density: combine(bell(8, 30, 1), bell(20, 30, 0.4)) },
  { label: '夏', density: combine(bell(15, 30, 1.2)) },
  { label: '秋', density: combine(bell(10, 30, 0.6), bell(22, 30, 1.0)) },
  { label: '冬', density: combine(bell(5, 30, 0.8), bell(25, 30, 0.6)) },
];
</script>
<template>
  <CfRidgePlot :rows="rows" :height="220" :overlap="0.5" />
</template>
import { CfRidgePlot } from '@chufix-design/react';

export default function Demo() {
  const rows = [
    { label: '春', density: combine(bell(8, 30, 1), bell(20, 30, 0.4)) },
    { label: '夏', density: combine(bell(15, 30, 1.2)) },
    { label: '秋', density: combine(bell(10, 30, 0.6), bell(22, 30, 1.0)) },
    { label: '冬', density: combine(bell(5, 30, 0.8), bell(25, 30, 0.6)) },
  ];
  return (
    <>
      <CfRidgePlot rows={rows} overlap={0.5} />
    </>
  );
}
import { CfRidgePlot } from '@chufix-design/react';

export default function Demo() {
  const rows = [
    { label: '春', density: combine(bell(8, 30, 1), bell(20, 30, 0.4)) },
    { label: '夏', density: combine(bell(15, 30, 1.2)) },
    { label: '秋', density: combine(bell(10, 30, 0.6), bell(22, 30, 1.0)) },
    { label: '冬', density: combine(bell(5, 30, 0.8), bell(25, 30, 0.6)) },
  ];
  return (
    <>
      <CfRidgePlot rows={rows} overlap={0.5} />
    </>
  );
}

API

PropTypeDefaultDescription
rowsRidgeRow[]{ label, density: number[], colorIndex? }[]
overlap0..10.6Inter-row overlap ratio

反馈与讨论

Ridge plot · Discussion

0
0 / 600
一键发送
正在加载评论...