D3.js geoPath map returning Error: <path> attribute d: Expected number

Viewed 572

I'm having a problem drawing a map in D3.js

The code below works fine for some json files but on the data I need to use it's returning a string of errors similar to this:

Error: attribute d: Expected number, "….21478248741596,NaNL547.70469610…".

And displaying this image (which although pretty is not the map of England I was hoping for)

This is the code:

const width = 800
const height = 800

const svg = d3.select('svg')
  .append('g')
  .attr('class', 'map');

const projection = d3.geoMercator()

Promise.all([
  d3.json('https://raw.githubusercontent.com/joewretham/d3_map_project/main/Clinical_Commissioning_Groups__April_2019__Boundaries_EN_BUC.json')
]).then(
  d => ready(null, d[0], d[1])
);

function ready(error, data) {

  var fixed = data.features.map(function(feature) {
    return turf.rewind(feature, {
      reverse: true
    });
  });

  const path = d3.geoPath().projection(projection);

  projection.fitSize([width, height], {
    "type": "FeatureCollection",
    "features": fixed
  })

  svg.append('g')
    .attr('class', 'countries')
    .selectAll('path')
    .data(fixed)
    .enter().append('path')
    .attr('d', path)
    .style('fill', "teal")
    .style('stroke', 'white')
    .style('opacity', 0.8)
    .style('stroke-width', 0.3);
};
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src='https://npmcdn.com/@turf/turf/turf.min.js'></script>
<svg id="partitionSVG" width="800" height="800">"</svg>

Does anyone know what's happening here? Because the code works with other sets of data I know it's something to do with the coordinates and I'm guessing they need to be transformed in some way but I don't know enough about geographic data to know what to do.

Thanks for any suggestions

Joe

1 Answers

Your JSON file has some uncommon projection. Normally, coordinates are given in lat/long. However, because of many reasons, like the fact that the earth is a sphere and sphere projections are mathematically difficult, several different projections exist. The most common is WGS84 (also called 4326, by its ID), and uses lat/long format. But, it turns out several national systems exist. In your case, it is the UK national system OSGB36.

Using this package, I was able to transform the projection from OSGB36 to WGS84, which gives the correct result:

const width = 800
const height = 800

const svg = d3.select('svg')
  .append('g')
  .attr('class', 'map');

console.log(window);

const projection = d3.geoMercator()

Promise.all([
  d3.json('https://raw.githubusercontent.com/joewretham/d3_map_project/main/Clinical_Commissioning_Groups__April_2019__Boundaries_EN_BUC.json')
]).then(
  d => ready(null, d[0], d[1])
);

function ready(error, data) {
  data = returnExports.toWGS84(data);

  var fixed = data.features.map(function(feature) {
    return turf.rewind(feature, {
      reverse: true
    });
  });

  const path = d3.geoPath().projection(projection);

  projection.fitSize([width, height], {
    "type": "FeatureCollection",
    "features": fixed
  })

  svg.append('g')
    .attr('class', 'countries')
    .selectAll('path')
    .data(fixed)
    .enter().append('path')
    .attr('d', path)
    .style('fill', "teal")
    .style('stroke', 'white')
    .style('opacity', 0.8)
    .style('stroke-width', 0.3);
};
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src='https://npmcdn.com/@turf/turf/turf.min.js'></script>
<script src='https://unpkg.com/proj4@2.6.2/dist/proj4-src.js'></script>
<script src='https://unpkg.com/gbify-geojson@0.2.1/index.js'></script>
<svg id="partitionSVG" width="800" height="800">"</svg>

If you have access to the generation of the file, you can change the input file once, or you can just call this function whenever necessary.

Related