How do I apply custom force cluster to each cluster?

Hello !

I am trying to apply an hexagon shape to each cluster using custom force cluster
In this chart, force cluster I have various clusters of circles. I have this function getHexRCFromIndex to place circles in a hexagon shape. I using the hexagon function inside forceCluster function to do so. But all my circles are attracting each other to form one hexagon shape but I want the hexagon shape to be applied to each cluster, so I would have 14 hexagons instead of just one. How do I do this?

I did create a grouping of the data and then apply the custom force. But nothing seems to be working. Could someone tell me where I am going wrong, please? or how I can use this grouped data inside the force cluster to create the hexagon shapes?

Hexagon force cluster

Thank you, in advance!

Each group in your grouped paintings needs to be its own cluster for it to look the the example image.

You seem to be currently drawing from data the csv file and not from the groupedPaintings data you have created.

I made a cell called keyz using lodash, so I could loop through the groups.

keyz = _.keys(groupedPaintings )

And added a loop to read the related data.
The transform (which doesnt go right but gives you a rough idea) is changed so the circles dont all do what they did.

  for (let idx = 0; idx < keyz.length; ++idx) {
    const node = svg.append("g")
      .attr("transform", `translate(${width/2},${height/idx})`) //this line has been added to show the hexagon, otherwise the hexagon forms at 
      .data(groupedPaintings[keyz[idx]] )
      .attr("fill",d => d.Titanium_White==0?"#da7b16":"white")

    simulations.on("tick", ticked)

  function ticked() {
          node.attr("cx", d=>d.x)
          node.attr("cy", d=>d.y)

There are many bugs with how I have done this but it should help you get on track to fix your problem. This notebook might be of more help in creating your grouped paintings Custom Cluster Force Layout using Force in a Box / John Alexis Guerra Gómez / Observable

1 Like

@urmilaj I have two questions:

  1. You already have d3.forceY in your simulation. Why do you also need the “cluster” force?
  2. If you already know that you want to arrange your nodes in a hexagon shape, why do you need a force simulation (instead of calculation the node positions explicitely?
1 Like

Hey Brett! Thank you for your response!


  1. I am using forceX and forceY to bring the nodes to their respective positions. Then, I use forceCluster which uses the getHexRCfFromIndex function to get the hexagon shape. But when I do this all the nodes attract each other to form one big hexagon instead of individual group hexagons.
  2. I’m using forceSimulation because the hex function takes the index values generated by the forceSimulation to generate the hex shape. (Now as I type this I realize the index values are the same as the data index values. So maybe I dont need to use forceSimulation at all, and explicitly calculate it, like you suggested. I shall give this a go.)

But can each clusters be shaped into a hexagon using forceSimulation? Is it possible?

Unlikely, because the manybody force will cause the nodes to interlock, preventing them from reaching their ideal position (which would be a hexagon).


1 Like

I was able to form hex shapes for each cluster by explicitly calculating values. Thank you for your response! Untitled / Urmila / Observable

Oh okay, Im new to using force simulation, so this has been a bit of a struggle. But in this notebook example below, they are using force simulation , appending squares in each node and then structuring the squares evenly, so I thought it would be possible to structure my circles in a hexagon as well.

They only use d3-force to arrange the clusters. Each square is an explicit layout that doesn’t take part in the collision (only the circles do). You can see that e.g. by repeatedly pressing play on the chart cell, or by taking a look at the function that starts with var curr_node = data.nodes[d.index];.

1 Like

Oh okay, that makes sense. Thank you for your explanation.

One last question, if manybody force cause the nodes to interlock and prevents forming of the cluster hexagons, How come the single hexagon is formed when I apply the force cluster function? Does this happen because after the simulation cools down the nodes arrange themselves using the hex function?

Your forceCollide() was essentially applying a fixed hex layout by gradually directing nodes to their target positions, similar to what happens in D3 Force Along a Path / Fabian Iwand / Observable.

You could remove all other forces and it would still “work”, because it’s not actually using forces to determine node positions.

Edit: Here’s a preset that might visualize better what I described above: D3 Force Along a Path / Fabian Iwand / Observable

1 Like

Oh Okay! Thank you for answering and taking the time to explain. This has been very helpful. I really appreciate it! :smiley: :pray:

1 Like