svg 可视化操作
本文是两篇系列文章中的第一篇,该系列文章演示了可视化技术,这些技术可以帮助您从数据中提取业务价值信息。 您将看到如何使用可伸缩矢量图形(SVG)和开放源代码的D3 JavaScript库来创建可在浏览器中查看的可视化效果,以通过形状和颜色传达信息。 我将通过示例来展示这些技术,这些示例可以可视化与社交媒体使用相关的浏览指标。 在第1部分中,我概述了SVG和D3如何协同工作以及一些基本示例。 第2部分将更深入地研究这种开放标准技术的强大组合的可视化功能。
分析社交媒体指标
公司了解客户行为的一种创新方式是通过社交媒体提出想法,并与潜在客户进行互动讨论。 社交媒体上的互动反映了双向的人类互动:要了解人们的好恶,您必须倾听他们的意见,就像您与任何想以积极方式与之互动的人所做的一样。
以一家家居装饰公司的假设场景为例,该公司以博客,视频,Facebook页面和讨论论坛的形式发布开放内容。 此内容通过社交媒体资源展示了公司的想法,并试图引发讨论和其他形式的用户交互。 内容迎合了各个客户的口味和喜好,因此可以帮助他们从一种社交资源导航到另一种社交资源。 为了判断不断变化的客户趋势并提出新的方法和新的设计,该公司希望从三个方面分析浏览数据:
- 受欢迎程度,以每种社交资源的观看次数表示
- 参与资源交互的用户数
- 用户从一种资源导航到另一种资源的方向
表1 , 2和3显示样品的数据显示的用户分别视图,用户交互和导航,数量,即发生在三个星期。 请注意,表使用颜色名称表示公司使用的社交媒体资源(例如博客和Facebook页面)的类型。
表1显示了每种资源的用户视图数量:
表1.每种社交资源的用户视图数
社会资源 | 蓝色 | 金 | 绿色 | 红 | 栗色 |
---|---|---|---|---|---|
第一周 | 7057 | 7483 | 3749 | 3846 | 4598 |
第二周 | 2371 | 7397 | 4589 | 2861 | 8249 |
第三周 | 5972 | 5672 | 9152 | 9725 | 8983 |
您可以在表1中看到,在第1周中蓝色资源被查看了7,057次,而黄金资源是该周中查看次数最多的资源。
表2显示了用户交互数据:
表2.在每种社交资源上进行交互的用户数
社会资源 | 蓝色 | 金 | 绿色 | 红 | 栗色 |
---|---|---|---|---|---|
第一周 | 2052年 | 2089 | 1586 | 1426 | 2632 |
第二周 | 2071 | 2190 | 7214 | 3782 | 2721 |
第三周 | 3076 | 3190 | 4532 | 3825 | 4831 |
从表2中可以看到,第一周有2052个用户在蓝色资源上进行了交互,并且在第一周内,褐红色资源上的用户交互度最高。
表3显示了从蓝色资源导航到其他资源的用户数量:
表3.蓝色社交资源的导航数据
社会资源 | 蓝金 | 蓝绿色 | 蓝到红 | 蓝色到栗色 |
---|---|---|---|---|
第一周 | 3057 | 3483 | 8749 | 8456 |
第二周 | 2371 | 7397 | 4589 | 2861 |
第三周 | 5972 | 5672 | 9152 | 9725 |
从表3中可以看到,第1周有3057位用户访问了蓝色资源后,他们导航到黄金资源,红色资源从蓝色资源中获得了最多的受众。
可视化浏览数据
与数字表相比,视觉表示提供了一种更轻松,更快捷的方式来解释大数据量。 表1 ,表2和表3中的数据可以通过多种方式以图形方式表示。 例如,图1是显示表1中第1周数据的简单方法:
图1.每个社交资源第1周的观看次数,以圆圈表示
图1将每个资源的视图数表示为一个圆圈。 圆的相对大小与它们表示的数字成比例,因此,观看最多的资源(金)由最大的圆表示。 每个圆圈还显示了第1周每种资源获得的实际观看次数。
图2是图1的略微变体,它使用不同的圆圈布局:
图2.第1周视图以不同的圆圈布局显示
每种资源的普及程度只是公司要分析的数据的一个维度。 图3显示了第1周中每种资源的视图数和在资源上进行交互的用户数,以一种直观的表示形式显示了二维:
图3.圆圈内的圆圈显示了第一周的用户视图数量和进行交互的用户数量
在图3中 ,外圈代表资源视图的总数,内圈代表在资源上进行交互的用户数。 我还在每个圆圈中加了数字,以显示实际的观看和互动数据。
图1 , 2和3层示出了简单的方法来组合颜色,形状,和实际的数字来表示数据。 通过查看图3 ,您可以看到在第1周中,黄金资源吸引了最多的用户观看,栗色资源吸引了最多的互动。
使用开放技术进行数据可视化
当前的开放标准和开放源代码工具功能强大,足以支持数据的图形表示。 SVG是一种开放的万维网联盟(W3C)标准,它定义了一种用于绘制二维图形对象的基于XML的格式。 (请参阅相关信息的链接,约SVG的介绍性文章。)SVG是由几个浏览器支持。 我在Google Chrome上测试了本文所有的SVG和JavaScript代码。
如果您正在使用数据和SVG,则D3库提供了一些魔术。 它会带走您的数据以及绘图说明,将数据与所需的SVG标签相关联,并立即生成SVG代码,您可以在浏览器中查看它。 当D3绘制复杂的图形对象时,它使您可以方便地使用数据,因此您可以一次又一步地深入到您的图形中,并仅处理绘制图形的每个小部分所需的少量数据。
对于本文和第2部分中的示例,我将从简单的工程图过渡到复杂的工程图,探索D3的功能,并为每个工程图提供SVG和JavaScript代码。 我从最简单的情况开始:SVG代码生成如图1所示的圆圈。
SVG数据表示
清单1是用于绘制图1中的圆圈的SVG代码:
清单1.绘制图1中圆圈的SVG代码
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
width="1000" height="1000">
<g transform="translate(70,143)">
<circle r="70.57" style="fill: #000fff;"></circle>
<text x="-10" fill="grey">7057</text>
</g>
<g transform="translate(216,143)">
<circle r="74.83" style="fill: #fff555;"></circle>
<text x="-10" fill="grey">7483</text>
</g>
<g transform="translate(329,143)">
<circle r="37.49" style="fill: #aaf000;">
</circle>
<text x="-10" fill="grey">3749</text>
</g>
<g transform="translate(404,143)">
<circle r="38.46" style="fill: #cc0000;"></circle>
<text x="-10" fill="grey">3846</text>
</g>
<g transform="translate(489,143)">
<circle r="45.98" style="fill: #993344;"></circle>
<text x="-10" fill="grey">4598</text>
</g>
</svg>
您可以看到清单1中的根标签是<svg>
。 <svg>
标记创建画布,在该画布上您可以使用其他SVG标记进行绘制,还可以用作这些标记的包装。 <svg>
标签的width
和height
属性指定SVG画布的尺寸。 我在清单1中设置的画布是1,000 x 1,000单位。
根<svg>
标记有五个<g>
子标记, 图1中每个圆圈一个。 <g>
标记用作完成每个圆及其随附文本的图形的包装。 每个<g>
标记都有一个名为transform
属性,其值是translate (X, Y)
。 translate (X, Y)
值确定绘制圆的点。 例如, 清单1中第一个<g>
标记的transform
属性将第一个圆的中心置于位置70、143。
五个<g>
标记中的每个标记对于transform
属性均具有不同的X
值,并且它们均具有相同的Y
值。 结果,五个圆沿水平线排列。 <g>
标记的不同X
值会导致每个圆画在前一个圆的旁边,并且中间没有可见的空格。 稍后,我将向您展示用于生成这些值的简单JavaScript。
进一步进入清单1 ,请注意,每个<g>
标记都有两个子代-一个<circle>
标记和一个<text>
标记-分别绘制了圆圈和其随附的文本。 每个<circle>
标记都有一个r
属性,该属性定义圆的半径。 请注意,每个<circle>
标记的r
属性的值是按比例缩小100的视图数。每个<circle>
标记还具有style
属性,该属性指定填充圆圈的颜色。 我使用六位数的十六进制格式来表示颜色的RGB(红色,绿色,蓝色)代码。 (参见相关主题上使用颜色的更多细节。)的<text>
标签包装每个圆圈内要被显示的文本。 我在每个<text>
标记中包含的x="-10"
属性使文本稍微移位以更好地定位。 <text>
标记的fill
属性指定文本颜色。
您可以下载本文的所有代码示例,然后在浏览器窗口中打开每个代码示例。 尝试在清单1中的SVG代码中添加更多的圆圈或文本,然后查看浏览器如何显示SVG。
使用JavaScript和D3生成SVG
清单2中JavaScript代码使用D3生成清单1中的SVG代码:
清单2.使用D3生成图1的SVG
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
//Step 1:
var views = [
[7057, 7483, 3749, 3846, 4598],
[ 2371, 7397, 4589, 2861, 8249],
[ 5972, 5672, 9152, 9725, 8983],
];
var width = 1000, height = 1000;
var colors = [ "blue",
"yellow",
"green",
"red",
"maroon"
];
var week = 0;
//Step 2:
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
//Step 3:
.selectAll("g")
.data(views[week])
.enter();
//Step 4:
var g = svg.append("g")
//Step 5:
.attr("transform", function(d,i){
var x = 0;
for (var count=0;
count<i;
count++ )
x+=views[week][count];
for (var count=0;
count<=i;
count++ )
x+=views[week][count];
return "translate(" + x/100 + "," + height / 7 + ")" }
);
//Step 6:
g.append("circle")
.attr("r", function(d){return d/100})
.style("fill", function(d, i){return colors[i];});
g.append("text")
.attr("x", -10)
.attr("fill", "grey")
.text(function(d){return d});
</script>
</body>
我添加了注释以指示清单2中的步骤:
步骤1 :第一步是将用户视图数据存储在数组中。 我还设置了一些变量来存储画布的尺寸和要在SVG绘图中使用的颜色。
步骤2:我开始将D3与d3.select("body").append("svg")
,这会将<svg>
标记添加到HTML页面的主体中。 在这里,我还通过调用.attr()
函数来设置SVG画布的宽度和高度。
步骤3 :这三个函数调用.selectAll().data().enter()
一起形成了D3带来的强度和易用性:
-
.selectAll("g")
调用选择根SVG标记的所有<g>
子标记。 尽管它现在无法选择任何内容(因为不存在),但它知道我要查找的内容。 -
.data(views[week])
调用将所有五种社交资源的一周用户浏览数据提供给D3。 -
.enter()
调用将各个<g>
标记与各个用户视图数据记录相关联。
步骤4 : .append("g")
调用告诉D3 添加足够的<g>
标签,以便为数据中的每个记录提供一个<g>
标签 。 因为开始时不存在<g>
标签,并且数据数组中的每个星期都有五条记录(每个社交资源一个),所以D3将五个<g>
标签添加到根<svg>
标签中。 第一个<g>
标记在内部与第一个数据记录(即views-data数组中的7057)关联,第二个<g>
标记与第二个记录在内部关联,依此类推。 D3在内部将数据与SVG标签相关联,因此我在创作时只需要传递一次数据数组,而不必担心将正确的数据与每个单独的SVG标签相关联。
步骤5 :我还必须为五个<g>
标签的每一个添加一个transform
属性,所以我调用.attr()
函数。 我只需要调用一次,D3在内部处理循环,以确保将transform
属性添加到五个<g>
标签的每个标签中。
.attr()
函数将要编写的属性的名称(在本例中为transform
)作为其第一个参数。 回想一下清单1的讨论, transform
属性决定了圆的位置,因此必须在函数中计算其值。 因此, .attr()
函数的第二个参数是另一个函数调用,该函数本身具有两个参数: d
和i
。
D3为您提供了进行函数调用的机会,因为在编写属性值时可能需要与<g>
标记关联的数据。 d
参数保存您正在为其为其编写transform
属性值的特定<g>
标记的数据(例如,对于与表示蓝色用户视图的记录相关联的第一个<g>
标记为7057)社会资源)。 D3的神奇之处在于,它内部处理与单个标签相关的正确数据关联,因此您不必担心选择正确的数据。 D3的神奇之处在于,它内部处理与单个标签相关的正确数据关联,因此您不必担心选择正确的数据。 在创作SVG时,您可以专注于数据处理。
i
参数是数据的从零开始的索引(例如,对于与第一条记录相关联的第一个<g>
标记, i
= 0)。 您可以在此步骤中看到,我使用i
参数计算<g>
标签的适当位置,从而在最左侧绘制了第一个(蓝色)社交资源的圆圈,然后绘制了与第一个圆圈相邻的第二个圆圈, 等等。
如果仅尝试运行步骤1-5的代码,则会看到五个<g>
子标记以及transform
属性,如清单3的SVG代码所示。(这些<g>
标记不会在浏览器中显示图形)窗口呢。)
清单3.仅带有五个<g>
标签的SVG代码
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
width="1000" height="1000">
<g transform="translate(70,143)">
</g>
<g transform="translate(216,143)">
</g>
<g transform="translate(329,143)">
</g>
<g transform="translate(404,143)">
</g>
<g transform="translate(489,143)">
</g>
</svg>
步骤6 :剩下的任务是向五个<g>
标签的每一个添加<circle>
标签和<text>
<g>
标签。 为此,您需要两次调用.append()
函数(对于<circle>
一次,对于<text>
标签一次)。
请注意,我使用.attr("r", function(d){return d/100})
来创建圆的r
属性(半径)。 在这种情况下,我必须只知道特定资源的视图数才能绘制成比例的圆。 这就是为什么我只需要d
参数而不需要i
参数的原因,所以我省略了i
。 d
参数自动包含正确的数据(视图数),因此我将d的值除以100以缩放圆的大小。
基于D3JavaScript代码已准备就绪,可以绘制图1的圆圈。 如果从浏览器窗口中的示例代码下载中打开Listing2.html,您会看到它生成了清单1的SVG并显示了图1的圆圈。
圆的布局略有不同
您可以稍微修改清单2中的代码以绘制如图2所示的圆的布局。 清单4显示了修改后JavaScript:
清单4.用于绘制图2布局的修改后的代码
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var views = [
[7057, 7483, 3749, 3846, 4598],
[ 2371, 7397, 4589, 2861, 8249],
[ 5972, 5672, 9152, 9725, 8983],
[ 9763, 8462, 9782, 1953, 5182],
[ 9567, 1571, 2895, 2783, 1874],
[ 2371, 7397, 4589, 2861, 8249]
];
var width = 1000, height = 1000;
var colors = [ "#0000ff", //blue
"#ffd700", //gold
"#008000", //green
"#ff0000", //red
"#800000" //maroon
];
var week = 0, scale = 100;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.selectAll("g").data(views[week]).enter();
var g = svg.append("g")
.attr("transform", function(d,i){
var x = 10000, y = 10000;
if (!(i%2)){
for (var count=0;
count<i;
count++)
x+=views[week][count];
for (var count=0;
count<=i;
count++)
y+=views[week][count];
} else {
for (var count=0;
count<i;
count++)
y+=views[week][count];
for (var count=0;
count<=i;
count++)
x+=views[week][count];
}
return "translate(" + x/scale + "," + y/scale + ")"}
);
g.append("circle")
.attr("r", function(d){return d/scale})
.style("fill", function(d, i){return colors[i];});
g.append("text")
.attr("x", -10)
.attr("fill", "grey")
.text(function(d){return d});
</script>
</body>
通过将清单2与清单4进行比较,您可以看到修改在于transform
属性值的计算, 清单4中以粗体突出显示了该属性。
围成一圈
现在看清单5,它是用于绘制图3的圆的SVG代码(圆内的圆同时表示视图和交互数据):
清单5.图3的SVG代码
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
width="1000" height="1000">
<g transform="translate(100,170.57)">
<circle r="70.57" style="fill: #0000ff;">
</circle>
<circle r="20.52" style="fill: #add8e6;">
</circle>
<text x="-15" y="35.52" fill="white">7057</text>
<text x="-15" y="5">2052</text>
</g>
<g transform="translate(245.4,170.57)">
<circle r="74.83" style="fill: #ffd700;">
</circle>
<circle r="20.89" style="fill: #ffff00;">
</circle>
<text x="-15" y="35.89" fill="white">7483</text>
<text x="-15" y="5">2089</text>
</g>
<g transform="translate(245.4,282.89)">
<circle r="37.49" style="fill: #008000;"></circle>
<circle r="15.86" style="fill: #90ee90;"></circle>
<text x="-15" y="30.86" fill="white">3749</text>
<text x="-15" y="5">1586</text>
</g>
<g transform="translate(321.35,282.89)">
<circle r="38.46" style="fill: #ff0000;"></circle>
<circle r="14.26" style="fill: #f08080;"></circle>
<text x="-15" y="29.26" fill="white">3846</text>
<text x="-15" y="5">1426</text>
</g>
<g transform="translate(321.35,367.33)">
<circle r="45.98" style="fill: #800000;"></circle>
<circle r="26.32" style="fill: #cd5c5c;"></circle>
<text x="-15" y="41.32" fill="white">4598</text>
<text x="-15" y="5">2632</text>
</g>
</svg>
您可以看到清单5在每个<g>
标记内有两个<circle>
和两个<text>
标记,而清单1仅具有一对<circle>
和<text>
标记。 这很容易理解,因为图3必须绘制两个具有相同中心的圆以给出一个圆内的圆的视图,并且两个圆中的每个圆都有一个与之关联的数字。
清单6显示了用于生成图3的基于D3JavaScript代码:
清单6.用于绘制图3JavaScript
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var viewsAndInteraction = [
[ [7057, 2052], [7483, 2089], [3749, 1586],
[3846, 1426], [4598, 2632] ],
[ [5972, 2071], [5672, 2190], [9152, 7214],
[9725, 3782], [8983, 2721] ],
[ [8749, 3076], [4768, 3190], [6738, 4532],
[9546, 3825], [6983, 4831] ]
];
var width = 1000, height = 1000;
var viewColors = [ "blue",
"gold",
"green",
"red",
"maroon"
];
var interactionColors = [ "lightblue",
"yellow",
"lightgreen",
"lightcoral",
"indianred"
];
var week = 0, scale = 100;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.selectAll("g")
.data(viewsAndInteraction[week])
.enter();
var g = svg.append("g")
.attr("transform", function(d,i){
var x = 10000, y = 10000;
if (!(i%2)){
for (var count=0;
count<i;
count++)
x+=viewsAndInteraction[week][count][0];
for (var count=0;
count<=i;
count++)
y+=viewsAndInteraction[week][count][0];
} else {
for (var count=0;
count<i;
count++)
y+=viewsAndInteraction[week][count][0];
for (var count=0;
count<=i;
count++)
x+=viewsAndInteraction[week][count][0];
}
return "translate(" + x/scale + "," + y/scale + ")"}
);
g.append("circle")
.attr("r", function(d){return d[0]/scale})
.style("fill", function(d, i){return viewColors[i];});
g.append("circle")
.attr("r", function(d){return d[1]/scale})
.style("fill", function(d, i){return interactionColors[i];});
g.append("text")
.attr("x", -15)
.attr("y", function(d){return (15 + d[1]/scale);})
.attr("fill", "white")
.text(function(d){return d[0]});
g.append("text")
.attr("x", -15)
.attr("y", 5)
.text(function(d){return d[1]});
</script>
</body>
如果将清单2中JavaScript与清单6中的代码进行比较,您会发现几乎所有内容都是相同的。 区别在于清单6 :
- 您必须使用视图和交互数据,因此
viewsAndInteraction
数组同时包含视图和交互数据。 - 有两对
g.append("circle")
和g.append("text")
函数调用可绘制两个圆,每个圆都与文本位于同一中心。
现在,您已经看到了所有三个图的SVG和JavaScript。 下一个示例将导航数据可视化。
可视化导航数据表示
图4使用不同颜色的圆弧和弦显示了第一周的一些导航数据:从蓝色资源导航到其他资源的用户数量:
图4.彩色圆弧和弦显示导航数据
图4中的彩色弧线代表不同的社会资源。 蓝色资源通过和弦连接到所有其他资源。 每个和弦代表导航。
蓝色和弦在蓝色资源处开始和结束,代表开始在蓝色资源处浏览并且不进一步浏览的用户数量。 从蓝色资源开始到黄金资源结束的金和弦代表从蓝色资源导航到金资源的用户数量。 同样, 图4描述了从蓝色资源到其余资源的导航。
请注意,和弦(从蓝色开始)按升序排列,首先由较小的和弦代表较少的用户。 因此,您无需数字即可查看哪些资源吸引了更多用户。
使用SVG绘制弧线和弦
清单7显示了绘制图4的部分SVG代码:
清单7.用于绘制图4的部分SVG代码
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
width="500" height="500">
<g transform="translate(250,250)">
<path style="fill: #0000ff;"
d="M1.1633760361312584e-14,-190A190,190 0 0,1
177.80498922385382,-66.97302298019123L140.372
3599135688,-52.873439194887816A150,150 0 0,0
9.18454765366783e-15,-150Z"></path>
<path style="fill: #ffd700;"
d="M177.80498922385382,-66.97302298019123A190,190 0 0,1
141.9432774826573,126.30164677264251L112.06048222315049,99
.71182639945462A150,150 0 0,0 140.3723599135688,-
52.873439194887816Z"></path>
<path style="fill: #008000;"
d="M141.9432774826573,126.30164677264251A190,190 0 0,1 -
141.87314929322426,126.38041584684909L-
112.00511786307179,99.77401251067033A150,150 0 0,0
112.06048222315049,99.71182639945462Z"></path>
<path style="fill: #ff0000;"
d="M-141.87314929322426,126.38041584684909A190,190 0
0,1 -136.03537960886078,-132.64379176830383L-
107.39635232278484,-104.7187829749767A150,150 0 0,0 -
112.00511786307179,99.77401251067033Z"></path>
<path style="fill: #800000;"
d="M-136.03537960886078,-132.64379176830383A190,190 0 0,1 -
3.7240908056998534e-13,-190L-2.9400716887104106e-13,-
150A150,150 0 0,0 -107.39635232278484,-
104.7187829749767Z"></path>
<g>
<!--Drawing SVG code for chords goes here. -->
</g>
</g>
</svg>
您可以看到清单7中的根<svg>
标记有一个<g>
子标记,而子标记又有五个<path>
标记和另一个内部<g>
子标记。 五个<path>
标记绘制五个彩色弧。 内部的<g>
标记包装用于绘制和弦的SVG代码,我将在稍后解释。 首先,我解释<path>
标记如何绘制五个弧。
绘制一组彩色弧
使用SVG <path>
标签可以很容易地绘制一组具有适当颜色的弧,其目的是定义绘制路径,就像用笔在纸上绘制一样。 路径可以是封闭的(例如,三角形)或开放的(例如,一组互连的线)。 您需要一条闭合的路径来绘制圆弧,如图5所示:
图5.用<path>
标签绘制弧
在图5中 ,圆弧的封闭路径的周长用黑色绘制,封闭路径用黄色填充。 如果用笔绘制此弧,则将绘制两条弯曲的曲线和两条黑色的直线,然后用黄色填充内部。
图4中的五个弧形中的每一个均使用相同的颜色作为其外围并填充其闭合路径。 因此,您需要五个<path>
标签,每个圆弧对应一个。
在清单7中 ,您可以看到五个<path>
标记中的每个标记都有两个属性: style
和d
。 style
属性定义用于绘制的颜色, d
属性定义绘制路径。
d
属性的值(例如M8.572244476756641e-15,-140A140,140 0 0,1 93.95877067680189,103.78703875197591L67.11340762628707,74.13359910855422A100,100 0 0,0 6.123031769111886e-15,-100Z
看起来很长并且复杂。 官方SVG规范要求使用此格式来定义该值,以定义确切的绘制路径。
格式包括M
后跟两个逗号分隔的数字,然后是A
然后是数个数字,然后是L
然后是两个逗号分隔的数字,然后是另一个A
然后是数个数字,最后是Z
此序列的装置:M OVE由后的数字定义的点M
,然后绘制由数字定义的A RC之后A
,然后绘制A L INE到由号码之后定义的点L
,然后绘制另一个甲 RC(第二圆弧)。 末端装置中的Z
返回初始位置 ,从而形成闭合路径。
好消息是,您无需了解有关此序列如何精确绘制所需圆弧的更多详细信息-因为所有这些值都是使用D3库计算的,该库包含用于绘制复杂图形的易于使用的功能。 稍后,我将向您展示D3 JavaScript代码,该代码执行所有绘图计算并动态生成图4的完整SVG代码。
每个圆的五个<path>
标记都是绘制弧所需要的。 在浏览器中打开Listing7.svg文件(请参阅下载 ),查看没有任何弦的彩色弧,如图6所示:
图6.彩色弧
现在,我将展示如何绘制和弦来表示导航。
绘制和弦
像弧一样,用一个<g>
标记绘制和弦,该标记是五个<path>
标记的包装,每个和弦一个,如清单8所示:
清单8.用于绘制五个和弦的SVG代码
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
width="500" height="500">
<g transform="translate(250,250)">
<!--Drawing SVG code for arcs goes here. -->
<g>
<path d="M9.18454765366783e-15,-150A150,150 0 0,1
19.52349842170555,-148.72401624948697Q 0,0
9.18454765366783e-15,-150Z"
style="fill: #0000ff;">
</path>
<path d="M19.52349842170555,- 148.72401624948697A150,150
0 0,1 41.344235247425466,-144.18964668729006Q 0,0
140.3723599135688,-52.873439194887816A150,150 0 0,1
144.99722485611238,-38.41620470616511Q 0,0
19.52349842170555,-148.72401624948697Z"
style="fill: #ffd700;">
</path>
<path d="M111.39598065576133,-100.4536484839712A150,150
0 0,1 140.3723599135688,-52.873439194887816Q 0,0
84.8772338498757,123.67641316756206A150,150 0 0,1
50.93706344958661,141.08655345968583Q 0,0
111.39598065576133,-100.4536484839712Z"
style="fill: #008000;">
</path>
<path d="M-149.71409635840777,9.256854302914952A150,150
0 0,1 -140.64142529945457,-52.15351847898602Q 0,0
68.6764412000974,-133.35496400243062A150,150 0 0,1
111.39598065576133,-100.4536484839712Q 0,0 -
149.71409635840777,9.256854302914952Z"
style="fill: #ff0000;">
</path>
<path d="M-59.58349836433014,-137.65829696268898A150,150
0 0,1 -1.6078040591602227e-13,-150Q 0,0
41.344235247425466,-144.18964668729006A150,150 0 0,1
68.6764412000974,-133.35496400243062Q 0,0 -
59.58349836433014,-137.65829696268898Z"
style="fill: #800000;">
</path>
</g>
</g>
</svg>
您可以看到清单8中所有和弦的<path>
标记(如清单7中的标记)对于要由D3计算的d
属性具有一个长而复杂的值。
清单8省略了弧的<path>
标记。 如果在浏览器中查看清单8中的SVG代码,您将看到没有弧的和弦(因此也没有圆的周长),如图7所示:
图7.五组不带圆弧的和弦
现在,我将向您展示用于生成图4的SVG代码的基于D3JavaScript代码。
使用D3绘制带有和弦的圆圈
您可以在清单9JavaScript代码中看到五个步骤,该步骤使用D3编写图4的SVG:
清单9.生成图4中的SVG代码的五个步骤
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
//Step 1:
var navigation = [
[3057, 3483, 8749, 8465, 4598],
[ 2371, 7397, 4589, 2861, 8249],
[ 5972, 5672, 9152, 9725, 8983],
[ 9763, 8462, 9782, 1953, 5182],
[ 9567, 1571, 2895, 2783, 1874]
];
var navigationChord = d3.layout.chord()
.matrix(navigation);
var chordCalculations = navigationChord.chords;
var colors = [ "blue",
"gold",
"green",
"red",
"maroon"
];
var width = 500, height = 500, radius = 150, arcStroke = 40;
//Step 2:
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
//Step 3:
.append("g")
.attr("transform", function(d,i){
return "translate(" + width/2 + "," + height / 2 + ")"
});
//Step 4:
svg.selectAll("path")
.data(navigationChord.groups())
.enter()
.append("path")
.style("fill", function(d, i) { return colors[i]; })
.attr("d", d3.svg.arc().innerRadius(radius)
.outerRadius(radius+arcStroke));
//Step 5:
navigationChord.sortSubgroups(d3.ascending);
svg.append("g")
.selectAll("path")
.data(chordCalculations)
.enter()
.append("path")
.attr("d", d3.svg.chord().radius(radius))
.style("fill", function(d, i) {
if (i < colors.length) return colors[i]})
.style("opacity", function(d, i){
if (!(i < colors.length)) return 0 });
</script>
</body>
步骤1存储数据并设置变量。 我将导航数据存储在一个名为navigation
的数组中,然后将其传递给内部处理布局的d3.layout
。 我将d3.layout
完成的计算存储在名为chordCalculations
的变量中,该变量在第5步中用于绘制和弦。
步骤2是编写<svg>
包装器并设置其尺寸。
步骤3是添加<g>
标记,用作所有图形标记的包装。
步骤4为您在清单7中看到的SVG代码的弧线创建了五个<path>
标记。 使用d3.svg.arc()
,它在内部进行所有计算,以为彩色弧的所有五个<path>
标签创建d
属性的值。
步骤5编写和弦的<path>
标记。 我首先将和弦按升序排列,然后将和弦计算传递到D3的四个神奇步骤: .selectAll().data().enter().append()
。 最后, d3.svg.chord()
绘制五个和弦的<path>
标记的d
属性的值。
下次
在本文中,我为发现SVG和D3协同工作的全部图形功能奠定了基础。 第2部分展示了D3布局的优势,它可以执行图形计算以在单个SVG画布上绘制形状的多个副本。 它还显示了如何绘制流行度,用户交互和导航数据的图表表示形式。 最后,我向您展示如何在单个SVG工程图中将圆,弧,和弦,图表和布局放在一起。
翻译自: https://www.ibm.com/developerworks/opensource/library/os-dataviz1/index.html
svg 可视化操作