【问题标题】:2 D3.js bar charts on the same HTML. One D3 script breaks the other相同 HTML 上的 2 个 D3.js 条形图。一个 D3 脚本破坏了另一个
【发布时间】:2021-02-23 18:40:50
【问题描述】:

我对 D3 和 JavaScript 比较陌生。我正在尝试在同一页面上插入两个 d3 条形图(d3 版本 6)。这两个条形图的功能基本相同。它们每个都有一个下拉选择器,允许用户过滤可视化数据,以及一个复选框,允许用户对可视化数据进行排序。

目前,两个条形图都将加载,下拉选择器对两者都适用,但切换仅适用于其中一个。我怀疑这与加载两个脚本有关。据我所知,无论哪个脚本最后写在 html 页面上,都会覆盖另一个。此外,如果您选择它然后使用下拉菜单进行排序,但当您取消选中该框时,条形会消失。

代码没有抛出任何错误,但是当您选择切换复选框时,这些条就会消失。我已经运行了 console.logs 来确认正在访问哪些数据,果然,当您选择切换复选框时,您会得到一个空数组。我尝试重命名变量,加载 csv 的副本,以便每个图表引用不同的数据源并尝试放置脚本,但我似乎找不到导致冲突的原因。

我附上我的代码。任何指导将不胜感激。我真的很想弄清楚这一点,我怀疑这会教给我一些重要的东西。提前谢谢你。

我将包含 3 个 sn-ps。

  1. HTML
  2. prcpTrends.js
  3. precipitation.js

下面是一段可以使用的 csv 数据。这是我在这里的第一篇文章,所以我不确定显示这些数据的最佳方法是什么,所以我只是将它粘贴在这里。我想我们会看看这是否有效。

CSV 数据 ...

