import type { Metadata } from 'next'; import Link from 'next/link'; import { PageHeader, Section, KV } from '@/components/ui/section'; import { ClaimBadge } from '@/components/ui/badge'; import { MAP_RAMP } from '@/lib/map-scale'; import { UNMAPPED_COUNTRY_NAMES } from '@cancerindex/ranking'; export const metadata: Metadata = { title: 'Methodology — clinical trial map', description: 'How trial sites per country are counted, aggregated over the cancer hierarchy, mapped to ISO 3166-1 and drawn (Equal Earth, quantile classes).' }; export const revalidate = 3600; /** Web rendering of docs/methodology/trial-map.md (kept in sync by hand; the markdown is the reference). */ export default function TrialMapMethodPage() { return (

formula ci-trial-sites-v1 · table trial_site_country_counts · source clinicaltrials ·{' '} Open the map

One row per (cancer, phase, recruiting_only, country). Cancer: all oncology trials, or one of the active top-level cancers; a trial belongs to a top-level cancer when any of its mapped conditions is the cancer or one of its descendants in the NCIt hierarchy (recursive traversal, depth ≤ 12 — the same traversal as the entity counters). A study mapped to several top-level cancers counts in each; the all-trials scope counts it once. Phase: any, or Phase 1–4; a PHASE2|PHASE3 study counts under both, EARLY_PHASE1 counts under Phase 1, studies with phase N/A count only under "any". Recruiting: as defined above.

Counts: sites = count(*), trials = count(DISTINCT trial_id). Rebuilt in one transaction by pnpm cix intel (≈ 11 800 rows, 178 country names, about 30 s). The freshness line shows the rebuild time.

Current short names and legacy long forms ("Korea, Republic of", "Russian Federation", "Viet Nam", "Réunion", "Palestinian Territory, occupied") are mapped to alpha-3, case-, whitespace- and apostrophe-insensitively. Territories keep their own code (Puerto Rico PRI, Hong Kong HKG, Réunion REU, Guam GUM…) because that is how the registrant counted the site; Kosovo uses the user-assigned XKX; "Virgin Islands" is read as the U.S. Virgin Islands.

Names without a current ISO code stay unmapped, appear in the table by name and are never painted:{' '} {UNMAPPED_COUNTRY_NAMES.filter((n) => n) .map((n) => `“${n}”`) .join(', ')} . A unit test checks that every distinct country name in the database either resolves or is on this explicit list, so a new spelling cannot silently vanish from the map.

Reference text: docs/methodology/trial-map.md. General methodology:{' '} How the index is built .

); }