Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexpected GeoJSON rectangles (type:"Polygon") on Mercator projection #1405

Open
iliatimofeev opened this issue Aug 22, 2018 · 6 comments
Open
Labels
discussion For discussing proposed changes feature-request For requesting new features or transforms

Comments

@iliatimofeev
Copy link

While exploring issue I made synthetic geojson to determine the problem.

Synthetic GeoJSON data
{
    "type": "FeatureCollection",
    "features": [{
        "id": "0",
        "type": "Feature",
        "properties": {
            "color": "#1f77b4"
        },
        "geometry": {
            "type": "Polygon",
            "coordinates": [
                [
                    [100.0, -50.0],
                    [100.0, 30.0],
                    [10.0, 30.0],
                    [10.0, -50.0],
                    [100.0, -50.0]
                ]
            ]
        },
        "bbox": [10.0, -50.0, 100.0, 30.0]
    }, {
        "id": "1",
        "type": "Feature",
        "properties": {
            "color": "#ff7f0e"
        },
        "geometry": {
            "type": "Polygon",
            "coordinates": [
                [
                    [-10.0, -90.0],
                    [-10.0, -20.0],
                    [-100.0, -20.0],
                    [-100.0, -90.0],
                    [-10.0, -90.0]
                ]
            ]
        },
        "bbox": [-100.0, -90.0, -10.0, -20.0]
    }, {
        "id": "2",
        "type": "Feature",
        "properties": {
            "color": "#2ca02c"
        },
        "geometry": {
            "type": "Polygon",
            "coordinates": [
                [
                    [-110.0, -100.0],
                    [-110.0, -30.0],
                    [-180.0, -30.0],
                    [-180.0, -100.0],
                    [-110.0, -100.0]
                ]
            ]
        },
        "bbox": [-180.0, -100.0, -110.0, -30.0]
    }],
    "bbox": [-180.0, -100.0, 100.0, 30.0]
}

A bit strange results of Vega (left), I expected the same I can get with leaflet.js (right).

vega leaflet

You can reproduce issue in vega editor or check bl.ock with both charts and dataset.

Summary of existing differences:

  1. Horizontal parts of rectangles are curved in contrast to graticule on the same projection.
  2. Polygons are shown as holes, but geometry objects fulfills "rfc7946. 3.1.6. Polygon description" and contains list of positions in counterclockwise order, which should be interpreted as exterior border.
  3. Green rectangle( id: 2) intentionally contains invalid point [-110.0, -100.0]. Leaflet.js clips it on the south with valid limit. Vega moves it to north and that causes wrong image in case of insignificant rounding errors as you can see in issue wrong 'Antarctica' iliatimofeev/gpdvega#1
Vega source
{
  "$schema": "https://vega.github.io/schema/vega/v4.json",
  "autosize": "pad",
  "padding": 5,
  "width": 300,
  "height": 300,
  "data": [
    {"name": "graticule", "transform": [{"type": "graticule"}]},
    {
      "name": "image",
      "values": {
        "type": "FeatureCollection",
        "features": [
          {
            "id": "0",
            "type": "Feature",
            "properties": {"color": "#1f77b4"},
            "geometry": {
              "type": "Polygon",
              "coordinates": [
                [[100, -50], [100, 30], [10, 30], [10, -50], [100, -50]]
              ]
            },
            "bbox": [10, -50, 100, 30]
          },
          {
            "id": "1",
            "type": "Feature",
            "properties": {"color": "#ff7f0e"},
            "geometry": {
              "type": "Polygon",
              "coordinates": [
                [[-10, -90], [-10, -20], [-100, -20], [-100, -90], [-10, -90]]
              ]
            },
            "bbox": [-100, -90, -10, -20]
          },
          {
            "id": "2",
            "type": "Feature",
            "properties": {"color": "#2ca02c"},
            "geometry": {
              "type": "Polygon",
              "coordinates": [
                [
                  [-110, -100],
                  [-110, -30],
                  [-180, -30],
                  [-180, -100],
                  [-110, -100]
                ]
              ]
            },
            "bbox": [-180, -100, -110, -30]
          }
        ],
        "bbox": [-180, -100, 100, 30]
      },
      "format": {"type": "json", "property": "features"}
    }
  ],
  "projections": [
    {
      "name": "projection",
      "size": {"signal": "[width, height]"},
      "fit": {"signal": "data('graticule')"},
      "type": "mercator"
    }
  ],
  "marks": [
    {
      "type": "shape",
      "from": {"data": "graticule"},
      "encode": {
        "update": {
          "strokeWidth": {"value": 1},
          "stroke": {"value": "#ddd"},
          "fill": {"value": null}
        }
      },
      "transform": [{"type": "geoshape", "projection": "projection"}]
    },
    {
      "name": "marks",
      "type": "shape",
      "from": {"data": "image"},
      "encode": {
        "update": {
          "stroke": {"field": "properties.color"},
          "fill": {"field": "properties.color"},
          "opacity": {"value": 0.3}
        }
      },
      "transform": [{"type": "geoshape", "projection": "projection"}]
    }
  ]
}
@iliatimofeev
Copy link
Author

