29/11/2024

Tech Guru

Trusted Source Technology

Changing Font Sizes

Changing Font Sizes

Preamble¶

In [1]:
from plotapi import Sankey

Sankey.set_license("your username", "your license key")

Introduction¶

The Plotapi Sankey diagram font-sizes changed independently.

As we can see, we have set our license details in the preamble with Sankey.set_license().

Dataset¶

Plotapi Sankey expects a list of dictionary items, these will define the flow between a source and a target.

In [2]:
links = [
    "source":"Group A", "target":"Rank 1", "value": 1000,
    "source":"Group B", "target":"Rank 1", "value": 300,
    "source":"Group B", "target":"Rank 2", "value": 600,
    "source":"Group B", "target":"Rank 3", "value": 400,
    "source":"Rank 1", "target":"Club A", "value": 700,
    "source":"Rank 1", "target":"Club B", "value": 400,
    "source":"Rank 1", "target":"Club C", "value": 200,
    "source":"Rank 2", "target":"Club B", "value": 200,
    "source":"Rank 2", "target":"Club C", "value": 400,
    "source":"Rank 3", "target":"Withdrawn", "value": 400,
    "source":"Club A", "target":"The Most Amazing Prize", "value": 500,
]

We can add many sources and targets in any arrangement.

Visualisation¶

The font-sizes can be adjusted through a combination of the following:

  • title_font_size – to change the title font-size.
  • node_font_size – to change the node label font-size.
  • link_font_size – to change the link label font-size.

Let’s demonstrate these in action.

Here we’re using .show() which outputs to a Jupyter Notebook cell, however, we may want to output to an HTML file with .to_html() instead. More on the different output methods later!

Be sure to interact with the visualisation to see what the settings can do!

In [18]:
Sankey(links, title="Font-size demonstration",
       node_font_size=10,
       link_font_size=30,
       title_font_size=30).show()

Plotapi – Sankey Diagram

#plotapi-chart-fe6f3ceb,
.tippy-box,
#plotapi-chart-fe6f3ceb-to_svg
font-family: “Assistant”, sans-serif !important;
text-align: center;

#plotapi-chart-fe6f3ceb .link:hover
stroke-opacity: .45;

#plotapi-chart-fe6f3ceb .node
cursor: move;

#plotapi-chart-fe6f3ceb .nodeTextSpan
paint-order: stroke;
stroke-width: 3px;
stroke-linecap: butt;
stroke-linejoin: miter;
font-weight: bold;

#plotapi-chart-fe6f3ceb .linkText>textPath
paint-order: stroke;
stroke-linecap: butt;
stroke-linejoin: miter;
font-weight: bold;

#plotapi-chart-fe6f3ceb .linkText>textPath::selection,
#plotapi-chart-fe6f3ceb .nodeText::selection,
#plotapi-chart-fe6f3ceb .nodeTextSpan::selection
background: none;

#plotapi-chart-fe6f3ceb svg
max-width: 800px;

