双击欧洲数据可视化

问题描述 投票:2回答:1

我想创建一个欧洲的等值区域地图,可以缩放。我还希望看到当用户双击某个国家/地区时,相关国家/地区会被缩放并划分为多个区域(NUTS 2),每个区域都会根据第二个度量进行着色。

这里有一个例子:enter image description here

假设欧洲由5个国家组成:Country1,...,Country5。每个国家都根据第一项措施着色(假设居民人数)。当用户双击Country4时,地图将被缩放,以便Country4位于屏幕的中心并完全查看。相邻的国家可能会被裁剪和模糊。

Country4现在显示为由其区域(R1,...,R6)组成。这些地区根据第二项措施(假设人均收入)着色。在第二种情况下,我希望未选择的国家(因此国家1,2,3和5)仍然按照措施1着色。

所以我想要一些like this,但能够双击并更详细地查看每个国家。

我怎么能这样做?我没有找到对我有用的例子。

我发现these json filesthis one我认为它们很有用(但我不知道如何使用它们)。

谢谢


我发现this file代表坚果2(地区)和this代表坚果0(国家)。

我如何合并两者?这个想法是从nuts2.json开始并添加nuts0.json的信息,但我怎么能用geometriesarcs?我不想创造不一致的地方..

json d3.js data-visualization geojson topojson
1个回答
3
投票

这是一个非常广泛的问题,包含几个问题和目标(地图缩放,等值线创建,两个分层地图),因此,任何答案都将是广泛的 - 但不一定无益。我的答案不会解决问题中的每个问题,但应该有助于创建您的预期最终愿景。我将重点关注似乎是关键问题:

我还希望看到当用户双击某个国家/地区时,相关国家/地区会被缩放并划分为多个区域,每个区域都会根据第二个度量进行着色。

你说“也”,这表明这是次要的,但你的图片和标题似乎更关注两层效应,并且有许多关于等值的例子和问题,但很少有关于互动的两层地图。

我认为关键的挑战是细分区域,为此,您需要在父区域和子区域之间使用某种公共标识符。在您的geojson或topojson中,您可以根据需要添加必要的标识符。理想情况下,您的geojson可能如下所示:

家长/国家:

{ 
    "type":"Feature",
    "properties"{ "country":NAME ... },
    "geometry": { ... }
} 

儿童/地区:

{ 
    "type":"Feature",
    "properties"{ "country":NAME, "regionName": NAME ... },
    "geometry": { ... }
} 

单击某个国家/地区(或双击等任何其他事件)时,您希望根据共享标识符绘制子区域:

country.on("click", function(d) {
  // remove other regions
  d3.selectAll(".region").remove();

  // filter out relevant regions of a geojson of all regions 
  var countryRegions = geojson.features.filter(function(region) { 
    return region.properties.country == d.properties.country;
  })
  // append the regions
  svg.selectAll(".region")
   .data(countryRegions)
   .enter()
   .append()
   .attr("class",".region")
})

如果您使用标准化命名的geojson文件,则可以使用文件名作为共享属性,执行以下操作:

country.on("click", function(d) {
  // remove other regions
  d3.selectAll(".region").remove();

  // get appropriate geojson:
  d3.json(d.properties.country+".json", function(error, regions) {

     // draw region features

  }) 

})

您可以通过在点击/其他事件中添加类似:country.style("opacity",0.4)的内容来提高点击/其他事件的国家/地区的透明度,模糊会增加一点复杂性。要么应该增强两个分层效果。在与国家打交道时不需要裁剪 - 国家很少重叠,无论如何,新特征通常都是在旧特征之上绘制的(这消除了由于坐标不精确造成的任何视觉重叠)。

这就是两层效应,使用相同的原则,您可以轻松创建三层地图,用子区域填充选定区域。


在此基础上,我将简要介绍缩放:

使用包含区域的geojson / topojson,然后可以更改投影以反映要素的范围 - 这允许您缩放到这些要素:

projection.fitSize([width,height],geojsonObject);

请注意,如果过滤一系列要素,fitSizefitExtent将无效,除非您将要素放在要素集中(并且都需要v4):

