D3js: как проектировать топографические карты?

учитывая растр ГИС с данными высот,как спроектировать топографическую карту в D3js ?

есть ли какой-либо пример рельефа / топографических карт обрезанных земель, сделанных с использованием D3js ?


не работает: Я исследовал возможность .tif > gdal_contour.py > .shp > topojson > d3js без успеха.

Я используйте makefile которые содержат все мои команды. Поскольку моя область интересов (Франция) - это урожай земельных участков, то gdal_contour.py подход создает сломанные изолинии, которые не создают замкнутых полигонов. Кроме того, конечный результат SVG терпит неудачу. Единственный пример топографической карты D3, который я знаю об Исландии, который, как остров, избегает этой проблемы: обрезка страны из мира не приводит к нарушению изолиний.

enter image description here

nb: этот проект является частью проекта #Wikipedia #wikimaps.

2 ответов


топографическая карта теперь на D3js, с полным рабочим процессом makefile ! См.http://bl.ocks.org/hugolpz/6279966 (

0. Требования:

  • географические зоны: вы можете настроить свою географическую область интереса, отредактировав одну строку в каждом из 2 файлов: makefile#boxing и html#Geo-frame_borders с вашими собственными десятичными координатами FO w,N,E, s границы, что-то вроде:

    var WNES = {"target":" France"," W": -5.3,"N": 51.6," E": 10.2," S": 41.0 };

  • программное обеспечение: make, curl, unzip, gdal (включая ogr, gdal_calc.py, gdal_polygonize.py), nodejs, topojson. Полезно:touch. Затем makefile удается загрузить источники, обработать их и вывести один файл topojson, который может использовать предоставленный код D3js.

1. Сохранить в имя папки: / topo_map / topo.МК

# topojsoning: 
final.json:  levels.json
    topojson --id-property none --simplify=0.5 -p name=elev -o final.json -- levels.json
    # simplification approach to explore further. Feedbacks welcome. 

# shp2jsoning:
levels.json: levels.shp
    ogr2ogr -f GeoJSON -where "elev < 10000" levels.json levels.shp

# merge
levels.shp: level0001.shp level0050.shp level0100.shp level0200.shp level0500.shp level1000.shp level2000.shp level3000.shp level4000.shp level5000.shp
    ogr2ogr levels.shp level0001.shp
    ogr2ogr -update -append levels.shp level0050.shp
    ogr2ogr -update -append levels.shp level0100.shp
    ogr2ogr -update -append levels.shp level0200.shp
    ogr2ogr -update -append levels.shp level0500.shp
    ogr2ogr -update -append levels.shp level1000.shp
    ogr2ogr -update -append levels.shp level2000.shp
    ogr2ogr -update -append levels.shp level3000.shp
    ogr2ogr -update -append levels.shp level4000.shp
    ogr2ogr -update -append levels.shp level5000.shp

# Polygonize slices:
level0001.shp: level0001.tif
    gdal_polygonize.py level0001.tif -f "ESRI Shapefile" level0001.shp level_0001 elev
level0050.shp: level0050.tif
    gdal_polygonize.py level0050.tif -f "ESRI Shapefile" level0050.shp level_0050 elev
level0100.shp: level0100.tif
    gdal_polygonize.py level0100.tif -f "ESRI Shapefile" level0100.shp level_0100 elev
level0200.shp: level0200.tif
    gdal_polygonize.py level0200.tif -f "ESRI Shapefile" level0200.shp level_0200 elev
level0500.shp: level0500.tif
    gdal_polygonize.py level0500.tif -f "ESRI Shapefile" level0500.shp level_0500 elev
level1000.shp: level1000.tif
    gdal_polygonize.py level1000.tif -f "ESRI Shapefile" level1000.shp level_1000 elev
level2000.shp: level2000.tif
    gdal_polygonize.py level2000.tif -f "ESRI Shapefile" level2000.shp level_2000 elev
level3000.shp: level3000.tif
    gdal_polygonize.py level3000.tif -f "ESRI Shapefile" level3000.shp level_3000 elev
