layerchart-upset

UpSet gallery

Show setup script
<script lang="ts">
	import { UpSet, exportPNG, exportSVG } from '../../../lib/index.js';
	import { genres, makeData } from '../../demo-data.js';

	const data = makeData();

	// Counts that were computed elsewhere (e.g. a manifest): no per-item rows needed.
	const contrasts = ['treated vs control', 'KO vs WT', 'aged vs young'];
	const counted = [
		{ id: 'a', sets: ['treated vs control'], size: 42 },
		{ id: 'b', sets: ['KO vs WT'], size: 17 },
		{ id: 'c', sets: ['treated vs control', 'KO vs WT'], size: 9 },
		{ id: 'd', sets: ['aged vs young'], size: 4 },
		{ id: 'e', sets: ['KO vs WT', 'aged vs young', 'treated vs control'], size: 2 }
	];
	let pickedCounted = $state<string | null>('c');
	let exportBox = $state<HTMLElement>();
	let exportSvg = $state('');
	let exportPng = $state('');
	const exportNow = async () => {
		exportSvg = exportSVG(exportBox!);
		const blob = await exportPNG(exportBox!, { scale: 2 });
		exportPng = `${blob.type}:${blob.size}`;
	};
</script>

Precomputed intersections

Pass counts you already have instead of per-item rows. Order is kept as given; emphasise one row; reserve empty slots; no set-size panel.

Show code
<UpSet
	intersections={counted}
	sets={contrasts}
	emphasizedSets={['KO vs WT']}
	minSlots={8}
	yTicks={[0, 20, 40]}
	labelWidth={140}
	bind:selected={pickedCounted}
/>

Empty intersections and export

showEmpty lists combinations nobody has as size-0 columns. exportSVG and exportPNG take the wrapper element.

Show code
<UpSet data={data.slice(0, 25)} sets={genres.slice(0, 4)} showEmpty scaleToggle />

Query overlays

Each query draws an overlay in every column, as tall as the number of its rows that pass filter. Hover a column to see the counts.

Show code
<UpSet
	{data}
	sets={genres}
	minSize={15}
	queries={[
		{ id: 'first half', color: '#f6ad55', filter: (r) => (r.id as number) < 300 },
		{ id: 'every 10th', color: '#c53030', filter: (r) => (r.id as number) % 10 === 0 }
	]}
/>

Stacked bars

stack splits each bar by a row attribute. Linear scale only; stack.legend adds the swatches.

  • 2000s
  • 1990s
  • 2010s
Show code
<UpSet {data} sets={genres} minSize={15} stack={{ by: "era", legend: true }} />

Stacked bars and queries from counts

Precomputed intersections can carry segments (counts per category, for stack without by) and counts (per query id, for queries without a filter); no rows are needed.

  • SE
  • RI
  • (none)
Show code
<UpSet
	sets={['A', 'B', 'C']}
	intersections={[
		{ sets: ['A'], size: 40, segments: { SE: 25, RI: 15 } },
		{ sets: ['A', 'B'], size: 30, segments: { SE: 10, RI: 12 } },
		{ sets: ['C'], size: 20, segments: { SE: 20 } }
	]}
	setSizes={{ A: 70, B: 30, C: 20 }}
	stack={{ legend: true, colors: { SE: '#4e79a7', RI: '#f28e2b' } }}
/>