Array.map()vs d3.selectAll()。data.enter() [英] Array.map() vs d3.selectAll().data.enter()

查看:56
本文介绍了Array.map()vs d3.selectAll()。data.enter()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图了解使用d3.selectAll.data.enter()循环数据集并绘制它的好处。

  var data = [4,8,15,16,23,42]; 

var x = d3.scale.linear()
.domain([0,d3.max(data)])
.range([0,420]);

let chartsvg = d3.select(。chart)。append(svg);

chartsvg.selectAll(rect)
.data(data)
.enter()
.append(rect)
.attr (x,0)
.attr(y,函数(d,i){
返回25 * i;
})
.attr(width ,函数(d){
返回x(d);
})
.attr(height,20)
.attr(fill,#f3b562 );

我看到d3的功能有很多好处,比如刻度,轴等等。但感觉就像使用用于循环遍历数据集的Array.map(),我可以使用更清晰的代码和更少的行来实现相同的功能,尤其是当我创建更复杂的可视化而不是像这样的简单准系统条形图时。

  var data = [4,8,15,16,23,42]; 

var x = d3.scale.linear()
.domain([0,d3.max(data)])
.range([0,420]);

let chartsvg = d3.select(。chart)。append(svg);

data.map(function(d,i){
chartsvg.append(rect)
.attr(x,0)
.attr (y,25 * i)
.attr(width,x(d))
.attr(height,20)
.attr(fill, #f3b562);
});


解决方案

D3代表数据驱动文档



D3中最强大的功能是它能够将数据绑定到DOM元素,它提供了库的名称。通过这样做,您可以通过多种方式根据绑定数据操作这些DOM元素,例如(但不限于):




  • 排序

  • 过滤器

  • 翻译

  • 样式

  • 追加

  • 删除



依此类推......



如果你没有将数据绑定到DOM元素,例如在你的问题中使用 map()方法(这与<$相同) c $ c> forEach()),您可以在开头保存几行,但最终会得到一个难以处理的代码来处理后者。让我们看看它:



map()方法



这是一个非常简单的代码,使用你的大多数片段,使用 map()方法创建条形图:



  var h = 250,w = 500,p = 40; var svg = d3.select(body)。append(svg)。attr (width,w).attr(height,h); var data = [{group:foo,value:14,name:A},{group:foo,value:35, name:B},{group:foo,value:87,name:C},{group:foo,value:12,name:D},{group:bar,值:84,名称:E},{group:bar,值:65,名称:F},{group:bar,值:34,名称:G},{group: baz,值:98,名称:H},{group:baz,值:12,名称:I},{group:baz,值:43,名称:J} ,{group:baz,价值:66,名称:K },{group:baz,值:42,name:L}]; var color = d3.scaleOrdinal(d3.schemeCategory10); var xScale = d3.scaleLinear()。range([0,w  -  p ]).domain([0,d3.max(data,function(d){return d.value})]); var yScale = d3.scaleBand()。range([0,h]).domain(data。 map(function(d){return d.name}))。padding(0.1); data.map(function(d,i){svg.append(rect)。attr(x,p).attr (y,yScale(d.name))。attr(width,xScale(d.value))。attr(height,yScale.bandwidth())。attr(fill,color(d。 group));}); var axis = d3.axisLeft(yScale); var gY = svg.append(g)。attr(transform,translate(+ p +,0)).call (轴);  

 < script src =https: //d3js.org/d3.v4.min.js\"></script>  



这似乎是一个不错的结果,酒吧都在那里。但是,无数据绑定到这些矩形。保留此代码,我们将在下面的挑战中使用它。



输入选择



现在让我们尝试使用相同的代码,但使用惯用的输入选项:



  var h = 250,w = 500,p = 40; var svg = d3.select(body)。append(svg)。attr(width,w).attr(height,h); var data = [{group:foo,value: 14,名称:A},{group:foo,值:35,名称:B},{group:foo,值:87,名称:C},{group:foo ,值:12,名称:D},{group:bar,值:84,名称:E},{group:bar,值:65,名称:F},{组:bar,值:34,名称:G},{group:baz,值:98,名称:H},{group:baz,值:12,名称:I },{group:baz,value:43,name:J},{group:baz,value:66,name:K},{group:baz,value:42, name:L}]; var color = d3.scaleOrdinal(d3.schemeCategory10); var xScale = d3.scaleLinear()。range([0,w  -  p])。domain([0,d3.max(data) ,function(d){return d.value})]); var yScale = d3.scaleBand()。range([0,h])。domain(data.map(function(d){return d.name}) ).padding(0.1); svg.selectAll(null).data(data,function(d){return d.name})。enter()。append(rect)。attr(x,p)。 attr(y,有趣ction(d){return yScale(d.name)})。attr(width,function(d){return xScale(d.value)})。attr(height,yScale.bandwidth())。attr (fill,function(d){return color(d.group)}); var axis = d3.axisLeft(yScale); var gY = svg.append(g)。attr(transform,translate (+ p +,0))。call(axis);  

 < script src =https://d3js.org/d3.v4.min.js>< / script>  



