Javascript D3:加载多个CSV文件,并使用平行坐标将其可视化

Javascript D3:加载多个CSV文件,并使用平行坐标将其可视化,javascript,csv,d3.js,parallel-coordinates,Javascript,Csv,D3.js,Parallel Coordinates,我有4个csv文件(比如4个类),每个都有100x200个元素(100个案例,200个特征)。 我需要使用平行坐标来可视化其中的一些功能(功能1、功能2、…、功能8;因此每个csv文件都有100x8)。要识别这些类,我需要使用4种不同的颜色 我已经有了平行坐标,可以在一个csv文件中可视化数据(100x10)。代码如下: <style type="text/css"> svg { font: 10px sans-serif; }

我有4个csv文件(比如4个类),每个都有100x200个元素(100个案例,200个特征)。 我需要使用平行坐标来可视化其中的一些功能(功能1、功能2、…、功能8;因此每个csv文件都有100x8)。要识别这些类,我需要使用4种不同的颜色

我已经有了平行坐标,可以在一个csv文件中可视化数据(100x10)。代码如下:

    <style type="text/css">

      svg {
        font: 10px sans-serif;
      }

      .background path {
        fill: none;
        stroke: #ccc;
        stroke-opacity: .1;
        shape-rendering: crispEdges;
      }

      .foreground path {
        fill: none;
        stroke: steelblue;
        stroke-opacity: .7;
      }

      .brush .extent {
        fill-opacity: .3;
        stroke: #fff;
        shape-rendering: crispEdges;
      }

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

      .axis text {
        text-shadow: 0 1px 0 #fff;
        cursor: move;
      }

    </style>
  </head>
<body>
<script type="text/javascript">

        var m = [30, 10, 10, 10],
            w = 1300 - m[1] - m[3],
            h = 500 - m[0] - m[2];

        var x = d3.scale.ordinal().rangePoints([0, w], 1),
            y = {},
            dragging = {};

        var line = d3.svg.line(),
            axis = d3.svg.axis().orient("left"),
            background,
            foreground;

     var svg = d3.select("body").append("svg:svg")
        .attr("width", w + m[1] + m[3])
        .attr("height", h + m[0] + m[2])
      .append("svg:g")
        .attr("transform", "translate(" + m[3] + "," + m[0] + ")");

      d3.csv("myData.csv")
      .row(function(d) {
        return {
        // Features that are needed to be visualize
         feature1   :  d.feature1,
         feature2   :  d.feature2,
         feature3   :  d.feature3,
         feature4   :  d.feature4,
         feature5   :  d.feature5,
         feature6   :  d.feature6,
         feature7   :  d.feature7,
         feature8   :  d.feature8
        };
      })
      .get(function(e, data) {
        x.domain(
            dimensions = d3.keys(data[0])
                            .filter(function(d) {
                                        return d != "source" && 
                                                (y[d] = d3.scale.linear()
                                                            .domain(d3.extent(data, function(p) { return +p[d]; }))
                                                            .range([h, 0]));
      }
      ));

      // Add grey background lines for context.
      background = svg.append("svg:g")
          .attr("class", "background")
        .selectAll("path")
          .data(data)
        .enter().append("svg:path")
          .attr("d", path);

      // Add blue foreground lines for focus.
      foreground = svg.append("svg:g")
          .attr("class", "foreground")
        .selectAll("path")
          .data(data)
        .enter().append("svg:path")
          .attr("d", path);

      // Add a group element for each dimension.
      var g = svg.selectAll(".dimension")
          .data(dimensions)
        .enter().append("svg:g")
          .attr("class", "dimension")
          .attr("transform", function(d) { return "translate(" + x(d) + ")"; })
          .call(d3.behavior.drag()
            .on("dragstart", function(d) {
              dragging[d] = this.__origin__ = x(d);
              background.attr("visibility", "hidden");
            })
            .on("drag", function(d) {
              dragging[d] = Math.min(w, Math.max(0, this.__origin__ += d3.event.dx));
              foreground.attr("d", path);
              dimensions.sort(function(a, b) { return position(a) - position(b); });
              x.domain(dimensions);
              g.attr("transform", function(d) { return "translate(" + position(d) + ")"; })
            })
            .on("dragend", function(d) {
              delete this.__origin__;
              delete dragging[d];
              transition(d3.select(this)).attr("transform", "translate(" + x(d) + ")");
              transition(foreground)
                  .attr("d", path);
              background
                  .attr("d", path)
                  .transition()
                  .delay(500)
                  .duration(0)
                  .attr("visibility", null);
            }));

      // Add an axis and title.
      g.append("svg:g")
          .attr("class", "axis")
          .each(function(d) { d3.select(this).call(axis.scale(y[d])); })
        .append("svg:text")
          .attr("text-anchor", "middle")
          .attr("y", -9)
          .text(String);

      // Add and store a brush for each axis.
      g.append("svg:g")
          .attr("class", "brush")
          .each(function(d) { d3.select(this).call(y[d].brush = d3.svg.brush().y(y[d]).on("brush", brush)); })
        .selectAll("rect")
          .attr("x", -8)
          .attr("width", 16);
    });

    function position(d) {
      var v = dragging[d];
      return v == null ? x(d) : v;
    }

    function transition(g) {
      return g.transition().duration(500);
    }

    // Returns the path for a given data point.
    function path(d) {
      return line(dimensions.map(function(p) { return [position(p), y[p](d[p])]; }));
    }

    // Handles a brush event, toggling the display of foreground lines.
    function brush() {
      var actives = dimensions.filter(function(p) { return !y[p].brush.empty(); }),
          extents = actives.map(function(p) { return y[p].brush.extent(); });
      foreground.style("display", function(d) {
        return actives.every(function(p, i) {
          return extents[i][0] <= d[p] && d[p] <= extents[i][1];
        }) ? null : "none";
      });
    }

        </script>
      </body>
