d3 / d3-geo-projection

Extended geographic projections for d3-geo.
https://observablehq.com/collection/@d3/d3-geo-projection
Other
1.1k stars 201 forks source link

More customizable Wagner projections (and others)? #205

Open TJung1968 opened 3 years ago

TJung1968 commented 3 years ago

Hello,

a while ago, I suggested the "Customizable Wagner" to be added to d3, which was a way to modify Wagner VII/VIII in certain ways, using Wagner’s transformation method ("Das Umbeziffern"). Now, there’s more of the same kind: A solution to modify Wagner I/II, III, VI and IX; and a few other projections with equally spaced parallels along the central meridian. This time, most of the code wasn’t written by me, but Peter Denner pete.denner@gmail.com – of course, he’s fine with me proposing the stuff here, and we both agree to contribute this code under D3’s licence.

But since I still don’t know how to contribute properly, I’ve again put the code, some demos and explanations on my website. A brief overview with links to interactive demos is here: https://map-projections.net/d3-customizable-wagner/

Now, there are a few differences to the existing geoWagner() function, e.g. the length of the pole line is set differently on Wagner I/II and III. The reason for this (and some other things) is provided in my (rather lengthy, sorry) blogpost https://blog.map-projections.net/more-umbeziffern-for-d3-geo-projections

There are some things that I’m not sure about yet: – The function name wagnerEquallySpacedParallels() seems a bit awkward – but nothing else came to my mind. I’m open to suggestions. – Since the setting of pole line length is different, maybe it’s better to use a different name for the parameter .poleline()? – The aspect ratio of the resulting projection is sometimes influenced by not one but two parameters. While I needed that to render certain existing projections (see blogpost), I’m not sure if this makes sense if the projections are added to d3-geo-projections.

And before I forget it – as a side effect there’s also a new function that renders the Apian II projection. If any questions remain, feel free to ask!

Fil commented 3 years ago

Wow, great work!

Regarding the aspect ratio, I don't think it would be useful to have two functions doing essentially the same; but I wonder if this should not be a feature of d3-geo for all projections.

I'd also like to look into the issue you mention of having to specify the parent projection with a number—this seems very different from what we do elsewhere; for example, interrupted projections have a parent (raw) projection, which is called when the projection is instantiated.

It's a lot to process, and I'm not sure I've managed to understand every detail of the very in-depth presentation, but it would be good to upgrade d3-geo-projection to cover these new cases.

TJung1968 commented 3 years ago

Thank you! It really would be nice to have a better way to specify the parent projection. As for the presentation… well, I know I’m not very good at explaining complicated things comprehensibly. Not even in my mother tongue, not to mention in English. :-/ If you’ve got specific question, again feel free to ask and I’ll try to do my best…

TJung1968 commented 3 years ago

Hello again, it really would be nice to have something different than a (arbitrarily chosen) number to specify the parent projection, because – Peter Denner came up with something new!

Just like the the function proposed above applies “Umbeziffern” on projections with equally spaced parallels, the new function applies it to equal-area projections. Currently, I’m in the process of testing, but I’ll soon have something to present here. At the moment, the block where the parent projections is set looks like this:

if (variant == 2) {
    var parent = d3Geo.geoSinusoidalRaw;
  } else if (variant == 5) {
    var parent = d3Geo.geoMollweideRaw;
  } else if (variant == 8) {
    var parent = d3Geo.geoAzimuthalEqualAreaRaw;
  } else if (variant == 54) {
    var parent = d3Geo.geoEckert4Raw;
  } else if (variant == 55) {
    var parent = d3Geo.geoEqualEarthRaw;
  } else if (variant == 56) {
    var parent = d3Geo.geoCrasterRaw;
  } else if (variant == 57) {
    var parent = d3Geo.geoSinuMollweideRaw;
  }

Of course, the parent projections should at least be ordered alphabetically with continuously ascending numbers… but still, that’s not a great solution…

Fil commented 3 years ago

A solution could be to pass the raw (parent) projection as an argument to the constructor, ie instead of d3.geoWagnerEquallySpacedParallels().parentProjection(9), use d3.geoWagnerEquallySpacedParallels(d3.geoAizmuthalEquidistantRaw) (with a default value)?

TJung1968 commented 3 years ago

I think I tried that a few months ago. As far as I remember (i.e. I may be wrong here), the problem was when I called the projection mutator, currently:

mutate = d3Geo.geoProjectionMutator(wagnerEquallySpacedParallelsRaw),
projection = mutate(poleline, parallels, ratio, xfactor, parentProjection);

and it always broke when I passed a string on parentProjection.

Fil commented 3 years ago

OK I'll give it a try. I see that the code is available on your blog.

TJung1968 commented 3 years ago

Yes, the one for wagnerEquallySpacedParallels() is there, not the one for the equal-area projections. But that doesn’t matter because the selection of the parent projection doesn’t differ there.