D3按行业和整体可视化数据的图表和算法解释

时间:2016-01-29 06:48:21

标签: javascript d3.js charts

我需要创建D3图表,如以下链接所示: np.nanmean

以下是图表的屏幕截图:

整体观点: D3 bubble chart (Data displayed as Overall and by Sector)

行业观点 enter image description here

我搜索过很多次,但无法找到相同的代码库或示例。所以,我不确定如何实现同样的目标。

请使用D3分享代码/指针以实现相同的图表。

提前致谢, Manish Kumar

1 个答案:

答案 0 :(得分:2)

您可以在下面找到链接中图表的代码。它在网站的源代码中。我建议你从中学习,但我不会复制它......

(function() {

var margin = {top: 20, right: 95, bottom: 10, left: 125},
    width = 970 - margin.left - margin.right,
    height,
    tickExtension = 20; // extend grid lines beyond scale range

var formatPercent = d3.format(".0%"),
    formatTenthPercent = d3.format(".1%"),
    formatNumber = d3.format(",.3s"),
    formatDollars = function(d) { return (d < 0 ? "-" : "") + "$" + formatNumber(Math.abs(d)).replace(/G$/, "B"); };

var nameAll = "S.\x26P.\xa0500 companies";

var x = d3.scale.linear()
    .domain([0, .6])
    .rangeRound([0, width - 60])
    .clamp(true)
    .nice();

var y = d3.scale.ordinal();

var y0 = d3.scale.ordinal()
    .domain([nameAll])
    .range([150]);

var r = d3.scale.sqrt()
    .domain([0, 1e9])
    .range([0, 1]);

var z = d3.scale.threshold()
    .domain([.1, .2, .3, .4, .5])
    .range(["#b35806", "#f1a340", "#fee0b6", "#d8daeb", "#998ec3", "#542788"].reverse());

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("top")
    .ticks(5)
    .tickFormat(formatPercent);

var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left")
    .tickSize(-width + 60 - tickExtension * 2, 0)
    .tickPadding(6);

var quadtree = d3.geom.quadtree()
    .x(function(d) { return d.x; })
    .y(function(d) { return d.y; });

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

d3.select(".g-graphic").append("svg")
    .style("margin-top", "20px")
    .attr("height", 80)
    .attr("width", width + margin.left + margin.right)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    .call(renderChartKey);

var gx = svg.append("g")
    .attr("class", "g-x g-axis")
    .call(xAxis);

var tickLast = gx.selectAll(".g-x .tick:last-of-type");

tickLast.select("text")
    .text(function() { return "\u2265 " + this.textContent; });

tickLast.select(function() { return this.parentNode.appendChild(this.cloneNode(true)); })
    .attr("transform", "translate(" + width + ",0)")
  .select("text")
    .text("N.A.");

var titleX = gx.append("text")
    .attr("class", "g-title")
    .attr("y", -9)
    .style("text-anchor", "end");

titleX.append("tspan")
    .attr("x", -20)
    .style("font-weight", "bold")
    .text("Effective tax rate");

titleX.append("tspan")
    .attr("x", -20)
    .attr("dy", "1em")
    .text("2007-12");

d3.tsv("http://graphics8.nytimes.com/newsgraphics/2013/05/13/corporate-taxes/ee84b0191a75f5c652087293ab0efd4710e21f94/companies.tsv", type, function(error, companies) {
  var sectors = d3.nest()
      .key(function(d) { return d.sector; })
      .entries(companies);

  // Compute the overall rate for all data.
  var overallRate = rate(d3.sum(companies, taxes), d3.sum(companies, earnings));

  // Compute the overall rate by sector.
  sectors.forEach(function(d) {
    d.rate = rate(d3.sum(d.values, taxes), d3.sum(d.values, earnings));
  });

  // Sort sectors by ascending overall rate.
  sectors.sort(function(a, b) {
    return a.rate - b.rate;
  });

  // Compute the rate for each company.
  companies.forEach(function(d) {
    d.rate = rate(d.taxes, d.earnings);
  });

  height = 120 * sectors.length;

  y
      .domain(sectors.map(function(d) { return d.key; }))
      .rangePoints([10, height], 1);

  svg.append("g")
      .attr("class", "g-y g-axis g-y-axis-sector")
      .attr("transform", "translate(-" + tickExtension + ",0)")
      .call(yAxis.scale(y))
      .call(yAxisWrap)
      .style("stroke-opacity", 0)
      .style("fill-opacity", 0)
    .selectAll(".tick text,.tick tspan")
      .attr("x", -95)
      .style("text-anchor", "start");

  svg.append("g")
      .attr("class", "g-y g-axis g-y-axis-overall")
      .attr("transform", "translate(-" + tickExtension + ",0)")
      .call(yAxis.scale(y0))
      .call(yAxisWrap);

  var companyClip = svg.append("defs").selectAll("clipPath")
      .data(companies)
    .enter().append("clipPath")
      .attr("id", function(d, i) { return "g-clip-company-" + i; })
    .append("circle")
      .attr("cx", function(d) { return d.cx; })
      .attr("cy", function(d) { return d.cy - y0(nameAll); })
      .attr("r", function(d) { return r(d.capitalization) + 20; });

  var gVoronoi = svg.append("g")
      .attr("class", "g-voronoi")

  gVoronoi.selectAll("path")
      .data(companies)
    .enter().append("path")
      .attr("clip-path", function(d, i) { return "url(#g-clip-company-" + i + ")"; })
      .on("mouseover", mouseover)
      .on("mouseout", mouseout);

  gVoronoi.call(updateVoronoi,
      function(d) { return d.cx; },
      function(d) { return d.cy + y0(nameAll); },
      420);

  var sector = svg.append("g")
      .attr("class", "g-sector")
    .selectAll("g")
      .data(sectors)
    .enter().append("g")
      .attr("transform", function(d) { return "translate(0," + y(d.key) + ")"; });

  var sectorNote = d3.select(".g-sector-notes")
      .style("opacity", 0)
      .style("display", "none")
    .selectAll("div")
      .data(sectors)
    .enter().append("div")
      .attr("class", "g-sector-note")
      .style("top", function(d) { return y(d.key) + "px"; })
      .html(function(d) { return sectorNoteByName[d.key]; });

  var sectorCompany = sector.append("g")
      .attr("class", "g-sector-company")
    .selectAll("circle")
      .data(function(d) { return d.values; })
    .enter().append("circle")
      .attr("cx", function(d) { return d.cx; })
      .attr("cy", function(d) { return d.cy - y(d.sector) + y0(nameAll); })
      .attr("r", function(d) { return r(d.capitalization); })
      .style("fill", function(d) { return isNaN(d.rate) ? null : z(d.rate); })
      .on("mouseover", mouseover)
      .on("mouseout", mouseout);

  var sectorOverall = sector.append("g")
      .attr("class", "g-overall")
      .attr("transform", function(d) { return "translate(" + x(d.rate) + "," + (y0(nameAll) - y(d.key)) + ")"; })
      .style("stroke-opacity", 0)
      .style("fill-opacity", 0);

  sectorOverall.append("line")
      .attr("y1", -100)
      .attr("y2", +127);

  var sectorOverallText = sectorOverall.append("text")
      .attr("y", -106);

  sectorOverallText.append("tspan")
      .attr("x", 0)
      .text(function(d) { return formatPercent(d.rate); });

  sectorOverallText.filter(function(d, i) { return !i; }).append("tspan")
      .attr("x", 0)
      .attr("dy", "-11")
      .style("font-size", "8px")
      .text("OVERALL");

  var overall = svg.append("g")
      .attr("class", "g-overall g-overall-all")
      .attr("transform", "translate(" + x(overallRate) + "," + y0(nameAll) + ")");

  overall.append("line")
      .attr("y1", -100)
      .attr("y2", +127);

  var overallText = overall.append("text")
      .attr("y", -106)
      .style("font-weight", "bold");

  overallText.append("tspan")
      .attr("x", 0)
      .style("font-size", "13px")
      .text(formatTenthPercent(overallRate));

  overallText.append("tspan")
      .attr("x", 0)
      .attr("dy", "-14")
      .style("font-size", "8px")
      .text("OVERALL");

  var currentView = "overall";

  d3.selectAll(".g-content button[data-view]")
      .datum(function(d) { return this.getAttribute("data-view"); })
      .on("click", transitionView);

  var searchInput = d3.select(".g-search input")
      .on("keyup", keyuped);

  var searchClear = d3.select(".g-search .g-search-clear")
      .on("click", function() {
        searchInput.property("value", "").node().blur();
        search();
      });

  var tip = d3.select(".g-tip");

  var tipMetric = tip.selectAll(".g-tip-metric")
      .datum(function() { return this.getAttribute("data-name"); });

  d3.selectAll(".g-annotations b,.g-sector-notes b")
      .datum(function() { return new RegExp("\\b" + d3.requote(this.textContent), "i"); })
      .on("mouseover", mouseoverAnnotation)
      .on("mouseout", mouseout);

  function keyuped() {
    if (d3.event.keyCode === 27) {
      this.value = "";
      this.blur();
    }
    search(this.value.trim());
  }

  function search(value) {
    if (value) {
      var re = new RegExp("\\b" + d3.requote(value), "i");
      svg.classed("g-searching", true);
      sectorCompany.classed("g-match", function(d) { return re.test(d.name) || re.test(d.sector) || (d.symbol && re.test(d.symbol)) || (d.alias && re.test(d.alias)); });
      var matches = d3.selectAll(".g-match");
      if (matches[0].length === 1) mouseover(matches.datum());
      else mouseout();
      searchClear.style("display", null);
    } else {
      mouseout();
      svg.classed("g-searching", false);
      sectorCompany.classed("g-match", false);
      searchClear.style("display", "none");
    }
  }

  function transitionView(view) {
    if (currentView === view) view = view === "overall" ? "sector" : "overall";
    d3.selectAll(".g-buttons button[data-view]").classed("g-active", function(v) { return v === view; })
    switch (currentView = view) {
      case "overall": return void transitionOverall();
      case "sector": return void transitionSector();
    }
  }

  function transitionOverall() {
    gVoronoi.style("display", "none");

    var transition = d3.transition()
        .duration(750);

    transition.select("svg")
        .delay(720)
        .attr("height", 420 + margin.top + margin.bottom)
        .each("end", function() {
          gVoronoi.call(updateVoronoi,
            function(d) { return d.cx; },
            function(d) { return d.cy + y0(nameAll); },
            420);
        });

    transition.select(".g-annotations-overall")
        .each("start", function() { this.style.display = "block"; })
        .style("opacity", 1);

    transition.select(".g-sector-notes")
        .style("opacity", 0)
        .each("end", function() { this.style.display = "none"; });

    transition.selectAll(".g-y-axis-sector")
        .style("stroke-opacity", 0)
        .style("fill-opacity", 0);

    transition.selectAll(".g-y-axis-overall")
        .style("stroke-opacity", 1)
        .style("fill-opacity", 1);

    var transitionOverall = transition.select(".g-overall-all")
        .delay(x(overallRate))
        .style("stroke-opacity", 1)
        .style("fill-opacity", 1);

    transitionOverall.select("line")
        .attr("y2", +127);

    transitionOverall.select("text")
        .attr("y", -106);

    var transitionSectorOverall = transition.selectAll(".g-sector .g-overall")
        .delay(function(d) { return x(d.rate); })
        .attr("transform", function(d) { return "translate(" + x(d.rate) + "," + (y0(nameAll) - y(d.key)) + ")"; })
        .style("stroke-opacity", 0)
        .style("fill-opacity", 0);

    transitionSectorOverall.select("line")
        .attr("y1", -100)
        .attr("y2", +127);

    transitionSectorOverall.select("text")
        .attr("y", -106);

    transition.selectAll(".g-sector-company circle")
        .delay(function(d) { return d.cx; })
        .attr("cx", function(d) { return d.cx; })
        .attr("cy", function(d) { return d.cy - y(d.sector) + y0(nameAll); });
  }

  function transitionSector() {
    gVoronoi.style("display", "none");

    var transition = d3.transition()
        .duration(750);

    transition.select("svg")
        .attr("height", height + margin.top + margin.bottom)
      .transition()
        .delay(720)
        .each("end", function() {
          gVoronoi.call(updateVoronoi,
            function(d) { return d.x; },
            function(d) { return y(d.sector) + d.y; },
            height);
        });

    transition.select(".g-annotations-overall")
        .style("opacity", 0)
        .each("end", function() { this.style.display = "none"; });

    transition.select(".g-sector-notes")
        .delay(250)
        .each("start", function() { this.style.display = "block"; })
        .style("opacity", 1);

    transition.selectAll(".g-y-axis-sector,.g-sector-note")
        .delay(250)
        .style("stroke-opacity", 1)
        .style("fill-opacity", 1);

    transition.selectAll(".g-y-axis-overall")
        .style("stroke-opacity", 0)
        .style("fill-opacity", 0);

    var transitionOverall = transition.select(".g-overall-all")
        .delay(x(overallRate))
        .style("stroke-opacity", 0)
        .style("fill-opacity", 0);

    transitionOverall.select("line")
        .attr("y2", height - y0(nameAll));

    var transitionSectorOverall = transition.selectAll(".g-sector .g-overall")
        .delay(function(d) { return x(d.rate); })
        .attr("transform", function(d) { return "translate(" + x(d.rate) + ",0)"; })
        .style("stroke-opacity", 1)
        .style("fill-opacity", 1);

    transitionSectorOverall.select("line")
        .attr("y1", -25)
        .attr("y2", +25);

    transitionSectorOverall.select("text")
        .attr("y", -31);

    transition.selectAll(".g-sector-company circle")
        .delay(function(d) { return d.x; })
        .attr("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return d.y; });
  }

  function updateVoronoi(gVoronoi, x, y, height) {
    companyClip
        .attr("cx", x)
        .attr("cy", y);

    gVoronoi
        .style("display", null)
      .selectAll("path")
        .data(d3.geom.voronoi().x(x).y(y)(companies))
        .attr("d", function(d) { return "M" + d.join("L") + "Z"; })
        .datum(function(d) { return d.point; });
  }

  function mouseoverAnnotation(re) {
    var matches = sectorCompany.filter(function(d) { return re.test(d.name) || re.test(d.alias); }).classed("g-active", true);
    if (d3.sum(matches, function(d) { return d.length; }) === 1) mouseover(matches.datum());
    else tip.style("display", "none");
  }

  function mouseover(d) {
    sectorCompany.filter(function(c) { return c === d; }).classed("g-active", true);

    var dx, dy;
    if (currentView === "overall") dx = d.cx, dy = d.cy + y0(nameAll);
    else dx = d.x, dy = d.y + y(d.sector);
    dy -= 19, dx += 50; // margin fudge factors

    tip.style("display", null)
        .style("top", (dy - r(d.capitalization)) + "px")
        .style("left", dx + "px");

    tip.select(".g-tip-title")
        .text(d.alias || d.name);

    tipMetric.select(".g-tip-metric-value").text(function(name) {
      switch (name) {
        case "rate": return isNaN(d.rate) ? "N.A." : formatPercent(d.rate);
        case "taxes": return formatDollars(d.taxes);
        case "earnings": return formatDollars(d.earnings);
      }
    });
  }

  function mouseout() {
    tip.style("display", "none");
    sectorCompany.filter(".g-active").classed("g-active", false);
  }
});

function renderChartKey(g) {
  var formatPercent = d3.format(".0%"),
      formatNumber = d3.format(".0f");

  // A position encoding for the key only.
  var x = d3.scale.linear()
      .domain([0, .6])
      .range([0, 240]);

  var xAxis = d3.svg.axis()
      .scale(x)
      .orient("bottom")
      .tickSize(13)
      .tickValues(z.domain())
      .tickFormat(function(d) { return d === .5 ? formatPercent(d) : formatNumber(100 * d); });

  g.append("text")
      .attr("x", -25)
      .style("text-anchor", "end")
      .style("font", "bold 9px sans-serif")
      .text("CHART KEY");

  var gColor = g.append("g")
      .attr("class", "g-key-color")
      .attr("transform", "translate(140,-7)");

  gColor.selectAll("rect")
      .data(z.range().map(function(d, i) {
        return {
          x0: i ? x(z.domain()[i - 1]) : x.range()[0],
          x1: i < 4 ? x(z.domain()[i]) : x.range()[1],
          z: d
        };
      }))
    .enter().append("rect")
      .attr("height", 8)
      .attr("x", function(d) { return d.x0; })
      .attr("width", function(d) { return d.x1 - d.x0; })
      .style("fill", function(d) { return d.z; });

  gColor.call(xAxis);

  var gColorText = g.append("text")
      .attr("x", 140 - 6)
      .style("text-anchor", "end");

  gColorText.append("tspan")
      .style("font-weight", "bold")
      .text("Color");

  gColorText.append("tspan")
      .style("fill", "#777")
      .text(" shows effective rate");

  var gSize = g.append("g")
      .attr("class", "g-key-size")
      .attr("transform", "translate(580,-7)");

  var gSizeInstance = gSize.selectAll("g")
      .data([1e9, 10e9, 50e9, 100e9])
    .enter().append("g")
      .attr("class", "g-sector");

  gSizeInstance.append("circle")
      .attr("r", r);

  gSizeInstance.append("text")
      .attr("x", function(d) { return r(d) + 4; })
      .attr("dy", ".35em")
      .text(function(d) { return "$" + Math.round(d / 1e9) + "B"; });

  var gSizeX = 0;

  gSizeInstance.attr("transform", function() {
    var t = "translate(" + gSizeX + ",3)";
    gSizeX += this.getBBox().width + 15;
    return t;
  });

  var gSizeText = g.append("text")
      .attr("x", 580 - 10)
      .style("text-anchor", "end");

  gSizeText.append("tspan")
      .style("font-weight", "bold")
      .text("Size");

  gSizeText.append("tspan")
      .style("fill", "#777")
      .text(" shows market capitalization");
}

function yAxisWrap(g) {
  g.selectAll(".tick text")
    .filter(function(d) { return /[ ]/.test(d) && this.getComputedTextLength() > margin.left - tickExtension - 10; })
      .attr("dy", null)
      .each(function(d) {
        d3.select(this).text(null).selectAll("tspan")
            .data(d.split(" "))
          .enter().append("tspan")
            .attr("x", this.getAttribute("x"))
            .attr("dy", function(d, i) { return (i * 1.35 - .35) + "em"; })
            .text(function(d) { return d; });
      });
}

function taxes(d) {
  return d.taxes;
}

function earnings(d) {
  return d.earnings;
}

function rate(taxes, earnings) {
  return earnings <= 0 ? NaN : taxes / earnings;
}

function type(d) {
  d.x = +d.x;
  d.y = +d.y;
  d.cx = +d.cx;
  d.cy = +d.cy;
  d.taxes *= 1e6;
  d.earnings *= 1e6;
  d.capitalization *= 1e6;
  return d;
}

var sectorNoteByName = {
  "Utilities": "Utilities benefited from the 2009 stimulus bill, which included tax breaks for companies that make capital-intensive investments, like power plants.",
  "Information technology": "Technology companies can often move operations overseas for accounting purposes. And younger firms tend to have recent losses, holding down the sector&rsquo;s overall rate.",
  "Industrials": "As with the corporate sector, large industrial companies &mdash; like <b>Boeing</b>, <b>Caterpillar</b>, <b>General Electric</b> and <b>Honeywell</b> &mdash; pay lower taxes on average than small companies.",
  "Telecom": "<b>Verizon</b> had a much lower effective tax rate than its rival <b>AT&T</b>, despite having similar profits over the six-year period.",
  "Health care": "Within health care, managed care companies pay relatively higher tax rates, and makers of equipment, supplies and technology pay relatively lower rates.",
  "Pharma": "Tax breaks for research and the ability to locate operations in low-tax countries have helped pharmaceutical and biotech companies to pay low taxes.",
  "Consumer products": "Movie studios and packaged-food company pay more than 30 percent, on average. Soft-drink companies pay only 19 percent, and restaurant companies, 25 percent.",
  "Materials": "The materials industry (chemicals, minerals, etc.) exemplifies a point often made by tax experts: within industries, tax rates vary greatly, in ways that often evade simple explanation.",
  "Financials": "As financial firms have recovered from the crisis, some have paid relatively high tax rates.",
  "Retailers": "Brick-and-mortar retailers, like <b>Bed Bath & Beyond</b> and <b>Home Depot</b>, tend to pay high tax rates. Online retailers, like <b>Amazon</b>, face low rates.",
  "Energy": "Large oil companies typically pay high rates, but some economists argue that the high rates do not cover the pollution costs imposed on society.",
  "Insurance": "Many insurers pay lower-than-average rates. But <b>A.I.G.</b> &mdash; which had an $83 billion loss while paying $8 billion in taxes &mdash; drives the sector&rsquo;s average up."
};

})()