npm package: @omicsos/pathway-viewer
Description: Interactive SVG pathway viewer for KEGG and Reactome with expression, coverage, and enrichment overlays
Latest version: 0.1.4

# @omicsos/pathway-viewer

Interactive pathway visualization for React. Renders KEGG and Reactome metabolic/signaling pathways as SVG with expression overlays, enrichment coloring, genome coverage, dark mode, and SVG/PNG export.

## Installation

```bash
npm install @omicsos/pathway-viewer
```

Import the stylesheet in your app entry point:

```tsx
import '@omicsos/pathway-viewer/styles.css';
```

## Quick Start

```tsx
import { PathwayViewer } from '@omicsos/pathway-viewer';
import type { UnifiedPathway } from '@omicsos/pathway-viewer';

const pathway: UnifiedPathway = {
  id: 'hsa00010',
  name: 'Glycolysis / Gluconeogenesis',
  source: 'kegg',
  organism: { code: 'hsa', name: 'Homo sapiens' },
  bounds: { minX: 0, minY: 0, maxX: 800, maxY: 600 },
  entities: [
    {
      id: 'ent-hk1',
      type: 'gene',
      label: 'HK1',
      position: { x: 200, y: 150 },
      size: { width: 46, height: 17 },
      shape: 'rectangle',
      identifiers: { geneSymbol: ['HK1'], ecNumber: ['2.7.1.1'] },
    },
  ],
  reactions: [],
  compartments: [],
};

function App() {
  return (
    <div style={{ width: '100%', height: '600px' }}>
      <PathwayViewer pathway={pathway} />
    </div>
  );
}
```

## Props Reference

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `pathway` | `UnifiedPathway` | - | Pathway data object |
| `pathwayId` | `string` | - | Pathway ID for adapter-based fetching |
| `source` | `'kegg' \| 'reactome'` | - | Data source for adapter fetching |
| `overlayColors` | `Record<string, string>` | - | Entity ID to color mapping for overlays |
| `onSelect` | `(entityIds: string[]) => void` | - | Selection callback |
| `onHover` | `(entityId: string \| null) => void` | - | Hover callback |
| `onEntityDetails` | `(entity: PathwayEntity) => void` | - | Entity details callback |
| `onPathwayNavigate` | `(pathwayId: string) => void` | - | Pathway navigation callback |
| `showToolbar` | `boolean` | `true` | Show zoom/search toolbar |
| `showLegend` | `boolean` | `true` | Show entity type legend |
| `showCompartments` | `boolean` | `true` | Show compartment boundaries |
| `showExport` | `boolean` | `true` | Show export button |
| `initialZoom` | `number \| 'fit'` | `'fit'` | Initial zoom level |
| `theme` | `'light' \| 'dark'` | `'light'` | Color theme |
| `overlayLegendConfig` | `OverlayLegendConfig` | - | Color scale legend configuration |
| `adapterConfig` | `AdapterConfig` | - | Adapter configuration for fetching |
| `className` | `string` | - | Additional CSS class |

## Adapters

### KEGG

```tsx
<PathwayViewer
  pathwayId="hsa00010"
  source="kegg"
  adapterConfig={{ proxyUrl: '/api/kegg-proxy' }}
/>
```

Programmatic usage:

```ts
import { KeggAdapter } from '@omicsos/pathway-viewer';

const adapter = new KeggAdapter({ proxyUrl: '/api/kegg-proxy' });
const pathway = await adapter.getPathway('hsa00010');
```

> **CORS Note:** The KEGG REST API does not support browser CORS requests.
> You must provide a `proxyUrl` via `adapterConfig` for browser environments.
> The proxy should forward requests to `https://rest.kegg.jp/`.

### Reactome

```tsx
<PathwayViewer
  pathwayId="R-HSA-70171"
  source="reactome"
/>
```

Programmatic usage:

```ts
import { ReactomeAdapter } from '@omicsos/pathway-viewer';

const adapter = new ReactomeAdapter();
const pathway = await adapter.getPathway('R-HSA-70171');
```

## Expression Overlay