Seems like it is the same on d3. bl.ock

image

@jheer
Copy link
Member

jheer commented Aug 22, 2018

Looks like this may be an issue for d3-geo. Vega doesn't do any custom processing of the GeoJSON here, it hands it off to the d3-geo projections and path utilities.

I do notice some different results if I adjust the precision and clipAngle parameters for the mercator projection (e.g., set "precision": 100 and the angled edges go away). However, I'm unable to find settings that perfectly match the Leaflet results. If I set "clipAngle": 180 the "holes" in the projection appear to reverse...

@iliatimofeev
Copy link
Author

I'm afraid that I'm not familiar with d3 to file issue :) all my experience is limited by copypasting Mike Bostock’s Block with my data. :( Could you push issue downstream to d3.geo?

@iliatimofeev
Copy link
Author

It comes that d3.geo uses some GeoJSON-like format, that is not conforms current specification rfc7946.

Spherical polygons also require a winding order convention to determine which side of the polygon is the inside: the exterior ring for polygons smaller than a hemisphere must be clockwise, while the exterior ring for polygons larger than a hemisphere must be anticlockwise. Interior rings representing holes must use the opposite winding order of their exterior ring. This winding order convention is also used by TopoJSON and ESRI shapefiles; however, it is the opposite convention of GeoJSON’s RFC 7946. (Also note that standard GeoJSON WGS84 uses planar equirectangular coordinates, not spherical coordinates, and thus may require stitching to remove antimeridian cuts.)

So somewhere data should be converted from rfc7946 GeoJSON to d3.geo format. And a question is where? I can do it on my side but it will mean that vega does not conform GeoJSON specification too.

@iliatimofeev
Copy link
Author

I have found an example workarounds:

  1. "parts of rectangles are curved"
    geostitch --segment? d3/d3-geo-projection#75
    https://beta.observablehq.com/@fil/wgs84-resampling
  2. Polygons are shown as holes
    GeoJSON (RFC 7946) compability d3/d3-geo#104 (comment)

I think that format suggested in #1319 could be extended with coordinates. For being it could be just a label (rfc and d3) then it can be extended with formal description of coordinate system object.

"format": {
      "type": "geojson",
      "feature": "features", // like topojson or jpath 
      "properties": "foreign" // default value "nested"
      "coordinates": "rfc7946" // default value "d3geo"
}

@jheer would you accept a PR for that or it out of scope?

@jheer
Copy link
Member

jheer commented Oct 8, 2018

Yes, I'd be happy to receive and review a PR along these lines! The right place to start would be the vega/vega-loader repo, which contains all the format processing logic. One might add a dedicated "geojson" type and update the "topojon" loader to subsequently route through that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion For discussing proposed changes feature-request For requesting new features or transforms
Projects
None yet
Development

No branches or pull requests

2 participants