Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dev/fixtures/chart-legends.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ createRoot(document.getElementById('root')!).render(
<ChartLegend aria-label="Regional services legend">
{serviceSeries.map(series => (
<ChartLegend.Item key={series.key}>
<ChartLegend.Marker kind="line" color={series.color} />
<ChartLegend.Marker color={series.color} />
<ChartLegend.Label>{series.label}</ChartLegend.Label>
</ChartLegend.Item>
))}
Expand Down
207 changes: 207 additions & 0 deletions dev/fixtures/gallery-basics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import {
BarChart,
AreaChart,
PieChart,
FunnelChart,
RetentionChart,
JourneyChart,
ScatterChart,
ComposedChart,
} from '@altertable/data-app/react/ui';
Expand Down Expand Up @@ -250,6 +253,210 @@ export function GalleryBasics() {
ariaLabel="Workspace performance"
/>
</Example>

<Example
name="FunnelChart"
description="Activation by plan. Filled columns show conversion; hatching shows drop-off from the previous step."
>
<FunnelChart
ariaLabel="Activation funnel"
unit="users"
steps={[
{ id: 'visit', label: 'Visited' },
{ id: 'signup', label: 'Signed up' },
{ id: 'activate', label: 'Activated' },
]}
series={[
{ id: 'free', label: 'Free plan', values: [1000, 600, 240] },
{ id: 'paid', label: 'Paid plan', values: [500, 400, 300] },
]}
/>
</Example>
<Example
name="RetentionChart"
description="Users returning each week after signup. Illustrative cohorts as of Oct 9; dotted tails mark the current partial week."
>
<RetentionChart
ariaLabel="Weekly signup retention"
unit="users"
series={[
{
id: 'sep7',
label: 'Sep 7 signups',
cohortSize: 1000,
points: [
{
offset: 0,
label: 'Week 0',
rate: 1,
retainedCount: 1000,
},
{
offset: 1,
label: 'Week 1',
rate: 0.47,
retainedCount: 470,
},
{
offset: 2,
label: 'Week 2',
rate: 0.39,
retainedCount: 390,
},
{
offset: 3,
label: 'Week 3',
rate: 0.34,
retainedCount: 340,
},
{
offset: 4,
label: 'Week 4',
rate: 0.31,
retainedCount: 310,
incomplete: true,
},
],
},
{
id: 'sep14',
label: 'Sep 14 signups',
cohortSize: 800,
points: [
{
offset: 0,
label: 'Week 0',
rate: 1,
retainedCount: 800,
},
{
offset: 1,
label: 'Week 1',
rate: 0.5,
retainedCount: 400,
},
{
offset: 2,
label: 'Week 2',
rate: 0.43,
retainedCount: 344,
},
{
offset: 3,
label: 'Week 3',
rate: 0.38,
retainedCount: 304,
incomplete: true,
},
{
offset: 4,
label: 'Week 4',
rate: null,
retainedCount: null,
},
],
},
]}
/>
</Example>
<Example
name="JourneyChart"
span={2}
description="Explore onboarding paths one branch at a time. Counts and flows use the Step 1 population."
>
<JourneyChart
ariaLabel="Onboarding journey"
unit="users"
paths={[
{
id: 'a',
steps: [
{ event: 'Signed up', property: null },
{ event: 'Workspace created', property: null },
{ event: 'Report created', property: null },
{ event: 'Subscribed', property: null },
],
count: 460,
converted: true,
truncated: false,
},
{
id: 'b',
steps: [
{ event: 'Signed up', property: null },
{ event: 'Workspace created', property: null },
{ event: 'Integration connected', property: null },
{ event: 'Subscribed', property: null },
],
count: 240,
converted: true,
truncated: false,
},
{
id: 'c',
steps: [
{ event: 'Signed up', property: null },
{ event: 'Workspace created', property: null },
],
count: 180,
converted: false,
truncated: false,
},
{
id: 'd',
steps: [
{ event: 'Signed up', property: null },
{ event: 'Documentation viewed', property: null },
{ event: 'Workspace created', property: null },
],
count: 80,
converted: null,
truncated: true,
},
{
id: 'e',
steps: [
{ event: 'Signed up', property: null },
{ event: 'Documentation viewed', property: null },
],
count: 40,
converted: false,
truncated: false,
},
{
id: 'f',
steps: [
{ event: 'Signed up', property: null },
{ event: 'Search', property: null },
{ event: 'Signed up', property: null },
],
count: 30,
converted: null,
truncated: false,
},
{
id: 'g',
steps: [
{ event: 'Signed up', property: null },
{ event: 'Settings', property: null },
],
count: 20,
converted: null,
truncated: true,
},
{
id: 'h',
steps: [
{ event: 'Signed up', property: null },
{ event: 'Invite sent', property: null },
],
count: 10,
converted: null,
truncated: true,
},
]}
/>
</Example>
</Grid>
</Stack>
</section>
Expand Down
Binary file added dev/screenshots/funnel-retention-charts.png

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To remove all images

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added dev/screenshots/journey-chart.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 17 additions & 2 deletions docs/ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,20 @@ the samples. Pie slices represent mutually exclusive parts of one total; shares
use the sum of supplied items, so include Other when showing a subset of the
whole. Scatter points represent independent X/Y observations.

### Product analytics charts

Use `<FunnelChart>`, `<RetentionChart>`, and `<JourneyChart>` from `/react/ui`
inside `<VisualizationWidget>`. Derive inputs from the displayed rows; the
binding owns loading, evidence, CSV, and story content. Types and JSDoc describe
input constraints; the gallery includes complete examples.

- `<FunnelChart>` compares ordered step counts across populations. Each series
uses its first step as the baseline; hatching shows previous-step drop-off.
- `<RetentionChart>` plots query-defined rates and retained counts by interval
offset. Use `null` for unobserved periods; `incomplete` produces a dotted tail.
- `<JourneyChart>` derives expandable branches and outcomes from full paths.
Truncated paths stop at the last loaded event.

### Composed charts

Use `<ComposedChart>` from `/react/ui` for multiple series or mixed marks inside
Expand Down Expand Up @@ -134,10 +148,11 @@ its columns aligned with the displayed measures.

### Legends

Include `<ComposedChart.Legend />` to derive labels and markers from the series;
Include `<ComposedChart.Legend />` to derive labels and colored square markers from the series;
omit it when no legend is needed. For any chart, compose `<ChartLegend>` with
`<ChartLegend.Item>`, `<ChartLegend.Marker>`, and `<ChartLegend.Label>` using the
same names and colors as the plot.
same names and colors as the plot. `<ChartLegend.Marker>` defaults to a square,
shared with chart tooltips and funnel summaries.
`<PieChart>` includes a legend by default; `showLegend={false}` omits it.

Legends align cells in a container-responsive grid, truncate labels, and reserve
Expand Down
27 changes: 15 additions & 12 deletions docs/widgets.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,21 @@ Choose the component by the reader's question. Compose dataset visuals inside
charts come from `/react/ui`; `<Ranking>`, `<Breakdown>`, and `<Comparison>`
are also available from `/react`.

| Question or need | Component | Guidance |
| --------------------------------------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------ |
| How do categories compare? | `<BarChart>` | Compare nonnegative category values; order by value for rank or by a meaningful category order. |
| Which items lead? | `<Ranking>` | Use a compact ordered list with values and optional detail. Tracks scale to the largest visible item, not a total. |
| How does a measure change over time? | `<LineChart>` | Use ordered, equally spaced samples to emphasize the trend. |
| How large is the measure over time? | `<AreaChart>` | Use the same samples as a line chart when filled magnitude relative to zero helps answer the question. |
| What makes up the whole? | `<PieChart>` | Use a few mutually exclusive parts of one total; include the remainder as Other. |
| What share of an observed total does each part represent? | `<Breakdown>` | Use a compact display of values and shares with an explicit total, including when only some parts are shown. |
| How do several measures relate on one plot? | `<ComposedChart>` | Compose bars, lines, areas, or scatter series; label units clearly and use separate axes for different units. |
| How are two numeric measures related? | `<ScatterChart>` | Use independent X/Y observations to explore relationships, clusters, and outliers. |
| How did one metric change between periods? | `<Comparison>` | Use the metric reading and its displayed comparison period. |
| What are the exact values or row details? | `<TableWidget>` | Use a bound table for lookup, search, and precise comparisons. |
| Question or need | Component | Guidance |
| --------------------------------------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------ |
| How do categories compare? | `<BarChart>` | Compare nonnegative category values; order by value for rank or by a meaningful category order. |
| Which items lead? | `<Ranking>` | Use a compact ordered list with values and optional detail. Tracks scale to the largest visible item, not a total. |
| How does a measure change over time? | `<LineChart>` | Use ordered, equally spaced samples to emphasize the trend. |
| How large is the measure over time? | `<AreaChart>` | Use the same samples as a line chart when filled magnitude relative to zero helps answer the question. |
| What makes up the whole? | `<PieChart>` | Use a few mutually exclusive parts of one total; include the remainder as Other. |
| What share of an observed total does each part represent? | `<Breakdown>` | Use a compact display of values and shares with an explicit total, including when only some parts are shown. |
| How do several measures relate on one plot? | `<ComposedChart>` | Compose bars, lines, areas, or scatter series; label units clearly and use separate axes for different units. |
| How are two numeric measures related? | `<ScatterChart>` | Use independent X/Y observations to explore relationships, clusters, and outliers. |
| Where do users drop out of a sequence? | `<FunnelChart>` | Use ordered counts from the same population reaching each successive step. |
| Do cohorts return over time? | `<RetentionChart>` | Use query-defined rates and retained counts by numeric offset; mark incomplete periods. |
| Which paths do users take? | `<JourneyChart>` | Use full paths with population counts and outcomes; explore branches step by step. |
| How did one metric change between periods? | `<Comparison>` | Use the metric reading and its displayed comparison period. |
| What are the exact values or row details? | `<TableWidget>` | Use a bound table for lookup, search, and precise comparisons. |

Prefer bars or a ranking when readers need to compare similarly sized categories;
use a pie for a simple composition question. Prefer a line when the trend is
Expand Down
3 changes: 3 additions & 0 deletions src/react/style-contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ export const dataAppStyleClasses = {
component: 'ChartLegend.Label',
kind: 'root',
},
'altertable-funnel-chart': { component: 'FunnelChart', kind: 'root' },
'altertable-retention-chart': { component: 'RetentionChart', kind: 'root' },
'altertable-journey-chart': { component: 'JourneyChart', kind: 'root' },
'altertable-composed-chart': {
component: 'ComposedChart',
kind: 'root',
Expand Down
1 change: 1 addition & 0 deletions src/react/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
@import './ui/PieChart.css' layer(atbl.components);
@import './ui/ScatterChart.css' layer(atbl.components);
@import './ui/ComposedChart.css' layer(atbl.components);
@import './ui/AnalyticsCharts.css' layer(atbl.components);
@import './annotations/colors.css' layer(atbl.components);
@import './annotations/AnnotationBar.css' layer(atbl.components);
@import './annotations/AnnotationControls.css' layer(atbl.components);
Expand Down
Loading