The network layer in MapWeave comes with a number of graph analysis functions that you can use to add insight to your data.
Using these functions, it's possible to score your data and then use these scores to add meaningful styling or labeling to the map. For example, add node styling to identify the most influential nodes or highlight the connections of a specific node.
The graph analysis functions are powered by a graph engine that runs separately from the network layer rendering methods.
Betweenness
The betweenness() graph function assesses the number of times a node lies on the shortest path between other nodes, bridging a path between them. It represents a measure of the impact that removing that node would have on the connectivity of the network.
In the example below, the nodes have been resized in proportion to their betweenness score, so more important nodes are larger.
MapWeave Example
Log in to view live examplesMapWeave Example
Log in to view live examples// create a network layer
const networkLayer = new NetworkLayer({
data: networkData,
});
// get the graph engine for the networkLayer
const graphEngine = networkLayer.getGraphEngine();
// run the calculations for betweenness and set the options
const betweennessScore = graphEngine.betweenness({ normalization: 'unnormalized' });
// change the scale of each node based on the betweenness score
for (const [key, value] of Object.entries(betweennessScore)) {
networkLayer.overrideStyle(key, { scale: value });
} function App() {
// create the graph engine, run the betweenness calculation and set the options
const betweennessScore = useMemo(
() => createNetworkGraphEngine(networkData).betweenness({ normalization: 'unnormalized' }),
[networkData],
);
const overriddenStyles = [];
// change the scale of each node based on the betweenness score
for (const [key, value] of Object.entries(betweennessScore)) {
overriddenStyles.push({ ids: key, overrideStyle: { scale: value } });
}
return (
<MapWeave options={options}>
<NetworkLayer data={networkData} overrideStyles={overriddenStyles} />
</MapWeave>
);
}
const root = createRoot(document.getElementById('mw'));
root.render(<App />); Components
The components() graph function calculates the separate connected components within a network layer. These components are made from nodes in the network layer that are in the same dataset but not connected to each other by links.
For example, the following graph contains two components. The color has been changed to differentiate the components from each other.
MapWeave Example
Log in to view live examplesMapWeave Example
Log in to view live examplesconst networkLayer = new NetworkLayer({
data: networkData, // create a network layer
});
// get the graph engine for the networkLayer
const graphEngine = networkLayer.getGraphEngine();
// run the calculations for components
const componentsScore = graphEngine.components();
// change the color of the nodes and links for one component of the graph
networkLayer.overrideStyle(componentsScore[1].nodeIds, { color: '#FD9067' });
networkLayer.overrideStyle(componentsScore[1].linkIds, { color: '#FD9067' }); function App() {
// create the graph engine and run the components function
const componentsScore = useMemo(
() => createNetworkGraphEngine(networkData).components(),
[networkData],
);
const overriddenStyles = [
// change the color of the nodes and links for one component of the graph
{ ids: componentsScore[1].nodeIds, overrideStyle: { color: '#FD9067' } },
{ ids: componentsScore[1].linkIds, overrideStyle: { color: '#FD9067' } },
];
return (
<MapWeave options={options}>
<NetworkLayer data={networkData} overrideStyles={overriddenStyles} />
</MapWeave>
);
}
const root = createRoot(document.getElementById('mw'));
root.render(<App />); Degrees
The degrees() graph function measures the number of direct, 'one-hop', connections each node has to other nodes within the network and shows very connected nodes that can quickly connect with the wider network.
In the example below, the degree of each node is displayed in its label.
MapWeave Example
Log in to view live examplesMapWeave Example
Log in to view live examplesconst networkLayer = new NetworkLayer({
data: networkData, // create a network layer
});
// get the graph engine for the networkLayer
const graphEngine = networkLayer.getGraphEngine();
// run the calculations for degrees and set the options
const degreesScore = graphEngine.degrees({ direction: 'to' });
// change the value for each label to be degrees
for (const [key, value] of Object.entries(degreesScore)) {
networkLayer.overrideStyle(key, { label: { text: `${value}` } });
} function App() {
// create the graph engine, run the degrees calculation and set the options
const degreesScore = useMemo(
() => createNetworkGraphEngine(networkData).degrees({ direction: 'to' }),
[networkData],
);
const overriddenStyles = Object.entries(degreesScore).map(([key, value]) => ({
ids: key,
overrideStyle: { label: { text: `${value}` } },
}));
return (
<MapWeave options={options}>
<NetworkLayer data={networkData} overrideStyles={overriddenStyles} />
</MapWeave>
);
}
const root = createRoot(document.getElementById('mw'));
root.render(<App />); Neighbors
The neighbors() graph function finds the nodes and links that are connected to a specified node or nodes within a specified number of hops.
For example, the neighboring nodes and links within two hops of the node with the id '3016' are shown here in orange.
MapWeave Example
Log in to view live examplesMapWeave Example
Log in to view live examplesconst networkLayer = new NetworkLayer({
// create a new network layer
data: networkData,
});
// the id of the node we are getting the neighbors for
const nodeOfInterest = '3016';
const nodeOfInterestStyle = {
// the style for the node we are getting the neighbors for
color: '#FD9067',
border: { color: '#774299', width: 1 },
};
// the style for neighbors
const neighborStyle = { color: '#FD9067' };
// get the graph engine
const graphEngine = networkLayer.getGraphEngine();
// use the neighbors function and set the options
const neighborsScore = graphEngine.neighbors(nodeOfInterest, { hops: 2 });
// override the style for the node we are getting neighbors for
networkLayer.overrideStyle(nodeOfInterest, nodeOfInterestStyle);
// override the style for the neighboring nodes
networkLayer.overrideStyle(neighborsScore.nodeIds, neighborStyle);
// override the style for the neighboring links
networkLayer.overrideStyle(neighborsScore.linkIds, neighborStyle); function App() {
// the id of the node we are getting the neighbors for
const nodeOfInterest = '3016';
// the style for the node we are getting the neighbors for
const nodeOfInterestStyle = {
color: '#FD9067',
border: { color: '#774299', width: 1 },
};
// the style for neighbors
const neighborStyle = { color: '#FD9067' };
// use the neighbors function and set the options
const geNeighbors = useMemo(
() => createNetworkGraphEngine(networkData).neighbors(nodeOfInterest, { hops: 2 }),
[networkData],
);
const overriddenStyles = [];
// override the style for the neighboring nodes
overriddenStyles.push({ ids: geNeighbors.nodeIds, overrideStyle: neighborStyle });
// override the style for the neighboring links
overriddenStyles.push({ ids: geNeighbors.linkIds, overrideStyle: neighborStyle });
// override the style for the node we are getting neighbors for
overriddenStyles.push({ ids: nodeOfInterest, overrideStyle: nodeOfInterestStyle });
return (
<MapWeave options={options}>
<NetworkLayer data={networkData} overrideStyles={overriddenStyles} />
</MapWeave>
);
}
const root = createRoot(document.getElementById('mw'));
root.render(<App />);