正如您所看到的,它比之前的 map()方法稍长一点,2行更长。



然而,这实际上将数据绑定到那些矩形。如果你在console.log中选择其中一个矩形的D3,你会看到类似这样的东西(在Chrome中):

  >选择
> _groups:Array(1)
> 0:数组(1)
> 0:rect
> __data__:对象
组:bar
名称:G
值:34

由于此代码实际上将数据绑定到DOM元素,因此您可以使用 map()方法。我将在下一个片段中显示此内容,该片段将用于提出挑战。



挑战



由于您的问题涉及更清晰的代码和更少的行,所以这对您来说是一个挑战。



我创建了3个按钮,一个用于 data 数组中的每个组(并且是所有组的第四个按钮) )。当您单击该按钮时,它会过滤数据并相应地更新图表:



  var h = 250,w = 500,p = 40; var svg = d3.select(body)。append(svg)。attr(width,w).attr( height,h); var g1 = svg.append(g)var g2 = svg.append(g)var data = [{group:foo,value:14,name:A}, {group:foo,value:35,name:B},{group:foo,value:87,name:C},{group:foo,value:12,name: D},{group:bar,值:84,名称:E},{group:bar,值:65,名称:F},{group:bar,值:34 ,名称:G},{group:baz,值:98,名称:H},{group:baz,值:12,名称:I},{group:baz ,值:43,名称:J},{group:baz,值:66,名称:K},{group:baz,值:42,名称:L}]; var color = d3。 scaleOrdinal(d3.schemeCategory10); var xScale = d3.scaleLinear()。range([0,w  -  p])。domain([0,d3.max(data,function(d){return d.value})] ); var yScale = d3.scaleBand()。range([0,h])。domain(data.map(function(d){return d.name}))。padding(0.1); g1.selectAll(null) .data(data,function(d){return d.name})。enter()。append(rect)。attr(x,p).attr(y,function(d){return yScale (d.name)})。attr(width,function(d){return xScale(d.value)})。attr(height,yScale.bandwidth())。attr(fill,function( d){返回颜色(d.group)})var axis = d3.axisLeft(yScale); var gY = g2.append(g)。attr(transform,translate(+ p +,0 ))。call(axis); d3.selectAll(button)。on(click,function(){var thisValue = this.id; var newData = data.filter(function(d){return d.group === thisValue;}); if(thisValue ===all){newData = data}; yScale.domain(newData.map(function(d){return d.name}))var rects = g1.selectAll(rect)。data(newData,function(d){return d.name})rects.enter ()。append(rect)。attr(x,p).attr(y,function(d){return yScale(d.name)})。attr(width,0).attr (height,yScale.bandwidth())。attr(fill,function(d){return color(d.group)})。transnsition().duration(1000).attr(width,function( d){return xScale(d.value)}); rects.transition()。duration(1000).attr(x,p).attr(y,function(d){return yScale(d.name)})。attr(width,function(d) ){return xScale(d.value)})。attr(height,yScale.bandwidth())。attr(fill,function(d){return color(d.group)}); rects.exit()。transnsition()。duration(1000).attr(width,0).remove(); gY.transition()。duration(1000).call(axis);}) 

 < script src =https://d3js.org/d3.v4.min.js>< / script>< button id =foo> Foo< / button> < button id =bar> Bar< / button>< button id =baz> Baz< / button>< button id =all> All< / button>< br>< ; br>  