var featureCollection = {type:"FeatureCollection",features:features};

要完成平滑缩放,您需要使用transition.attrTween转换投影。这有点棘手,因为您需要插入投影平移和投影比例(并且取决于地图投影和类型,可能是旋转)。

或者,您可以通过操纵svg进行缩放,但有很多关于如何实现此效果的示例和问题(我在下面的示例中使用了其他方法)。

以上内容将允许您:缩放到区域,绘制相关区域以及区域/视图之间的过渡。

我创建了一个简单的通用示例,使用虚拟地理数据,即operational here,(使用单击事件),关键部分在下面有更多的评论(除了转换函数,请参阅示例以查看它)。此示例需要大量调整以匹配您的预期数据和可视化。

我使用了一些未在下面的代码中声明的变量(请参阅example获取完整代码),但它们大多数是标准的:geo​​Path(path),geoProjection(projection),宽度,高度等,还有baseProjection是首发投影。我也使用虚拟数据,因此我使用d3.geoIdentity而不是更标准的投影。

// get the parent geojson
d3.json("geojson.json", function(error, geojson) {
  if (error) throw error;

  // get the regions:
  d3.json("geojsonSubdivisions.json", function(error, subdivisions) {
    if (error) throw error;

  // a color scale for the countries:
  var color = d3.scaleLinear().range(["steelblue","darkblue"]).domain([0,4]);
  // a color scale for the regions:
  var subdivisionColor = ["lightsalmon","salmon","coral"];

  // refine the two projections, one for the default/base, and one for the current      
  baseProjection.fitSize([width,height],geojson);
  projection.fitSize([width,height],geojson);

  // append the countries:
  svg.append("g")
    .attr("class", "topLevel")
    .selectAll("path")
    .data(geojson.features)
    .enter()
    .append("path")
    .attr("fill",function(d,i) { return color(i); })
    .attr("opacity",0.7)
    .attr("d", path)
    .style("stroke","black")
    .style("stroke-width",0)
    // style on mouseover:
    .on("mouseover", function() {
        d3.select(this)
          .style("stroke-width",15)
          .raise();
    })
    // undo mouseover styles:
    .on("mouseout", function(d,i) {
        d3.select(this)
          .style("stroke-width", 0 );
    })
    // now zoom in when clicked and show subdivisions:
    .on("click", function(d) {
        // remove all other subdivisions:
        d3.selectAll(".subdivision")
          .remove();

        // get new features:
        var features = subdivisions.features.filter(function(feature) { return feature.id == d.id });

        // draw new features
        svg.selectAll(null)
          .data(features)
          .enter()
          .append("path")
          .attr("class","subdivision")
          .attr("fill", function(d,i) { return subdivisionColor[i] })
          .attr("d", path)
          .style("stroke","black")
          .style("stroke-width",0)
          .on("click", function() {
            zoom(projection,baseProjection); // zoom out when clicked
            d3.selectAll(".subdivision")     
              .remove();    // remove regions when clicked
          })
          // style on mouseover
          .on("mouseover", function() {
                d3.select(this)
                  .style("stroke-width",5)
                  .raise(); // raise it so stroke is not under anything
          })
          // undo style changes on mouseout
          .on("mouseout", function(d,i) {
                d3.select(this)
                  .style("stroke-width", 0 );
          })
          .raise()

        // make a feature collection of the regions:
        var featureCollection = { "type":"FeatureCollection", "features": features }

        // zoom to the selected area:
           // if current projection is default projection:
        if ( projection.translate().toString() === baseProjection.translate().toString() && projection.scale() === baseProjection.scale() ) {
            zoom(baseProjection,projection.fitExtent([[50,50],[width-50,height-50]],featureCollection));
        }
        // current projection != default, zoom out and then in:
        else {
            // provide an end projection point for the transition:
            var endProjection = d3.geoIdentity()
              .reflectY(true)
              .fitExtent([[50,50],[width-50,height-50]],featureCollection)

            zoom(projection,endProjection,baseProjection);
        }
    }); 
  });
});
© www.soinside.com 2019 - 2024. All rights reserved.