온톨로지 그래프 웹페이지에 임베드하기, 라이브러리 선택과 최소 코드
온톨로지 그래프를 웹페이지에 임베드하는 일은 데이터를 노드·엣지 JSON으로 바꾸고 렌더링 라이브러리를 빈 div에 얹는 두 단계다. 2026년 7월 기준 Cytoscape.js·vis-network·WebVOWL의 성격을 비교하고 최소 임베드 코드를 짚는다.
목차
임베드는 두 단계로 나뉜다
온톨로지 그래프를 웹페이지에 임베드하는 일은 결국 두 가지를 얹는 작업이다. 하나는 그래프 데이터를 렌더링 라이브러리가 읽는 형식, 곧 노드(node, 개념이나 개체)와 엣지(edge, 둘을 잇는 관계) 목록으로 바꾸는 것이고, 다른 하나는 그 데이터를 그려 줄 자바스크립트 시각화 라이브러리를 페이지의 빈 <div>에 얹는 것이다. 2026년 7월 기준으로 실무에서 고르는 렌더러는 Cytoscape.js, vis-network, vasturiano의 force-graph, OWL 온톨로지 전용인 WebVOWL 정도로 좁혀진다. Cytoscape.js 공식 문서에 따르면 현재 안정 버전은 3.34.0이고 MIT 라이선스다.
온톨로지(ontology)는 어떤 분야의 개념과 그 사이의 관계를 기계가 읽을 수 있게 형식적으로 정의한 모델이다. 이 글이 다루는 범위는 이렇게 정의한 그래프를 정적 페이지나 SPA(브라우저에서 화면을 갈아 끼우는 단일 페이지 애플리케이션) 안에서 브라우저가 직접 그리게 하는 클라이언트 사이드 임베드다. 서버에서 SPARQL 질의로 데이터를 실시간으로 끌어오는 백엔드 구성이나 3D·VR 렌더링은 다루지 않고, 노드 규모는 수천 개 이하를 전제로 한다.
실무에서 쓰는 라이브러리 네 가지
일반적인 지식 그래프나 개체 관계 시각화는 Cytoscape.js와 vis-network가 무난하고, OWL 표준 온톨로지를 정해진 표기법대로 보여줘야 하면 WebVOWL을 고른다. 네 라이브러리는 렌더링 방식과 입력 데이터 형식에서 성격이 갈린다.
| 라이브러리 | 렌더링 | 입력 데이터 | 잘 맞는 경우 |
|---|---|---|---|
| Cytoscape.js | 캔버스 | 노드·엣지 JSON | 개체 관계에 그래프 분석까지 |
| vis-network | 캔버스 | 노드·엣지 JSON | 빠른 프로토타입, 물리 조정 |
| force-graph | 캔버스 | 노드·링크 JSON | 힘 기반 배치, 대화형 탐색 |
| WebVOWL | SVG | OWL 변환 JSON | OWL 표준 표기 준수 |
Cytoscape.js는 시각화만이 아니라 최단 경로나 중심성 같은 그래프 이론 알고리즘을 함께 제공한다. 원래 토론토 대학에서 만들어 생물정보학 저널에 발표한 프로젝트이며, 화면에 그린 그래프를 분석 코드로 이어 갈 때 유리하다. vis-network는 vis.js 공식 저장소 설명 기준으로 HTML 캔버스로 렌더링하고 수천 개 노드까지 부드럽게 동작하며, 그보다 커지면 클러스터링으로 노드를 묶어 다룬다. force-graph는 프로젝트 문서에 따르면 HTML5 캔버스와 d3-force 물리 엔진으로 힘 기반 배치를 그리고, 확대·이동과 노드 드래그, 클릭 상호작용을 기본으로 지원한다.
최소 코드로 붙여 보기
가장 빠른 검증은 CDN 스크립트 한 줄과 빈 컨테이너 div로 시작하는 것이다. Cytoscape.js 공식 문서는 컨테이너를 너비·높이가 지정된 빈 div로 두고, CSS를 <head> 안 Cytoscape 관련 코드보다 앞에 배치하라고 안내한다. 아래는 노드 두 개와 엣지 하나를 그리는 최소 예제다.
<div id="cy" style="width: 600px; height: 400px;"></div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cytoscape.min.js"></script>
<script>
const cy = cytoscape({
container: document.getElementById('cy'),
elements: [
{ data: { id: 'person' } },
{ data: { id: 'org' } },
{ data: { id: 'worksAt', source: 'person', target: 'org' } }
],
style: [
{ selector: 'node',
style: { label: 'data(id)', 'background-color': '#3b82f6' } }
],
layout: { name: 'grid' }
});
</script>핵심은 container로 넘긴 div에 명시적인 width·height가 있어야 한다는 점이다. div 크기를 0으로 두면 그래프가 화면에 나타나지 않는다. elements 배열에 노드는 { data: { id } }, 엣지는 { data: { id, source, target } } 형태로 넣고, style로 색과 라벨을, layout으로 배치 알고리즘을 지정한다. grid 대신 cose 같은 힘 기반 레이아웃으로 바꾸면 관계가 많은 그래프가 더 읽기 쉽게 퍼진다.
코드 없이 붙이는 완성형 위젯 — 마이크로소프트 온톨로지 플레이그라운드
라이브러리를 직접 배선하기 전에, 이미 만들어진 드롭인 위젯을 쓰는 길도 있다. 마이크로소프트가 공개한 오픈소스 프로젝트 온톨로지 플레이그라운드는 ontology-embed.js라는 자립형 자바스크립트 파일을 함께 제공한다. 페이지에 <script> 태그 한 줄을 넣고 컨테이너를 하나 두면 인터랙티브 온톨로지 뷰어가 그 자리에 렌더된다. 그래프 엔진은 이 글에서 다룬 Cytoscape.js와 같아, 팬·줌·노드 클릭 검사(click-to-inspect)가 그대로 동작한다.
불러올 온톨로지는 세 가지로 지정한다. 카탈로그에 있는 온톨로지의 ID, 외부 URL, 또는 페이지 안에 인라인 base64로 넣은 데이터다. 다크·라이트 테마를 모두 지원하고 정적 파일이라 백엔드가 필요 없다. 정확한 속성 이름과 옵션은 저장소의 임베드 가이드(docs/embed-guide.md)에 정리돼 있고, 코드는 깃허브 저장소, 동작은 라이브 데모에서 확인할 수 있다.

