Appearance
CSV
This example shows how to import a CSV file into an Ogma visualisation. The dataset contains edges network data for character relationships within George R. R. Martin's A Storm of Swords, the third novel in his series A Song of Ice and Fire (also known as the HBO television adaptation Game of Thrones). This data was originally compiled by A. Beveridge and J. Shan, "Network of Thrones," Math Horizons Magazine , Vol. 23, No. 4 (2016), pp. 18-22..
The Papa Parse library is used to correctly parse the CSV file.
ts
import Ogma, { RawEdge, RawNode } from '@linkurious/ogma';
import { getIconCode } from './utils';
const ogma = new Ogma({
container: 'graph-container'
});
// some UI logic
const layout = () =>
ogma.layouts.force({
locate: { padding: 80 }
});
// Add some edge styling rules
ogma.styles.addEdgeRule({
color: e => '#80ce87',
shape: 'arrow',
width: e => Math.log(e.getData('weight'))
});
// Add some node styling rules
ogma.styles.addNodeRule({
text: {
content: n => n.getData('label'),
minVisibleSize: 2
},
radius: n => n.getDegree(),
icon: {
content: () => getIconCode('icon-circle-user-round'),
font: 'Lucide',
color: 'rgb(61,139,223)',
minVisibleSize: 0
},
outerStroke: {
color: 'rgb(61,139,223)',
width: 2
},
color: 'white'
});
interface Results {
data: { source: string; target: string; weight: string }[];
}
const toRawGraph = (results: Results) => {
// format the incoming JSON to the RawGraph format
// use a Set here to avoid duplicates
const nodesSet = new Set<string>();
const edges: RawEdge[] = [];
results.data.forEach((item, i) => {
nodesSet.add(item.source);
nodesSet.add(item.target);
// mind parallel edges
const edgeId = item.source + '-' + item.target + '-' + i;
// cast to Number numeric values as in CSV everything is a string!
edges.push({
id: edgeId,
source: item.source,
target: item.target,
data: { weight: Number(item.weight) }
});
});
// now iterate on the nodesSet to create the node list
const nodes: RawNode[] = [];
nodesSet.forEach(id => {
nodes.push({ id, data: { label: id } });
});
return ogma.setGraph({ nodes, edges }).then(layout);
};
document.querySelector('#load-csv')!.addEventListener('click', evt => {
// load the csv from the URL and parse it returning a JSON
// @ts-expect-error we are using a global variable here
return Papa.parse('files/got-edges.csv', {
download: true,
header: true,
complete: toRawGraph
});
});
html
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<link
href="https://cdn.jsdelivr.net/npm/lucide-static@0.483.0/font/lucide.css"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap"
rel="stylesheet"
/>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.1.0/papaparse.min.js"
integrity="sha256-Fh801SO9gqegfUdkDxyzXzIUPWzO/Vatqj8uN+5xcL4="
crossorigin="anonymous"
></script>
<link type="text/css" rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="graph-container"></div>
<div class="toolbar">
<div class="controls">
<button id="load-csv" class="btn menu">Click to load CSV</button>
</div>
</div>
<script type="module" src="index.ts"></script>
</body>
</html>
css
#graph-container {
top: 0;
bottom: 0;
left: 0;
right: 0;
position: absolute;
margin: 0;
overflow: hidden;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
}
.toolbar {
display: block;
position: absolute;
top: 20px;
right: 20px;
padding: 10px;
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.65);
border-radius: 4px;
background: #ffffff;
color: #222222;
font-weight: 300;
max-width: 350px;
}
.controls {
text-align: center;
margin-top: 5px;
}
.btn {
padding: 6px 8px;
background-color: white;
cursor: pointer;
font-size: 18px;
border: none;
border-radius: 5px;
outline: none;
}
.btn:hover {
color: #333;
background-color: #e6e6e6;
}
.menu {
border: 1px solid #ddd;
width: 80%;
font-size: 14px;
margin-top: 10px;
}
ts
// dummy icon element to retrieve the HEX code, it should be hidden
const placeholder = document.createElement('span');
document.body.appendChild(placeholder);
placeholder.style.visibility = 'hidden';
// helper routine to get the icon HEX code
export function getIconCode(className: string) {
placeholder.className = className;
const code = getComputedStyle(placeholder, ':before').content;
return code[1];
}