level4000.shp: level4000.tif
    gdal_polygonize.py level4000.tif -f "ESRI Shapefile" level4000.shp level_4000 elev
level5000.shp: level5000.tif
    gdal_polygonize.py level5000.tif -f "ESRI Shapefile" level5000.shp level_5000 elev

# Raster slicing:
level0001.tif: crop.tif
    gdal_calc.py -A crop.tif --outfile=level0001.tif --calc="1*(A>0)"       --NoDataValue=0
level0050.tif: crop.tif
    gdal_calc.py -A crop.tif --outfile=level0050.tif --calc="50*(A>50)"      --NoDataValue=0
level0100.tif: crop.tif
    gdal_calc.py -A crop.tif --outfile=level0100.tif --calc="100*(A>100)"     --NoDataValue=0
level0200.tif: crop.tif
    gdal_calc.py -A crop.tif --outfile=level0200.tif --calc="200*(A>200)"     --NoDataValue=0
level0500.tif: crop.tif
    gdal_calc.py -A crop.tif --outfile=level0500.tif --calc="500*(A>500)"     --NoDataValue=0
level1000.tif: crop.tif
    gdal_calc.py -A crop.tif --outfile=level1000.tif --calc="1000*(A>1000)"     --NoDataValue=0
level2000.tif: crop.tif
    gdal_calc.py -A crop.tif --outfile=level2000.tif --calc="2000*(A>2000)"     --NoDataValue=0
level3000.tif: crop.tif
    gdal_calc.py -A crop.tif --outfile=level3000.tif --calc="3000*(A>3000)"     --NoDataValue=0
level4000.tif: crop.tif
    gdal_calc.py -A crop.tif --outfile=level4000.tif --calc="4000*(A>4000)"     --NoDataValue=0
level5000.tif: crop.tif
    gdal_calc.py -A crop.tif --outfile=level5000.tif --calc="5000*(A>5000)"     --NoDataValue=0

# boxing: 
crop.tif: ETOPO1_Ice_g_geotiff.tif
    gdal_translate -projwin -5.3 41.0 10.2 51.6 ETOPO1_Ice_g_geotiff.tif crop.tif
    # ulx uly lrx lry  // W S E N

# unzip:
ETOPO1_Ice_g_geotiff.tif: ETOPO1.zip
    unzip ETOPO1.zip
    touch ETOPO1_Ice_g_geotiff.tif

# download:
ETOPO1.zip:
    curl -o ETOPO1.zip 'http://www.ngdc.noaa.gov/mgg/global/relief/ETOPO1/data/ice_surface/grid_registered/georeferenced_tiff/ETOPO1_Ice_g_geotiff.zip'

clean:
    rm `ls | grep -v 'zip' | grep -v 'Makefile'`
# Makefile v4b (@Lopez_lz) 

2. Создать данные запустив makfile :

cd ./topo_map
make -f ./topo.mk

3. D3js & HTML код с автофокусом:

<!-- language: html -->
<style>
svg { border: 5px solid #333; background-color: #C6ECFF;}

/* TOPO */
path.Topo_1 { fill:#ACD0A5; stroke: #0978AB; stroke-width: 1px; }
path.Topo_50 {fill: #94BF8B; }
path.Topo_100 {fill: #BDCC96; }
path.Topo_200 {fill: #E1E4B5; }
path.Topo_500 {fill: #DED6A3; }
path.Topo_1000 {fill:#CAB982 ; }
path.Topo_2000 {fill: #AA8753; }
path.Topo_3000 {fill: #BAAE9A; }
path.Topo_4000 {fill: #E0DED8 ; }
path.Topo_5000 {fill: #FFFFFF ; }
.download { 
  background: #333; 
  color: #FFF; 
  font-weight: 900; 
  border: 2px solid #B10000; 
  padding: 4px; 
  margin:4px;
}
</style>
<body>
<script src="http://code.jquery.com/jquery-2.0.2.min.js"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script>
// 1. -------------- SETTINGS ------------- //
// Geo-frame_borders in decimal ⁰: France
var WNES = { "W": -5.3, "N":51.6, "E": 10.2, "S": 41.0 };

// Geo values of interest :
var latCenter = (WNES.S + WNES.N)/2,
    lonCenter = (WNES.W + WNES.E)/2,
    geo_width = (WNES.E - WNES.W),
    geo_height= (WNES.N - WNES.S);
// HTML expected frame dimensions
var width  = 600,
    height = width * (geo_height / geo_width);

// Projection: projection, reset scale and translate
var projection = d3.geo.equirectangular()
      .scale(1)
      .translate([0, 0]);

// SVG injection:
var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

// Path
var path = d3.geo.path()
    .projection(projection)
    .pointRadius(4);

// Data (getJSON: TopoJSON)
d3.json("final.json", showData);

// 2. ---------- FUNCTION ------------- //
function showData(error, fra) {
    var Levels = topojson.feature(fra, fra.objects.levels);

// Focus area box compute for derive scale & translate.
// [​[left, bottom], [right, top]​] // E   W    N   S
var b = path.bounds(Levels),
    s = 1 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height),
    t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2];

// Projection update
projection
    .scale(s)
    .translate(t);

//Append Topo polygons
    svg.append("path")
        .datum(Levels)
        .attr("d", path)
    svg.selectAll(".levels")
        .data(topojson.feature(fra, fra.objects.levels).features)
      .enter().append("path")
        .attr("class", function(d) { return "Topo_" + d.properties.name; })
        .attr("data-elev", function(d) { return d.properties.name; })
        .attr("d", path)

}
</script>
<br />
<div>
    <a class="download ac-icon-download" href="javascript:javascript: (function () { var e = document.createElement('script'); if (window.location.protocol === 'https:') { e.setAttribute('src', 'https://raw.github.com/NYTimes/svg-crowbar/gh-pages/svg-crowbar.js'); } else { e.setAttribute('src', 'http://nytimes.github.com/svg-crowbar/svg-crowbar.js'); } e.setAttribute('class', 'svg-crowbar'); document.body.appendChild(e); })();"><!--⤋--><big>⇩</big> Download</a> -- Works on Chrome. Feedback me for others web browsers ?
</div>
<br />
</body>
</html>

4. Результат будет именно такой: (применяется к вашей области интересов)

enter image description here

если вы публикуете карту(ы) онлайн, пожалуйста, поделитесь ссылкой :)

Примечание: поощрение +1 Добро пожаловать.


Если кто-то ищет обновление, вот код сборки, который я получил сегодня. Требуется мне вручную загрузить .zip-файл и переместите его в каталог topo_map, а затем несколько изменений (выделены жирным шрифтом):

# topojsoning (USE GEO2TOPO not TOPOJSON): 
final.json: levels.json
    geo2topo --id-property none --simplify=0.5 -p name=elev -o final.json -- levels.json
    # simplification approach to explore further. Feedbacks welcome. 

# shp2jsoning:
levels.json: levels.shp
    ogr2ogr -f GeoJSON -where "elev < 10000" levels.json levels.shp

# merge
levels.shp: level0001.shp level0050.shp level0100.shp level0200.shp level0500.shp level1000.shp level2000.shp level3000.shp level4000.shp level5000.shp
    ogr2ogr levels.shp level0001.shp
    ogr2ogr -update -append levels.shp level0050.shp
    ogr2ogr -update -append levels.shp level0100.shp
    ogr2ogr -update -append levels.shp level0200.shp
    ogr2ogr -update -append levels.shp level0500.shp
    ogr2ogr -update -append levels.shp level1000.shp
    ogr2ogr -update -append levels.shp level2000.shp
    ogr2ogr -update -append levels.shp level3000.shp
    ogr2ogr -update -append levels.shp level4000.shp
    ogr2ogr -update -append levels.shp level5000.shp

# Polygonize slices:
level0001.shp: level0001.tif
    gdal_polygonize.py level0001.tif -f "ESRI Shapefile" level0001.shp level_0001 elev
level0050.shp: level0050.tif
    gdal_polygonize.py level0050.tif -f "ESRI Shapefile" level0050.shp level_0050 elev
level0100.shp: level0100.tif
    gdal_polygonize.py level0100.tif -f "ESRI Shapefile" level0100.shp level_0100 elev
level0200.shp: level0200.tif
    gdal_polygonize.py level0200.tif -f "ESRI Shapefile" level0200.shp level_0200 elev
level0500.shp: level0500.tif
    gdal_polygonize.py level0500.tif -f "ESRI Shapefile" level0500.shp level_0500 elev
level1000.shp: level1000.tif
    gdal_polygonize.py level1000.tif -f "ESRI Shapefile" level1000.shp level_1000 elev
level2000.shp: level2000.tif
    gdal_polygonize.py level2000.tif -f "ESRI Shapefile" level2000.shp level_2000 elev
level3000.shp: level3000.tif
    gdal_polygonize.py level3000.tif -f "ESRI Shapefile" level3000.shp level_3000 elev
level4000.shp: level4000.tif
    gdal_polygonize.py level4000.tif -f "ESRI Shapefile" level4000.shp level_4000 elev
level5000.shp: level5000.tif
    gdal_polygonize.py level5000.tif -f "ESRI Shapefile" level5000.shp level_5000 elev

# Raster slicing:
level0001.tif: crop.tif
    gdal_calc.py -A crop.tif --outfile=level0001.tif --calc="1*(A>0)"       --NoDataValue=0
level0050.tif: crop.tif
    gdal_calc.py -A crop.tif --outfile=level0050.tif --calc="50*(A>50)"      --NoDataValue=0
level0100.tif: crop.tif
    gdal_calc.py -A crop.tif --outfile=level0100.tif --calc="100*(A>100)"     --NoDataValue=0
level0200.tif: crop.tif
    gdal_calc.py -A crop.tif --outfile=level0200.tif --calc="200*(A>200)"     --NoDataValue=0
level0500.tif: crop.tif
    gdal_calc.py -A crop.tif --outfile=level0500.tif --calc="500*(A>500)"     --NoDataValue=0
level1000.tif: crop.tif
    gdal_calc.py -A crop.tif --outfile=level1000.tif --calc="1000*(A>1000)"     --NoDataValue=0
level2000.tif: crop.tif
    gdal_calc.py -A crop.tif --outfile=level2000.tif --calc="2000*(A>2000)"     --NoDataValue=0
level3000.tif: crop.tif
    gdal_calc.py -A crop.tif --outfile=level3000.tif --calc="3000*(A>3000)"     --NoDataValue=0
level4000.tif: crop.tif
    gdal_calc.py -A crop.tif --outfile=level4000.tif --calc="4000*(A>4000)"     --NoDataValue=0
level5000.tif: crop.tif
    gdal_calc.py -A crop.tif --outfile=level5000.tif --calc="5000*(A>5000)"     --NoDataValue=0

# boxing: 
crop.tif: ETOPO1_Ice_g_geotiff.tif
    gdal_translate -projwin -84.9 47.0 -69.9 33.7 ETOPO1_Ice_g_geotiff.tif crop.tif
    # ulx uly lrx lry  // W N E S <- Coordinate order
# unzip:
ETOPO1_Ice_g_geotiff.tif: ETOPO1.zip
    unzip ETOPO1.zip
    touch ETOPO1_Ice_g_geotiff.tif

# download:
#ETOPO1.zip:
 #   curl -o ETOPO1.zip 'http://www.ngdc.noaa.gov/mgg/global/relief/ETOPO1/data/ice_surface/grid_registered/georeferenced_tiff/ETOPO1_Ice_g_geotiff.zip'

clean:
    rm `ls | grep -v 'zip' | grep -v 'Makefile'`
# Makefile v4b (@Lopez_lz)