Public
Edited
Jul 7, 2023
2 forks
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
cities
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
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
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
async function mvrp(
data,
options = {
objective: {
minimise_num_depots: false,
travel_cost: "distance"
}
}
) {
const optimizeRequest = await axios
.post(`https://api.nextbillion.io/optimise-mvrp?` + `key=${apiKey}`, {
...data,
options
})
.then((res) => res.data);

const mvrpRequestId = optimizeRequest.id;
let attempts = 0;

while (attempts < 10) {
const result = await axios({
url: `https://api.nextbillion.io/optimise-mvrp/result?id=${mvrpRequestId}&key=${apiKey}`,
method: "GET",
headers: {}
});

if (
result.data &&
result.data.status === "Ok" &&
result.data.message == ""
) {
return result.data;
}
attempts++;
await new Promise((resolve) => setTimeout(resolve, 5 * 1000));
}
}
Insert cell
Insert cell
// async function getData(city, nPoints, nRegions, nVehiclesPerRegion) {
// const url = `https://m4aqpzp5ah6n7ilzunwyo5ma2u0ezqcc.lambda-url.us-east-2.on.aws/?region=${city}&number=${
// nPoints + 10
// }&vehicles=${nRegions * nVehiclesPerRegion}&type=darp`;
// const response = await fetch(url);
// const json = await response.json();

// console.log(json.pointsArray.length);

// const locations = [];

// const nResidentialPoints = Math.floor(nPoints * RESIDENTIAL_PERCENT);
// const nCommercialPoints = Math.floor(nPoints * COMMERCIAL_PERCENT);

// const points = json.pointsArray.map((point) => [
// parseFloat(point.pickup_longitude),
// parseFloat(point.pickup_latitude),
// ]);

// const regions = getRegions(points, nRegions);

// let pointIdx = 0;
// while (pointIdx < nPoints) {
// const point = json.pointsArray[pointIdx];

// const locationType =
// pointIdx < nResidentialPoints
// ? "residential"
// : pointIdx < nResidentialPoints + nCommercialPoints
// ? "commercial"
// : "medical";

// for (const [regionId, region] of regions.entries()) {
// const pt = [
// parseFloat(point.pickup_longitude),
// parseFloat(point.pickup_latitude),
// ];

// if (turf.inside(turf.point(pt), region.polygon)) {
// const solid = Math.random() < 0.5;
// const organic = Math.random() < 0.5;
// let _skills = [];
// if (solid) _skills.push(skills.solid);
// if (organic) _skills.push(skills.organic);
// if (locationType === "medical") _skills.push(skills.medical);

// locations.push({
// name: locationType === "residential" ? point.name : point.business,
// regionId,
// point: pt,
// type: locationType,
// skills: _skills,
// });
// pointIdx++;
// break;
// }
// }
// }

// let vehicles = [];
// let veh_idx = 0;

// regions.forEach((r, r_idx) => {
// // Assign one medical truck per region
// vehicles.push({
// name: `Truck ${veh_idx}`,
// id: veh_idx,
// license: json.vehicleArray.at(veh_idx++).license,
// region: r_idx,
// skills: [2],
// });

// for (let i = 0; i < inputs.nVehiclesPerRegion - 1; i++) {
// // Assign the remaining trucks either [0], [1], or [0, 1]
// let skills = [];
// const randn = Math.floor(Math.random() * 3);
// if (randn === 0) skills = [0];
// else if (randn === 1) skills = [1];
// else skills = [0, 1];

// vehicles.push({
// name: `Truck ${veh_idx}`,
// id: veh_idx,
// license: json.vehicleArray.at(veh_idx++)?.license,
// region: r_idx,
// skills,
// });
// 1;
// }
// });

// console.log({
// locations: locations.length,
// vehicles: vehicles.length,
// regions: regions.length,
// points: points.length,
// });

