d3.js bar charts transitioning between multiple cs

2019-06-07 03:47发布

I'm working on visualizing term frequencies for some Twitter data I've collected about the Winter Olympics. I'd like to make a histogram using d3 that will visualize these counts and allow users to toggle between datasets for each day of the games. I have an initial visualization I'm fairly happy with here, modified from this example. However, when clicking the "Update" button in the lower right corner, this simply overlays a new histogram on top of the existing one. Both datasets are CSV's, and there are seven of them total that I'd like to be able to toggle through.

I've searched Stack Overflow for other relevant tips and found this, but it doesn't seem to cover quite what I need: Transitioning bar chart with combobox variable toggle in d3.js. The main issue with using this example is that it creates transitions between different histograms using the same json data, whereas I need to create transitions between histograms that each pull data from different CSV data files. Here's my code so far. Major points of confusion are commented appropriately. Any guidance would be greatly appreciated.

<!DOCTYPE html>
<meta charset="utf-8">
<style>

body {
  font: 10px sans-serif;
}

.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

.bar {
  fill: #3c9dd0;
}

.bar:hover {
  fill: #ffc073;
 }

.x.axis path {
  display: none;
}

.d3-tip {
  line-height: 1;
  font-weight: bold;
  padding: 12px;
  background: rgba(0, 0, 0, 0.8);
  color: #fff;
  border-radius: 2px;
}

/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
  box-sizing: border-box;
  display: inline;
  font-size: 10px;
  width: 100%;
  line-height: 1;
  color: rgba(0, 0, 0, 0.8);
  content: "\25BC";
  position: absolute;
  text-align: center;
}

/* Style northward tooltips differently */
.d3-tip.n:after {
  margin: -1px 0 0 0;
  top: 100%;
  left: 0;
}
</style>
<body>
<button onclick="update()">Update</button>

<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<script>

var margin = {top: 40, right: 20, bottom: 30, left: 40},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

// var formatPercent = d3.format(".0%");

var x = d3.scale.ordinal()
    .rangeRoundBands([0, width], .1);

var y = d3.scale.linear()
    .range([height, 0]);

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");

var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");

var tip = d3.tip()
  .attr('class', 'd3-tip')
  .offset([-10, 0])
  .html(function(d) {
    return "<strong>Term: </strong><span style='color:orangered'>" + d.letter + "</span>"      + " <strong>Frequency:</strong> <span style='color:orangered'>" + d.frequency + "</span>";
})

var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

svg.call(tip);

d3.csv("data1.csv", type, function(error, data) {
  x.domain(data.map(function(d) { return d.letter; }));
  y.domain([0, d3.max(data, function(d) { return d.frequency; })]);

  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);

  svg.append("g")
      .attr("class", "y axis")
      .call(yAxis)
    .append("text")
      .attr("transform", "rotate(-90)")
      .attr("y", 6)
      .attr("dy", ".71em")
      .style("text-anchor", "end")
      .text("Frequency");

  svg.selectAll(".bar")
      .data(data)
    .enter().append("rect")
      .attr("class", "bar")
      .attr("x", function(d) { return x(d.letter); })
      .attr("width", x.rangeBand())
      .attr("y", function(d) { return y(d.frequency); })
      .attr("height", function(d) { return height - y(d.frequency); })
      .on('mouseover', tip.show)
      .on('mouseout', tip.hide)

});

// Test on updating data. Confusion starts here.
function update(){
  d3.csv("data2.csv", type, function(error, data) {
  x.domain(data.map(function(d) { return d.letter; }));
  y.domain([0, d3.max(data, function(d) { return d.frequency; })]);

  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);

  svg.append("g")
      .attr("class", "y axis")
      .call(yAxis)
     .append("text")
      .attr("transform", "rotate(-90)")
      .attr("y", 6)
      .attr("dy", ".71em")
      .style("text-anchor", "end")
      .text("Frequency");

  svg.selectAll(".bar")
      .data(data)
    .enter().append("rect")
      .attr("class", "bar")
      .attr("x", function(d) { return x(d.letter); })
      .attr("width", x.rangeBand())
      .attr("y", function(d) { return y(d.frequency); })
      .attr("height", function(d) { return height - y(d.frequency); })
      .on('mouseover', tip.show)
      .on('mouseout', tip.hide)

})

// Confusion continues here. I know I need a transition, but I have
// no idea how to implement it.
d3.transition().selectAll(".bar")
      .attr('d', function(d) {return y(d.frequency);})

}

function type(d) {
  d.frequency = +d.frequency;
  return d;
}

</script>

1条回答
SAY GOODBYE
2楼-- · 2019-06-07 04:02

In your update function, you're executing the same code as initially -- you need to take into account the existing elements here. The code should look something like this:

// update axes
svg.select(".x").call(xAxis);
svg.select(".y").call(yAxis);

// update bars
var sel = svg.selectAll(".bar").data(data);
// add new bars
sel.enter().append("rect")
  .attr("class", "bar");
// update existing (and new) bars
sel.attr("x", function(d) { return x(d.letter); })
  .attr("width", x.rangeBand())
  .attr("y", function(d) { return y(d.frequency); })
  .attr("height", function(d) { return height - y(d.frequency); })
  .on('mouseover', tip.show)
  .on('mouseout', tip.hide);
// remove bars no longer present
sel.exit().remove();

To make the change with a transition, add .transition() before the update of the attributes, e.g.

sel.transition()
  .attr("x", function(d) { return x(d.letter); })
  // etc
查看更多
登录 后发表回答