Appearance
Excel
This example shows how to transform a XLSX file into an Ogma visualization. The dataset contains an XLSX spreadsheet file with 2 tabs: "nodes" and "edges". The 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 SheetJS Community Edition is used to correctly parse the XLSX file.
ts
import Ogma from '@linkurious/ogma';
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: {
font: 'Font Awesome 5 Free',
content: n => '\uf007',
color: 'rgb(61,139,223)',
minVisibleSize: 0
},
outerStroke: {
color: 'rgb(61,139,223)',
width: 2
},
color: 'white'
});
interface Workbook {
Sheets: {
[key: string]: any;
};
}
interface Record {
id: string;
label: string;
target: string;
source: string;
weight: number;
}
const toRawGraph = (workbook: Workbook) => {
// format the incoming workbook object to the RawGraph format
// we know there are two tabs in the workbook: "nodes" and "edges" but in case Sheet.js provides a list of them
// Luckily there's a utility function to help iterate throught the sheets records
const nodes = XLSX.utils.sheet_to_json(workbook.Sheets.nodes).map(record => {
return { id: record.id, data: { label: record.label } };
});
const edges = XLSX.utils
.sheet_to_json(workbook.Sheets.edges)
.map((record: Record, row: number) => {
return {
id: record.source + '-' + record.target + '-' + row,
source: record.source,
target: record.target,
data: { weight: record.weight }
};
});
return ogma.setGraph({ nodes: nodes, edges: edges }).then(layout);
};
document.querySelector('#load-xlsx')!.addEventListener('click', evt => {
// load the xlsx from the URL and parse it returning a JSON
return fetch('files/got.xlsx')
.then(res => {
/* get the data as a Blob */
if (!res.ok) throw new Error('fetch failed');
return res.arrayBuffer();
})
.then(ab => {
/* parse the data when it is received */
const data = new Uint8Array(ab);
// @ts-expect-error we are using a global variable here
const workbook = XLSX.read(data, { type: 'array' });
toRawGraph(workbook);
});
});
html
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<link
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/solid.min.css"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/xlsx@0.11.12/dist/xlsx.core.min.js"></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-xlsx" class="btn menu">click to load XLSX</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;
}