← Examples
Our World in Data · /v1/resolve · choropleth

Renewable electricity, joined by name

Our World in Data publishes the renewable share of each country's electricity, keyed by plain country names. Most match mapjson straight away — but some are spelled differently: Turkey vs Türkiye, East Timor vs Timor-Leste, Cote d'Ivoire vs Ivory Coast. Passing the names through mapjson's /v1/resolve maps every one to the right country (and would drop any non-country aggregates), then the values colour the map.

fetching Our World in Data + resolving names…

0%
100% renewable electricity

API Calls

// live data — Our World in Data (keyed by country names)
https://ourworldindata.org/grapher/share-electricity-renewables.csv?csvType=filtered

// resolve those names to countries — mapjson ontology (up to 1000 keys per call)
POST https://api.mapjson.com/v1/resolve  { "keys": ["Turkey", "East Timor", "Czechia", …] }

// geometry — mapjson
https://api.mapjson.com/v1/geo?layer=countries&filter=world&detail=medium&properties=iso2,name

Code

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <script src="https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/topojson-client@3/dist/topojson-client.min.js"></script>
  <style>
    body { margin: 0; background: #eef2ec; }
    svg { width: 100%; height: auto; display: block; }
  </style>
</head>
<body>
  <svg id="map"></svg>
  <script>
  const W = 1200, H = 620;
  const svg = d3.select("#map").attr("viewBox", `0 0 ${W} ${H}`);
  const tt = d3.select("body").append("div").style("position","fixed").style("pointer-events","none").style("opacity",0).style("background","#1c2833").style("color","#fff").style("font","11px ui-monospace,monospace").style("padding","5px 9px").style("border-radius","4px").style("z-index",10);
  const projection = d3.geoNaturalEarth1().rotate([-11, 0]);
  const path = d3.geoPath(projection);
  const color = d3.scaleSequential(d3.interpolateGreens).domain([0, 100]).clamp(true);
  const COL = "renewable_share_of_electricity__pct";

  // One call — /v1/resolve accepts up to 1000 keys. Track any names the ontology had to fix.
  async function resolveByName(names){
    const res = await fetch("https://api.mapjson.com/v1/resolve", {
      method:"POST", headers:{"Content-Type":"application/json"}, body: JSON.stringify({ keys: names })
    }).then(r=>r.json());
    const iso = {}, fixes = [];
    res.results.forEach(r=>{
      if (r.crosswalk && r.crosswalk.iso2 && r.status !== "miss"){
        iso[r.key] = r.crosswalk.iso2;
        if (r.name && r.name !== r.key) fixes.push(`${r.key} → ${r.name}`);
      }
    });
    return { iso, fixes };
  }

  (async function(){
    const [rows, world] = await Promise.all([
      d3.csv("https://ourworldindata.org/grapher/share-electricity-renewables.csv?csvType=filtered&useColumnShortNames=true"),
      d3.json("https://api.mapjson.com/v1/geo?layer=countries&filter=world&detail=medium&properties=iso2,name&format=geojson"),
    ]);
    const valByName = {}; rows.forEach(r => { if (r[COL] !== "" && r[COL] != null) valByName[r.entity] = +r[COL]; });
    const { iso: iso2ByName, fixes } = await resolveByName(Object.keys(valByName));
    const valByIso = {}; for (const [n,v] of Object.entries(valByName)){ const iso = iso2ByName[n]; if (iso) valByIso[iso] = v; }
    projection.fitExtent([[6,6],[W-6,H-6]], world);
    svg.append("g").selectAll("path").data(world.features).join("path").attr("d", path)
      .attr("fill", d => valByIso[d.properties.iso2] != null ? color(valByIso[d.properties.iso2]) : "#dfe3da")
      .attr("stroke", "#ffffff").attr("stroke-width", 0.4).style("cursor","default")
      .on("mousemove",(e,d)=>{ const v = valByIso[d.properties.iso2];
        tt.style("opacity",1).style("left",(e.clientX+12)+"px").style("top",(e.clientY-8)+"px")
          .html(`${d.properties.name||""}${v!=null?" · <b>"+Math.round(v)+"%</b> renewable":""}`);})
      .on("mouseout",()=>tt.style("opacity",0));
    const live = document.getElementById("live");
    if (live) live.innerHTML = `<b>${Object.keys(valByIso).length}</b> countries joined by name in one <code>/v1/resolve</code> call. `
      + (fixes.length ? `${fixes.length} needed the ontology — e.g. ${fixes.slice(0,3).join(", ")} — spellings a plain text match would silently drop.` : `every name matched outright.`);
  })();
  </script>
</body>
</html>