站、名称、纬度、经度、日期、EMXP、PRCP
USC00381997,"CONWAY, SC US",33.8313,-79.0558,2010,,42.05
USC00381997,"CONWAY, SC US",33.8313,-79.0558,2011,2.65,37.96
USC00381997,"CONWAY, SC US",33.8313,-79.0558,2012,5.95,53.92
USC00381997,"CONWAY, SC US",33.8313,-79.0558,2013,2.65,51.65
US1SCHR0061,"CONWAY 6.2 E, SC US",33.82948,-78.95277,2012,3.53,53.76
US1SCHR0061,"CONWAY 6.2 E, SC US",33.82948,-78.95277,2013,3.21,58.24
US1SCHR0061,"CONWAY 6.2 E, SC US",33.82948,-78.95277,2014,3.69,52.84
US1SCHR0061,"CONWAY 6.2 E, SC US",33.82948,-78.95277,2015,10.82,77.65
US1SCHR0061,"CONWAY 6.2 E, SC US",33.82948,-78.95277,2016,7.49,73.1
US1SCHR0061,"CONWAY 6.2 E, SC US",33.82948,-78.95277,2017,3.01,52.29
US1SCHR0061,"CONWAY 6.2 E, SC US",33.82948,-78.95277,2018,6.4,67.57
US1SCHR0061,"CONWAY 6.2 E, SC US",33.82948,-78.95277,2019,4.31,48.8
US1SCHR0061,"CONWAY 6.2 E, SC US",33.82948,-78.95277,2020,4.57,72.44
US1SCHR0010,"MYRTLE BEACH 8.6 SW, SC US",33.6192,-79.0145,2012,3.21,47.08
US1SCHR0010,"MYRTLE BEACH 8.6 SW, SC US",33.6192,-79.0145,2014,3.71,66.72
US1SCHR0010,"MYRTLE BEACH 8.6 SW, SC US",33.6192,-79.0145,2015,7.05,72.65
US1SCHR0076,"美特尔海滩 9.1 WSW, SC US",33.646118,-79.036631,2015,8.04,71.29
US1SCHR0076,"美特尔海滩 9.1 WSW, SC US",33.646118,-79.036631,2016,8.41,69.54
US1SCHR0033,"LORIS 2.9 WSW, SC US",34.037885,-78.935069,2012,3.39,54.93
US1SCHR0033,"LORIS 2.9 WSW, SC US",34.037885,-78.935069,2013,3.4,63.96
US1SCHR0033,"LORIS 2.9 WSW, SC US",34.037885,-78.935069,2015,3.73,60.56
US1SCHR0033,"LORIS 2.9 WSW, SC US",34.037885,-78.935069,2016,6.97,61.37
US1SCHR0033,"LORIS 2.9 WSW, SC US",34.037885,-78.935069,2017,3.09,56.54
US1SCHR0066,"美特尔海滩 9.2 WSW, SC US",33.623648,-79.025797,2014,3.08,64.24
US1SCHR0066,"美特尔海滩 9.2 WSW, SC US",33.623648,-79.025797,2020,3.95,66.58
US1SCHR0063,"MURRELLS INLET 1.7 N, SC US",33.578576,-79.045388,2013,4.19,50.72
US1SCHR0063,"MURRELLS INLET 1.7 N, SC US",33.578576,-79.045388,2014,3.46,62.16
US1SCHR0063,"MURRELLS INLET 1.7 N, SC US",33.578576,-79.045388,2018,3.63,54.76
US1SCHR0063,"MURRELLS INLET 1.7 N, SC US",33.578576,-79.045388,2020,4,70.33
US1SCHR0064,"MYRTLE BEACH 2.4 ENE, SC US",33.715721,-78.855623,2015,9.35,69.26
US1SCHR0064,"MYRTLE BEACH 2.4 ENE, SC US",33.715721,-78.855623,2017,2.76,45.67
US1SCHR0075,"美特尔海滩 7.4 NNW, SC US",33.790506,-78.957247,2014,3.14,51.79
US1SCHR0075,"美特尔海滩 7.4 NNW, SC US",33.790506,-78.957247,2015,8.42,87.71
US1SCHR0075,"MYRTLE BEACH 7.4 NNW, SC US",33.790506,-78.957247,2019,4.51,54.74
US1SCHR0075,"美特尔海滩 7.4 NNW, SC US",33.790506,-78.957247,2020,3.62,74.55
US1SCHR0014,"MURRELLS INLET 4.0 NE, SC US",33.5994932,-79.0065316,2013,3.79,48.06
US1SCHR0014,"MURRELLS INLET 4.0 NE, SC US",33.5994932,-79.0065316,2014,3.32,59.28
US1SCHR0014,"MURRELLS INLET 4.0 NE, SC US",33.5994932,-79.0065316,2016,10,60.14
US1SCHR0014,"MURRELLS INLET 4.0 NE, SC US",33.5994932,-79.0065316,2017,4.04,47.89
US1SCHR0014,"MURRELLS INLET 4.0 NE, SC US",33.5994932,-79.0065316,2019,6.15,51.88
US1SCHR0014,"MURRELLS INLET 4.0 NE, SC US",33.5994932,-79.0065316,2020,4.49,65.3
US1SCHR0046,"MYRTLE BEACH 5.0 WNW, SC US",33.72668,-78.9728839,2012,2.85,39.44
US1SCHR0046,"MYRTLE BEACH 5.0 WNW, SC US",33.72668,-78.9728839,2013,4.48,52.29
US1SCHR0046,"MYRTLE BEACH 5.0 WNW, SC US",33.72668,-78.9728839,2014,3.51,53.09
US1SCHR0046,"MYRTLE BEACH 5.0 WNW, SC US",33.72668,-78.9728839,2015,9.55,72.26
US1SCHR0046,"MYRTLE BEACH 5.0 WNW, SC US",33.72668,-78.9728839,2016,6.78,68.54
US1SCHR0046,"MYRTLE BEACH 5.0 WNW, SC US",33.72668,-78.9728839,2017,3.25,47.37
US1SCHR0046,"MYRTLE BEACH 5.0 WNW, SC US",33.72668,-78.9728839,2019,5.63,57.22
US1SCHR0106,"MYRTLE BEACH 4.8 NNW, SC US",33.76386,-78.91961,2019,4.94,53.29
US1SCHR0106,"MYRTLE BEACH 4.8 NNW, SC US",33.76386,-78.91961,2020,4.95,76.84
US1SCHR0019,"LORIS 1.4 ENE, SC US",34.067521,-78.868929,2016,5.08,59.64
US1SCHR0019,"LORIS 1.4 ENE, SC US",34.067521,-78.868929,2018,11,73.78
USW00093718,"北默特尔比奇, SC US",33.81619,-78.72048,2010,2.72,41.91
USW00093718,"北默特尔比奇, SC US",33.81619,-78.72048,2011,2.04,33.5
USW00093718,"北默特尔比奇, SC US",33.81619,-78.72048,2012,1.96,39.27
USW00093718,"北默特尔比奇, SC US",33.81619,-78.72048,2013,3.25,48.59
USW00093718,"北默特尔比奇, SC US",33.81619,-78.72048,2014,2.25,41.01
USW00093718,"北默特尔比奇, SC US",33.81619,-78.72048,2015,7.88,64.87
USW00093718,"北默特尔比奇, SC US",33.81619,-78.72048,2016,8.9,56.26
USW00093718,"北默特尔比奇, SC US",33.81619,-78.72048,2017,3.73,49.13
USW00093718,"北默特尔比奇, SC US",33.81619,-78.72048,2018,5.71,68.53
USW00093718,"北默特尔比奇, SC US",33.81619,-78.72048,2019,10.39,56.02
USW00093718,"北默特尔比奇, SC US",33.81619,-78.72048,2020,4.12,55.72

