You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在SAS EG中用JavaScript+D3 3.x生成桑基图遇空白输出求助

在SAS EG中生成D3桑基图的完整解决方案

我明白你在SAS EG里尝试用PROC STREAM/TEMPLATE生成D3桑基图却得到空白页面的困扰——大概率是数据传递环节没处理好,或者桑基图需要的nodes+links格式没正确生成。下面是一步到位的解决方案,直接用你提供的测试数据生成可用的桑基图:

步骤1:准备SAS数据集

先把你的输入数据转换成SAS数据集,方便后续处理:

/* 创建桑基图的链接数据 */
data sankey_links;
    length source $1 target $1;
    input source $ target $ value;
    datalines;
A X 5
A Y 7
A Z 6
B X 2
B Y 9
B Z 4
X L 5
;
run;

步骤2:将SAS数据转为JSON格式

桑基图需要JSON格式的数据,我们用PROC JSON生成JSON字符串并存储到宏变量中:

/* 临时存储JSON文件 */
filename json_temp temp;

/* 导出SAS数据集为JSON,保留原始字段名 */
proc json out=json_temp nosastags pretty;
    export sankey_links / keysource=source keytarget=target keyvalue=value;
run;

/* 将JSON内容读入宏变量,方便嵌入HTML */
data _null_;
    infile json_temp lrecl=32767 truncover;
    length json_str $32767;
    retain json_str '';
    input line $char32767.;
    json_str = catx('', json_str, line);
    /* 转义双引号,避免HTML里的语法冲突 */
    json_str = tranwrd(json_str, '"', '\\"');
    call symputx('sankey_json', json_str);
run;
filename json_temp clear;

步骤3:用PROC STREAM生成包含D3代码的HTML

这里我们直接把D3 v3的CDN引用、桑基图代码和嵌入的JSON数据整合到HTML中,重点修改了原代码的数据源部分(不再异步加载外部JSON,而是直接使用SAS传递的链接数据,并自动生成节点列表):

/* 生成最终的HTML文件,可指定输出路径 */
filename sankey_html "&your_output_path./sankey_diagram.html";

proc stream out=sankey_html;
begin
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>SAS D3 Sankey Diagram</title>
    <!-- 引用D3.js v3版本(桑基图依赖v3的API) -->
    <script src="https://d3js.org/d3.v3.min.js"></script>
    <style>
        .link {
            fill: none;
            stroke: #000;
            stroke-opacity: .2;
        }
        .link:hover {
            stroke-opacity: .5;
        }
        .node rect {
            cursor: move;
            fill-opacity: .9;
            shape-rendering: crispEdges;
        }
        .node text {
            pointer-events: none;
            text-shadow: 0 1px 0 #fff;
        }
    </style>
</head>
<body>
<script>
// 从SAS传递过来的链接数据
var links = &sankey_json.;

// 自动生成桑基图需要的节点列表(去重所有source/target)
var nodes = {};
links.forEach(function(link) {
  link.source = nodes[link.source] || (nodes[link.source] = {name: link.source});
  link.target = nodes[link.target] || (nodes[link.target] = {name: link.target});
  link.value = +link.value;
});

// 组装桑基图需要的标准格式:nodes + links
var graph = {
  nodes: d3.values(nodes),
  links: links
};

// 桑基图核心配置(和原代码一致)
var width = 960,
    height = 500;

var color = d3.scale.category20();

var sankey = d3.sankey()
    .nodeWidth(15)
    .nodePadding(10)
    .size([width, height]);

var path = sankey.link();

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
  .append("g")
    .attr("transform", "translate(0,0)");

sankey
    .nodes(graph.nodes)
    .links(graph.links)
    .layout(32);

// 绘制链接
var link = svg.append("g").selectAll(".link")
    .data(graph.links)
  .enter().append("path")
    .attr("class", "link")
    .attr("d", path)
    .style("stroke-width", function(d) { return Math.max(1, d.dy); })
    .sort(function(a, b) { return b.dy - a.dy; });

link.append("title")
    .text(function(d) { return d.source.name + " → " + d.target.name + "\n" + d.value; });

// 绘制节点
var node = svg.append("g").selectAll(".node")
    .data(graph.nodes)
  .enter().append("g")
    .attr("class", "node")
    .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
  .call(d3.behavior.drag()
    .origin(function(d) { return d; })
    .on("dragstart", function() { this.parentNode.appendChild(this); })
    .on("drag", dragmove));

node.append("rect")
    .attr("height", function(d) { return d.dy; })
    .attr("width", sankey.nodeWidth())
    .style("fill", function(d) { return d.color = color(d.name.replace(/ .*/, "")); })
    .style("stroke", function(d) { return d3.rgb(d.color).darker(2); })
  .append("title")
    .text(function(d) { return d.name + "\n" + d.value; });

node.append("text")
    .attr("x", -6)
    .attr("y", function(d) { return d.dy / 2; })
    .attr("dy", ".35em")
    .attr("text-anchor", "end")
    .attr("transform", null)
    .text(function(d) { return d.name; })
  .filter(function(d) { return d.x < width / 2; })
    .attr("x", 6 + sankey.nodeWidth())
    .attr("text-anchor", "start");

// 节点拖拽功能
function dragmove(d) {
  d3.select(this).attr("transform", "translate(" + d.x + "," + (d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))) + ")");
  sankey.relayout();
  link.attr("d", path);
}
</script>
</body>
</html>
;
end;
run;
filename sankey_html clear;

关键注意事项(解决空白问题的核心)

  • D3版本匹配:原代码用的是D3 v3,必须引用d3.v3.min.js,不能用v4+版本(API完全不兼容)。
  • 数据格式转换:桑基图需要nodes(节点列表)和links(链接列表)两个部分,你提供的原始数据只有links,必须通过JS代码自动提取节点并生成nodes数组。
  • 宏变量转义:SAS宏变量里的双引号要转义成\",否则会破坏HTML/JS的语法结构,导致代码无法执行。
  • 路径权限:确保你指定的&your_output_path.是SAS EG有读写权限的路径,比如你的个人目录或者服务器共享目录。

运行完这段代码后,找到生成的HTML文件,用浏览器打开就能看到和你期望的同款桑基图了!

内容的提问来源于stack exchange,提问作者user7078484

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 07:54:08