// return {
// locations,
// vehicles,
// regions,
// };
// };
Insert cell
async function getData(city, nPoints, nRegions, nVehiclesPerRegion) {
const url = `https://m4aqpzp5ah6n7ilzunwyo5ma2u0ezqcc.lambda-url.us-east-2.on.aws/?region=${city}&number=${nPoints}&vehicles=${
nRegions * nVehiclesPerRegion
}&type=darp`;
const response = await fetch(url);
const json = await response.json();

const locations = [];

const nResidentialPoints = Math.floor(nPoints * RESIDENTIAL_PERCENT);
const nCommercialPoints = Math.floor(nPoints * COMMERCIAL_PERCENT);

const points = json.pointsArray.map((point) => [
parseFloat(point.pickup_longitude),
parseFloat(point.pickup_latitude)
]);

const regions = getRegions(points, nRegions);

json.pointsArray.forEach((point, pointIdx) => {
const locationType =
pointIdx < nResidentialPoints
? "residential"
: pointIdx < nResidentialPoints + nCommercialPoints
? "commercial"
: "medical";

for (const [regionId, region] of regions.entries()) {
const pt = [
parseFloat(point.pickup_longitude),
parseFloat(point.pickup_latitude)
];

if (turf.inside(turf.point(pt), region.polygon)) {
const solid = Math.random() < 0.5;
const organic = Math.random() < 0.5;
let _skills = [];
if (solid) _skills.push(skills.solid);
if (organic) _skills.push(skills.organic);
if (locationType === "medical") _skills.push(skills.medical);

locations.push({
name: locationType === "residential" ? point.name : point.business,
regionId,
point: pt,
type: locationType,
skills: _skills
});
break;
}
}
});

let vehicles = [];
let veh_idx = 0;

regions.forEach((r, r_idx) => {
// Assign one medical truck per region
vehicles.push({
name: `Truck ${veh_idx}`,
id: veh_idx,
license: json.vehicleArray.at(veh_idx++).license,
region: r_idx,
skills: [2]
});

for (let i = 0; i < inputs.nVehiclesPerRegion - 1; i++) {
// Assign the remaining trucks either [0], [1], or [0, 1]
let skills = [];
const randn = Math.floor(Math.random() * 3);
if (randn === 0) skills = [0];
else if (randn === 1) skills = [1];
else skills = [0, 1];

vehicles.push({
name: `Truck ${veh_idx}`,
id: veh_idx,
license: json.vehicleArray.at(veh_idx++)?.license,
region: r_idx,
skills
});
1;
}
});

return {
locations,
vehicles,
regions
};
}
Insert cell
function getRegions(points, count) {
const extreme = findExtremeCoordinates(points);
const bounds = [...extreme[0], ...extreme[1]];
const rest = points.filter((point) => {
return (point[0] === extreme[0][0] && point[1] === extreme[0][1]) ||
(point[0] === extreme[1][0] && point[1] === extreme[1][1])
? false
: true;
});

const sampledPoints = _.sampleSize(rest, count - 2);
sampledPoints.push(...extreme);

const delaunay = d3Delaunay.Delaunay.from(sampledPoints);
const voronoi = delaunay.voronoi(bounds);

const regions = [];
for (let point of voronoi.cellPolygons()) {
regions.push({
polygon: turf.lineToPolygon(turf.lineString(point)),
color: colors[regions.length]
});
}

return regions;
}
Insert cell
function createMap(id, center, zoom = 10) {
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
});

return nbmap;
}
Insert cell
Insert cell
Insert cell
Insert cell
vehiclesMap = {
const vehiclesMap = new Map();
vehicles.forEach((vehicle, idx) => {
vehiclesMap.set(idx, vehicle);
});

return vehiclesMap;
}
Insert cell
data = getData(
'la',
inputs.nPoints + 2,
inputs.nRegions,
inputs.nVehiclesPerRegion
)
Insert cell
allLocations = data.locations
Insert cell
vehicles = data.vehicles
Insert cell
vehiclesTable = {
const vehiclesAssignedInitially = Object.fromEntries(
initialRouteOptimizationResult.flatMap((r) =>
r.result.routes.map((route) => [
route.vehicle,
route.steps.filter((step) => step.type === "pickup").length
])
)
);
return vehicles.map((vehicle) => ({
name: vehicle.name,
license: vehicle.license,
solid: vehicle.skills.includes(0) ? "Yes" : "No",
organic: vehicle.skills.includes(1) ? "Yes" : "No",
medical: vehicle.skills.includes(2) ? "Yes" : "No",
"# Jobs Assigned": vehiclesAssignedInitially[vehicle.id] ?? 0
}));
}
Insert cell
locationsTable = locations.map((l) => ({
Name: l.name,
Location: `${l.point.map((ax) => _.round(ax, 5)).join(", ")}`,
Type: _.capitalize(l.type),
Region: l.regionId,
"Solid waste": l.skills.includes(0) ? "Yes" : "No",
"Organic waste": l.skills.includes(1) ? "Yes" : "No",
"Medical waste": l.skills.includes(2) ? "Yes" : "No"
}))
Insert cell
regions = data.regions
Insert cell
depot = allLocations[0]
Insert cell
recycling = allLocations[1]
Insert cell
locations = allLocations.slice(2)
Insert cell
centroid = {
const point = city.centroid.split(",");
return [point[1], point[0]];
}
Insert cell
city = cities.find(c => c.value === 'la')
Insert cell
Insert cell
truckCapacity = 100
Insert cell
RESIDENTIAL_PERCENT = 0.7
Insert cell
COMMERCIAL_PERCENT = 0.25
Insert cell
HOSPITAL_PERCENT = 0.05
Insert cell
shiftStartTime = inputs.shiftStart.getTime() / 1000
Insert cell
shiftEndTime = dateFns
.addHours(inputs.shiftStart, inputs.shiftDuration)
.getTime() / 1000
Insert cell
skills = {
return {
solid: 0,
organic: 1,
medical: 2
};
}
Insert cell
priorities = {
return {
residential: 0,
commercial: 1,
medical: 2
};
}
Insert cell
icons = {
return {
residential: "🏠",
commercial: "🏪",
medical: "🏥",
trash: "🗑️",
depot: "🏭",
recycling: "♻️"
};
}
Insert cell
wasteVolume = {
return {
residential: 5,
commercial: 20,
medical: 30
};
}
Insert cell
Insert cell
Insert cell
turf = require("https://unpkg.com/@turf/turf@6/turf.min.js")
Insert cell
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
Insert cell
nextbillion.setApiKey(apiKey)
Insert cell
Insert cell
dateFns = await require("https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.30.1/date_fns.js")
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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more