/* ../static/precipitation.js */

d3.csv("/static/Horry_County_Precipitation.csv").then(d => chartTrend(d));

function chartTrend(csv) {
  csv.forEach(function(d) {
    d.DATE = d.DATE;
    d.PRCP = +d.PRCP;
    return d;

  })

  const weatherStation = csv
    .map((a) => a.NAME)
    .filter((value, index, self) => self.indexOf(value) === index);
  weatherStation.sort(function(a, b) {
    return b - a;
  });
  console.log(weatherStation)

  d3
    .select("#weatherStation")
    .selectAll("option")
    .data(weatherStation)
    .enter()
    .append("option")
    .text((d) => d);

  var svg = d3.select("#prcpTrends"),
    margin = {
      top: 70,
      right: -35,
      bottom: 50,
      left: 110
    },
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom;

  //   Setting x Scale
  const x = d3
    .scaleBand()
    .range([margin.left, width - margin.right])
    .padding(0.1)
    .paddingOuter(0.2);

  var y = d3.scaleLinear().range([height - margin.bottom, margin.top]);

  var colorScale = d3.scaleOrdinal()
    .range(["#ed5151", "#149ece", "#3caf99", "#004c73", "#fc921f", "#a8a800", "#f789d8", "#732600", "#ff00c5", "#9e559c", "#a7c636", "#7f7f7f", "#6b6bd6", "#a87000"]);

  var xAxis = (g) =>
    g
    .attr("transform", "translate(0," + (height - margin.bottom) + ")")
    .call(d3.axisBottom(x).tickSizeOuter(0))
    .selectAll('text')
    .attr("y", 10)
    .attr("x", 0)
  //   .attr("dy", ".35em")
  //   .attr("transform", "rotate(60)")
  //   .style("text-anchor", "start");

  var yAxis = (g) =>
    g
    .attr("transform", "translate(" + margin.left + ",0)")
    .call(d3.axisLeft(y)
      .ticks(5)
      .tickSize(-width));

  svg.append("g").attr("class", "x-axis");

  svg
    .append("g")
    .attr("class", "y-axis")
    .append("text")
    .attr("class", "yAxisPRCP")
    .attr("y", -30)
    .attr("x", -85)
    .attr("transform", `rotate(-90)`)
    // .attr("fill", "#635f5d")
    // .style("font-size", "2.5em")
    .text("Precipitation (in)");

  svg
    .append("text")
    .attr("y", 40)
    .attr("x", 185)
    .attr("class", "title")
    .text("Weather Station Precipitation Totals");

  update(d3.select("#weatherStation").property("value"), 0);

  function update(name, speed) {
    var data = csv.filter(d => d.NAME == name);
    console.log(data)
    y.domain([0, d3.max(data, (d) => d.PRCP)]).nice();

    svg.selectAll(".y-axis").transition().duration(speed).call(yAxis);

    data.sort(
      d3.select("#sortPRCP").property("checked") ?
      (a, b) => b.PRCP - a.PRCP :
      (a, b) => a.NAME - b.NAME
    );

    x.domain(data.map((d) => d.DATE));

    svg.selectAll(".x-axis").transition().duration(speed).call(xAxis);

    var bar = svg.selectAll(".bar").data(data, (d) => d.DATE);

    bar.exit().remove();

    var bar1 = bar
      .enter()
      .append("rect")
      .attr("class", "bar")
      .style("fill", "#149ece")
      .attr("opacity", ".5")
      .attr("width", x.bandwidth())
      .attr("height", (d) => y(0) - y(d.PRCP));

    bar1
      .merge(bar)
      .transition()
      .duration(speed)
      .attr("x", (d) => x(d.DATE))
      .attr("y", (d) => y(d.PRCP))
      .attr("width", x.bandwidth())
      .attr("height", (d) => y(0) - y(d.PRCP));


    // Adding Tooltip Behavior
    bar1
      .on("mouseover", function(event, d) {
        d3.select(this).style("fill", "#ebe028");
        d3.select("#stationName").text(" " + d.NAME)
        d3.select("#annualPrecipitationTrends").text(" " + d.PRCP + " inches");

        //Position the tooltip <div> and set its content
        let x = event.pageX - 500;
        let y = event.pageY - 1000;

        //Position tooltip and make it visible
        d3.select("#tooltipTrends")
          .style("left", x + "px")
          .style("top", y + "px")
          .style("opacity", 1);
      })

      .on("mouseout", function() {
        d3.select(this).style("fill", "#149ece");

        //Hide the tooltip
        d3.select("#tooltipTrends").style("opacity", "0");
      });
  }
  chartTrend.update = update;
}


