contour functionality using different projections
See original GitHub issueI tried to use the contour transform for other projections than identity for an array that covers the whole world.
My source file is a GeoTiff containing the global annual precipitation (for year 2016 based on CFSv2 data):
The geographic coordinate system is WGS:84 (epsg:4326), origin (top-left corner) is (-180.02,87.58), pixel size is (1.0,-1.0) for x and y respectively and the file has a width of 360 pixels and a height of 168 pixels.
I managed to visualise this file using the identity projection, but once I try to use the mercator projection, I start to see certain issues:
While I see that it applies a certain projection transformation, it gets wrongly projected.
I then did some trial and error with the data transformation and prepared 6 datafiles. 3 files had a longitude from -180 to 180, one normal, one upside down, and one upside down and vertically rolled 84 pixels (array height divide by 2`) and 3 files where longitude goes from 0 to 360.
Eventually found out that the version that goes from 0 to 360 in longitude, which is placed upside down and vertically rolled by half the height of the array is positioned correctly on the mercator projection:
But somehow everything below 0 degrees latitude is cut-off and there is a stiching issue at the geographical prime meridian. That are two problems, but quite glad I got this far.
Then I tried to change the rotate parmeters. I see that the geographical lines (equator, international date line, arctic- and antartic circle) are reprojecting nicely, but the contours are giving some strange results:
Where mercator still has some stable rotations (rotate0), other projections (eg. robinson) have not any rotation which show the contours somehow right.
The following specification were used (vega-editor link):
Click to expand
{
"$schema": "https://vega.github.io/schema/vega/v4.json",
"width": 500,
"height": 500,
"autosize": "none",
"signals": [
{
"name": "contour_data",
"value": "-180:180",
"bind": {"input": "select", "options": [
"-180:180", "-180:180 flipud", "-180:180 flipud roll vert",
"0:360", "0:360 flipud", "0:360 flipud roll vert"]}
},
{
"name": "contour_proj",
"value": "identity",
"bind": {"input": "select", "options": ["identity", "basemap"]}
},
{
"name": "basemap_proj",
"value": "mercator",
"bind": {"input": "select", "options": ["mercator", "robinson"]}
},
{
"name": "contour_fill", "value": true,
"bind": {"input": "radio", "options": [true, false]}
},
{
"name": "scale",
"value": 78,
"bind": {"input": "range", "min": 54, "max": 202, "step": 8}
},
{
"name": "rotate0",
"value": 0,
"bind": {"input": "select", "options": [-360, -270,-180, -90, 0, 90, 180, 270, 360]}
},
{
"name": "rotate1",
"value": 0,
"bind": {"input": "select", "options": [-360, -270,-180, -90, 0, 90, 180, 270, 360]}
},
{
"name": "rotate2",
"value": 0,
"bind": {"input": "select", "options": [-180, -135, -90,-45, 0, 45, 90, 135, 180]}
},
{
"name": "center0",
"value": 0,
"bind": {"input": "select", "options": [-180, -135, -90,-45, 0, 45, 90, 135, 180]}
},
{
"name": "center1",
"value": 0,
"bind": {"input": "select", "options": [-89,-45, 0, 45, 89]}
},
{
"name": "precipitation",
"update": "if(contour_data === '-180:180', data('p-180:180')[0], if(contour_data === '-180:180 flipud', data('p-180:180-flipud')[0], if(contour_data === '-180:180 flipud roll vert', data('p-180:180-flipud-roll-vert')[0], if(contour_data === '0:360', data('p0:360')[0], if(contour_data === '0:360 flipud', data('p0:360-flipud')[0], data('p0:360-flipud-roll-vert')[0])))))"
}
],
"data": [
{
"name": "sphere",
"values": [{"type": "Sphere"} ],
"transform": [{"type": "geopath", "projection": "proj_basemap" } ]
},
{
"name": "graticule",
"transform": [{"type": "graticule"}, {"type": "geopath", "projection": "proj_basemap"}]
},
{
"name": "geographic_lines",
"url": "https://raw.githubusercontent.com/martynafford/natural-earth-geojson/master/110m/physical/ne_110m_geographic_lines.json",
"format": {"type": "json", "property": "features"},
"transform": [{"type": "geopath", "projection": "proj_basemap"}]
},
{
"name": "world",
"url": "https://raw.githubusercontent.com/vega/datalib/master/test/data/world-110m.json",
"format": {"type": "topojson", "feature": "countries"},
"transform": [{"type": "geopath", "projection": "proj_basemap"}]
},
{
"name": "p-180:180",
"url": "https://raw.githubusercontent.com/mattijn/datasets/master/annual-precip_-180-180.json"
},
{
"name": "p-180:180-flipud",
"url": "https://raw.githubusercontent.com/mattijn/datasets/master/annual-precip_-180-180_flip-ud.json"
},
{
"name": "p-180:180-flipud-roll-vert",
"url": "https://raw.githubusercontent.com/mattijn/datasets/master/annual-precip_-180-180_flip-ud_roll-vert.json"
},
{
"name": "p0:360",
"url": "https://raw.githubusercontent.com/mattijn/datasets/master/annual-precip_0-360.json"
},
{
"name": "p0:360-flipud",
"url": "https://raw.githubusercontent.com/mattijn/datasets/master/annual-precip_0-360_flip-ud.json"
},
{
"name": "p0:360-flipud-roll-vert",
"url": "https://raw.githubusercontent.com/mattijn/datasets/master/annual-precip_0-360_flip-ud_roll-vert.json"
},
{
"name": "contours",
"transform": [
{
"type": "contour",
"values": {"signal": "precipitation.values"},
"size": [{"signal": "precipitation.width"}, {"signal": "precipitation.height"}],
"smooth": true,
"thresholds": {"signal": "sequence(0, 3000, 500)"}
}
]
}
],
"projections": [
{
"name": "proj_basemap",
"type": {"signal": "basemap_proj"},
"scale": {"signal": "scale"},
"rotate": [{"signal": "rotate0"}, {"signal": "rotate1"}, {"signal": "rotate2"}],
"center": [{"signal": "center0"}, {"signal": "center1"}],
"translate": [{"signal": "width/2"}, {"signal": "height/2"}]
},
{
"name": "proj_identity",
"type": "identity",
"scale": {"signal": "width / precipitation.width"},
"translate": [0, {"signal": "height/4"}]
}
],
"scales": [
{
"name": "color",
"type": "sequential",
"domain": [0, 3000],
"range": {"scheme": "bluepurple"}
}
],
"marks": [
{
"type": "path",
"from": {"data": "sphere"},
"encode": {
"update": {
"fill": {"value": "#fefef6"},
"stroke": {"value": null},
"path": {"field": {"signal": "if(contour_proj === 'basemap', 'path', 'null')"}}
}
}
},
{
"type": "path",
"from": {"data": "graticule"},
"clip": {"sphere": "proj_basemap"},
"interactive": false,
"encode": {
"update": {
"strokeWidth": {"value": 0.5},
"stroke": {"value": "#ddd"},
"fill": {"value": null},
"path": {"field": {"signal": "if(contour_proj === 'basemap', 'path', 'null')"}}
}
}
},
{
"type": "path",
"from": {"data": "world"},
"clip": {"sphere": "proj_basemap"},
"interactive": false,
"encode": {
"update": {
"strokeWidth": {"value": 1},
"stroke": {"value": "#dadada"},
"fill": {"value": "#ccc"},
"zindex": {"value": 0},
"path": {"field": {"signal": "if(contour_proj === 'basemap', 'path', 'null')"}}
}
}
},
{
"type": "path",
"from": {"data": "contours"},
"clip": {"sphere": "proj_basemap"},
"encode": {
"update": {
"strokeWidth": {"value": 0.5},
"stroke": {"signal": "if(contour_proj === 'identity', null, 'firebrick')"},
"fill": {"signal": "if(contour_proj === 'identity', null, if(contour_fill === false, null, scale('color', datum.value)))"},
"fillOpacity": {"value": 0.5}
}
},
"transform": [{"type": "geopath", "field": "datum", "projection": "proj_basemap"}]
},
{
"type": "path",
"from": { "data": "contours"},
"encode": {
"update": {
"strokeWidth": {"value": 0.5},
"stroke": {"signal": "if(contour_proj === 'identity', 'firebrick', null)"},
"fill": {"signal": "if(contour_proj === 'identity', if(contour_fill === false, null, scale('color', datum.value)), null)"},
"fillOpacity": {"value": 0.5}
}
},
"transform": [{"type": "geopath", "field": "datum", "projection": "proj_identity"}]
},
{
"type": "path",
"from": {"data": "geographic_lines"},
"clip": {"sphere": "proj_basemap"},
"interactive": false,
"encode": {
"update": {
"strokeWidth": {"value": 2},
"stroke": {"value": "green"},
"fill": {"value": null},
"path": {"field": {"signal": "if(contour_proj === 'basemap', 'path', 'null')"}}
}
}
},
{
"type": "path",
"from": {"data": "sphere"},
"encode": {
"update": {
"fill": {"value": null},
"stroke": {"value": "black"},
"strokeWidth": {"value": 0.5},
"strokeDash": {"value": [8, 3]},
"path": {"field": {"signal": "if(contour_proj === 'basemap', 'path', 'null')"}}
}
}
}
],
"legends": [
{
"title": "Annual Precipitation (mm)",
"orient": "top-left",
"type": "symbol",
"fill": "color",
"format": ".0f",
"clipHeight": 16,
"direction":"horizontal",
"fillColor": "#fefef6"
}
]
}
Issue Analytics
- State:
- Created 5 years ago
- Comments:8 (8 by maintainers)

Top Related StackOverflow Question
A new version of d3-contour with a weight parameter for density estimation has been released, as well as an update version of vega-geo. So this functionality will be included in the Vega release.
Using the new vega release (congrats!), I tried the
weightfunctionality withincontourstransform. The behaviour of the contours seems different to the behaviour of the contours in the notebook of @Fil (pretty awesome notebook btw!)Using a drag rotate event (specs).
The contours in the North Atlantic (between US and EU) seems to indicate that the
weightis increasing while doing amousemoveevent. That seems not right. As far as I can see, this doesn’t happen in @Fil 's notebook.I also tried to use the
This is an animated gif, but it also auto rotates in the editor.
But here seems another issue that I maybe understand. Since it calculates the
timereventstreamto make the earth auto rotate (specs).xandycoordinates located on screen, also the coordinates on the dark side of the earth are incorporated in thecontourstransform as thesexandyare next to the visible coordinates. (edit: no, I don’t think this happens)Besides that, the
timerevent worked out reasonably well, two things:timerRegarding
scaleof thecontourcolors, I now use"domain": [0,16]since I checked the values of thecontoursusingGiving:
I’ve now idea where these numbers relates to, as the original values goes from 0 to > 3000