清洁代码以某种方式基于意见,但我们可以轻松地衡量规模。



因此,这是挑战:尝试创建一个相同的代码,但使用 map()方法,即不绑定任何数据。做我在这里做的所有过渡。您将尝试重新创建的代码是 on(click)函数内的所有代码。



之后,我们将比较代码的大小和惯用的输入,更新和退出选择的大小。



Chalenge#2



在绑定数据时,显示D3功能可能会更加有趣。 / p>

在这个新代码中,我在1秒后对原始数据数组进行排序,并重新绘制图表。然后,点击更新按钮,我将另一个数据数据绑定到条形图。



这里的好处是关键函数,它将每个条与每个数据点相关联,在本例中为 name 属性:

  .data(数据,函数(d){
返回d.name
})

以下是代码,请在点击更新前等待1秒钟:



  var h = 250,w = 500,p = 40; var svg = d3.select(body)。append(svg)。attr( width,w).attr(height,h); var data2 = [{group:foo,value:10,name:A},{group:foo,value:20,name: B},{group:foo,value:30,name:C},{group:foo,value:40,name:D},{group:bar,value: 50,名称:E },{group:bar,值:60,名称:F},{group:bar,值:70,名称:G},{group:baz,值:80,名称:H},{group:baz,value:85,name:I},{group:baz,value:90,name:J},{group:baz,value :95,名称:K},{group:baz,值:100,名称:L}]; var data = [{group:foo,value:14,name:A} ,{group:foo,value:35,name:B},{group:foo,value:87,name:C},{group:foo,value:12,name: D},{group:bar,值:84,名称:E},{group:bar,值:65,名称:F},{group:bar,值: 34,姓名:G},{group:baz,值:98,姓名:H},{group:baz,值:12,姓名:I},{group:baz ,值:43,名称:J},{group:baz,值:66,名称:K},{group:baz,值:42,名称:L}]; var color = d3.scaleOrdinal(d3.schemeCategory10); var xScale = d3.scaleLinear()。range([0,w  -  p])。domain([0,d3.max(data,function(d){return d .value})]); var yScale = d3.scaleBa nd()。range([0,h])。domain(data.map(function(d){return d.name}))。padding(0.1); svg.selectAll(。bars)。data(data ,function(d){return d.name})。enter()。append(rect)。attr(class,bars)。attr(x,p).attr(y, function(d){return yScale(d.name)})。attr(width,function(d){return xScale(d.value)})。attr(height,yScale.bandwidth())。attr (填充,函数(d){返回颜色(d.group)})var axis = d3.axisLeft(yScale); var gY = svg.append(g)。attr(transform,translate( + p +,0))。call(axis); setTimeout(function(){data.sort(function(a,b){return d3.ascending(a.value,b.value)}); yScale.domain(data.map(function(d){return d.name})); svg.selectAll(。bars)。data(data,function(d){return d.name})。transnsition()。duration(500).attr(y,function(d){return yScale(d .name)})。attr(width,function(d){return xScale(d.value)}); gY.transition()。duration(1000).call(axis);},1000)d3.selectAll(button)。on(click,function(){svg.selectAll(。bars)。data (data2,function(d){return d.name})。transnsition()。duration(500).attr(y,function(d){return yScale(d.name)})。attr(width ,function(d){return xScale(d.value)}); gY.transition()。duration(1000).call(axis);}) 

 < script src =https://d3js.org/d3.v4.min.js>< / script> ;< button>更新< / button>< br>< br>  