var select = d3
  .select("#weatherStation")
  .style("border-radius", "5px")
  .on("change", function() {
    chartTrend.update(this.value, 750);
  });

var checkbox = d3
  .select("#sortPRCP")
  .style("margin-left", "1%")
  .on("click", function() {
    chartTrend.update(select.property("value"), 750);
  });

/* ../static/prcpTrends.js */

d3.csv("/static/Horry_County_Precipitation.csv").then(d => chart(d));

function chart(csv) {
  csv.forEach(function(d) {
    d.DATE = d.DATE;
    d.PRCP = +d.PRCP;
    return d;

  })


  const years = csv
    .map((a) => a.DATE)
    .filter((value, index, self) => self.indexOf(value) === index);
  years.sort(function(a, b) {
    return b - a;
  });
  // console.log(years)

  d3
    .select("#year")
    .selectAll("option")
    .data(years)
    .enter()
    .append("option")
    .text((d) => d);

  var svg = d3.select("#precipitation_barchart"),
    margin = {
      top: 70,
      right: -35,
      bottom: 50,
      left: 110
    },
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom;

  // Setting x Scale
  const x = d3
    .scaleBand()
    .range([margin.left, width - margin.right])
    .padding(0.1)
    .paddingOuter(0.2);

  var y = d3.scaleLinear().range([height - margin.bottom, margin.top]);

  var colorScale = d3.scaleOrdinal()
    .range(["#ed5151", "#149ece", "#3caf99", "#004c73", "#fc921f", "#a8a800", "#f789d8", "#732600", "#ff00c5", "#9e559c", "#a7c636", "#7f7f7f", "#6b6bd6", "#a87000"]);

  var xAxis = (g) =>
    g
    .attr("transform", "translate(0," + (height - margin.bottom) + ")")
    .call(d3.axisBottom(x).tickSizeOuter(0))
    .selectAll('text')
    .attr("y", 0)
    .attr("x", 9)
    .attr("dy", ".35em")
    .attr("transform", "rotate(60)")
    .style("text-anchor", "start");

  var yAxis = (g) =>
    g
    .attr("transform", "translate(" + margin.left + ",0)")
    .call(d3.axisLeft(y)
      .ticks(5)
      .tickSize(-width));

  svg.append("g").attr("class", "x-axis");

  svg
    .append("g")
    .attr("class", "y-axis")
    .append("text")
    .attr("class", "yAxisPRCP")
    .attr("y", -30)
    .attr("x", -85)
    .attr("transform", `rotate(-90)`)
    // .attr("fill", "#635f5d")
    // .style("font-size", "2.5em")
    .text("Precipitation (in)");

  svg
    .append("text")
    .attr("y", 35)
    .attr("x", 270)
    .attr("class", "title")
    .text("Annual Precipitation Totals");

  update(d3.select("#year").property("value"), 0);

  function update(year, speed) {
    var data = csv.filter(d => d.DATE == year);
    // console.log(data)
    y.domain([0, d3.max(data, (d) => d.PRCP)]).nice();

    svg.selectAll(".y-axis").transition().duration(speed).call(yAxis);

    data.sort(
      d3.select("#sort").property("checked") ?
      (a, b) => b.PRCP - a.PRCP :
      (a, b) => a.NAME - b.NAME
    );

    x.domain(data.map((d) => d.NAME));

    svg.selectAll(".x-axis").transition().duration(speed).call(xAxis);

    var bar = svg.selectAll(".bar").data(data, (d) => d.NAME);

    bar.exit().remove();

    var bar1 = bar
      .enter()
      .append("rect")
      .attr("class", "bar")
      .style("fill", function(d) {
        return colorScale(d.NAME);
      })
      .attr("opacity", ".5")
      .attr("width", x.bandwidth())
      .attr("height", (d) => y(0) - y(d.PRCP));

    bar1
      .merge(bar)
      .transition()
      .duration(speed)
      .attr("x", (d) => x(d.NAME))
      .attr("y", (d) => y(d.PRCP))
      .attr("width", x.bandwidth())
      .attr("height", (d) => y(0) - y(d.PRCP));


    // Adding Tooltip Behavior
    bar1
      .on("mouseover", function(event, d) {
        d3.select(this).style("fill", "#ebe028");
        d3.select("#stationName").text(" " + d.NAME)
        d3.select("#annualPrecipitation").text(" " + d.PRCP + " inches");

        //Position the tooltip <div> and set its content
        let x = event.pageX - 1100;
        let y = event.pageY - 1000;

        //Position tooltip and make it visible
        d3.select("#tooltip")
          .style("left", x + "px")
          .style("top", y + "px")
          .style("opacity", 1);
      })

      .on("mouseout", function() {
        d3.select(this).style("fill", function(d) {
          return colorScale(d.NAME);
        });

        //Hide the tooltip
        d3.select("#tooltip").style("opacity", "0");
      });
  }
  chart.update = update;
}