(function() {

var dependencies_paths =
‘d3’: ‘https://plotapi.com/static/js/d3.v7.min’,
‘d3-sankey’: ‘https://plotapi.com/static/js/d3-sankey’,
‘@popperjs/core’: ‘https://plotapi.com/static/js/popper.min’,
‘tippy’: ‘https://plotapi.com/static/js/tippy.min’,
‘d3-path’: ‘https://plotapi.com/static/js/d3-path’,
‘d3-shape’: ‘https://plotapi.com/static/js/d3-shape’,
‘d3-array’: ‘https://plotapi.com/static/js/d3-array’

var jupyter_classic = !(typeof(IPython)===”undefined”);

if(jupyter_classic)
require.config(

paths: dependencies_paths

);

require([‘d3′,’tippy’, ‘d3-sankey’], function(d3, tippy, d3sankey)
window.d3 = d3;
window.tippy = tippy;
window.d3sankey = d3sankey;
plotapi_plot();
);

else
var dependencies = Object.values(dependencies_paths);

function dependency_loader(dependencies_loaded)
var script = document.createElement(“script”);
script.type = “text/javascript”;
script.src = dependencies[dependencies_loaded] + “.js”;

script.onload = function ()
if(dependencies_loaded < dependencies.length-1)
dependency_loader(dependencies_loaded+1)

else
d3sankey = d3;
plotapi_plot();

;
document.body.appendChild(script);

dependency_loader(0);

function plotapi_plot(){
width_in = 800
height_in = 500
margin =
left: 10,
top: 10,
right: 10,
bottom: 10
;

margin.right += (100 + (24 * .25));
margin.left += (100 + (24 * .25));

margin.top += (30.0 + 10);

var width = width_in – margin.left – margin.right;
var height = height_in – margin.top – margin.bottom;
var initialMousePosition = ;
var initialNodePosition = ;

function mouseoverLink(data)
return function (d, i)

tippy_content = "“+i.source.name+” ” + “→” + ” “+i.target.name+”

+ “occurs in ” + ““+i.value+” instances

+ (i.description ? “
” + i.description : “”);
if (this._tippy == null)
tippy(this,
touch: ‘hold’,
allowHTML: true,
followCursor: true,
content: tippy_content,
arrow: true,
maxWidth: 350,
theme: ‘translucent’,
);

function mouseoverNode(data)
return function (d, i)

animateGradient(d, i);
tippy_content = ““+i.name+”

+ “occurs in ” + “” + i.value + “ instances

+ (i.description ? “
” + i.description : “”);
if (this._tippy == null)
tippy(this,
touch: ‘hold’,
allowHTML: true,
followCursor: ‘vertical’,
content: tippy_content,
arrow: true,
maxWidth: 350,
theme: ‘translucent’,
);

function register_mouse_interaction()
d3.select(“#plotapi-chart-fe6f3ceb-to_svg”)
.on(“click”, function ()
var config = filename: “diagram”;
to_svg(d3.select(“#plotapi-chart-fe6f3ceb”).select(“svg”).node(), config);
);

svgNodes.on(“mouseover”, mouseoverNode(data)).on(“mouseout”, animateReset);
svgBackgroundLinks.on(“mouseover”, mouseoverLink(data))

function wrap(text) {
text.each(function ()
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
tspan = text.text(null).append(“tspan”).attr(“x”, 0).classed(“nodeTextSpan”,
true),
lines = 0;
while (word = words.pop())
line.push(word)
tspan.text(line.join(” “))
if (tspan.node().getComputedTextLength() > (text.classed(“rotated”)? d3.select(this.parentNode).select(“.node”).attr(“height”) : 100) && line.length > 1)
line.pop()
if (line.length != 0)
tspan.text(line.join(” “))

line = [word]
tspan = text.append(“tspan”)
.attr(“x”, 0)
.attr(“dy”, “1em”)
.text(word)
.classed(“nodeTextSpan”, true);

lines = lines + 1;

text.select(“tspan:nth-child(1)”).attr(“dy”, “” + (-(lines * 0.5)) + “em”);
)
}

function reduceUnique(previous, current)
if (previous.indexOf(current)
return obj.id === index
)
if(node != undefined)
if(node.hasOwnProperty(‘color’))
if(node.color)
return node.color;

var ratio = index / (data.nodes.length – (0.0));
return d3.interpolateRainbow(ratio);

function darkenColor(color, factor)
return d3.color(color).darker(factor)

var data =
nodes: [‘id’: 0, ‘name’: ‘Group A’, ‘description’: ”, ‘color’: ”, ‘id’: 1, ‘name’: ‘Group B’, ‘description’: ”, ‘color’: ”, ‘id’: 2, ‘name’: ‘Rank 1’, ‘description’: ”, ‘color’: ”, ‘id’: 3, ‘name’: ‘Rank 2’, ‘description’: ”, ‘color’: ”, ‘id’: 4, ‘name’: ‘Rank 3’, ‘description’: ”, ‘color’: ”, ‘id’: 5, ‘name’: ‘Club A’, ‘description’: ”, ‘color’: ”, ‘id’: 6, ‘name’: ‘Club B’, ‘description’: ”, ‘color’: ”, ‘id’: 7, ‘name’: ‘Club C’, ‘description’: ”, ‘color’: ”, ‘id’: 8, ‘name’: ‘Withdrawn’, ‘description’: ”, ‘color’: ”, ‘id’: 9, ‘name’: ‘The Most Amazing Prize’, ‘description’: ”, ‘color’: ”],
links: [‘source’: 0, ‘target’: 2, ‘value’: 1000.0, ‘description’: ”, ‘source’: 1, ‘target’: 2, ‘value’: 300.0, ‘description’: ”, ‘source’: 1, ‘target’: 3, ‘value’: 600.0, ‘description’: ”, ‘source’: 1, ‘target’: 4, ‘value’: 400.0, ‘description’: ”, ‘source’: 2, ‘target’: 5, ‘value’: 700.0, ‘description’: ”, ‘source’: 2, ‘target’: 6, ‘value’: 400.0, ‘description’: ”, ‘source’: 2, ‘target’: 7, ‘value’: 200.0, ‘description’: ”, ‘source’: 3, ‘target’: 6, ‘value’: 200.0, ‘description’: ”, ‘source’: 3, ‘target’: 7, ‘value’: 400.0, ‘description’: ”, ‘source’: 4, ‘target’: 8, ‘value’: 400.0, ‘description’: ”, ‘source’: 5, ‘target’: 9, ‘value’: 500.0, ‘description’: ”]
;

const svg = d3.select(“#plotapi-chart-fe6f3ceb”)
.append(“svg”)
.attr(“viewBox”, “0 0 ” + (width + margin.left + margin.right) + ” ” + (height + margin.top + margin.bottom))
.attr(“class”,”plotapi-plot”)
.attr(“preserveAspectRatio”, “xMinYMin meet”)
.style(“background-color”, “transparent”).style(“border”, “none”).append(“g”)
.attr(“transform”, “translate(“+margin.left+”,”+margin.top+”)”);

svg.append(“text”)
.attr(“x”, (width / 2)).attr(“y”, 0 – (margin.top) + 10)
.attr(“text-anchor”, “middle”)
.style(“font-size”, 30.0)
.style(“dominant-baseline”, “hanging”)
.style(“text-decoration”, “underline”)
.text(“Font-size demonstration”);

const sankey = d3sankey.sankey()
.size([width, height])
.nodeWidth(24)
.nodePadding(16)
.nodeAlign(d3sankey.sankeyLeft);

var graph = sankey(data);
var nodeDepths = graph.nodes.map(n => n.depth).reduce(reduceUnique, []);

graph.nodes.forEach(node =>
var fillColor = color(node.index);
node.fillColor = fillColor;
node.strokeColor = darkenColor(fillColor, 0.3);
node.width = node.x1 – node.x0;
node.height = node.y1 – node.y0;
);

var svgLinks = svg.append(“g”)
.classed(“links”, true)
.selectAll(“g”)
.data(graph.links)
.enter()
.append(“g”);

var svgBackgroundLinks = svg.append(“g”)
.classed(“background_links”, true)
.selectAll(“g”)
.data(graph.links)
.enter()
.append(“g”);

var gradients = svgLinks.append(“linearGradient”)
.attr(“gradientUnits”, “userSpaceOnUse”)
.attr(“x1”, d => d.source.x1)
.attr(“x2”, d => d.target.x0)
.attr(“id”, d => “”+getGradientId(d));

addGradientStop(gradients, 0.0, d => color(d.source.index));
addGradientStop(gradients, 1.0, d => color(d.target.index));

svgLinks.append(“path”)
.classed(“link”, true)
.attr(“id”, d => “path_”+getGradientId(d))
.attr(“d”, d3sankey.sankeyLinkHorizontal())
.attr(“fill”, “none”).attr(“stroke”, d => “url(#”+getGradientId(d)+”)”)
.attr(“stroke-width”, d => (d.width == 0) ? d.width : Math.max(1.0, d.width))
.attr(“stroke-opacity”, 0.45);

svgBackgroundLinks.append(“path”)
.classed(“link”, true)
.attr(“id”, d => “path_bg_”+getGradientId(d))
.attr(“d”, d3sankey.sankeyLinkHorizontal())
.attr(“fill”, “none”)
.attr(“stroke”, d => “url(#”+getGradientId(d)+”)”)
.attr(“stroke-width”, d => (d.width == 0) ? d.width : Math.max(1.0, d.width))
.attr(“stroke-opacity”, 0.2);

var svgNodeGroups = svg.append(“g”)
.classed(“nodes”, true)
.selectAll(“rect”)
.data(graph.nodes)
.enter()
.append(“g”)
.attr(“id”, d => “node_group_”+d.index)
.classed(“nodeGroup”, true);

var svgNodes = svgNodeGroups.append(“rect”)
.classed(“node”, true)
.attr(“x”, d => d.x0)
.attr(“y”, d => d.y0).
attr(“width”, d => d.width)
.attr(“height”, d => d.height)
.attr(“fill”, d => d.fillColor)
.attr(“opacity”, 1)
.attr(“stroke”, d => d.strokeColor)
.attr(“stroke-width”, 3);

svgNodeGroups.append(“text”)
.classed(“nodeText”, true)
.classed(“rotated”, function (d)
rotated = true;

if (d.sourceLinks.length == 0)
rotated = false;

if (d.depth == 0)
rotated = false;

return rotated;
)
.style(“fill”, “white”)
.style(“font-size”, 10.0)
.style(“stroke”, d => darkenColor(d.fillColor, 1))
.attr(“pointer-events”, “none”)
.style(“text-anchor”, function (d)
alignment = “middle”;

if (d.sourceLinks.length == 0)
alignment = “start”;

if (0 == d.depth)
alignment = “end”;

return alignment;
)
.attr(‘transform’, function (d)

p_rotate = -90;
width_denom = 2;
depthOffset = 0;

if (d.sourceLinks.length == 0)
depthOffset = (24 * .75);
p_rotate = 0;
width_denom = 2;

if (d.depth == 0)
depthOffset = -(24 * .75);
p_rotate = 0;
width_denom = 2;

return “translate(” + (d.x0 + (d.width / width_denom) + depthOffset) + “,”
+ (d.y0 + (d.height / 2)) + “) rotate(” + p_rotate + “)”;
)
.text(d => d.name)
.call(wrap);

var nodeTextspans = d3.selectAll(“.nodeTextSpan”).style(“dominant-baseline”, “central”);

function drawLinkText()
var labelText = svg.selectAll(“.linkText”)
.data(graph.links)
.enter()
.append(“text”)
.attr(“class”, “linkText”)
.attr(“id”, d => “link_text_”+d.index)
.attr(“x”, function (d)
var pathElement = d3.select(“#path_”+getGradientId(d));
var pathLength = pathElement.node().getTotalLength();
var startPoint = pathElement.node().getPointAtLength(0);
var endPoint = pathElement.node().getPointAtLength(pathLength);

w = Math.pow(Math.abs(endPoint.x – startPoint.x),2);
h = Math.pow(Math.abs(endPoint.y – startPoint.y),2);

di = Math.sqrt((w + h));

return di / 2;
)
.attr(“dy”, function (d) return 0;)
.append(“textPath”)
.style(“text-anchor”, “middle”)
.attr(“fill”,function (d, i) return d3.interpolateRgb(d3.rgb(d.source.fillColor), d3.rgb(d.target.fillColor))(0.5);)
.style(“dominant-baseline”, “central”)
.style(“alignment-baseline”, “central”)
.attr(“pointer-events”, “none”)
.attr(“xlink:href”, d => “#path_”+getGradientId(d))
.attr(“font-size”, 30.0)
.text(function (d, i) return (d.value == 0) ? “” : “”.replace(“”,d.value););

function animateInitialState()
var links = svgLinks.selectAll(“path.link”)
.interrupt()
.each(function (d, i)
var length = this.getTotalLength();

d3.select(this)
.attr(“stroke-dasharray”, length + ” ” + length)
.attr(“stroke-opacity”, 0.45);

d3.select(this).attr(“stroke-dashoffset”, length);
)

function animateReset()
svgLinks.selectAll(“path.link”)
.interrupt()
.transition()
.duration(200)
.ease(d3.easeLinear)
.attr(“stroke-opacity”, 0)
.on(“end”, () =>
animateInitialState();
);

animateShowLinkText();

function animateGradient(d, i)
animateInitialState();
animateHideLinkText(d, i);
animateNextNode(d, i);

function animateHideLinkText(d, i)
var links = svgLinks.selectAll(“path.link”)
.each(function (d, i)
d3.select(“#link_text_”+d.index)
.transition()
.duration(200)
.ease(d3.easeLinear)
.style(“opacity”, 0);

d3.select(“#node_group_”+d.index)
.transition()
.duration(200)
.ease(d3.easeLinear)
.style(“opacity”, 0.5);
);

d3.select(“#node_group_”+i.index).interrupt().style(“opacity”, 1);

animateHideNextLinks(d, i);

function animateHideNextLinks(d, i)
var links = svgLinks.selectAll(“path.link”)
.filter((link) =>
return i.sourceLinks.indexOf(link) !== -1;
)
.each(function (d, i)
d3.select(“#link_text_”+d.index).interrupt().style(“opacity”, 1);
d3.select(“#node_group_”+d.target.index).interrupt().style(“opacity”, 1);
animateHideNextLinks(d, d.target);
)

function animateShowLinkText(d, i)
var links = svgLinks.selectAll(“path.link”)
.each(function (d, i)
d3.select(“#link_text_”+d.index)
.transition()
.duration(200)
.ease(d3.easeLinear)
.style(“opacity”, 1);
);

var nodes = svgNodeGroups
.transition()
.duration(200)
.ease(d3.easeLinear)
.style(“opacity”, 1);

function animateNextNode(d, i)
var links = svgLinks.selectAll(“path.link”)
.filter((link) =>
return i.sourceLinks.indexOf(link) !== -1;
)
.each(function (d, i)
var length = this.getTotalLength();

d3.select(this)
.attr(“stroke-dasharray”, length + ” ” + length)
.attr(“stroke-dashoffset”, length);
)
.transition()
.duration(function (d, i)
return (d.target.depth – d.source.depth) * 200;
)
.ease(d3.easeLinear)
.attr(“stroke-dashoffset”, 0)
.on(“end”, function (d, i)
animateNextNode(d, d.target);
);

function animateIntro(data)
svgNodeGroups.style(“opacity”, 0);

svgBackgroundLinks.selectAll(“path.link”)
.interrupt()
.each(function (d, i)
var length = this.getTotalLength();
d3.select(this)
.attr(“stroke-dasharray”, length + ” ” + length)
.attr(“stroke-opacity”, 0.2)
.attr(“stroke-dashoffset”, length);
);

svg.selectAll(“.linkText”).style(“opacity”, 0);

data.nodes.forEach(node =>
if (node.depth == 0) animateIntroNextNode(node, node)
);

function animateIntroNextNode(d, i)
svgNodeGroups
.filter((node) =>
return node.index == i.index;
)
.transition()
.duration(animated_intro_interval)
.ease(d3.easeLinear)
.style(“opacity”, 1)
.on(“end”, function (d, i)
if (d.depth == d3.max(nodeDepths))
svg.selectAll(“.linkText”)
.transition()
.duration(animated_intro_interval)
.ease(d3.easeLinear)
.style(“opacity”, 1);

register_mouse_interaction();

);

animateIntroNexLinks(d, i)

function animateIntroNexLinks(d, i)
svgBackgroundLinks.selectAll(“path.link”)
.filter((link) =>
return i.sourceLinks.indexOf(link) !== -1;
)
.each(function (d, i)
var length = this.getTotalLength();
d3.select(this)
.attr(“stroke-dasharray”, length + ” ” + length)
.attr(“stroke-dashoffset”, length);
)
.transition()
.duration(function (d, i)
return (d.target.depth – d.source.depth) * animated_intro_interval;
)
.ease(d3.easeLinear)
.attr(“stroke-dashoffset”, 0)
.on(“end”, function (d, i)
animateIntroNextNode(d, d.target);
);

animateInitialState();
drawLinkText();

register_mouse_interaction();

d3.select(“#plotapi-chart-fe6f3ceb svg”)
.append(“svg:a”)
.attr(“xlink:href”, “https://plotapi.com”)
.attr(“target”, “_blank”)
.append(“image”)
.attr(“xlink:href”, “https://plotapi.com/gallery/icon/plotapi.svg”)
.attr(‘width’, 20)
.attr(‘height’, 20)
.attr(‘x’, width+margin.left + margin.right-20)
.attr(‘y’, 0)
.style(“opacity”, 0)
.attr(“id”,”plotapi-chart-fe6f3ceb_icon”)

d3.select(“#plotapi-chart-fe6f3ceb_icon”)
.append(“title”)
.text(“Produced with Plotapi”);

d3.select(“#plotapi-chart-fe6f3ceb_icon”).on(“mouseover”, function(d, i)
d3.select(“#plotapi-chart-fe6f3ceb_icon”).style(“opacity”, 1)
);

d3.select(“#plotapi-chart-fe6f3ceb_icon”).on(“mouseout”, function(d, i)
d3.select(“#plotapi-chart-fe6f3ceb_icon”).style(“opacity”, 0.6)
);

d3.select(“#plotapi-chart-fe6f3ceb svg”).on(“mouseenter”, function()
d3.select(“#plotapi-chart-fe6f3ceb_icon”).style(“opacity”, 0.6)
);

d3.select(“#plotapi-chart-fe6f3ceb svg”).on(“mouseleave”, function()

d3.select(“#plotapi-chart-fe6f3ceb_icon”).style(“opacity”, 0);
);
}
}());

Below are the default sizes for reference.

In [19]:
Sankey(links, title="Font-size demonstration").show()

Plotapi – Sankey Diagram

#plotapi-chart-3f44b77e,
.tippy-box,
#plotapi-chart-3f44b77e-to_svg
font-family: “Assistant”, sans-serif !important;
text-align: center;

#plotapi-chart-3f44b77e .link:hover
stroke-opacity: .45;

#plotapi-chart-3f44b77e .node
cursor: move;

#plotapi-chart-3f44b77e .nodeTextSpan
paint-order: stroke;
stroke-width: 3px;
stroke-linecap: butt;
stroke-linejoin: miter;
font-weight: bold;

#plotapi-chart-3f44b77e .linkText>textPath
paint-order: stroke;
stroke-linecap: butt;
stroke-linejoin: miter;
font-weight: bold;

#plotapi-chart-3f44b77e .linkText>textPath::selection,
#plotapi-chart-3f44b77e .nodeText::selection,
#plotapi-chart-3f44b77e .nodeTextSpan::selection
background: none;

#plotapi-chart-3f44b77e svg
max-width: 800px;

(function() {

var dependencies_paths =
‘d3’: ‘https://plotapi.com/static/js/d3.v7.min’,
‘d3-sankey’: ‘https://plotapi.com/static/js/d3-sankey’,
‘@popperjs/core’: ‘https://plotapi.com/static/js/popper.min’,
‘tippy’: ‘https://plotapi.com/static/js/tippy.min’,
‘d3-path’: ‘https://plotapi.com/static/js/d3-path’,
‘d3-shape’: ‘https://plotapi.com/static/js/d3-shape’,
‘d3-array’: ‘https://plotapi.com/static/js/d3-array’

var jupyter_classic = !(typeof(IPython)===”undefined”);

if(jupyter_classic)
require.config(

paths: dependencies_paths

);

require([‘d3′,’tippy’, ‘d3-sankey’], function(d3, tippy, d3sankey)
window.d3 = d3;
window.tippy = tippy;
window.d3sankey = d3sankey;
plotapi_plot();
);

else
var dependencies = Object.values(dependencies_paths);

function dependency_loader(dependencies_loaded)
var script = document.createElement(“script”);
script.type = “text/javascript”;
script.src = dependencies[dependencies_loaded] + “.js”;

script.onload = function ()
if(dependencies_loaded < dependencies.length-1)
dependency_loader(dependencies_loaded+1)

else
d3sankey = d3;
plotapi_plot();

;
document.body.appendChild(script);

dependency_loader(0);

function plotapi_plot(){
width_in = 800
height_in = 500
margin =
left: 10,
top: 10,
right: 10,
bottom: 10
;

margin.right += (100 + (24 * .25));
margin.left += (100 + (24 * .25));

margin.top += (16 + 10);

var width = width_in – margin.left – margin.right;
var height = height_in – margin.top – margin.bottom;
var initialMousePosition = ;
var initialNodePosition = ;

function mouseoverLink(data)
return function (d, i)

tippy_content = "“+i.source.name+” ” + “→” + ” “+i.target.name+”

+ “occurs in ” + ““+i.value+” instances

+ (i.description ? “
” + i.description : “”);
if (this._tippy == null)
tippy(this,
touch: ‘hold’,
allowHTML: true,
followCursor: true,
content: tippy_content,
arrow: true,
maxWidth: 350,
theme: ‘translucent’,
);

function mouseoverNode(data)
return function (d, i)

animateGradient(d, i);
tippy_content = ““+i.name+”

+ “occurs in ” + “” + i.value + “ instances

+ (i.description ? “
” + i.description : “”);
if (this._tippy == null)
tippy(this,
touch: ‘hold’,
allowHTML: true,
followCursor: ‘vertical’,
content: tippy_content,
arrow: true,
maxWidth: 350,
theme: ‘translucent’,
);

function register_mouse_interaction()
d3.select(“#plotapi-chart-3f44b77e-to_svg”)
.on(“click”, function ()
var config = filename: “diagram”;
to_svg(d3.select(“#plotapi-chart-3f44b77e”).select(“svg”).node(), config);
);

svgNodes.on(“mouseover”, mouseoverNode(data)).on(“mouseout”, animateReset);
svgBackgroundLinks.on(“mouseover”, mouseoverLink(data))

function wrap(text) {
text.each(function ()
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
tspan = text.text(null).append(“tspan”).attr(“x”, 0).classed(“nodeTextSpan”,
true),
lines = 0;
while (word = words.pop())
line.push(word)
tspan.text(line.join(” “))
if (tspan.node().getComputedTextLength() > (text.classed(“rotated”)? d3.select(this.parentNode).select(“.node”).attr(“height”) : 100) && line.length > 1)
line.pop()
if (line.length != 0)
tspan.text(line.join(” “))

line = [word]
tspan = text.append(“tspan”)
.attr(“x”, 0)
.attr(“dy”, “1em”)
.text(word)
.classed(“nodeTextSpan”, true);

lines = lines + 1;

text.select(“tspan:nth-child(1)”).attr(“dy”, “” + (-(lines * 0.5)) + “em”);
)
}

function reduceUnique(previous, current)
if (previous.indexOf(current)
return obj.id === index
)
if(node != undefined)
if(node.hasOwnProperty(‘color’))
if(node.color)
return node.color;

var ratio = index / (data.nodes.length – (0.0));
return d3.interpolateRainbow(ratio);

function darkenColor(color, factor)
return d3.color(color).darker(factor)

var data =
nodes: [‘id’: 0, ‘name’: ‘Group A’, ‘description’: ”, ‘color’: ”, ‘id’: 1, ‘name’: ‘Group B’, ‘description’: ”, ‘color’: ”, ‘id’: 2, ‘name’: ‘Rank 1’, ‘description’: ”, ‘color’: ”, ‘id’: 3, ‘name’: ‘Rank 2’, ‘description’: ”, ‘color’: ”, ‘id’: 4, ‘name’: ‘Rank 3’, ‘description’: ”, ‘color’: ”, ‘id’: 5, ‘name’: ‘Club A’, ‘description’: ”, ‘color’: ”, ‘id’: 6, ‘name’: ‘Club B’, ‘description’: ”, ‘color’: ”, ‘id’: 7, ‘name’: ‘Club C’, ‘description’: ”, ‘color’: ”, ‘id’: 8, ‘name’: ‘Withdrawn’, ‘description’: ”, ‘color’: ”, ‘id’: 9, ‘name’: ‘The Most Amazing Prize’, ‘description’: ”, ‘color’: ”],
links: [‘source’: 0, ‘target’: 2, ‘value’: 1000.0, ‘description’: ”, ‘source’: 1, ‘target’: 2, ‘value’: 300.0, ‘description’: ”, ‘source’: 1, ‘target’: 3, ‘value’: 600.0, ‘description’: ”, ‘source’: 1, ‘target’: 4, ‘value’: 400.0, ‘description’: ”, ‘source’: 2, ‘target’: 5, ‘value’: 700.0, ‘description’: ”, ‘source’: 2, ‘target’: 6, ‘value’: 400.0, ‘description’: ”, ‘source’: 2, ‘target’: 7, ‘value’: 200.0, ‘description’: ”, ‘source’: 3, ‘target’: 6, ‘value’: 200.0, ‘description’: ”, ‘source’: 3, ‘target’: 7, ‘value’: 400.0, ‘description’: ”, ‘source’: 4, ‘target’: 8, ‘value’: 400.0, ‘description’: ”, ‘source’: 5, ‘target’: 9, ‘value’: 500.0, ‘description’: ”]
;

const svg = d3.select(“#plotapi-chart-3f44b77e”)
.append(“svg”)
.attr(“viewBox”, “0 0 ” + (width + margin.left + margin.right) + ” ” + (height + margin.top + margin.bottom))
.attr(“class”,”plotapi-plot”)
.attr(“preserveAspectRatio”, “xMinYMin meet”)
.style(“background-color”, “transparent”).style(“border”, “none”).append(“g”)
.attr(“transform”, “translate(“+margin.left+”,”+margin.top+”)”);

svg.append(“text”)
.attr(“x”, (width / 2)).attr(“y”, 0 – (margin.top) + 10)
.attr(“text-anchor”, “middle”)
.style(“font-size”, 16)
.style(“dominant-baseline”, “hanging”)
.style(“text-decoration”, “underline”)
.text(“Font-size demonstration”);

const sankey = d3sankey.sankey()
.size([width, height])
.nodeWidth(24)
.nodePadding(16)
.nodeAlign(d3sankey.sankeyLeft);

var graph = sankey(data);
var nodeDepths = graph.nodes.map(n => n.depth).reduce(reduceUnique, []);

graph.nodes.forEach(node =>
var fillColor = color(node.index);
node.fillColor = fillColor;
node.strokeColor = darkenColor(fillColor, 0.3);
node.width = node.x1 – node.x0;
node.height = node.y1 – node.y0;
);

var svgLinks = svg.append(“g”)
.classed(“links”, true)
.selectAll(“g”)
.data(graph.links)
.enter()
.append(“g”);

var svgBackgroundLinks = svg.append(“g”)
.classed(“background_links”, true)
.selectAll(“g”)
.data(graph.links)
.enter()
.append(“g”);

var gradients = svgLinks.append(“linearGradient”)
.attr(“gradientUnits”, “userSpaceOnUse”)
.attr(“x1”, d => d.source.x1)
.attr(“x2”, d => d.target.x0)
.attr(“id”, d => “”+getGradientId(d));

addGradientStop(gradients, 0.0, d => color(d.source.index));
addGradientStop(gradients, 1.0, d => color(d.target.index));

svgLinks.append(“path”)
.classed(“link”, true)
.attr(“id”, d => “path_”+getGradientId(d))
.attr(“d”, d3sankey.sankeyLinkHorizontal())
.attr(“fill”, “none”).attr(“stroke”, d => “url(#”+getGradientId(d)+”)”)
.attr(“stroke-width”, d => (d.width == 0) ? d.width : Math.max(1.0, d.width))
.attr(“stroke-opacity”, 0.45);

svgBackgroundLinks.append(“path”)
.classed(“link”, true)
.attr(“id”, d => “path_bg_”+getGradientId(d))
.attr(“d”, d3sankey.sankeyLinkHorizontal())
.attr(“fill”, “none”)
.attr(“stroke”, d => “url(#”+getGradientId(d)+”)”)
.attr(“stroke-width”, d => (d.width == 0) ? d.width : Math.max(1.0, d.width))
.attr(“stroke-opacity”, 0.2);

var svgNodeGroups = svg.append(“g”)
.classed(“nodes”, true)
.selectAll(“rect”)
.data(graph.nodes)
.enter()
.append(“g”)
.attr(“id”, d => “node_group_”+d.index)
.classed(“nodeGroup”, true);

var svgNodes = svgNodeGroups.append(“rect”)
.classed(“node”, true)
.attr(“x”, d => d.x0)
.attr(“y”, d => d.y0).
attr(“width”, d => d.width)
.attr(“height”, d => d.height)
.attr(“fill”, d => d.fillColor)
.attr(“opacity”, 1)
.attr(“stroke”, d => d.strokeColor)
.attr(“stroke-width”, 3);

svgNodeGroups.append(“text”)
.classed(“nodeText”, true)
.classed(“rotated”, function (d)
rotated = true;

if (d.sourceLinks.length == 0)
rotated = false;

if (d.depth == 0)
rotated = false;

return rotated;
)
.style(“fill”, “white”)
.style(“font-size”, 16)
.style(“stroke”, d => darkenColor(d.fillColor, 1))
.attr(“pointer-events”, “none”)
.style(“text-anchor”, function (d)
alignment = “middle”;

if (d.sourceLinks.length == 0)
alignment = “start”;

if (0 == d.depth)
alignment = “end”;

return alignment;
)
.attr(‘transform’, function (d)

p_rotate = -90;
width_denom = 2;
depthOffset = 0;

if (d.sourceLinks.length == 0)
depthOffset = (24 * .75);
p_rotate = 0;
width_denom = 2;

if (d.depth == 0)
depthOffset = -(24 * .75);
p_rotate = 0;
width_denom = 2;

return “translate(” + (d.x0 + (d.width / width_denom) + depthOffset) + “,”
+ (d.y0 + (d.height / 2)) + “) rotate(” + p_rotate + “)”;
)
.text(d => d.name)
.call(wrap);

var nodeTextspans = d3.selectAll(“.nodeTextSpan”).style(“dominant-baseline”, “central”);

function drawLinkText()
var labelText = svg.selectAll(“.linkText”)
.data(graph.links)
.enter()
.append(“text”)
.attr(“class”, “linkText”)
.attr(“id”, d => “link_text_”+d.index)
.attr(“x”, function (d)
var pathElement = d3.select(“#path_”+getGradientId(d));
var pathLength = pathElement.node().getTotalLength();
var startPoint = pathElement.node().getPointAtLength(0);
var endPoint = pathElement.node().getPointAtLength(pathLength);

w = Math.pow(Math.abs(endPoint.x – startPoint.x),2);
h = Math.pow(Math.abs(endPoint.y – startPoint.y),2);

di = Math.sqrt((w + h));

return di / 2;
)
.attr(“dy”, function (d) return 0;)
.append(“textPath”)
.style(“text-anchor”, “middle”)
.attr(“fill”,function (d, i) return d3.interpolateRgb(d3.rgb(d.source.fillColor), d3.rgb(d.target.fillColor))(0.5);)
.style(“dominant-baseline”, “central”)
.style(“alignment-baseline”, “central”)
.attr(“pointer-events”, “none”)
.attr(“xlink:href”, d => “#path_”+getGradientId(d))
.attr(“font-size”, 16)
.text(function (d, i) return (d.value == 0) ? “” : “”.replace(“”,d.value););

function animateInitialState()
var links = svgLinks.selectAll(“path.link”)
.interrupt()
.each(function (d, i)
var length = this.getTotalLength();

d3.select(this)
.attr(“stroke-dasharray”, length + ” ” + length)
.attr(“stroke-opacity”, 0.45);

d3.select(this).attr(“stroke-dashoffset”, length);
)

function animateReset()
svgLinks.selectAll(“path.link”)
.interrupt()
.transition()
.duration(200)
.ease(d3.easeLinear)
.attr(“stroke-opacity”, 0)
.on(“end”, () =>
animateInitialState();
);

animateShowLinkText();

function animateGradient(d, i)
animateInitialState();
animateHideLinkText(d, i);
animateNextNode(d, i);

function animateHideLinkText(d, i)
var links = svgLinks.selectAll(“path.link”)
.each(function (d, i)
d3.select(“#link_text_”+d.index)
.transition()
.duration(200)
.ease(d3.easeLinear)
.style(“opacity”, 0);

d3.select(“#node_group_”+d.index)
.transition()
.duration(200)
.ease(d3.easeLinear)
.style(“opacity”, 0.5);
);

d3.select(“#node_group_”+i.index).interrupt().style(“opacity”, 1);

animateHideNextLinks(d, i);

function animateHideNextLinks(d, i)
var links = svgLinks.selectAll(“path.link”)
.filter((link) =>
return i.sourceLinks.indexOf(link) !== -1;
)
.each(function (d, i)
d3.select(“#link_text_”+d.index).interrupt().style(“opacity”, 1);
d3.select(“#node_group_”+d.target.index).interrupt().style(“opacity”, 1);
animateHideNextLinks(d, d.target);
)

function animateShowLinkText(d, i)
var links = svgLinks.selectAll(“path.link”)
.each(function (d, i)
d3.select(“#link_text_”+d.index)
.transition()
.duration(200)
.ease(d3.easeLinear)
.style(“opacity”, 1);
);

var nodes = svgNodeGroups
.transition()
.duration(200)
.ease(d3.easeLinear)
.style(“opacity”, 1);

function animateNextNode(d, i)
var links = svgLinks.selectAll(“path.link”)
.filter((link) =>
return i.sourceLinks.indexOf(link) !== -1;
)
.each(function (d, i)
var length = this.getTotalLength();

d3.select(this)
.attr(“stroke-dasharray”, length + ” ” + length)
.attr(“stroke-dashoffset”, length);
)
.transition()
.duration(function (d, i)
return (d.target.depth – d.source.depth) * 200;
)
.ease(d3.easeLinear)
.attr(“stroke-dashoffset”, 0)
.on(“end”, function (d, i)
animateNextNode(d, d.target);
);

function animateIntro(data)
svgNodeGroups.style(“opacity”, 0);

svgBackgroundLinks.selectAll(“path.link”)
.interrupt()
.each(function (d, i)
var length = this.getTotalLength();
d3.select(this)
.attr(“stroke-dasharray”, length + ” ” + length)
.attr(“stroke-opacity”, 0.2)
.attr(“stroke-dashoffset”, length);
);

svg.selectAll(“.linkText”).style(“opacity”, 0);

data.nodes.forEach(node =>
if (node.depth == 0) animateIntroNextNode(node, node)
);

function animateIntroNextNode(d, i)
svgNodeGroups
.filter((node) =>
return node.index == i.index;
)
.transition()
.duration(animated_intro_interval)
.ease(d3.easeLinear)
.style(“opacity”, 1)
.on(“end”, function (d, i)
if (d.depth == d3.max(nodeDepths))
svg.selectAll(“.linkText”)
.transition()
.duration(animated_intro_interval)
.ease(d3.easeLinear)
.style(“opacity”, 1);

register_mouse_interaction();

);

animateIntroNexLinks(d, i)

function animateIntroNexLinks(d, i)
svgBackgroundLinks.selectAll(“path.link”)
.filter((link) =>
return i.sourceLinks.indexOf(link) !== -1;
)
.each(function (d, i)
var length = this.getTotalLength();
d3.select(this)
.attr(“stroke-dasharray”, length + ” ” + length)
.attr(“stroke-dashoffset”, length);
)
.transition()
.duration(function (d, i)
return (d.target.depth – d.source.depth) * animated_intro_interval;
)
.ease(d3.easeLinear)
.attr(“stroke-dashoffset”, 0)
.on(“end”, function (d, i)
animateIntroNextNode(d, d.target);
);

animateInitialState();
drawLinkText();

register_mouse_interaction();

d3.select(“#plotapi-chart-3f44b77e svg”)
.append(“svg:a”)
.attr(“xlink:href”, “https://plotapi.com”)
.attr(“target”, “_blank”)
.append(“image”)
.attr(“xlink:href”, “https://plotapi.com/gallery/icon/plotapi.svg”)
.attr(‘width’, 20)
.attr(‘height’, 20)
.attr(‘x’, width+margin.left + margin.right-20)
.attr(‘y’, 0)
.style(“opacity”, 0)
.attr(“id”,”plotapi-chart-3f44b77e_icon”)

d3.select(“#plotapi-chart-3f44b77e_icon”)
.append(“title”)
.text(“Produced with Plotapi”);

d3.select(“#plotapi-chart-3f44b77e_icon”).on(“mouseover”, function(d, i)
d3.select(“#plotapi-chart-3f44b77e_icon”).style(“opacity”, 1)
);

d3.select(“#plotapi-chart-3f44b77e_icon”).on(“mouseout”, function(d, i)
d3.select(“#plotapi-chart-3f44b77e_icon”).style(“opacity”, 0.6)
);

d3.select(“#plotapi-chart-3f44b77e svg”).on(“mouseenter”, function()
d3.select(“#plotapi-chart-3f44b77e_icon”).style(“opacity”, 0.6)
);

d3.select(“#plotapi-chart-3f44b77e svg”).on(“mouseleave”, function()

d3.select(“#plotapi-chart-3f44b77e_icon”).style(“opacity”, 0);
);
}
}());

You can do so much more than what’s presented in this example, and we’ll cover this in later sections. If you want to see the full list of growing features, check out the Plotapi Documentation.