你的挑战是一样的:改变 .on(点击)里面的代码,就是这个......

  svg.selectAll(。bars)。data(data2,function(d){
return d.name
} )
.transition()
.duration(500)
.attr(y,function(d){
return yScale(d.name)
} )
.attr(width, function(d){
return xScale(d.value)
});

gY.transition()。duration(1000).call(axis);

...代码相同,但对于您而言 map()方法。



请注意,由于我对条形图进行了排序,因此您无法再按数据数组的索引更改这些条形图!



< h3>结论

第一次绘制元素时, map()方法可以为您节省2行。但是,它会让事情变得非常麻烦。


I am trying to understand what's benefit of using d3.selectAll.data.enter() to loop through a dataset and plot it.

  var data = [4, 8, 15, 16, 23, 42];

  var x = d3.scale.linear()
      .domain([0, d3.max(data)])
      .range([0, 420]);

  let chartsvg = d3.select(".chart").append("svg");

  chartsvg.selectAll("rect")
    .data(data)
    .enter()
    .append("rect")
    .attr("x", 0)
    .attr("y", function(d, i) {
    return 25*i;
  })
    .attr("width", function(d) {
    return x(d);
  })
    .attr("height", 20)
    .attr("fill", "#f3b562");

I see a lot of benefit of d3's functionalities like scale, axes, etc. But it feels like using Array.map() for looping through the dataset, I can achieve the same functionality with much cleaner code and fewer lines, especially when I am creating a much more complex visualization and not a simple barebones bar chart like this.

  var data = [4, 8, 15, 16, 23, 42];

  var x = d3.scale.linear()
      .domain([0, d3.max(data)])
      .range([0, 420]);

  let chartsvg = d3.select(".chart").append("svg");

  data.map(function(d, i){
    chartsvg.append("rect")
      .attr("x", 0)
      .attr("y", 25*i)  
      .attr("width", x(d))
      .attr("height", 20)
      .attr("fill", "#f3b562");
  });

解决方案

D3 stands for Data-Driven Documents

The most powerful feature in D3, which gives the very name of the library, is its ability to bind data to DOM elements. By doing this, you can manipulate those DOM elements based on the bound data in several ways, such as (but not limited to):

  • Sort
  • Filter
  • Translate
  • Style
  • Append
  • Remove

And so on...

If you don't bind data to the DOM elements, for instance using the map() approach in your question (which is the same of a forEach()), you may save a couple of lines at the beginning, but you will end up with an awkward code to deal with latter. Let's see it:

The map() approach

Here is a very simple code, using most of your snippet, to create a bar chart using the map() approach:

var h = 250,
  w = 500,
  p = 40;
var svg = d3.select("body")
  .append("svg")
  .attr("width", w)
  .attr("height", h);

var data = [{
  group: "foo",
  value: 14,
  name: "A"
}, {
  group: "foo",
  value: 35,
  name: "B"
}, {
  group: "foo",
  value: 87,
  name: "C"
}, {
  group: "foo",
  value: 12,
  name: "D"
}, {
  group: "bar",
  value: 84,
  name: "E"
}, {
  group: "bar",
  value: 65,
  name: "F"
}, {
  group: "bar",
  value: 34,
  name: "G"
}, {
  group: "baz",
  value: 98,
  name: "H"
}, {
  group: "baz",
  value: 12,
  name: "I"
}, {
  group: "baz",
  value: 43,
  name: "J"
}, {
  group: "baz",
  value: 66,
  name: "K"
}, {
  group: "baz",
  value: 42,
  name: "L"
}];


var color = d3.scaleOrdinal(d3.schemeCategory10);

var xScale = d3.scaleLinear()
  .range([0, w - p])
  .domain([0, d3.max(data, function(d) {
    return d.value
  })]);

var yScale = d3.scaleBand()
  .range([0, h])
  .domain(data.map(function(d) {
    return d.name
  }))
  .padding(0.1);

