Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
companiesToOriginHubDirections = Promise.all(
MANUFACTURERS.map((manufacturer) =>
getDirection(manufacturer.location, ORIGIN_HUB.location)
)
)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
mvrpFromDestinationHubs = {
async function performMVRP(cityCode) {
const orders = ORDERS.filter((order) => order.city === cityCode);
const locations = [
transformPoint(
DESTINATION_HUBS.find((hub) => hub.city === cityCode).location
)
];
const hubLocationIndex = 0;

let jobId = 0;
const jobs = [];
let locationIndex = 1;

for (let i = 0; i < orders?.length; i++) {
const order = orders[i];
const store = STORES[order.storeId];
jobs.push({
id: jobId++,
delivery: [PRODUCTS[order.itemId].weight],
location_index: locationIndex++,
skills: PRODUCTS[order.itemId].skills
});
locations.push(transformPoint(store.location));
}

let vehicles = [];
for (const vehicle of shortHaulTrucks[cityCode]) {
vehicles.push({
id: vehicle.id,
skills: _.random() < 0.2 ? [] : [0],
start_index: hubLocationIndex,
capacity: [inputs.shortHaulTruckCapacity],
end_index: hubLocationIndex,
description: vehicle.description
});
}

const result = await MVRP({
locations: {
id: 1,
location: locations.join("|")
},
jobs,
vehicles
});
return {
cityCode,
...result
};
}

return Promise.all(
_.map(
DESTINATION_HUBS.map((hub) => hub.city),
performMVRP
)
);
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Select a data source…
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
Insert cell
{
const center = CITIES[selectedDestination.cityCode].centroid;

const nbmap = new nextbillion.maps.Map({
container: document.getElementById("destination-map"),
center: {
lat: center[1],
lng: center[0]
},
zoom: 10,
maxZoom: 15,
minZoom: 0,
style: "https://api.nextbillion.io/maps/streets/style.json",
scrollZoom: true
});

nbmap.on("load", () => {
STORES.filter((store) => store.city === selectedDestination.cityCode).map(
(store) => drawStore(nbmap.map, store)
);
drawHub(
nbmap.map,
DESTINATION_HUBS.find((hub) => hub.city === selectedDestination.cityCode)
);
selectedDestinationTrucks.forEach((route, i) => {
drawRoute(
nbmap.map,
`route-${i}`,
route,
COLORS[route.vehicle % COLORS.length]
);
});
});
}
Insert cell
Insert cell
async function getDirection(
origin,
destination,
options = {
mode: "truck",
option: "flexible",
route_type: "shortest",
truck_size: "200,210,600"
}
) {
const baseUrl = "https://api.nextbillion.io/directions/json";
const from = `origin=${transformPoint(origin)}`;
const to = `destination=${transformPoint(destination)}`;
const mode = `mode=${options.mode}`;
const option = `option=${options.option}`;
const truck_size = `truck_size=${option.truck_size}`;
const routeType = `route_type=${options.route_type}`;
const url = `${baseUrl}?${from}&${to}&${mode}&${routeType}&${option}&key=${API_KEY}`;
const result = await fetch(url);
return result.json().then((r) => r.routes);
}
Insert cell
function drawRoute(map, source, data, color = "#7e22ce", width = 5) {
const { distance, duration, geometry } = data;
const parsedGeometry = {
type: "LineString",
coordinates: nextbillion.utils.polyline
.decode(geometry, 5)
.map((c) => c.reverse())
};
const popupLngLat =
parsedGeometry.coordinates[
Math.floor(parsedGeometry.coordinates.length / 2)
];
if (!map.getSource(source)) {
map.addSource(source, {
type: "geojson",
data: {
type: "Feature",
geometry: {
type: "LineString",
coordinates: nextbillion.utils.polyline
.decode(geometry, 5)
.map((c) => c.reverse())
}
}
});

map.addLayer({
id: source,
type: "line",
source,
layout: { "line-join": "round", "line-cap": "round" },
paint: {
"line-color": color,
"line-width": width
// "line-dasharray": [1, 2]
}
});
}
}
Insert cell
function transformPoint(p) {
return [p[1], p[0]].join(",");
}
Insert cell
async function MVRP(data) {
const optimizeRequestUrl =
`https://api.nextbillion.io/optimise-mvrp?` + `key=${API_KEY}`;

const optimizeRequest = await axios
.post(optimizeRequestUrl, {
...data,
options: {
objective: { minimise_num_depots: false, travel_cost: "distance" },
routing: { mode: "truck" }
}
})
.then((res) => res.data);

const mvrpRequestId = optimizeRequest.id;
const previewurl = `https://nb-playground-staging.netlify.app/optimization-tester?apiKey=${API_KEY}&requestID=${mvrpRequestId}`;
const getResultUrl = `https://api.nextbillion.io/optimise-mvrp/result?id=${mvrpRequestId}&key=${API_KEY}`;

// Wait until the Route Optimization result is ready
let attempts = 0;
while (attempts < 10) {
const result = await axios({ url: getResultUrl, method: "GET" });

if (
result.data &&
result.data.status === "Ok" &&
result.data.message == ""
) {
console.log(result);
return result.data;
}
attempts++;
await new Promise((resolve) => setTimeout(resolve, 5 * 1000));
}
}
Insert cell
function drawHub(map, hub) {
const hubLocation = { lat: hub.location[1], lng: hub.location[0] };
const element = document.createElement("div");
element.innerHTML = `<div style='text-align: center;><div style='text-align: center;>🏢<div><div class='display-text'>Hub: ${hub.name}</div></div>`;
element.style.fontSize = "15px";
element.style.color = "black";
element.style.fontWeight = "600";
new nextbillion.maps.Marker({ element }).setLngLat(hubLocation).addTo(map);
}
Insert cell
function drawStepIdx(map, location, stepIdx) {
const stepIdxLocation = { lat: location[1], lng: location[0] };
const element = document.createElement("div");
element.innerText = NUMBER_EMOJIS[stepIdx];
element.style.fontSize = "15px";
new nextbillion.maps.Marker({ element })
.setLngLat(stepIdxLocation)
.addTo(map);
}
Insert cell
function drawManufacturer(map, company) {
const element = document.createElement("div");
element.innerHTML = `<div style='text-align: center;'><div style='text-align: center;'>🏭</div><div class="display-text">Company: ${company.name}</div></div>`;
element.style.color = "black";
element.style.fontWeight = "600";
element.style.fontSize = "15px";
new nextbillion.maps.Marker({ element })
.setLngLat({
lat: company.location[1],
lng: company.location[0]
})
.addTo(map);
}
Insert cell
function drawStore(map, store) {
const element = document.createElement("div");
element.innerHTML = `<div style='text-align: center;'><div style='text-align: center;'>🏬</div><div class='display-text'>Store: ${store.name}</div></div>`;
element.style.color = "black";
element.style.fontWeight = "600";
element.style.fontSize = "15px";
new nextbillion.maps.Marker({ element })
.setLngLat({
lat: store.location[1],
lng: store.location[0]
})
.addTo(map);
}
Insert cell
function* createMap(id, center, zoom = 10, onLoad) {
const container = html`
<div id="${id}" style="height:600px;width:100%;"></div>
`;
yield container;

const nbmap = new nextbillion.maps.Map({
container: document.getElementById(id),
center: {
lat: center[1],
lng: center[0]
},
zoom,
maxZoom: 15,
minZoom: 0,
style: "https://api.nextbillion.io/maps/streets/style.json",
scrollZoom: true
});

nbmap.on("load", () => {
onLoad(nbmap);
});
}
Insert cell
Insert cell
Insert cell
ORIGIN_HUB = {
return {
name: "Columbus Shipping Corp",
city: "columbus",
location: [-82.99876, 39.9869],
postalCode: "43201-2816"
};
}
Insert cell
PRODUCTS = {
return {
ac: {
id: "ac",
name: "AC",
weight: 300,
skills: []
},
fridge: {
id: "fridge",
name: "Frige",
weight: 1000,
skills: [0]
},
dish_washer: {
id: "dish_washer",
name: "Dish Washer",
weight: 500,
skills: []
},
washing_machine: {
id: "washing_machine",
name: "Washing Machine",
weight: 800,
skills: [0]
}
};
}
Insert cell
MANUFACTURERS = {
return [
{
name: "Best AC Company",
item: "ac",
city: "columbus",
location: [-82.92288, 40.09587],
postalCode: "43081",
id: 0
},
{
name: "Cool Fridges",
item: "fridge",
city: "columbus",
location: [-82.84959, 39.89277],
postalCode: "43110",
id: 1
},
{
name: "Dishy Dish Washers Corp",
item: "dish_washer",
city: "columbus",
location: [-83.1163, 39.90666],
postalCode: "43123",
id: 2
},
{
name: "Wishing Machines",
item: "washing_machine",
city: "columbus",
location: [-83.34013, 40.1381],
postalCode: "43064",
id: 3
}
];
}
Insert cell
DESTINATION_HUBS = {
return [
{
name: "Austin Hub",
city: "austin",
location: [-97.73751, 30.32101],
postalCode: "78756-2625"
},
{
name: "Los Angeles Hub",
city: "la",
location: [-118.24741, 34.04014],
postalCode: "90014-2417"
},
{
name: "Detroit Hub",
city: "detroit",
location: [-83.07939, 42.38504],
postalCode: "48202"
}
];
}
Insert cell
ORDERS = STORES.flatMap((store) => {
const orders = [];
for (const manufacturer of MANUFACTURERS) {
const quantity = _.random(
ordersPerStore.LOWER_LIMIT,
ordersPerStore.UPPER_LIMIT
);
for (let i = 0; i < quantity; i++) {
orders.push({
storeId: store.id,
itemId: manufacturer.item,
quantity: 1,
city: store.city
});
}
}
return orders;
})
Insert cell
lol = STORES.flatMap((store) => {
const orders = [];
for (const manufacturer of MANUFACTURERS) {
if (_.random()) {
const quantity = _.random(0, 30);
for (let i = 0; i < quantity; i++) {
orders.push({
storeId: store.id,
itemId: manufacturer.item,
quantity: 1,
city: store.city
});
}
}
}
return orders;
})
Insert cell
STORES = {
return [
{
name: "Smitham Inc",
city: "austin",
location: [-97.67775, 30.22351],
postalCode: "78742-2811",
id: 0
},
{
name: "Goyette, Stroman and Schiller",
city: "austin",
location: [-97.75569, 30.25644],
postalCode: "78704-1614",
id: 1
},
{
name: "Feest and Hermann",
city: "austin",
location: [-97.85122, 30.40729],
postalCode: "78726",
id: 2
},
{
name: "Bashirian and Sons",
city: "austin",
location: [-97.77488, 30.53963],
postalCode: "78613-6923",
id: 3
},
{
name: "Jones - Durgan",
city: "la",
location: [-118.12816, 34.09664],
postalCode: "91801-3547",
id: 4
},
{
name: "Larson - Schowalter",
city: "la",
location: [-118.29751, 33.9826],
postalCode: "90044-2731",
id: 5
},
{
name: "Baumbach, Gutkowski and Schinner",
city: "la",
location: [-118.08295, 33.94231],
postalCode: "90670-3643",
id: 6
},
{
name: "Stark Inc",
city: "la",
location: [-118.39707, 33.99065],
postalCode: "90230-5358",
id: 7
},
{
name: "Casper, Bashirian and Bogisich",
city: "detroit",
location: [-83.26847, 42.44302],
postalCode: "48219-1122",
id: 8
},
{
name: "Keeling Inc",
city: "detroit",
location: [-82.91314, 42.38731],
postalCode: "48230-1504",
id: 9
},
{
name: "Mueller - Bosco",
city: "detroit",
location: [-83.23414, 42.34304],
postalCode: "48228-4940",
id: 10
},
{
name: "Rice - MacGyver",
city: "detroit",
location: [-82.96492, 42.4793],
postalCode: "48021-1008",
id: 11
}
];
}
Insert cell
LONG_HAUL_TRUCKS = [
"T680",
"579",
"Cascadia",
"VNL",
"LT",
"Anthem",
"5700XE",
"T880",
"389",
"Coronado",
"VNR",
"LoneStar",
"Pinnacle",
"4900",
"W990"
]
Insert cell
NUMBER_EMOJIS[0]
Insert cell
NUMBER_EMOJIS = ["1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣", "9️⃣"]
Insert cell
USA_CENTROID = [-99.0909, 39.8355]
Insert cell
CITIES = {
return {
columbus: {
name: "Columbus",
state: "Ohio",
centroid: [-83.001647, 39.963483]
},
austin: {
name: "Austin",
state: "Texas",
centroid: [-97.7431, 30.2672]
},
la: {
name: "Los Angeles",
state: "California",
centroid: [-118.243683, 34.052235]
},
detroit: {
name: "Detroit",
state: "Michigan",
centroid: [-83.045753, 42.331429]
}
};
}
Insert cell
COLORS = [
"#FF6633",
"#FF33FF",
"#00B3E6",
"#E6B333",
"#3366E6",
"#B34D4D",
"#E666FF",
"#4DB3FF",
"#CC80CC",
"#809900"
]
Insert cell
Insert cell
Insert cell
nextbillion.setApiKey(API_KEY)
Insert cell
faker = (await import("https://esm.run/@faker-js/faker@latest")).faker
Insert cell
axios = {
let axios = await require("axios");
return axios;
}
Insert cell
import {
guard,
colors,
renderPolygon,
d3Delaunay,
findExtremeCoordinates
} from "@texoslab/nbai-helpers"
Insert cell
import {
nextbillion,
secret2,
styles,
routeStyles
} from "@nbai/nextbillion-ai-dependencies"
Insert cell
d3 = require("d3-selection")
Insert cell
html`<b>Add the stylesheet for the NB.ai SDK </b><br><code>&nbsp;&lt;link href="https://maps-gl.nextbillion.io/maps/v2/api/css" rel="stylesheet"&gt;</code>`
Insert cell
Insert cell
<style>
.custom-popup p {
margin: 0;
padding: 0;
}
.display-text {
background-color: white;
}
.sign {
text-align: center;
}
</style>
Insert cell
geoviewer = require("https://d12qcqjlhp2ahm.cloudfront.net/index_alltrans.min.js").then(
(f) => f.view
)
Insert cell
milestones = require("d3-milestones")
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more