var select = d3
  .select("#year")
  .style("border-radius", "5px")
  .on("change", function() {
    chart.update(this.value, 750);
  });

var checkbox = d3
  .select("#sort")
  .style("margin-left", "30%")
  .on("click", function() {
    chart.update(select.property("value"), 750);
  });
<!--HTML code for bar charts in question. -->
<!-- Start precipitation by weather station bar chart -->
<div class="row">
  <div id="precipitationVisualization" class="col-md-6 col-sm-6 mb-4">
    Choose Weather Station:
    <select id="weatherStation"></select>
    <input type="checkbox" id="sortPRCP"> Toggle sort by Precipitation Volume
    <div class="row">
      <svg id="prcpTrends" width="768" height="400"></svg>
      <div id="tooltipTrends">
        <!-- Station Name:<span id="stationName" class="info"></span><br>  -->
        Annual Precipitation:<span id="annualPrecipitationTrends" class="info"></span><br>
      </div>
    </div>
  </div>


  <!-- Start precipitation by year bar chart -->
  <div id="precipitationVisualization" class="col-md-6 col-sm-6 mb-4">
    Choose year:
    <select id="year"></select>
    <input type="checkbox" id="sort"> Toggle sort by Precipitation Volume
    <div class="row">
      <svg id="precipitation_barchart" width="768" height="400"></svg>
      <div id="tooltip">
        <!-- Station Name:<span id="stationName" class="info"></span><br>  -->
        Annual Precipitation:<span id="annualPrecipitation" class="info"></span><br>
      </div>
    </div>
  </div>
</div>



<script src="../static/d3.js"></script>
<script src="https://d3js.org/d3.v6.min.js"></script>
<script src="https://d3js.org/d3-scale.v3.min.js" defer></script>
<script src="https://d3js.org/d3-axis.v1.min.js" defer></script>
<!--
<script src="../static/precipitation.js"></script>
<script src="../static/prcpTrends.js"></script>
-->

【问题讨论】:

  • 所以,我已将您的三个 sn-ps 合并为一个,但您的 d3 脚本引用了 Stack Overflow 服务器上显然不存在的 CSV 文件。如果您可以将数据(可能更少)作为内联数据包含到 d3 中(对不起,我无论如何都不是 d3 专家),这将有助于使脚本运行得更干净。
  • 谢谢邪猴。这是我第一次在这里发布问题,所以我不是 100% 确定它是如何工作的,但我将一段 CSV 数据复制并粘贴到我的邮件正文中。我不确定这是否正确。让我知道是否需要以另一种方式执行此操作。再次感谢。

标签: javascript html d3.js


【解决方案1】:

我找到了解决问题的方法。对于同一页面上的两个图表,我为 on change 事件使用了相同的变量名称。我只需要使用不同的名称。我需要对我的代码进行以下更新。请注意,我只是将一个图表上“select”的变量名称更改为另一个图表上的“select2”。

    // I used this for one chart...
    var select = d3
      .select("#weatherStation")
      .style("border-radius", "5px")
      .on("change", function () {
       chartTrend.update1(this.value, 750);
      });

    var checkbox = d3
      .select("#sortPRCP")
      .style("margin-left", "1%")
      .on("click", function () {
       chartTrend.update1(select.property("value"), 750);
      });

    // I updated the variable name for the second...
    var select2 = d3
      .select("#weatherStation")
      .style("border-radius", "5px")
      .on("change", function () {
       chartTrend.update1(this.value, 750);
      });

    var checkbox = d3
      .select("#sortPRCP")
      .style("margin-left", "1%")
      .on("click", function () {
       chartTrend.update1(select2.property("value"), 750);
      });

【讨论】:

    猜你喜欢
    • 2018-11-08
    • 2013-04-15
    • 2013-07-08
    • 2014-03-20
    • 2016-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-20
    相关资源
    最近更新 更多