data.map(function(d, i) {
  svg.append("rect")
    .attr("x", p)
    .attr("y", yScale(d.name))
    .attr("width", xScale(d.value))
    .attr("height", yScale.bandwidth())
    .attr("fill", color(d.group));
});

var axis = d3.axisLeft(yScale);
var gY = svg.append("g").attr("transform", "translate(" + p + ",0)")
  .call(axis);

<script src="https://d3js.org/d3.v4.min.js"></script>

It seems to be a nice result, the bars are all there. However, there is no data bound to those rectangles. Keep this code, we'll use it in the challenge below.

Enter selections

Now let's try the same code, but using the idiomatic "enter" selection:

var h = 250,
  w = 500,
  p = 40;
  
var svg = d3.select("body")
  .append("svg")
  .attr("width", w)
  .attr("height", h);

var data = [{
  group: "foo",
  value: 14,
  name: "A"
}, {
  group: "foo",
  value: 35,
  name: "B"
}, {
  group: "foo",
  value: 87,
  name: "C"
}, {
  group: "foo",
  value: 12,
  name: "D"
}, {
  group: "bar",
  value: 84,
  name: "E"
}, {
  group: "bar",
  value: 65,
  name: "F"
}, {
  group: "bar",
  value: 34,
  name: "G"
}, {
  group: "baz",
  value: 98,
  name: "H"
}, {
  group: "baz",
  value: 12,
  name: "I"
}, {
  group: "baz",
  value: 43,
  name: "J"
}, {
  group: "baz",
  value: 66,
  name: "K"
}, {
  group: "baz",
  value: 42,
  name: "L"
}];


var color = d3.scaleOrdinal(d3.schemeCategory10);

var xScale = d3.scaleLinear()
  .range([0, w - p])
  .domain([0, d3.max(data, function(d) {
    return d.value
  })]);

var yScale = d3.scaleBand()
  .range([0, h])
  .domain(data.map(function(d) {
    return d.name
  }))
  .padding(0.1);

svg.selectAll(null)
  .data(data, function(d) {
    return d.name
  })
  .enter()
  .append("rect")
  .attr("x", p)
  .attr("y", function(d) {
    return yScale(d.name)
  })
  .attr("width", function(d) {
    return xScale(d.value)
  })
  .attr("height", yScale.bandwidth())
  .attr("fill", function(d) {
    return color(d.group)
  });

var axis = d3.axisLeft(yScale);
var gY = svg.append("g").attr("transform", "translate(" + p + ",0)")
  .call(axis);

<script src="https://d3js.org/d3.v4.min.js"></script>

As you can see, it's a little longer than the previous map() method, 2 lines longer.

However, this actually binds data to those rectangles. If you console.log a D3 selection of one of those rectangles, you'll see something like this (in Chrome):

> Selection
  > _groups: Array(1)
    > 0: Array(1)
      > 0: rect
        > __data__: Object
          group: "bar"
          name: "G"
          value: 34

Since this code actually binds data to the DOM elements, you can manipulate them in a way that would be cumbersome (to say the least) using the map() approach. I'll show this in the next snippet, which will be used to propose a challenge.

Challenge

Since your question talks about cleaner code and fewer lines, here is a challenge for you.

I created 3 buttons, one for each groups in the data array (and a fourth one for all the groups). When you click the button, it filters the data and updates the chart accordingly:

var h = 250,
  w = 500,
  p = 40;
var svg = d3.select("body")
  .append("svg")
  .attr("width", w)
  .attr("height", h);

var g1 = svg.append("g")
var g2 = svg.append("g")

