【问题标题】:D3js: How to design topographic maps?D3js:如何设计地形图?
【发布时间】:2013-08-18 15:14:19
【问题描述】:

给定一个带有高程数据的 GIS 栅格,如何在 D3js 中设计地形图?

有没有使用 D3js 制作的耕地地形/地形图示例?


不工作:我探索了.tif > gdal_contour.py > .shp > topojson > d3js 的可能性,但没有成功。

use a makefile 包含我所有的命令。由于我感兴趣的区域(法国)是一片土地,gdal_contour.py 方法会生成不创建闭合多边形的断开等值线。此外,SVG 最终结果失败。我知道的唯一一个 D3 地形图示例is about Iceland,作为一个岛屿,它避免了这个问题:将这个国家从世界中裁剪出来并不会导致等值线断开。

nb:该项目是#Wikipedia #wikimaps 项目的一部分。

【问题讨论】:

    标签: d3.js gis gdal topojson


    【解决方案1】:

    现在 D3js 上的地形图,具有完整的 makefile 工作流程!请参阅http://bl.ocks.org/hugolpz/6279966

    0。要求:

    • 地理区域:您可以通过在 2 个文件中的每一个中编辑一行来自定义您感兴趣的地理区域:makefile#boxing 和 html#Geo-frame_borders 使用您自己的 W,N 小数坐标,E,S 边框,类似于:

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

    • 软件: makecurlunzipgdal(包括ogrgdal_calc.pygdal_polygonize.py)、nodejs、@ 987654332@。有帮助:touch。然后,makefile 设法下载源代码,对其进行处理,并输出提供的 D3js 代码可以使用的单个 topojson 文件。

    1.保存到文件夹名称:/topo_map/topo.mk

    # 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 (@hugo_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.结果将是这样的:(适用于您感兴趣的领域)

    如果您在线发布地图,请分享链接:)

    注意:鼓励 +1 欢迎。

    【讨论】:

    • Requirements#Softwares:我之前在不同时间安装了这些软件。如果有人得到她/他的部分或全部sudo apt-get install 命令来运行,感谢在这里或在线分享:)
    • 我在尝试上述 Makefile 时看到以下错误:Input file size is 21601, 10801 Computed -srcwin 10482 2940 930 -635 from projected window. Error: Computed -srcwin 10482 2940 930 -635 has negative width and/or height. *** [crop.tif] Error code 1
    • 任务crop.tif: 失败。似乎您的宽度和/或高度是负数。此外,检查您的-projwin 值及其在gdal_translate -projwin -5.3 41.0 10.2 51.6 ETOPO1_Ice_g_geotiff.tif crop.tif 行中的位置。顺序是西、北、东、南边界,但如果您绘制太平洋地图并穿越180th meridian,则可能需要更改。
    • 谢谢。我完全按照上面显示的方式使用 Makefile。我会摆弄坐标,看看我能不能找出问题所在
    • @Annan:是的,应该可以。 1)您可以删除任务#boxing,因为您将其全部保留,并相应地编辑文件的其余部分。如果是这样,您将处理一个巨大的 TIFF 文件。因此,我还建议您对 ETOPO1_Ice_g_geotiff.tif 进行简单的调整大小,使其宽度约为 2~4000px。然后你就可以玩了。
    【解决方案2】:

    如果有人在寻找更新,这是我今天运行的构建代码。要求我手动下载 .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) 
    

    【讨论】:

    • 谢谢尼克。差异在diffchecker.com/lFTXbr1A 处可见。您能否澄清为什么在您的答案中进行这些编辑?至于 CLI 命令 topojson => geo2json,CLI 有变化吗?对于下载 url,理想情况下,只要提供的 url 失败,您只需在 makefile 中查找并更新 url。对于WSEN => WNESgdal_translate manual 似乎证实了我的初始配置。由于 gdal 很聪明,您的可能也可以使用 :)
    • 是的,我将编辑我的回复以反映更改。主要有两个变化,topojson => geo2json 和裁剪的坐标顺序。
    猜你喜欢
    • 2015-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多