If you’re having trouble understanding D3’s merge command, you are certainly not alone. There are hundreds of very similar questions on Stackoverflow. It does take some time to understand D3’s data binding, and the best way to learn it is to play with it.

New elements are added in green. Existing elements are colored orange.

const canvas = d3.select("#canvas");

function update(data) {

    // Select all existing circles. The first time this runs, there will not be
    // anything to select, but that's not a problem.
    let circles = canvas.selectAll("circle")

    // Set the class to "update" for all existing circles.
    circles.attr("class", "update");

    // The enter() command will add all new circles with the class "enter". The
    // merge() command will transition any existing circles.
           .attr("class", "enter")
           .attr("cx", d => xPos(d.index, data.length))
           .attr("cy", height / 2.0)
           .attr("r", d => d.radius)
           .attr("cx", d => xPos(d.index, data.length))
           .attr("r", d => d.radius);

    // Remove any circles that need to be removed.

The complete code for this blog entry is available in Github.

Hopefully this helps you to decipher enter, merge, and exit. Play with it. Build something small and learn how it all works before you try to do this with a really complicated visualization.