【问题标题】:What is wrong with this data visualization code?这个数据可视化代码有什么问题?
【发布时间】:2021-05-10 17:29:26
【问题描述】:

我正在尝试使用手动添加的另一组数据运行This Code。下面是我的脚本,但是当我打开文件时出现了一个空白屏幕。我的代码有什么问题?我认为我输入数据的方式有问题。我能够在我的屏幕上出现统一的气泡,但是当我尝试添加将更改大小以匹配变量的函数时,代码停止工作。数据中的前两个变量是占位符,用于匹配原始代码的 csv 文件以获得相似的样式结果,但它们并不一定重要。我只需要最终代码即可在鼠标悬停时输出数据并在查看时更改气泡的大小和形状。

<script>

  // set the dimensions and margins of the graph
  var width = 500
  var height = 500
  
  // append the svg object to the body of the page
  var svg = d3.select("#my_dataviz")
    .append("svg")
      .attr("width", width)
      .attr("height", height)
  
  // create dummy data -> just one element per circle
  var data = [
  { "Asia": "Southeast Asia", "Burundi": 3.14 }, 
  { "Asia": "Southeast Asia", "South Sudan": 3.39 }, 


  var color = d3.scaleOrdinal()
    .domain(["Asia", "Europe", "Africa", "Oceania", "Americas"])
    .range(d3.schemeSet1);

   // Size scale for countries
   var size = d3.scaleLinear()
    .domain([0, 1010])
    .range([7,55])

  var node = svg.append("g")
    .selectAll("circle")
    .data(data)
    .enter()
    .append("circle")
      .attr("class", "node")
      .attr("r", function(d){ return size(d.value)})
      .attr("cx", width / 2)
      .attr("cy", height / 2)
      .style("fill", function(d){ return color(d.region)})
      .style("fill-opacity", 0.8)
      .attr("stroke", "black")
      .style("stroke-width", 1)
      .on("mouseover", mouseover)

【问题讨论】:

  • 有没有机会在 sn-p 中把它变成minimal reproducible example?这将使您更容易理解和协助解决您的问题。
  • 您看不到圆,因为圆的半径未定义。检查页面将显示您的圆圈已附加,但半径无效。您的数据数组项没有名为 value 的属性,这是问题的原因。使用.attr("r", 5),您将看到您的圈子。如果您希望每个数据都有一个名为 value 的属性,则需要处理您的数据。
  • 我想我的问题是如何处理我的数据来定义我附加圆的半径?有没有办法在代码块中做到这一点而不通过 csv 文件运行它

标签: javascript svg d3.js


【解决方案1】:

您看不到圆,因为圆的半径未定义:检查页面会显示您的圆在那里,但由于它们没有有效的半径,因此不会呈现。

你在这里设置半径:

.attr("r", function(d){ return size(d.value)})

但是您的数据数组中的项目没有名为value 的属性。 d 表示数据数组中的单个项目。 链接代码解析一个包含名为 value 的列的 csv,它创建一个数组,其中每个项目都有一个名为 `value 的属性。我们将需要处理您的数据以赋予我们的数据该属性,可能类似于:

 data = data.map(function(d) {
    let entries = Object.entries(d);
    return {region: entries[0][0] ,subregion: entries[0][1] ,country: entries[1][0], value: entries[1][1]}
 })

就个人而言,我最初会生成具有一致字段名称的数据,而不是依赖于依赖于使用 JavaScript 对象方法对键/对象对进行排序的事实处理,因为这可能会引入一些跨浏览器问题,一些我不是最熟悉的。

// set the dimensions and margins of the graph
  var width = 500
  var height = 500
  
  // append the svg object to the body of the page
  var svg = d3.select("body")
    .append("svg")
      .attr("width", width)
      .attr("height", height)
  
  // create dummy data -> just one element per circle
  var data = [
  { "Asia": "Southeast Asia", "Burundi": 3.14 }, 
  { "Asia": "Southeast Asia", "South Sudan": 3.39 }, 
  { "Asia": "Southeast Asia", "Malawi": 7.63 }, 
  { "Asia": "Southeast Asia", "Mozambique": 14.22 }, 
  { "Asia": "Southeast Asia", "Democratic Republic of the Congo": 40.92 }, 
  { "Asia": "Southeast Asia", "Central African Republic": 2.32 }, 
  { "Asia": "Southeast Asia", "Afghanistan": 19.44 }, 
  { "Asia": "Southeast Asia", "Madagascar": 14.26 }, 
  { "Asia": "Southeast Asia", "Sierra Leone": 4.14}, 
  { "Asia": "Southeast Asia", "Niger": 12.97}, 
  { "Asia": "Southeast Asia", "Eritrea": 2.08}, 
  { "Asia": "Southeast Asia", "Chad": 10.51}, 
  { "Asia": "Southeast Asia", "Yemen": 19.24}, 
  { "Asia": "Southeast Asia", "Liberia": 3.31}, 
  { "Asia": "Southeast Asia", "Togo": 5.71}, 
  { "Asia": "Southeast Asia", "Haiti": 8.35}, 
  { "Asia": "Southeast Asia", "Sudan": 32.21}, 
  { "Asia": "Southeast Asia", "Gambia": 1.8},
  { "Asia": "Southeast Asia", "Guinea-Bissau": 1.51}, 
  { "Asia": "Southeast Asia", "Burkina Faso": 16.07}, 
  { "Americas": "Caribbean", "Jeff Bezos": 189.3}, 
  { "Americas": "Caribbean", "Elon Musk": 182.2}, 
  { "Americas": "Caribbean", "Bernard Arnault": 157.7},
  { "Americas": "Caribbean", "Bill Gates": 123.7}, 
  { "Americas": "Caribbean", "Mark Zuckerberg": 95.7}, 
  { "Americas": "Caribbean", "Warren Buffet": 91.7}, 
  { "Americas": "Caribbean", "Larry Page": 90.9},
  { "Americas": "Caribbean", "Zhong Shanshan": 89.8}, 
  { "Americas": "Caribbean", "Sergey Brin": 88.2}, 
  { "Americas": "Caribbean", "Larry Elison": 85.2}, 
  { "Americas": "Caribbean", "Steve Ballmer": 80.4},
  { "Americas": "Caribbean", "Mukesh Ambani": 78}, 
  { "Americas": "Caribbean", "Francois Bettencourt Meyers": 75.6}, 
  { "Americas": "Caribbean", "Armando Ortega": 74}, 
  { "Americas": "Caribbean", "Colin Zheng Huang": 69.1}, 
  { "Americas": "Caribbean", "Alice Walton": 65.1}, 
  { "Americas": "Caribbean", "Jim Walton": 64.9}, 
  { "Americas": "Caribbean", "Rob Walton": 64.6},
  { "Americas": "Caribbean", "Carlos Slim Helu": 64}, 
  { "Americas": "Caribbean", "Jack Ma": 62}, 
  { "Africa": "Western Africa", "Total of 20 Poorest Countries": 232.22},
  { "Europe": "Southern Europe", "Wealth Gained by American Billionaires during Coronavirus Pandemic": 1010}]


     data = data.map(function(d) {
        let entries = Object.entries(d);
        return {region: entries[0][0] ,subregion: entries[0][1] ,country: entries[1][0], value: entries[1][1]}
     })


  var color = d3.scaleOrdinal()
    .domain(["Asia", "Europe", "Africa", "Oceania", "Americas"])
    .range(d3.schemeSet1);

   // Size scale for countries
   var size = d3.scaleLinear()
    .domain([0, 1010])
    .range([7,55])

     // create a tooltip
  var Tooltip = d3.select("#my_dataviz")
    .append("div")
    .style("opacity", 0)
    .attr("class", "tooltip")
    .style("background-color", "white")
    .style("border", "solid")
    .style("border-width", "2px")
    .style("border-radius", "5px")
    .style("padding", "5px")

     // Three function that change the tooltip when user hover / move / leave a cell
  var mouseover = function(d) {
    Tooltip
      .style("opacity", 1)
  }
  var mousemove = function(d) {
    Tooltip
      .html('<u>' + d.key + '</u>' + "<br>" + d.value + " billion dollars")
      .style("left", (d3.mouse(this)[0]+20) + "px")
      .style("top", (d3.mouse(this)[1]) + "px")
  }
  var mouseleave = function(d) {
    Tooltip
      .style("opacity", 0)
  }

  // Initialize the circle: all located at the center of the svg area
  var node = svg.append("g")
    .selectAll("circle")
    .data(data)
    .enter()
    .append("circle")
      .attr("class", "node")
      .attr("r", function(d){ return size(d.value)})
      .attr("cx", width / 2)
      .attr("cy", height / 2)
      .style("fill", function(d){ return color(d.region)})
      .style("fill-opacity", 0.8)
      .attr("stroke", "black")
      .style("stroke-width", 1)
      .on("mouseover", mouseover) // What to do when hovered
      .on("mousemove", mousemove)
      .on("mouseleave", mouseleave)
      .call(d3.drag() // call specific function when circle is dragged
         .on("start", dragstarted)
         .on("drag", dragged)
         .on("end", dragended));
  
  // Features of the forces applied to the nodes:
  var simulation = d3.forceSimulation()
      .force("center", d3.forceCenter().x(width / 2).y(height / 2)) // Attraction to the center of the svg area
      .force("charge", d3.forceManyBody().strength(0.5)) // Nodes are attracted one each other of value is > 0
      .force("collide", d3.forceCollide().strength(0.5).radius(function(d){ return size(d.value)+5}).iterations(1)) // Force that avoids circle overlapping
  
  // Apply these forces to the nodes and update their positions.
  // Once the force algorithm is happy with positions ('alpha' value is low enough), simulations will stop.
  simulation
      .nodes(data)
      .on("tick", function(d){
        node
            .attr("cx", function(d){ return d.x; })
            .attr("cy", function(d){ return d.y; })
      });

    // What happens when a circle is dragged?
function dragstarted(d) {
  if (!d3.event.active) simulation.alphaTarget(.03).restart();
  d.fx = d.x;
  d.fy = d.y;
}
function dragged(d) {
  d.fx = d3.event.x;
  d.fy = d3.event.y;
}
function dragended(d) {
  if (!d3.event.active) simulation.alphaTarget(.03);
  d.fx = null;
  d.fy = null;
}
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"&gt;&lt;/script&gt;

我已经更新了力布局的半径属性以反映半径(并篡改了强度以产生更好的结果)

【讨论】:

  • 哦,哇,非常感谢。我绝对知道问题就在那里,但不知道如何解决它。我真的非常感谢你抽出时间来帮助我。
  • 如果我要在工具提示上定义国家名称以及值,我是否还必须运行一个单独的函数来定义该组数据?
  • 每个数据有四个属性:region, subregion, country, value already:上面节点的颜色已经有 region 例如(d.region),你可以使用访问大陆/国家/etc基准的适当属性。记录数据始终是一个很好的调试检查,以确保数据按照您的预期和您想要的结构绑定 - 您应该在那里看到所有四个属性。
猜你喜欢
  • 2011-02-18
  • 2012-08-07
  • 2014-08-29
  • 2013-06-05
  • 2014-06-04
  • 2011-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多