Search

Graph Analysis

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.

// 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.

const 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.

const 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.

const 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 />);

Terms of use

These terms do not alter or supersede any existing agreements between you (or your employer) and us.

By accessing or using any Content you agree to be bound by these Terms of Use. Please review these terms carefully before using the website.

The contents of this website, including but not limited to any text, code samples, API references, schemas, interactive tools, and other materials (collectively, the 'Content'), are made available for informational and internal evaluation purposes only. All intellectual property rights in the Content are reserved. No licence is granted to use the Content for any commercial purpose, or to copy, distribute, modify, reverse-engineer, or incorporate any part of the Content into any product or service, without our prior written consent.

This Content is provided “as is” and “as available,” without any representations, warranties, or guarantees of any kind, whether express or implied, including but not limited to implied warranties of merchantability, fitness for a particular purpose, non-infringement, or accuracy. To the fullest extent permitted by applicable law, we expressly exclude and disclaim all implied warranties, conditions, and other terms that might otherwise be implied.

We disclaim all liability for any loss or damage, whether direct, indirect, incidental, consequential, or otherwise, arising from any reliance placed on the Content or from your use of it, to the fullest extent permitted by applicable law. By continuing to access or use the Content, you acknowledge and agree to these terms.