Charts · Distributions & comparisons
EcdfChart
| minutes | desktop | phone |
|---|---|---|
| 1 | 1.1% | 2.6% |
| 1.5 | 4.5% | 6.6% |
| 2 | 11.4% | 11.8% |
| 2.5 | 13.6% | 15.8% |
| 3 | 17% | 25% |
| 3.5 | 22.7% | 30.3% |
| 4 | 30.7% | 38.2% |
| 4.5 | 35.2% | 45.4% |
| 5 | 40.9% | 52% |
| 5.5 | 43.2% | 55.9% |
| 6 | 48.9% | 61.2% |
| 6.5 | 54.5% | 65.1% |
| 7 | 54.5% | 67.1% |
| 7.5 | 58% | 69.1% |
| 8 | 62.5% | 71.7% |
| 8.5 | 64.8% | 75% |
| 9 | 67% | 78.3% |
| 9.5 | 70.5% | 80.9% |
| 10 | 70.5% | 84.2% |
| 10.5 | 72.7% | 86.8% |
| 11 | 73.9% | 89.5% |
| 11.5 | 73.9% | 93.4% |
| 12 | 78.4% | 94.1% |
| 12.5 | 79.5% | 94.7% |
| 13 | 80.7% | 95.4% |
| 13.5 | 83% | 95.4% |
| 14 | 85.2% | 96.1% |
| 14.5 | 86.4% | 96.7% |
| 15 | 87.5% | 97.4% |
| 15.5 | 88.6% | 98% |
| 16.5 | 90.9% | 98% |
| 17 | 90.9% | 99.3% |
| 18 | 92% | 99.3% |
| 18.5 | 93.2% | 99.3% |
| 19.5 | 94.3% | 99.3% |
| 20 | 95.5% | 99.3% |
| 21.5 | 96.6% | 100% |
| 23.5 | 97.7% | 100% |
| 27 | 98.9% | 100% |
| 27.5 | 100% | 100% |
| minutes | desktop | phone |
|---|---|---|
| 1 | 1.1% | 2.6% |
| 1.5 | 4.5% | 6.6% |
| 2 | 11.4% | 11.8% |
| 2.5 | 13.6% | 15.8% |
| 3 | 17% | 25% |
| 3.5 | 22.7% | 30.3% |
| 4 | 30.7% | 38.2% |
| 4.5 | 35.2% | 45.4% |
| 5 | 40.9% | 52% |
| 5.5 | 43.2% | 55.9% |
| 6 | 48.9% | 61.2% |
| 6.5 | 54.5% | 65.1% |
| 7 | 54.5% | 67.1% |
| 7.5 | 58% | 69.1% |
| 8 | 62.5% | 71.7% |
| 8.5 | 64.8% | 75% |
| 9 | 67% | 78.3% |
| 9.5 | 70.5% | 80.9% |
| 10 | 70.5% | 84.2% |
| 10.5 | 72.7% | 86.8% |
| 11 | 73.9% | 89.5% |
| 11.5 | 73.9% | 93.4% |
| 12 | 78.4% | 94.1% |
| 12.5 | 79.5% | 94.7% |
| 13 | 80.7% | 95.4% |
| 13.5 | 83% | 95.4% |
| 14 | 85.2% | 96.1% |
| 14.5 | 86.4% | 96.7% |
| 15 | 87.5% | 97.4% |
| 15.5 | 88.6% | 98% |
| 16.5 | 90.9% | 98% |
| 17 | 90.9% | 99.3% |
| 18 | 92% | 99.3% |
| 18.5 | 93.2% | 99.3% |
| 19.5 | 94.3% | 99.3% |
| 20 | 95.5% | 99.3% |
| 21.5 | 96.6% | 100% |
| 23.5 | 97.7% | 100% |
| 27 | 98.9% | 100% |
| 27.5 | 100% | 100% |
| minutes | desktop | phone |
|---|---|---|
| 1 | 1.1% | 2.6% |
| 1.5 | 4.5% | 6.6% |
| 2 | 11.4% | 11.8% |
| 2.5 | 13.6% | 15.8% |
| 3 | 17% | 25% |
| 3.5 | 22.7% | 30.3% |
| 4 | 30.7% | 38.2% |
| 4.5 | 35.2% | 45.4% |
| 5 | 40.9% | 52% |
| 5.5 | 43.2% | 55.9% |
| 6 | 48.9% | 61.2% |
| 6.5 | 54.5% | 65.1% |
| 7 | 54.5% | 67.1% |
| 7.5 | 58% | 69.1% |
| 8 | 62.5% | 71.7% |
| 8.5 | 64.8% | 75% |
| 9 | 67% | 78.3% |
| 9.5 | 70.5% | 80.9% |
| 10 | 70.5% | 84.2% |
| 10.5 | 72.7% | 86.8% |
| 11 | 73.9% | 89.5% |
| 11.5 | 73.9% | 93.4% |
| 12 | 78.4% | 94.1% |
| 12.5 | 79.5% | 94.7% |
| 13 | 80.7% | 95.4% |
| 13.5 | 83% | 95.4% |
| 14 | 85.2% | 96.1% |
| 14.5 | 86.4% | 96.7% |
| 15 | 87.5% | 97.4% |
| 15.5 | 88.6% | 98% |
| 16.5 | 90.9% | 98% |
| 17 | 90.9% | 99.3% |
| 18 | 92% | 99.3% |
| 18.5 | 93.2% | 99.3% |
| 19.5 | 94.3% | 99.3% |
| 20 | 95.5% | 99.3% |
| 21.5 | 96.6% | 100% |
| 23.5 | 97.7% | 100% |
| 27 | 98.9% | 100% |
| 27.5 | 100% | 100% |
| minutes | desktop | phone |
|---|---|---|
| 1 | 1.1% | 2.6% |
| 1.5 | 4.5% | 6.6% |
| 2 | 11.4% | 11.8% |
| 2.5 | 13.6% | 15.8% |
| 3 | 17% | 25% |
| 3.5 | 22.7% | 30.3% |
| 4 | 30.7% | 38.2% |
| 4.5 | 35.2% | 45.4% |
| 5 | 40.9% | 52% |
| 5.5 | 43.2% | 55.9% |
| 6 | 48.9% | 61.2% |
| 6.5 | 54.5% | 65.1% |
| 7 | 54.5% | 67.1% |
| 7.5 | 58% | 69.1% |
| 8 | 62.5% | 71.7% |
| 8.5 | 64.8% | 75% |
| 9 | 67% | 78.3% |
| 9.5 | 70.5% | 80.9% |
| 10 | 70.5% | 84.2% |
| 10.5 | 72.7% | 86.8% |
| 11 | 73.9% | 89.5% |
| 11.5 | 73.9% | 93.4% |
| 12 | 78.4% | 94.1% |
| 12.5 | 79.5% | 94.7% |
| 13 | 80.7% | 95.4% |
| 13.5 | 83% | 95.4% |
| 14 | 85.2% | 96.1% |
| 14.5 | 86.4% | 96.7% |
| 15 | 87.5% | 97.4% |
| 15.5 | 88.6% | 98% |
| 16.5 | 90.9% | 98% |
| 17 | 90.9% | 99.3% |
| 18 | 92% | 99.3% |
| 18.5 | 93.2% | 99.3% |
| 19.5 | 94.3% | 99.3% |
| 20 | 95.5% | 99.3% |
| 21.5 | 96.6% | 100% |
| 23.5 | 97.7% | 100% |
| 27 | 98.9% | 100% |
| 27.5 | 100% | 100% |
Example
The chart above, in each framework. Pick a framework once and every example on the site follows it.
npm install @silverpoint/react @silverpoint/grounds @silverpoint/fontsimport '@silverpoint/fonts/fonts.css';
import '@silverpoint/grounds/styles.css';
import { EcdfChart } from '@silverpoint/react/ecdf-chart';
const data = [
{ reader: 'R001', device: 'desktop', minutes: 4 },
{ reader: 'R002', device: 'phone', minutes: 17 },
{ reader: 'R003', device: 'phone', minutes: 3 },
{ reader: 'R004', device: 'phone', minutes: 6.5 },
{ reader: 'R005', device: 'phone', minutes: 3.5 },
{ reader: 'R006', device: 'phone', minutes: 3 },
{ reader: 'R007', device: 'phone', minutes: 4.5 },
{ reader: 'R008', device: 'desktop', minutes: 23.5 },
{ reader: 'R009', device: 'phone', minutes: 1 },
{ reader: 'R010', device: 'desktop', minutes: 1 },
{ reader: 'R011', device: 'phone', minutes: 6.5 },
{ reader: 'R012', device: 'desktop', minutes: 4.5 },
// … 228 more rows of the same shape
];
export default function App() {
return (
<div style={{ width: 480 }}>
<EcdfChart
data={data}
valueKey="minutes"
groupKey="device"
title="Reading time by device"
unit="min"
/>
</div>
);
}npm install @silverpoint/vue @silverpoint/grounds @silverpoint/fonts<script setup lang="ts">
import '@silverpoint/fonts/fonts.css';
import '@silverpoint/grounds/styles.css';
import { SpEcdfChart } from '@silverpoint/vue/ecdf-chart';
const data = [
{ reader: 'R001', device: 'desktop', minutes: 4 },
{ reader: 'R002', device: 'phone', minutes: 17 },
{ reader: 'R003', device: 'phone', minutes: 3 },
{ reader: 'R004', device: 'phone', minutes: 6.5 },
{ reader: 'R005', device: 'phone', minutes: 3.5 },
{ reader: 'R006', device: 'phone', minutes: 3 },
{ reader: 'R007', device: 'phone', minutes: 4.5 },
{ reader: 'R008', device: 'desktop', minutes: 23.5 },
{ reader: 'R009', device: 'phone', minutes: 1 },
{ reader: 'R010', device: 'desktop', minutes: 1 },
{ reader: 'R011', device: 'phone', minutes: 6.5 },
{ reader: 'R012', device: 'desktop', minutes: 4.5 },
// … 228 more rows of the same shape
];
</script>
<template>
<div style="width: 480px">
<SpEcdfChart
:data="data"
value-key="minutes"
group-key="device"
title="Reading time by device"
unit="min"
/>
</div>
</template>npm install @silverpoint/angular @silverpoint/grounds @silverpoint/fonts// src/styles.css:
// @import '@silverpoint/fonts/fonts.css';
// @import '@silverpoint/grounds/styles.css';
import { Component } from '@angular/core';
import { SpEcdfChart } from '@silverpoint/angular/ecdf-chart';
@Component({
selector: 'app-root',
imports: [SpEcdfChart],
template: `
<div style="width: 480px">
<sp-ecdf-chart
[data]="data"
valueKey="minutes"
groupKey="device"
title="Reading time by device"
unit="min"
/>
</div>
`,
})
export class App {
protected readonly data = [
{ reader: 'R001', device: 'desktop', minutes: 4 },
{ reader: 'R002', device: 'phone', minutes: 17 },
{ reader: 'R003', device: 'phone', minutes: 3 },
{ reader: 'R004', device: 'phone', minutes: 6.5 },
{ reader: 'R005', device: 'phone', minutes: 3.5 },
{ reader: 'R006', device: 'phone', minutes: 3 },
{ reader: 'R007', device: 'phone', minutes: 4.5 },
{ reader: 'R008', device: 'desktop', minutes: 23.5 },
{ reader: 'R009', device: 'phone', minutes: 1 },
{ reader: 'R010', device: 'desktop', minutes: 1 },
{ reader: 'R011', device: 'phone', minutes: 6.5 },
{ reader: 'R012', device: 'desktop', minutes: 4.5 },
// … 228 more rows of the same shape
];
}pip install reflex-silverpoint-reactimport reflex as rx
from reflex_silverpoint_react import ecdf_chart
DATA = [
{"reader": "R001", "device": "desktop", "minutes": 4},
{"reader": "R002", "device": "phone", "minutes": 17},
{"reader": "R003", "device": "phone", "minutes": 3},
{"reader": "R004", "device": "phone", "minutes": 6.5},
{"reader": "R005", "device": "phone", "minutes": 3.5},
{"reader": "R006", "device": "phone", "minutes": 3},
{"reader": "R007", "device": "phone", "minutes": 4.5},
{"reader": "R008", "device": "desktop", "minutes": 23.5},
{"reader": "R009", "device": "phone", "minutes": 1},
{"reader": "R010", "device": "desktop", "minutes": 1},
{"reader": "R011", "device": "phone", "minutes": 6.5},
{"reader": "R012", "device": "desktop", "minutes": 4.5},
# … 228 more rows of the same shape
]
def index() -> rx.Component:
return rx.box(
ecdf_chart(
data=DATA,
value_key="minutes",
group_key="device",
title="Reading time by device",
unit="min",
),
width="480px",
)
app = rx.App()
app.add_page(index)Import
Each chart has its own subpath, so a bundle only carries the charts it uses. Every adapter also exports every chart from its barrel.
| Framework | Import |
|---|---|
| React | import { EcdfChart } from '@silverpoint/react/ecdf-chart'; |
| Vue | import { SpEcdfChart } from '@silverpoint/vue/ecdf-chart'; |
| Angular | import { SpEcdfChart } from '@silverpoint/angular/ecdf-chart'; // <sp-ecdf-chart> |
| Reflex | from reflex_silverpoint_react import ecdf_chart |
Props
The props EcdfChart adds to the ones every chart takes. Accessor props (…Key, keys, names) name fields of your rows and are ignored without data.
| React / Angular | Vue | Reflex | Type | Description |
|---|---|---|---|---|
valueKey | value-key | value_key | Accessor<number | null | undefined> | — |
groupKey | group-key | group_key | Accessor<string | null | undefined> | Two groups at most are drawn. |
markers | markers | markers | readonly number[] | Quantiles, in 0-1, drawn as rules. |
Common props
Every chart also takes these. Framework conventions: camelCase in React and Angular, kebab-case in Vue templates, snake_case in Reflex. Read more about them.
Show the 22 common props
| React / Angular | Vue | Reflex | Type | Description |
|---|---|---|---|---|
data | data | data | readonly Datum[] | Rows to draw. If omitted, the demo dataset is rendered (REQ-093) and the accessor props (…_key, keys, names) are ignored. |
ground | ground | ground | GroundRef | Style ground: silverpoint or cyanotype, or a ground object. Defaults to the app provider's, or silverpoint. |
substrate | substrate | substrate | SubstrateName | Prepared substrate within the ground (REQ-046). |
mode | mode | mode | InkMode | ink by default; precision disables inking (REQ-021). |
seed | seed | seed | Seed | Seed. If omitted, it is derived from id stably (REQ-003). |
id | id | id | string | Stable identifier. If omitted, it is generated deterministically. |
height | height | height | number | Height of the drawing area in px. Width is the container's unless pinned. |
width | width | width | number | — |
chrome | chrome | chrome | 'card' | 'bare' | card draws the full frame; bare only the drawing area (REQ-095). |
hatchFill | hatch-fill | hatch_fill | 'tile' | 'per-shape' | How areas are filled (REQ-029). |
title | title | title | string | — |
badge | badge | badge | string | — |
value | value | value | string | number | — |
unit | unit | unit | string | — |
footerLeft | footer-left | footer_left | string | — |
footerRight | footer-right | footer_right | string | — |
label | label | label | string | Accessible name. If omitted, it is derived from title (REQ-120). |
description | description | description | string | Long description for screen readers (REQ-120). |
dataTable | data-table | data_table | 'visible' | 'hidden' | 'none' | Tabular alternative; hidden leaves it for assistive technology only (REQ-121). |
locale | locale | locale | string | — |
numberFormat | number-format | number_format | Intl.NumberFormatOptions | — |
className | class-name | class_name | string | — |
Events
Pointer and keyboard exploration are built in. The item under the pointer or focus is reported, and a click, Enter or Space selects it. The item is { seriesKey, index, datum, value, point: { x, y } }.
| Framework | Active item | Selection | Custom readout |
|---|---|---|---|
| React | onActiveChange | onSelect | tooltip={(item, readout) => …} |
| Vue | @active-change | @select | <template #tooltip> |
| Angular | (activeChange) | (select) | <ng-template spTooltip> |
| Reflex | on_active_change | on_select | tooltip=tooltip_template(…) |