12

我在使用d3 sankey实现时遇到的一个问题是无法指定节点在 x 轴上的位置。我一直在研究源代码,实际上并没有一种“干净”的方式来以合理的比例指定 x 值(即 1-5,其中图表为 5 个节点宽)。我正在创建一些可以用作教育课程规划器的东西,因此 x 值将与学期相对应。假设我有一门直到大学二年级才能上的课程,这将是 x 为 3(1/2 是大一,3/4 是大二,等等)。问题是,如果事先没有任何链接到这门课程,它的 x 总是为 1,所以我想把它推到右边的两个空格。

我注意到实际桑基图中的 x 值并不能反映它有多少个节点,所以这有点难以做到。

我也遇到过这个问题,我意识到默认情况下图表不会让我定位节点。我可以毫无问题地调整 sankey.js 示例来完成此操作,但目前我对如何执行此操作感到困惑。

4

6 回答 6

17

这个有可能。请参阅此JSFiddle

在此处输入图像描述

可以修改 sankey.js 中的computeNodeBreadths函数以查找已分配给节点 (node.xPos) 的显式 x 位置:

  function computeNodeBreadths() {
    var remainingNodes = nodes,
        nextNodes,
        x = 0;

    while (remainingNodes.length) {
      nextNodes = [];
      remainingNodes.forEach(function(node) {

        if (node.xPos)
            node.x = node.xPos;
        else
            node.x = x;

        node.dx = nodeWidth;
        node.sourceLinks.forEach(function(link) {
          nextNodes.push(link.target);
        });
      });
      remainingNodes = nextNodes;
      ++x;
    }

    //
    moveSinksRight(x);
    scaleNodeBreadths((width - nodeWidth) / (x - 1));
  }

然后,您需要做的就是在所需节点上指定 xPos。在上面的示例中,我在 node2 上设置了 xPos = 1。请参阅 JSFiddle 示例中的 getData():

... }, {
        "node": 2,
        "name": "node2",
        "xPos": 1
    }, { ...
于 2014-02-04T00:16:07.803 回答
4

如果有人正在寻找如何修复已部署节点(矩形)的初始位置,您可以这样做:

sankey.layout = function(iterations) {
    computeNodeLinks();
    computeNodeValues();
    computeNodeBreadths();
    computeNodeDepths(iterations);
    computeAbsolutePositions(); // add this in sankey.js file
    computeLinkDepths();
    return sankey;
};

并添加职位本身:

function computeAbsolutePositions() {
    nodes[0].x = 0;
    nodes[0].y = 0;
    nodes[1].x = 260;
    nodes[1].y = 0;
};

请注意,当您像这样对矩形进行硬编码时,您必须自己注意矩形的位置,因为该示例中没有使用 sankey.js 最初使用的碰撞检查功能。

希望可以帮助某人!

于 2015-04-24T08:08:13.540 回答
2

让我们称之为 x 坐标layerlayer=0将是左边缘,layer=n将是右边缘。在您的JSON文件中的nodes字段中,添加键值对layer: your_desired_x_as_integer

然后去 sankey.js 文件并找到函数componentsByBreadth.forEach。将行替换为node.x = component.x + node.x;

if (node.layer) node.x=node.layer;
else node.x = component.x + node.x;

您也可以像这样定义层的密度,例如,放置在层 0、1、2 或 0、4、8 上的节点将有一个中心节点,两个在 sankey 宽度的边缘,但 0、1、5 将没有。

如果您需要更多帮助,我的 D3 Sankey 应用程序中包含此功能,其中包括:http: //sankey.csaladen.es

于 2015-05-01T03:56:39.953 回答
0

可能不是您想要的干净答案,但您可以显式更改源和目​​标 x 属性,然后更新链接

http://bl.ocks.org/danharr/af796d91926d254dfe99

于 2014-10-30T17:14:59.587 回答
0

有一个 d3-sankey 的修改版本支持这个(和一些其他特性),它似乎是针对 d3 v4 构建的:

https://github.com/ricklupton/d3-sankey-diagram#layout-rankSets

它包括一个rankSets允许 x 定位的选项。

但是,我发现了一些警告:

  • 不支持官方 API,因此您无法更改链接的阴影等。
  • 针对 d3 v4 而不是 v7 构建(最新的,好像这个评论)
  • 不是 api 兼容的,所以不是替代品。
  • 文档看起来与官方d3-sankey文档非常相似,以至于我一开始误以为它是官方文档。

有一个未解决的问题,其中包含已升级为与 d3 v7 一起使用的版本,但它仍然与官方d3-sankeyapi 不兼容。

在官方 repo 上有几个与此相关的公开票证,没有一个被合并,所以如果你想保持与主线的兼容性,你必须分叉官方分支并维护你的分叉。

于 2022-01-31T13:21:57.363 回答
0

对于d3v7 和 d3-sankey 0.12.3,补丁d3-sankey.js支持明确设置节点的级别,如下所示:

替换computeNodeLayersd3-sankey以下函数:

    //
    // Patch computeNodeLayers to use existing layer if specified (fixedLayer)
    //
    function computeNodeLayers({ nodes }) {
      const x = d3Array.max(nodes, d => d.depth) + 1;
      const kx = (x1 - x0 - dx) / (x - 1);
      const columns = new Array(x);
      for (const node of nodes) {
        // Patch: Override here
        var i = Math.max(0, Math.min(x - 1, Math.floor(align.call(null, node, x))));
        i = node.fixedLayer !== undefined ? node.fixedLayer : 1
        node.layer = i
        node.x0 = x0 + i * kx;
        node.x1 = node.x0 + dx;
        if (columns[i]) columns[i].push(node);
        else columns[i] = [node];
      }
      if (sort) for (const column of columns) {
        column.sort(sort);
      }
      return columns;
    }

如果你node有一个fixedLayer属性,它将被用来代替计算的节点层。

适用于https://github.com/d3/d3-sankey v0.12.3 使用d3v7

于 2022-01-31T15:01:58.127 回答