简体   繁体   English

d3.js具有不同颜色和符号的散点图 - 遇到的问题

[英]d3.js scatterplot with different colors and symbols - issues encountered

I am trying to create a scatterplot of hundreds of datapoints, each with about 5 different attributes. 我正在尝试创建数百个数据点的散点图,每个数据点有大约5个不同的属性。 The data is loaded from a .csv as an array of objects, each of which looks like this: 数据从.csv加载为对象数组,每个对象如下所示:

{hour: "02",yval: "63",foo: "33", goo:"0", bar:"1"},

I want to display the scatterplot with the following attributes: 我想显示具有以下属性的散点图:

Shape for bar : bar

-circle to represent all points where bar=0 , and a triangle-down to represent those where bar=1 (this is a dummy variable). -circle表示bar=0所有点,而three-down表示bar=1那些(这是一个虚拟变量)。

Color for foo and goo : foogoo颜色:

  • All points start as grey. 所有点都以灰色开始。 goo is categorical with values [0,1,2] while foo is quantitative with a range from 0-50. goo是值[0,1,2]的分类,而foo是定量的,范围从0到50。 foo and goo are mutually exclusive, so only one of them has a value. foo和goo是互斥的,因此只有其中一个具有值。 In other words, for each data point either foo=0 or goo=0 . 换句话说,对于每个数据点, foo=0goo=0
  • Points with goo=1 should be orange; goo=1点数应为橙色; points with goo=2 should be red. goo=2点数应为红色。
  • foo should be mapped onto a linear color scale from light blue to dark blue, ie d3.scale.linear().domain([0, 50]).range(["#87CEFF", "#0000FF"]); foo应该映射到从浅蓝色到深蓝色的线性色标,即d3.scale.linear().domain([0, 50]).range(["#87CEFF", "#0000FF"]);

I can do each of these individually, but defining everything together is creating issues for me. 我可以单独完成这些,但是将所有内容组合在一起会为我创造问题。

My code with reproducible data is here: http://jsfiddle.net/qy5ohw0x/3/ 我的代码具有可重现的数据在这里: http//jsfiddle.net/qy5ohw0x/3/

Issues 问题

  • For the symbol, i tried 对于符号,我试过

.append("svg:path")

.attr("d", d3.svg.symbol())

which did not work. 这没用。 I tried a different approach altogether, but this did not map the values correctly: 我尝试了一种不同的方法,但这没有正确映射值:

var series = svg.selectAll("g.series") 
    .data(dataSet, function(d, i) { return d.bar; })
    .enter() 
    .append("svg:g")

series.selectAll("g.point")
    .data(dataSet)
    .enter()
    .append("svg:path")
    .attr("transform", function(d, i) { return "translate(" + d.hour +  "," + d.yval + ")"; })
    .attr("d", function(d,i, j) { return d3.svg.symbol().type(symbolType[j])(); })
    .attr("r", 2);
  • For the goo colors (grey/orange/red), i mapped the values to the 3 colors manually: 对于goo颜色(灰色/橙色/红色),我手动将值映射到3种颜色:

First define var colors = ["grey", "orange", "red"]; 首先定义var colors = ["grey", "orange", "red"];

Then while drawing the data points chain 然后在绘制数据点链的同时

.style("fill", function (d) { return colors[d.type]; })

This worked alone, but not with the different symbols. 这单独工作,但不是用不同的符号。

  • Finally, can i chain a second color .attr for foo ? 最后,我可以为foo链接第二种颜色.attr吗? d3.scale.linear().domain([0, 50]).range(["#87CEFF", "#0000FF"]); would probably work if this is possible. 如果可能的话可能会有用。

Again, the jsfiddle is here: http://jsfiddle.net/qy5ohw0x/3/ 再次,jsfiddle在这里: http//jsfiddle.net/qy5ohw0x/3/

Thanks!! 谢谢!!

Just do all the logic and comparisons in a function(d) for each attribute. 只需对function(d)中的每个属性进行所有逻辑和比较。

First set up some helpers: 首先设置一些助手:

// symbol generators
var symbolTypes = {
    "triangleDown": d3.svg.symbol().type("triangle-down"),
    "circle": d3.svg.symbol().type("circle")
};

// colors for foo
var fooColors = d3.scale
    .linear()
    .domain([0, 50])
    .range(["#87CEFF", "#0000FF"]);

Then append a path for each symbol: 然后为每个符号附加一个路径:

svg.selectAll("path")
    .data(dataSet)
    .enter().append("path")
    .attr("class", "dot")
    // position it, can't use x/y on path, so translate it
    .attr("transform", function(d) { 
        return "translate(" + (x(d.hour) + (Math.random() * 12 - 6)) + "," +  y(d.yval) + ")"; 
    })
    // assign d from our symbols
    .attr("d", function(d,i){
        if (d.bar === "0") // circle if bar === 0
            return symbolTypes.circle();
        else
            return symbolTypes.triangleDown();
    })
    // fill based on goo and foo
    .style("fill", function(d,i){
        if (d.goo !== "0"){
            if (d.goo === "1")
                return "red";
            else
                return "orange";
        }else{
            return fooColors(d.foo);
        }
    });

Updated fiddle . 更新了小提琴

On a side note, I actually think straight d3 is way more intuitive than nvd3 for this situation. 另外,我认为在这种情况下,直接d3nvd3更直观。

It's much simplier with nvd3.js nvd3.js简化得多

function prepareData (data) {
    return [{
        key:     'Group 1',
        values:  data.map(function (item) {
            item.shape = item.bar == "0" ? 'circle' : 'triangle-down';
            item.x = Number(item.hour);
            item.y = Number(item.yval);
            item.size = 0.1;
            item.disabled = Math.random() > 0.4;
            return item;
        })
    }]
}

nv.addGraph(function() {
  var chart = nv.models.scatterChart()
                .showDistX(false)    
                .showDistY(true)
                .showLegend(false)

  //Axis settings
  chart.xAxis.tickFormat(d3.format('3.0f'));
  chart.yAxis.tickFormat(d3.format('3.0f'));

  d3.select('#chart svg')
      .datum(prepareData(dataSet))
      .call(chart)

  // A bit hacky but works
  var fooscale = d3.scale.linear().domain([0, 50]).range(["#87CEFF", "#0000FF"]);
  function colorer(d) {
      if (d.goo == '1')
          return 'orange';
      else if (d.goo == '2')
          return 'red';
      else if (d.goo == '0')
          return fooscale(d.foo);
      return 'gray';
  }
  d3.selectAll('.nv-point')
      .attr({
          'stroke': colorer,
          'fill':   colorer
      })


  nv.utils.windowResize(chart.update);

  return chart;
});

See https://jsfiddle.net/qy5ohw0x/4/ https://jsfiddle.net/qy5ohw0x/4/

PS Unfortunately Nvd3 lacks docs, so use it's github instead PS很遗憾Nvd3缺少文档,所以请使用它的github代替

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM