How to generate D3.js circular dendrogram code from Python - javascript

The following figure is generated with D3.js.
based on the code here:
<!DOCTYPE html>
<meta charset="utf-8">
<title>Flare Dendrogram</title>
<style>
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.node {
font: 10px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var radius = 960 / 2;
var cluster = d3.layout.cluster()
.size([360, radius - 120]);
var diagonal = d3.svg.diagonal.radial()
.projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });
var svg = d3.select("body").append("svg")
.attr("width", radius * 2)
.attr("height", radius * 2)
.append("g")
.attr("transform", "translate(" + radius + "," + radius + ")");
d3.json("/d/4063550/flare.json", function(error, root) {
var nodes = cluster.nodes(root);
var link = svg.selectAll("path.link")
.data(cluster.links(nodes))
.enter().append("path")
.attr("class", "link")
.attr("d", diagonal);
var node = svg.selectAll("g.node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })
node.append("circle")
.attr("r", 4.5);
node.append("text")
.attr("dy", ".31em")
.attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
.attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; })
.text(function(d) { return d.name; });
});
d3.select(self.frameElement).style("height", radius * 2 + "px");
</script>
Is there a way I can use Python to generate the above exact figure (HTML)?

Assuming that you want to avoid having to write javascript and using python instead, you could have a look at pyjs. From their website:
pyjs contains a Python-to-JavaScript compiler, an AJAX framework and a
Widget Set API. pyjs started life as a Python port of Google Web Toolkit,
the Java-to-JavaScript compiler.
I haven't used it and am unsure how you would go about including the d3 library. However their wiki has the following page:
https://github.com/pyjs/pyjs/wiki/Calling-a-jQuery-component-from-Pyjs
That article might give you an idea of whether pyjs is useful to you.

Is there a way I can use Python to generate the above exact figure (HTML)?
Not too dissimilar to pandita's suggestion, you could use Brython, which allows you to run Python in a web browser. Some sample skeleton code (using D3.js; I don't know of any Python libraries that give you a dendogram result as good as D3.js.):
<!DOCTYPE html>
<meta charset="utf-8">
<title>Flare Dendrogram</title>
<style>
/* CSS goes here */
</style>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="brython.js"></script>
<script type="text/python">
#
# Python code to generate dendogram here
# (equivalent to the sample JavaScript code provided)
#
</script>
<body onload="brython()">
</body>
</html>
But this doesn't seem like a great solution.
You may also find this StackOverflow page helpful: How do I create a radial cluster like the following code-example in Python?

Related

.ease(d3.easeLinear) yields Cannot read property 'indexOf' of undefined

I've copied and pasted the code from Point-Along-Path Interpolation example on bl.ocks.org and then added the line about transition easing (highlighted below with a comment), but it yields the error Cannot read property 'indexOf' of undefined error. What's wrong?
(JSFiddle here)
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<style>
path {
fill: none;
stroke: #000;
stroke-width: 3px;
}
circle {
fill: steelblue;
stroke: #fff;
stroke-width: 3px;
}
</style>
<script src="d3.v3.min.js"></script>
<script>
var points = [
[480, 200],
[580, 400],
[680, 100],
[780, 300],
[180, 300],
[280, 100],
[380, 400]
];
var svg = d3.select("body").append("svg")
.attr("width", 960)
.attr("height", 500);
var path = svg.append("path")
.data([points])
.attr("d", d3.svg.line()
.tension(0) // Catmull–Rom
.interpolate("cardinal-closed"));
svg.selectAll(".point")
.data(points)
.enter().append("circle")
.attr("r", 4)
.attr("transform", function(d) { return "translate(" + d + ")"; });
var circle = svg.append("circle")
.attr("r", 13)
.attr("transform", "translate(" + points[0] + ")");
transition();
function transition() {
circle.transition()
.duration(10000)
.ease(d3.easeLinear) // this is the line I've added
.attrTween("transform", translateAlong(path.node()))
.each("end", transition);
}
// Returns an attrTween for translating along the specified path element.
function translateAlong(path) {
var l = path.getTotalLength();
return function(d, i, a) {
return function(t) {
var p = path.getPointAtLength(t * l);
return "translate(" + p.x + "," + p.y + ")";
};
};
}
</script>
You are adding an ease function as one would do in v4 or 5 of d3. D3v4 made a structural change to how D3 approaches parameters passed to a number of methods. Rather than pass a string to these methods to specify certain functionality, in D3v4+, one passes an object or function (that is often a property of D3) to the method instead.
So in d3v3:
transition.ease("linear")
Is now in d3v4+
transition.ease(d3.easeLinear);
So, as your code is d3v3, you just need to use the older format. Here's an updated fiddle.

Cannot color svg elements in D3

I made a D3 map following Let's make a map tutorial by M. Bostock.
It is intended to create .subunit.id class and color it using CSS like .subunit.23 { fill: #f44242; }. But while .subunit is adressed well I can not reach each unit by specifying its id. Any ideas?
TopoJSON file is available here
https://gist.github.com/Avtan/649bbf5a28fd1f76278c752aca703d18
<!DOCTYPE html>
<meta charset="utf-8">
<html lang="en">
<style>
.subunit {
fill: #4286f4;
stroke: #efbfe9;}
.subunit.23 { fill: #f44242; }
</style>
<head>
<title>D3 Uzbekisztan map</title>
<meta charset="utf-8">
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script> -->
</head>
<body>
<script>
var width = 960,
height = 1160;
var projection = d3.geo.albers()
.center([-10, 40])
.rotate([-75, 0])
.parallels([38, 44])
.scale(4000)
.translate([width / 2, height / 2]);
var path = d3.geo.path()
.projection(projection);
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
d3.json("uzb_topo.json", function (error, uzb) {
if (error) return console.error(error);
console.log(uzb);
svg.selectAll(".subunit")
.data(topojson.feature(uzb, uzb.objects.uzb).features)
.enter().append("path")
.attr("class", function(d) { return "subunit " + d.id; })
.attr("d", path);
});
</script>
</body>
</html>
IDs cannot start by a number. Right now, you're setting two different classes, and the last one start with a number.
A simple solution is removing the space in your class name. So, this:
.attr("class", function(d) { return "subunit " + d.id; })
Should be this:
.attr("class", function(d) { return "subunit" + d.id; })//no space
And set your CSS accordingly.
Another solution is adding a letter before the number, like this:
.attr("class", function(d) { return "subunit " + "a" + d.id; })
So, you'll have the classes "a01", "a02", "a03" etc...

d3 is not defined - ReferenceError

I am trying to use a "fancy graph" found at http://bl.ocks.org/kerryrodden/7090426:
The way I've done it was to download the code and simply edit the CSV file to match my data. Then I simply open the .html-file in Firefox to see the interactive graph. However, using it at a another computer I get the following errors:
ReferenceError: d3 is not defined sequences.js:25
ReferenceError: d3 is not defined index.html:28
As I have almost no knowledge of d3 or javascript I am a bit lost.
Can any of you give me a hint to what is causing the errors and how I should correct the code?
I've done a single alteration to the code making it the following:
Javascript:
// Dimensions of sunburst.
var width = 750;
var height = 600;
var radius = Math.min(width, height) / 2;
// Breadcrumb dimensions: width, height, spacing, width of tip/tail.
var b = {
w: 75, h: 30, s: 3, t: 10
};
// Mapping of step names to colors.
var colors = {
"G0": "#5687d1",
"G1": "#5c7b61",
"G2": "#de783b",
"G3": "#6ab975",
"G4": "#a173d1",
"G5": "#72d1a1",
"Afgang": "#615c7b"
};
// Total size of all segments; we set this later, after loading the data.
var totalSize = 0;
var vis = d3.select("#chart").append("svg:svg")
.attr("width", width)
.attr("height", height)
.append("svg:g")
.attr("id", "container")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var partition = d3.layout.partition()
.size([2 * Math.PI, radius * radius])
.value(function(d) { return d.size; });
var arc = d3.svg.arc()
.startAngle(function(d) { return d.x; })
.endAngle(function(d) { return d.x + d.dx; })
.innerRadius(function(d) { return Math.sqrt(d.y); })
.outerRadius(function(d) { return Math.sqrt(d.y + d.dy); });
// Use d3.text and d3.csv.parseRows so that we do not need to have a header
// row, and can receive the csv as an array of arrays.
d3.text("sequences.csv", function(text) {
var csv = d3.csv.parseRows(text);
var json = buildHierarchy(csv);
createVisualization(json);
});
// Main function to draw and set up the visualization, once we have the data.
function createVisualization(json) {
// Basic setup of page elements.
initializeBreadcrumbTrail();
drawLegend();
d3.select("#togglelegend").on("click", toggleLegend);
// Bounding circle underneath the sunburst, to make it easier to detect
// when the mouse leaves the parent g.
vis.append("svg:circle")
.attr("r", radius)
.style("opacity", 0);
// For efficiency, filter nodes to keep only those large enough to see.
var nodes = partition.nodes(json)
.filter(function(d) {
return (d.dx > 0.005); // 0.005 radians = 0.29 degrees
});
nodes = nodes.filter(function(d) {
return (d.name != "end"); // BJF: Do not show the "end" markings.
});
var path = vis.data([json]).selectAll("path")
.data(nodes)
.enter().append("svg:path")
.attr("display", function(d) { return d.depth ? null : "none"; })
.attr("d", arc)
.attr("fill-rule", "evenodd")
.style("fill", function(d) { return colors[d.name]; })
.style("opacity", 1)
.on("mouseover", mouseover);
// Add the mouseleave handler to the bounding circle.
d3.select("#container").on("mouseleave", mouseleave);
// Get total size of the tree = value of root node from partition.
totalSize = path.node().__data__.value;
};
// Fade all but the current sequence, and show it in the breadcrumb trail.
function mouseover(d) {
var percentage = (100 * d.value / totalSize).toPrecision(3);
var percentageString = percentage + "%";
if (percentage < 0.1) {
percentageString = "< 0.1%";
}
d3.select("#percentage")
.text(percentageString);
d3.select("#explanation")
.style("visibility", "");
var sequenceArray = getAncestors(d);
updateBreadcrumbs(sequenceArray, percentageString);
// Fade all the segments.
d3.selectAll("path")
.style("opacity", 0.3);
// Then highlight only those that are an ancestor of the current segment.
vis.selectAll("path")
.filter(function(node) {
return (sequenceArray.indexOf(node) >= 0);
})
.style("opacity", 1);
}
// Restore everything to full opacity when moving off the visualization.
function mouseleave(d) {
// Hide the breadcrumb trail
d3.select("#trail")
.style("visibility", "hidden");
// Deactivate all segments during transition.
d3.selectAll("path").on("mouseover", null);
// Transition each segment to full opacity and then reactivate it.
d3.selectAll("path")
.transition()
.duration(1000)
.style("opacity", 1)
.each("end", function() {
d3.select(this).on("mouseover", mouseover);
});
d3.select("#explanation")
.transition()
.duration(1000)
.style("visibility", "hidden");
}
// Given a node in a partition layout, return an array of all of its ancestor
// nodes, highest first, but excluding the root.
function getAncestors(node) {
var path = [];
var current = node;
while (current.parent) {
path.unshift(current);
current = current.parent;
}
return path;
}
function initializeBreadcrumbTrail() {
// Add the svg area.
var trail = d3.select("#sequence").append("svg:svg")
.attr("width", width)
.attr("height", 50)
.attr("id", "trail");
// Add the label at the end, for the percentage.
trail.append("svg:text")
.attr("id", "endlabel")
.style("fill", "#000");
}
// Generate a string that describes the points of a breadcrumb polygon.
function breadcrumbPoints(d, i) {
var points = [];
points.push("0,0");
points.push(b.w + ",0");
points.push(b.w + b.t + "," + (b.h / 2));
points.push(b.w + "," + b.h);
points.push("0," + b.h);
if (i > 0) { // Leftmost breadcrumb; don't include 6th vertex.
points.push(b.t + "," + (b.h / 2));
}
return points.join(" ");
}
// Update the breadcrumb trail to show the current sequence and percentage.
function updateBreadcrumbs(nodeArray, percentageString) {
// Data join; key function combines name and depth (= position in sequence).
var g = d3.select("#trail")
.selectAll("g")
.data(nodeArray, function(d) { return d.name + d.depth; });
// Add breadcrumb and label for entering nodes.
var entering = g.enter().append("svg:g");
entering.append("svg:polygon")
.attr("points", breadcrumbPoints)
.style("fill", function(d) { return colors[d.name]; });
entering.append("svg:text")
.attr("x", (b.w + b.t) / 2)
.attr("y", b.h / 2)
.attr("dy", "0.35em")
.attr("text-anchor", "middle")
.text(function(d) { return d.name; });
// Set position for entering and updating nodes.
g.attr("transform", function(d, i) {
return "translate(" + i * (b.w + b.s) + ", 0)";
});
// Remove exiting nodes.
g.exit().remove();
// Now move and update the percentage at the end.
d3.select("#trail").select("#endlabel")
.attr("x", (nodeArray.length + 0.5) * (b.w + b.s))
.attr("y", b.h / 2)
.attr("dy", "0.35em")
.attr("text-anchor", "middle")
.text(percentageString);
// Make the breadcrumb trail visible, if it's hidden.
d3.select("#trail")
.style("visibility", "");
}
function drawLegend() {
// Dimensions of legend item: width, height, spacing, radius of rounded rect.
var li = {
w: 75, h: 30, s: 3, r: 3
};
var legend = d3.select("#legend").append("svg:svg")
.attr("width", li.w)
.attr("height", d3.keys(colors).length * (li.h + li.s));
var g = legend.selectAll("g")
.data(d3.entries(colors))
.enter().append("svg:g")
.attr("transform", function(d, i) {
return "translate(0," + i * (li.h + li.s) + ")";
});
g.append("svg:rect")
.attr("rx", li.r)
.attr("ry", li.r)
.attr("width", li.w)
.attr("height", li.h)
.style("fill", function(d) { return d.value; });
g.append("svg:text")
.attr("x", li.w / 2)
.attr("y", li.h / 2)
.attr("dy", "0.35em")
.attr("text-anchor", "middle")
.text(function(d) { return d.key; });
}
function toggleLegend() {
var legend = d3.select("#legend");
if (legend.style("visibility") == "hidden") {
legend.style("visibility", "");
} else {
legend.style("visibility", "hidden");
}
}
// Take a 2-column CSV and transform it into a hierarchical structure suitable
// for a partition layout. The first column is a sequence of step names, from
// root to leaf, separated by hyphens. The second column is a count of how
// often that sequence occurred.
function buildHierarchy(csv) {
var root = {"name": "root", "children": []};
for (var i = 0; i < csv.length; i++) {
var sequence = csv[i][0];
var size = +csv[i][1];
if (isNaN(size)) { // e.g. if this is a header row
continue;
}
var parts = sequence.split("-");
var currentNode = root;
for (var j = 0; j < parts.length; j++) {
var children = currentNode["children"];
var nodeName = parts[j];
var childNode;
if (j + 1 < parts.length) {
// Not yet at the end of the sequence; move down the tree.
var foundChild = false;
for (var k = 0; k < children.length; k++) {
if (children[k]["name"] == nodeName) {
childNode = children[k];
foundChild = true;
break;
}
}
// If we don't already have a child node for this branch, create it.
if (!foundChild) {
childNode = {"name": nodeName, "children": []};
children.push(childNode);
}
currentNode = childNode;
} else {
// Reached the end of the sequence; create a leaf node.
childNode = {"name": nodeName, "size": size};
children.push(childNode);
}
}
}
return root;
};
HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Flow for G1 customers</title>
<script src="http://d3js.org/d3.v3.min.js"></script>
<link rel="stylesheet" type="text/css"
href="https://fonts.googleapis.com/css?family=Open+Sans:400,600">
<link rel="stylesheet" type="text/css" href="sequences.css"/>
</head>
<body>
<div id="main">
<div id="sequence"></div>
<div id="chart">
<div id="explanation" style="visibility: hidden;">
<span id="percentage"></span><br/>
of G1 customers follow this flow.
</div>
</div>
</div>
<div id="sidebar">
<input type="checkbox" id="togglelegend"> Legend<br/>
<div id="legend" style="visibility: hidden;"></div>
</div>
<script type="text/javascript" src="sequences.js"></script>
<script type="text/javascript">
// Hack to make this example display correctly in an iframe on bl.ocks.org
d3.select(self.frameElement).style("height", "700px");
</script>
</body>
</html>
Had the same issue, though I initially thought it is because of security restrictions of browser, that wasn't the case. It worked when I added the charset to the script tag as shown below:
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
The same is shown in the d3 docs, though it doesn't mention this issue specifically: http://d3js.org/
Yes, having it locally works too.
<script src="d3.min.js"></script>
Here is the full example:
<!doctype html>
<html>
<head>
<title>D3 tutorial</title>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<!--<script src="d3.min.js"></script>-->
</head>
<body>
<script>
var canvas = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 500);
var circle = canvas.append("circle")
.attr("cx",250)
.attr("cy", 250)
.attr("r", 50)
.attr("fill", "red");
</script>
</body>
</html>
There may be security restrictions that prevent your browser from downloading the D3 script. What you can do is to download the scripts, place them in the same folder as your files, and change the referenced paths in your source.
You may also need to add:
<meta charset="utf-8">
or
<meta content="utf-8" http-equiv="encoding">
to your head section
in case browser does not prevent it from downloading and still getting the error, d3.js should be placed before jquery.
I just moved my reference to the package as the first import in my head tag:
<head>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
...
...
</head>
Seemed to work for me
Replace <meta charset="ISO-8859-1"> with <meta charset="UTF-8">
I had to do a grunt build to get get rid of this error. (Using Yeoman and Ember.js.)
And for JavaScript noobs like me - problem could be that you don't import it correctly. Try reading import docs and things like:
import * as d3 from 'd3-transition'
If you are using Visual Studio you can go to Tools -> Options -> Text Editor -> JavaScript -> IntelliSense and check the box "Download remote references". That did the trick for me.
UPDATE: there is now a d3-webpack-loader package which makes it easy to load d3 in webpack. I am not the creator of the package, I've only used it to see if it works. Here's a quick example.
// Install the loader
npm install --save d3-webpack-loader
// Install the d3 microservices you need
npm install --save d3-color
npm install --save d3-selection
In our entry.js file we'll require d3 using the d3-webpack-loader with:
const d3 = require('d3!');
and can then use some of the d3 methods with:
d3.selectAll("p").style("color", d3.color("red").darker());
Super late to this response but none of the above solutions worked out for me. I found a fix though!
I am on macOS Catalina. For some bizarre reason, it turned out to be a decompression/unpack issue with the .tgz file from Observable's website. I use an application called The Unarchiver to decompress files, but in this case, the .tgz file did not properly unpack. There was a folder and file missing compared to a friend's computer not using the same program.
Solution: I unpacked .tgz without a third party program – just used macOS (simply double clicking on the file). Then, I loaded the page locally and it worked!
If double clicking on the file fails to unpack, try running tar -xzf filename.tgz in Terminal.
I assume that you are importing the d3 from online.
In your HTML, make sure that you are importing the d3 before connecting your JavaScript file.
// Importing D3.js
<script src="https://d3js.org/d3.v5.min.js" charset="utf-8" defer></script>
// Importing D3-Scale
<script src="https://d3js.org/d3-scale.v3.min.js"></script>
// Connecting my JS file
<script src="app.js" defer></script>

D3.js code in Reveal.js slide

I'm trying to make D3.js work on Reveal.js slides, but I can't get it to run even the most basic snippet:
<section>
<h2>Title</h2>
<div id="placeholder"></div>
<script type="text/javascript">
d3.select("#placeholder").append("p").text("TEST");
</script>
</section>
Doesn't show the "TEST" word. What am I doing wrong?
Okay here we go.
I have made a basic example with Reveal.js & D3.js and it works well.
There are two slides
First slide contains Bar chart
Second slide renders Bubble chart by taking data from a json input file
Your code works fine if it is placed outside of the section at the bottom. I have placed all D3.js code at the end of the html page before body closer.
The folder structure is show below (in snapshot)
I placed my JS inside the HTML (in order to make it easier to read/comprehend)
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Reveal.js with D3 JS</title>
<link rel="stylesheet" href="css/reveal.min.css">
<link rel="stylesheet" href="css/theme/default.css" id="theme">
<style>
.chart rect {
fill: #63b6db;
}
.chart text {
fill: white;
font: 10px sans-serif;
text-anchor: end;
}
text {
font: 10px sans-serif;
}
</style>
</head>
<body>
<div class="reveal">
<div class="slides">
<section>
<h2>Barebones Presentation</h2>
<p>This example contains the bare minimum includes and markup required to run a reveal.js presentation.</p>
<svg class="chart"></svg>
</section>
<section id="sect2">
<h2>No Theme</h2>
<p>There's no theme included, so it will fall back on browser defaults.</p>
<svg class="bubleCharts"></svg>
</section>
</div>
</div>
<script src="js/reveal.min.js"></script>
<script>
Reveal.initialize();
</script>
<script src="js/d3.min.js"></script>
<script type="text/javascript">
//------ code to show D3 Bar Chart on First Slide-------
var data = [44, 28, 15, 16, 23, 5];
var width = 420,
barHeight = 20;
var x = d3.scale.linear()
.domain([0, d3.max(data)])
.range([0, width]);
var chart = d3.select(".chart")
.attr("width", width)
.attr("height", barHeight * data.length);
var bar = chart.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * barHeight + ")"; });
bar.append("rect")
.attr("width", x)
.attr("height", barHeight - 1);
bar.append("text")
.attr("x", function(d) { return x(d) - 3; })
.attr("y", barHeight / 2)
.attr("dy", ".35em")
.text(function(d) { return d; });
//---Code below will show Bubble Charts on the secon Slide -------
var diameter = 560,
format = d3.format(",d"),
color = d3.scale.category20c();
var bubble = d3.layout.pack()
.sort(null)
.size([diameter, diameter])
.padding(1.5);
var svg = d3.select(".bubleCharts")
.attr("width", diameter)
.attr("height", diameter)
.attr("class", "bubble");
d3.json("flare.json", function(error, root) {
var node = svg.selectAll(".node")
.data(bubble.nodes(classes(root))
.filter(function(d) { return !d.children; }))
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
node.append("title")
.text(function(d) { return d.className + ": " + format(d.value); });
node.append("circle")
.attr("r", function(d) { return d.r; })
.style("fill", function(d) { return color(d.packageName); });
node.append("text")
.attr("dy", ".3em")
.style("text-anchor", "middle")
.text(function(d) { return d.className.substring(0, d.r / 3); });
});
// Returns a flattened hierarchy containing all leaf nodes under the root.
function classes(root) {
var classes = [];
function recurse(name, node) {
if (node.children) node.children.forEach(function(child) { recurse(node.name, child); });
else classes.push({packageName: name, className: node.name, value: node.size});
}
recurse(null, root);
return {children: classes};
}
d3.select(self.frameElement).style("height", diameter + "px");
</script>
</body>
</html>
Output/results
Slide 1
Slide 2
Download complete code https://github.com/aahad/D3.js/tree/master/Reveal JS with D3 JS
To learn more about how Bar Chart or Bubble Chart code works: check followings:
Bubble Chart examples: http://bl.ocks.org/mbostock/4063269
Bar Chart examples: http://bost.ocks.org/mike/bar/
Both existing answers are fine, but I'd like to point out a 3rd approach that worked for me and has some advantages.
Reveal.js has an event system and it also works with the per-slide data states.
This means that you can have a separate javascript block for each slide and have it execute only when that slide is loaded. This lets you do D3-based animations upon load of the slide and has the further advantage of placing the code for the slide closer to the text/markup of it.
For example, you could set your slide like this. Note the data-state attribute:
<section data-state="myslide1">
<h2>Blah Blah</h2>
<div id="slide1d3container"></div>
</section>
And then have an associated script block:
<script type="text/javascript">
Reveal.addEventListener( 'myslide1', function() {
var svg = d3.select("#slide1d3container").append("svg")
// do more d3 stuff
} );
</script>
Here's an example of a presentation that uses this technique:
http://explunit.github.io/d3_cposc_2014.html
I found out by myself. Of course I cannot match against ids that are not loaded yet: it works if I put the d3 javascript code after the Reveal.initialize script block at the end of the index.html file.

Selected element won't change in d3

This snippet is a slightly modified version of the example http://bl.ocks.org/4063550 of a Reingold-Tilford Tree. Everything is similar, except I have slightly changed the code where one appends the text to a node. I want to attach an id to each node text so that I can later tweak the text a bit so the graph is more readable.
Here I add the id's and slightly tweak the rotation of the entire diagram. My changes are enclosed with the **.
node.append("text")
.attr("dy", ".31em")
**.attr("id", function(d,i) {return "n" + i;})**
.attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
.attr("transform", function(d) { return d.x < 180 ? "**rotate(10)**translate(8)" :"**rotate(199)**translate(-8)"; })
.text(function(d) { return d.name; });
});
Right after the example code with the above being the only changes, I want to put the following line, for example, into the same script.
d3.select("#n1").text("test");
When I load the page it's not changing the text at node id = "n1"! If I put exactly that same line into the console with Firebug, it changes the n1 node's text as desired.
After browsing countless tutorials and the like, I think that I don't understand something fundamental about how this stuff works, any advice would be appreciated!
Edit: Here is the complete html file as requested! It is verbatim the example I linked above, with the only exceptions being what I described above.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.node {
font: 12px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var diameter = 960;
var tree = d3.layout.tree()
.size([360, diameter / 2 - 120])
.separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });
var diagonal = d3.svg.diagonal.radial()
.projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });
var svg = d3.select("body").append("svg")
.attr("width", diameter)
.attr("height", diameter)
.append("g")
.attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")");
d3.json("thesis.json", function(error, root) {
var nodes = tree.nodes(root),
links = tree.links(nodes);
var link = svg.selectAll(".link")
.data(links)
.enter().append("path")
.attr("class", "link")
.attr("d", diagonal);
var node = svg.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; });
node.append("circle")
.attr("r", 4.5);
node.append("text")
.attr("dy", ".25em")
.attr("id", function(d,i) {return "n" + i;})
.attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
.attr("transform", function(d) { return d.x < 180 ? "rotate(10)translate(8)" : "rotate(199)translate(-8)"; })
.text(function(d) { return d.name; });
});
d3.select(self.frameElement).style("height", diameter + "px");
d3.select("#n1").text("test");
</script>
</body>
</html>
The issue is that d3.json makes an asynchronous call. That is, the code within that block is only executed when the network call returns with the JSON data. The code after the block is executed immediately though. So, you are trying to modify an element that does not exist yet.
The solution is to move the code that modifies the graph inside the d3.json block, or into a function that is called inside that block.

Categories