🏠 back to Observable

Type error .join() not a function


I really have a hard time grasping (several month, if no a year of confused learning) how to handle external dataset in js or d3. I kind of feel like a monkey in a library. It may have been my js skills so I checked what I knew on sololearn.com. Completed the tutorial in javascript, finding it easy. So there must be something else, a twist of mind I can’t take and I don’t know why.

The last three days I’ve bee trying to learn how to use the force and simulation functions for networks. I have two approaches:

  1. port some code locally
  2. fork some notebook and change the dataset.

I’m failing on both.

  1. Starting with https://observablehq.com/@d3/disjoint-force-directed-graph I downloaded the graph.json and reproduced the following js code in a file.
    const height=600,
          width = 600;

        .then(function(data) {
    	const links = data.links.map(d => Object.create(d));
    	const nodes = data.nodes.map(d => Object.create(d));

    	const simulation = d3.forceSimulation(nodes)
    	      .force("link", d3.forceLink(links).id(d => d.id))
    	      .force("charge", d3.forceManyBody())
    	      .force("x", d3.forceX())
    	      .force("y", d3.forceY());

    	// create the DOM element for the view Box
    	const svg = d3.select("#canvas")
    	      .attr("viewBox", [-width / 2, -height / 2, width, height]);

    	const link = svg.append("g")
    	      .attr("stroke", "#999")
    	      .attr("stroke-opacity", 0.6)
    	  mbnetwork.js:26 Uncaught (in promise) TypeError: svg.append(...).attr(...).attr(...).selectAll(...).data(...).join is not a function
    	  at mbnetwork.js:26
    	  (anonymous)	@	mbnetwork.js:26
    	  Promise.then (async)		
    	  (anonymous)	@	mbnetwork.js:5
    	      .attr("stroke-width", d => Math.sqrt(d.value));

    	const node = svg.append("g")
    	      .attr("stroke", "#fff")
    	      .attr("stroke-width", 1.5)
    	      .attr("r", 5)

    	    .text(d => d.id);

    	// what is the on tick?
    	simulation.on("tick", () => {
    		.attr("x1", d => d.source.x)
    		.attr("y1", d => d.source.y)
    		.attr("x2", d => d.target.x)
    		.attr("y2", d => d.target.y);

    		.attr("cx", d => d.x)
    		.attr("cy", d => d.y);

    	invalidation.then(() => simulation.stop());


    function drag(simulation) {
        // Qu'est ce que d3.event.active ?
        function dragstrated(d){
    	// si il y a pas d'évenement actif restart simulation ?
    	// d3.event.active the number of currently active drag gestures, drag gesture ?
    	// 0 on start and end
    	if (!d3.event.active) simulation.alphaTarget(.3).restart();
    	// the above is true on start and end drag gestures
    	// set de the element speed ?
    	d.fx = d.x;
    	d.fy = d.y;

        function dragended(d) {
    	// how is the diff made between start and end ?
    	if (!d3.event.active) simulation.alphaTarget(0);
    	d.fx = null;
    	d.fy = null;

        function dragged(d) {
    	d.fx = d3.event.x;
    	d.fy = d3.event.y;

        return d3.drag()
    	.on("start", dragstarted)
    	.on("drag", dragged)
    	.on("end", dragended);

But as indicated in the code, I get an Type error .join() is not a function. I don’t understand it.

  1. Also I get a similar message chart = TypeError: svg.node is not a function when trying use my own xml dataset. https://observablehq.com/@maliky/afficher-un-reseau-dans-la-vue

I guess there are related by I have no clue how to solve them.

Thank you

I think I’ve solved the issue for you with this suggestion. The problem was that your code declared the svg variable in the callback of the then method. This meant that when you returned svg.node(), you were referring to the svg variable that the Observable standard library provides. My suggestion updates your code to use await to eliminate the callback.

1 Like

Ok, Thank you. Yes it was scope version and your suggestion help. Although, I’m not quite sure about the usage of await in that context. My understanding is that we should use await, and moving the svg declaration in the above scope was enough to solve that problem.