var data = [{
  group: "foo",
  value: 14,
  name: "A"
}, {
  group: "foo",
  value: 35,
  name: "B"
}, {
  group: "foo",
  value: 87,
  name: "C"
}, {
  group: "foo",
  value: 12,
  name: "D"
}, {
  group: "bar",
  value: 84,
  name: "E"
}, {
  group: "bar",
  value: 65,
  name: "F"
}, {
  group: "bar",
  value: 34,
  name: "G"
}, {
  group: "baz",
  value: 98,
  name: "H"
}, {
  group: "baz",
  value: 12,
  name: "I"
}, {
  group: "baz",
  value: 43,
  name: "J"
}, {
  group: "baz",
  value: 66,
  name: "K"
}, {
  group: "baz",
  value: 42,
  name: "L"
}];


var color = d3.scaleOrdinal(d3.schemeCategory10);

var xScale = d3.scaleLinear()
  .range([0, w - p])
  .domain([0, d3.max(data, function(d) {
    return d.value
  })]);

var yScale = d3.scaleBand()
  .range([0, h])
  .domain(data.map(function(d) {
    return d.name
  }))
  .padding(0.1);

g1.selectAll(null)
  .data(data, function(d) {
    return d.name
  })
  .enter()
  .append("rect")
  .attr("x", p)
  .attr("y", function(d) {
    return yScale(d.name)
  })
  .attr("width", function(d) {
    return xScale(d.value)
  })
  .attr("height", yScale.bandwidth())
  .attr("fill", function(d) {
    return color(d.group)
  })


var axis = d3.axisLeft(yScale);
var gY = g2.append("g").attr("transform", "translate(" + p + ",0)")
  .call(axis);

d3.selectAll("button").on("click", function() {

  var thisValue = this.id;

  var newData = data.filter(function(d) {
    return d.group === thisValue;
  });
  
  if(thisValue === "all"){ newData = data};

  yScale.domain(newData.map(function(d) {
    return d.name
  }))

  var rects = g1.selectAll("rect")
    .data(newData, function(d) {
      return d.name
    })

  rects.enter()
    .append("rect")
    .attr("x", p)
    .attr("y", function(d) {
      return yScale(d.name)
    })
    .attr("width", 0)
    .attr("height", yScale.bandwidth())
    .attr("fill", function(d) {
      return color(d.group)
    })
    .transition()
    .duration(1000)
    .attr("width", function(d) {
      return xScale(d.value)
    });

  rects.transition()
    .duration(1000)
    .attr("x", p)
    .attr("y", function(d) {
      return yScale(d.name)
    })
    .attr("width", function(d) {
      return xScale(d.value)
    })
    .attr("height", yScale.bandwidth())
    .attr("fill", function(d) {
      return color(d.group)
    });

  rects.exit()
    .transition()
    .duration(1000)
    .attr("width", 0)
    .remove();

  gY.transition().duration(1000).call(axis);
})

<script src="https://d3js.org/d3.v4.min.js"></script>
<button id="foo">Foo</button>
<button id="bar">Bar</button>
<button id="baz">Baz</button>
<button id="all">All</button>
<br>
<br>

A cleaner code is somehow opinion-based, but we can easily measure size.

Thus, here is the challenge: try to create a code that does the same, but using the map() approach, that is, without binding any data. Do all the transitions I'm doing here. The code you will try to recreate is all the code inside the on("click") function.

After that, we'll compare the size of your code and the size of an idiomatic "enter", "update" and "exit" selections.

Chalenge #2

This challenge number 2 may be even more interesting to show D3 capabilities when it comes to binding data.

In this new code, I'm sorting the original data array after 1 second, and redrawing the chart. Then, clicking on the "update" button, I'm binding another data array to the bars.

The nice thing here is the key function, that associates each bar to each data point using, in this case, the name property:

.data(data, function(d) {
    return d.name
})

Here is the code, please wait 1 second before clicking "update":

var h = 250,
  w = 500,
  p = 40;

var svg = d3.select("body")
  .append("svg")
  .attr("width", w)
  .attr("height", h);