```tsx
import { PathwayViewer, useExpressionOverlay } from '@omicsos/pathway-viewer';

function ExpressionView({ pathway }) {
  const expressionData = { 'ent-hk1': 2.5, 'ent-pfkl': -1.3 };

  const { overlayColors, legendConfig } = useExpressionOverlay(
    pathway.entities,
    {
      data: expressionData,
      colorScheme: 'diverging',
      low: '#0000FF',
      mid: '#FFFFFF',
      high: '#FF0000',
    },
  );

  return (
    <PathwayViewer
      pathway={pathway}
      overlayColors={overlayColors}
      overlayLegendConfig={legendConfig}
    />
  );
}
```

## Enrichment Overlay

```tsx
import { PathwayViewer, useEnrichmentOverlay } from '@omicsos/pathway-viewer';

function EnrichmentView({ pathway }) {
  const entityPValues = { 'ent-hk1': 0.001, 'ent-pfkl': 0.05 };

  const overlayColors = useEnrichmentOverlay(
    pathway.entities,
    { entityPValues, threshold: 0.05 },
  );

  return (
    <PathwayViewer
      pathway={pathway}
      overlayColors={overlayColors}
    />
  );
}
```

## Genome Coverage

```tsx
import { PathwayViewer, useGenomeCoverage } from '@omicsos/pathway-viewer';

function CoverageView({ pathway }) {
  const genomes = [
    { id: 'genome1', label: 'Sample A', presentGeneIds: new Set(['ent-hk1']) },
    { id: 'genome2', label: 'Sample B', presentGeneIds: new Set(['ent-hk1', 'ent-pfkl']) },
  ];

  const { overlayColors, sliceDataMap } = useGenomeCoverage(
    pathway.entities,
    { genomes, mode: 'binary' },
  );

  return (
    <PathwayViewer
      pathway={pathway}
      overlayColors={overlayColors}
    />
  );
}
```

## Export

### Built-in Export Button

The export button is shown by default when the toolbar is visible. Users can click it to download SVG or PNG files.

```tsx
<PathwayViewer
  pathway={pathway}
  showExport={true}
  showToolbar={true}
/>
```

### Programmatic Export

```tsx
import { exportSvg, exportPng } from '@omicsos/pathway-viewer';

// SVG export
const svgElement = document.querySelector('svg');
exportSvg(svgElement, {
  filename: 'my-pathway.svg',
  backgroundColor: '#ffffff',
  legend: { visible: true, theme: 'light' },
});

// PNG export (async)
await exportPng(svgElement, {
  filename: 'my-pathway.png',
  scale: 2,
  backgroundColor: '#ffffff',
});
```

## Dark Mode

```tsx
<PathwayViewer
  pathway={pathway}
  theme="dark"
/>
```

### CSS Variable Customization

Override any theme variable for custom branding:

```css
.pathway-viewer-light {
  --pv-bg: #f8f9fa;
  --pv-toolbar-bg: #f0f0f0;
  --pv-entity-default-fill: #fafafa;
}

.pathway-viewer-dark {
  --pv-bg: #0d1117;
  --pv-toolbar-bg: #161b22;
  --pv-entity-default-fill: #21262d;
}
```

Available CSS custom properties:

| Variable | Description |
|----------|-------------|
| `--pv-bg` | Background color |
| `--pv-text` | Primary text color |
| `--pv-toolbar-bg` | Toolbar background |
| `--pv-toolbar-border` | Toolbar border |
| `--pv-toolbar-btn-text` | Toolbar button text |
| `--pv-tooltip-bg` | Tooltip background |
| `--pv-tooltip-border` | Tooltip border |
| `--pv-tooltip-text` | Tooltip text |
| `--pv-tooltip-secondary` | Tooltip secondary text |
| `--pv-legend-bg` | Legend background |
| `--pv-legend-border` | Legend border |
| `--pv-legend-text` | Legend text |
| `--pv-compartment-stroke` | Compartment boundary stroke |
| `--pv-compartment-label` | Compartment label color |
| `--pv-edge-color` | Default reaction edge color |
| `--pv-entity-default-fill` | Default entity fill |
| `--pv-entity-default-stroke` | Default entity stroke |
| `--pv-input-bg` | Input background |
| `--pv-input-border` | Input border |
| `--pv-input-text` | Input text |
| `--pv-link-color` | Link color |