OWL·RDF 온톨로지는 어떻게 데이터로 바꾸나
표준 온톨로지 파일(OWL, RDF)을 그대로 읽어 그리는 라이브러리는 없다. 시각화 라이브러리는 노드·엣지 JSON만 이해하므로, 온톨로지를 그 형식으로 옮기는 변환 단계가 반드시 앞에 온다. WebVOWL이 이 문제를 정면으로 다룬다. WebVOWL 프로젝트 설명에 따르면 OWL 온톨로지를 OWL2VOWL 변환기(자바로 작성, OWL API 기반)로 JSON으로 바꾼 뒤 D3 기반 force-directed 레이아웃과 SVG로 그리며, 표기법은 VOWL(Visual Notation for OWL Ontologies)이라는 표준을 따른다.
다만 WebVOWL 문서는 OWL 2의 모든 구문을 그리지는 못한다고 밝힌다. 복잡한 데이터타입이나 일부 인스턴스 수준 구문은 아직 지원하지 않는다. 표준 표기가 목적이 아니라면, RDF 트리플(주어-술어-목적어 형태의 최소 진술 단위)을 직접 순회해 주어와 목적어를 노드로, 술어를 엣지 라벨로 매핑하는 변환 스크립트를 짜서 Cytoscape.js용 JSON을 만드는 편이 자유도가 높다. 온톨로지 자체를 아직 설계하지 않았다면, 개념과 관계를 먼저 잡는 설계 절차부터 밟아야 변환 매핑도 깔끔해진다.
노드가 많아지면 무엇을 조심하나
핵심은 노드 수다. 수천 개를 넘어가면 렌더링 방식과 클러스터링을 함께 고민해야 한다. 앞서 봤듯 vis.js 공식 설명은 vis-network가 수천 개 노드까지 부드럽게 동작하고 그 이상은 클러스터링으로 묶으라고 안내한다. 렌더링 방식도 규모에 영향을 준다. 캔버스는 화면을 픽셀로 다시 그려 노드가 늘어도 DOM 부담이 없지만, SVG는 요소마다 DOM 노드를 만들어 수천 개를 넘어가면 브라우저가 무거워진다. WebVOWL이 SVG 기반이라 큰 온톨로지에서 느려질 수 있는 이유가 여기 있다.
실무 판단 기준은 이렇게 잡는다. 수백 개 이하면 어떤 라이브러리든 무난하고, 수천 개 규모면 캔버스 기반(Cytoscape.js, vis-network, force-graph)에 클러스터링을 얹는다. 그보다 크면 전체를 한 번에 그리지 말고, 클릭한 노드 주변만 펼쳐 보여주는 1-hop 확장 방식으로 바꾸는 게 낫다. 처음부터 전체 그래프를 렌더하면 초기 로딩과 상호작용이 함께 느려지고, 화면도 노드 뭉치로 뒤덮여 읽기 어려워진다.