var data2 = [{
  group: "foo",
  value: 10,
  name: "A"
}, {
  group: "foo",
  value: 20,
  name: "B"
}, {
  group: "foo",
  value: 30,
  name: "C"
}, {
  group: "foo",
  value: 40,
  name: "D"
}, {
  group: "bar",
  value: 50,
  name: "E"
}, {
  group: "bar",
  value: 60,
  name: "F"
}, {
  group: "bar",
  value: 70,
  name: "G"
}, {
  group: "baz",
  value: 80,
  name: "H"
}, {
  group: "baz",
  value: 85,
  name: "I"
}, {
  group: "baz",
  value: 90,
  name: "J"
}, {
  group: "baz",
  value: 95,
  name: "K"
}, {
  group: "baz",
  value: 100,
  name: "L"
}];

var data = [{
  group: "foo",
  value: 14,
  name: "A"
}, {
  group: "foo",
  value: 35,
  name: "B"
}, {
  group: "foo",
  value: 87,
  name: "C"
}, {
  group: "foo",
  value: 12,
  name: "D"
}, {
  group: "bar",
  value: 84,
  name: "E"
}, {
  group: "bar",
  value: 65,
  name: "F"
}, {
  group: "bar",
  value: 34,
  name: "G"
}, {
  group: "baz",
  value: 98,
  name: "H"
}, {
  group: "baz",
  value: 12,
  name: "I"
}, {
  group: "baz",
  value: 43,
  name: "J"
}, {
  group: "baz",
  value: 66,
  name: "K"
}, {
  group: "baz",
  value: 42,
  name: "L"
}];

var color = d3.scaleOrdinal(d3.schemeCategory10);

var xScale = d3.scaleLinear()
  .range([0, w - p])
  .domain([0, d3.max(data, function(d) {
    return d.value
  })]);

var yScale = d3.scaleBand()
  .range([0, h])
  .domain(data.map(function(d) {
    return d.name
  }))
  .padding(0.1);

svg.selectAll(".bars")
  .data(data, function(d) {
    return d.name
  })
  .enter()
  .append("rect")
  .attr("class", "bars")
  .attr("x", p)
  .attr("y", function(d) {
    return yScale(d.name)
  })
  .attr("width", function(d) {
    return xScale(d.value)
  })
  .attr("height", yScale.bandwidth())
  .attr("fill", function(d) {
    return color(d.group)
  })

var axis = d3.axisLeft(yScale);
var gY = svg.append("g").attr("transform", "translate(" + p + ",0)")
  .call(axis);

setTimeout(function() {

  data.sort(function(a, b) {
    return d3.ascending(a.value, b.value)
  });

  yScale.domain(data.map(function(d) {
    return d.name
  }));

  svg.selectAll(".bars").data(data, function(d) {
      return d.name
    })
    .transition()
    .duration(500)
    .attr("y", function(d) {
      return yScale(d.name)
    })
    .attr("width", function(d) {
      return xScale(d.value)
    });

  gY.transition().duration(1000).call(axis);

}, 1000)

d3.selectAll("button").on("click", function() {

  svg.selectAll(".bars").data(data2, function(d) {
      return d.name
    })
    .transition()
    .duration(500)
    .attr("y", function(d) {
      return yScale(d.name)
    })
    .attr("width", function(d) {
      return xScale(d.value)
    });

  gY.transition().duration(1000).call(axis);
})

<script src="https://d3js.org/d3.v4.min.js"></script>
<button>Update</button>
<br>
<br>

Your challenge here is the same: change the code inside .on("click"), which is just this...

svg.selectAll(".bars").data(data2, function(d) {
        return d.name
    })
    .transition()
    .duration(500)
    .attr("y", function(d) {
        return yScale(d.name)
    })
    .attr("width", function(d) {
        return xScale(d.value)
    });

gY.transition().duration(1000).call(axis);

... to a code that does the same, but for your map() approach.

Notice that, since I sorted the bars, you cannot change them by the index of your data array anymore!

Conclusion

The map() approach may save you 2 lines when you first draw the elements. However, it will make things terribly cumbersome latter on.

这篇关于Array.map()vs d3.selectAll()。data.enter()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