Interpolating along lines with custom projections

I would like to be able to create custom map projections for use with Plot. As I understand it, to do this one needs to create a projection stream via d3.geoTransform. While I can transform points this way, lines don’t get correctly interpolated via adaptive sampling.

Am I missing something obvious? Is there any way to do this?

Example and explanation here:

Thanks.

In this case I think you have to use d3.geoProjection

Plot.plot({
  projection: {
    type: ({ width, height }) => {
      const radians = (deg) => (Math.PI * deg) / 180;
      return d3.geoProjection((lambda, phi) => [
        lambda * Math.cos(phi) + width / 2,
        phi
      ]).fitSize([width, height], {type: "Sphere"});
    }
  },
  marks: [Plot.graticule({ strokeOpacity: 1 })]
})

Or, if you want to use the lower level geoTransform and control yourself how lines are interpolated, you’ll have to define the lineStart and lineEnd methods.

With geoProjection (and all spherical projections) these are handled by the projection stream, which does many things (including rotation, clipping, etc.), and in particular does the line adaptive sampling in https://github.com/d3/d3-geo/blob/main/src/projection/resample.js#L21

1 Like

That’s great - thanks. It simplifies things significantly as it looks like the function expected by geoProjection assumes angles in radians and there’s no need to worry about explicit scaling and translation as this can be handled by fitSize.

projection: {
    type: ({ width, height }) => {
      return d3
        .geoProjection((λ, ϕ) => [λ * Math.cos(ϕ), ϕ])
        .fitSize([width, height], { type: "Sphere" });
    }
  }

(don’t know if it’s considered bad practice to use Greek letters directly in code, but to me it makes the code clearer when handling projections.)

1 Like