Data Format
flowmap.gl visualizes movement between geographic locations. This guide explains how to structure your data.
FlowmapData Structure
The FlowmapLayer accepts data in the following structure:
interface FlowmapData<L, F> {
locations: Iterable<L>; // Array or iterable of location objects
flows: Iterable<F>; // Array or iterable of flow objects
clusterLevels?: ClusterLevels; // Optional pre-computed clusters
}
Location Data
Each location represents a geographic point. At minimum, locations need:
- A unique identifier
- Latitude coordinate
- Longitude coordinate
- Optional: name for display
Example Location Data
const locations = [
{id: 'NYC', name: 'New York', lat: 40.7128, lon: -74.0060},
{id: 'LA', name: 'Los Angeles', lat: 34.0522, lon: -118.2437},
{id: 'CHI', name: 'Chicago', lat: 41.8781, lon: -87.6298},
{id: 'HOU', name: 'Houston', lat: 29.7604, lon: -95.3698},
];
Location Accessor Functions
Tell flowmap.gl how to read your location data with accessor functions:
new FlowmapLayer({
// ...
getLocationId: (loc) => loc.id,
getLocationLat: (loc) => loc.lat,
getLocationLon: (loc) => loc.lon,
getLocationName: (loc) => loc.name, // Optional
});
Flow Data
Each flow represents movement from an origin to a destination. At minimum, flows need:
- Origin location ID
- Destination location ID
- Magnitude (count/amount)
Example Flow Data
const flows = [
{origin: 'NYC', dest: 'LA', count: 1200},
{origin: 'NYC', dest: 'CHI', count: 850},
{origin: 'LA', dest: 'NYC', count: 900},
{origin: 'LA', dest: 'CHI', count: 500},
{origin: 'CHI', dest: 'HOU', count: 300},
];
Flow Accessor Functions
Tell flowmap.gl how to read your flow data with accessor functions:
new FlowmapLayer({
// ...
getFlowOriginId: (flow) => flow.origin,
getFlowDestId: (flow) => flow.dest,
getFlowMagnitude: (flow) => flow.count,
});
Complete Example
import {FlowmapLayer} from '@flowmap.gl/layers';
const data = {
locations: [
{id: 'NYC', name: 'New York', lat: 40.7128, lon: -74.0060},
{id: 'LA', name: 'Los Angeles', lat: 34.0522, lon: -118.2437},
{id: 'CHI', name: 'Chicago', lat: 41.8781, lon: -87.6298},
],
flows: [
{origin: 'NYC', dest: 'LA', count: 1200},
{origin: 'NYC', dest: 'CHI', count: 850},
{origin: 'LA', dest: 'CHI', count: 500},
],
};
const layer = new FlowmapLayer({
id: 'flowmap-layer',
data,
getLocationId: (loc) => loc.id,
getLocationLat: (loc) => loc.lat,
getLocationLon: (loc) => loc.lon,
getLocationName: (loc) => loc.name,
getFlowOriginId: (flow) => flow.origin,
getFlowDestId: (flow) => flow.dest,
getFlowMagnitude: (flow) => flow.count,
});
Loading Data from CSV
A common pattern is loading data from CSV files:
import Papa from 'papaparse';
// locations.csv:
// id,name,lat,lon
// NYC,New York,40.7128,-74.0060
// LA,Los Angeles,34.0522,-118.2437
// flows.csv:
// origin,dest,count
// NYC,LA,1200
// NYC,CHI,850
async function loadData() {
const [locationsResponse, flowsResponse] = await Promise.all([
fetch('/data/locations.csv'),
fetch('/data/flows.csv'),
]);
const locationsText = await locationsResponse.text();
const flowsText = await flowsResponse.text();
const locations = Papa.parse(locationsText, {
header: true,
dynamicTyping: true,
}).data;
const flows = Papa.parse(flowsText, {
header: true,
dynamicTyping: true,
}).data;
return {locations, flows};
}
Loading Data from JSON
// data.json
{
"locations": [
{"id": "NYC", "name": "New York", "lat": 40.7128, "lon": -74.0060},
{"id": "LA", "name": "Los Angeles", "lat": 34.0522, "lon": -118.2437}
],
"flows": [
{"origin": "NYC", "dest": "LA", "count": 1200}
]
}
// Loading
const response = await fetch('/data.json');
const data = await response.json();
Custom Field Names
Your data doesn't need to use specific field names. The accessor functions let you map any structure:
// Data with custom field names
const locations = [
{location_code: 'NYC', display_name: 'New York', latitude: 40.7128, longitude: -74.0060},
];
const flows = [
{from_location: 'NYC', to_location: 'LA', passenger_count: 1200},
];
// Map custom fields with accessors
new FlowmapLayer({
data: {locations, flows},
getLocationId: (loc) => loc.location_code,
getLocationLat: (loc) => loc.latitude,
getLocationLon: (loc) => loc.longitude,
getLocationName: (loc) => loc.display_name,
getFlowOriginId: (flow) => flow.from_location,
getFlowDestId: (flow) => flow.to_location,
getFlowMagnitude: (flow) => flow.passenger_count,
});
Pre-computed Clusters
For large datasets, you can provide pre-computed cluster levels to improve performance. See the Clustering documentation for details.
const data = {
locations,
flows,
clusterLevels: [
{
zoom: 4,
nodes: [
{id: 'cluster-1', lat: 40.0, lon: -90.0, children: ['NYC', 'CHI']},
// ...
],
},
// ...
],
};