现在,我有两个问题:

首先,我不知道如何同时加载4个csv文件?将来,我可能需要增加类的数量(即增加需要可视化的csv文件的数量),因此可能组合csv文件,只加载一个csv文件不是个好主意。我怎么办


其次,我应该如何为它们所属的csv文件的行着色?

要异步加载多个文件,可以使用队列库,例如

然后,加载文件后,可以在单个重叠的
g
组元素中渲染这些文件,并基于文件加载顺序的索引对整个组应用颜色

下面是一个未经测试和未完成的解决方案,可能会给您一些线索:

var q = queue(), // create the queue
    dataSources = [ // your data sources
        'dataSource1.csv',
        'dataSource2.csv',
        ...
    ],
    colorScale = d3.scale.category20(); // categorical color scale bundled with d3

// Returns a different color for elements based on their index in the data:
function colorByIndex(d, i) {
    return colorScale(i);
}

// Go through each data source and add it to the queue:
dataSources.forEach(function (source) {
    q.defer(function (callback) {
        d3.csv(source, callback);
    });
});

// Wait for all requests to be completed:
q.awaitAll(function (error, results) {
    // TODO: check for errors!
    // Select and create groups of elements that are to be colored differently:
    d3.selectAll('.group').data(results) // array of arrays
        .append('g')
        .style('color', colorByIndex) // this applies color to the entire group
            .selectAll('???') // whatever you render, paths perhaps
            .data(function (d) { return d; })
            ...
            // at this point the d variable is an array of data
            // straight from each of your csv files, you can
            // proceed rendering as you usually do and there's
            // no longer need to apply any colors
});
或者,您可以将
结果
合并到一个数组中,并用它来自哪个文件的指示符标记每一行,如下所示:

['dataSource1.csv', 'a1', 'b1', 'c1', ...],
['dataSource1.csv', 'a2', 'b2', 'c2', ...],
['dataSource2.csv', 'a3', 'b3', 'c3', ...],
...

然后根据指示器的值应用颜色。

谢谢您的回答。我正在尝试将您的代码放入我的代码中。我应该在哪里选择我感兴趣的功能?我应该把这个代码放在“.row(function(d){return{//需要可视化功能1:d.feature1、功能2:d.feature2、功能3:d.feature3、功能4:d.feature4、功能5:d.feature5、功能6:d.feature6、功能7、功能8:d.feature8}})”而不是“return d;”在您的代码中?@sara_123您可以直接从
.data(函数(d){return d;})
添加它。只需将
return d;
替换为您自己的“features”映射即可我想我在这里做错了什么,因为代码没有运行,它正在抱怨.get函数。我改变的是:q.awaitAll(函数(错误,结果){d3.selectAll('.group').data(结果)。append('g')。style('color',colorByIndex)。selectAll('path')。data(函数(d){return{feature1:d.feature1,feature2:d.feature2,…,feature8:d.feature8};}).get(函数(e,数据){/*我代码的其余部分*/}/*end of.get*/);}/*q.awaitAll的结尾*/)@Oleg,我仍然困在这里:(
['dataSource1.csv', 'a1', 'b1', 'c1', ...],
['dataSource1.csv', 'a2', 'b2', 'c2', ...],
['dataSource2.csv', 'a3', 'b3', 'c3', ...],
...