## PathwayBrowser

Browse and search pathways before loading them:

```tsx
import { PathwayBrowser, KeggAdapter } from '@omicsos/pathway-viewer';

function Browser() {
  const adapter = new KeggAdapter({ organism: 'hsa' });

  return (
    <PathwayBrowser
      adapter={adapter}
      onSelect={(pathwayId) => console.log('Selected:', pathwayId)}
    />
  );
}
```

## EHLD Rendering

Reactome Enhanced High-Level Diagrams (hand-drawn SVG illustrations):

```tsx
import { EhldRenderer } from '@omicsos/pathway-viewer';

<EhldRenderer
  svgContent={ehldSvgString}
  overlayColors={{ 'R-HSA-12345': '#FF0000' }}
/>
```

## API Reference

### Key Exports

| Export | Type | Description |
|--------|------|-------------|
| `PathwayViewer` | Component | Main viewer component |
| `SVGRenderer` | Component | Low-level SVG renderer |
| `ExportButton` | Component | Export dropdown button |
| `Legend` | Component | Entity type legend |
| `Toolbar` | Component | Zoom/search toolbar |
| `Tooltip` | Component | Entity hover tooltip |
| `EhldRenderer` | Component | EHLD SVG renderer |
| `PathwayBrowser` | Component | Pathway search/browse |
| `EntityNode` | Component | Gene/enzyme node |
| `CompoundNode` | Component | Compound (circle) node |
| `CompartmentBox` | Component | Compartment boundary |
| `SlicedNode` | Component | Multi-genome sliced node |
| `exportSvg` | Function | Download SVG file |
| `exportPng` | Function | Download PNG file |
| `useExpressionOverlay` | Hook | Expression overlay colors |
| `useEnrichmentOverlay` | Hook | Enrichment overlay colors |
| `useGenomeCoverage` | Hook | Genome coverage overlay |
| `useZoomPan` | Hook | Zoom/pan interaction |
| `useSearch` | Hook | Entity search |
| `usePathwayFetch` | Hook | Adapter-based fetching |
| `KeggAdapter` | Class | KEGG REST API adapter |
| `ReactomeAdapter` | Class | Reactome API adapter |
| `createColorScale` | Function | Color scale factory |
| `computeExpressionColors` | Function | Expression color computation |
| `computeEnrichmentColors` | Function | Enrichment color computation |
| `computeGenomeCoverage` | Function | Coverage computation |
| `parseKgml` | Function | KGML XML parser |
| `parseReactomeLayout` | Function | Reactome layout parser |

### Key Types

| Type | Description |
|------|-------------|
| `UnifiedPathway` | Normalized pathway data model |
| `PathwayEntity` | Entity (gene, compound, enzyme, etc.) |
| `PathwayReaction` | Reaction edge with substrates/products |
| `PathwayCompartment` | Cellular compartment boundary |
| `PathwayViewerProps` | PathwayViewer component props |
| `OverlayLegendConfig` | Color scale legend configuration |
| `ColorScaleConfig` | Color scale creation config |
| `ExportSvgOptions` | SVG export options |
| `ExportPngOptions` | PNG export options |
| `PathwayAdapter` | Adapter interface |

## Screenshots

Screenshots can be captured from the development playground:

```bash
npm run dev
```

![Light mode](docs/screenshots/light.png)
![Dark mode](docs/screenshots/dark.png)
![Expression overlay](docs/screenshots/expression-overlay.png)

## Development

```bash
# Start dev server with playground
npm run dev

# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Type check
npm run typecheck

# Build for production
npm run build
```

## Acknowledgments

This library uses data from these public bioinformatics databases:

- **[KEGG](https://www.genome.jp/kegg/)** — Kyoto Encyclopedia of Genes and Genomes (Kanehisa Laboratories)
- **[Reactome](https://reactome.org/)** — Open-source curated pathway database (EMBL-EBI / OICR / NYULH)

Visualization powered by [D3.js](https://d3js.org/) by Mike Bostock (ISC License).

## License

Apache-2.0 — see [LICENSE](./LICENSE) for details.