Kavoos
Kavoos

Reputation: 417

Updating D3 (v6) scatter plot doesn't add new circles

I'm trying to create a (connected) scatter plot. For the creating circles I do this:

    g
      .selectAll('.time-analysis circle')
      .data(getData())
      .enter()
      .append('circle')
      .attr('cx', d => x(d.period) || 0)
      .attr('cy', d => y(d.amount))
      .attr('r', 7)
      .attr('fill', '#90A4AE')

and for updating the plot, I do this:

    let dots = d3
      .selectAll('.time-analysis circle')
      .data(getData())

    dots.exit().remove()

    dots
      .transition()
      .attr('cx', d => x(d.period) || 0)
      .attr('cy', d => y(d.amount))

    dots
      .enter()
      .append('circle')
      .attr('r', 7)
      .attr('fill', '#90A4AE')
      .merge(dots)
      .transition()
      .attr('cx', d => x(d.period) || 0)
      .attr('cy', d => y(d.amount))

Problem is no new circle going to be added to the plot. For example, I have 20 circles, the new data have 5, I'll lost 15 circles, which is good, but when the new data arrives with 10 circles, I won't see that 5 new circles. As you can see in the screenshot below, the last part of the chart has no circles.

enter image description here

Any idea?

I also tried this but with no success:

    d3
      .selectAll('.time-analysis circle')
      .data(getData())
      .join(
        enter => enter
          .append('circle')
          .attr('r', 7)
          .attr('fill', '#90A4AE')
          .call(
            enter => enter
              .transition()
              .attr('cx', d => x(d.period) || 0)
              .attr('cy', d => y(d.amount))
          ),
        update => update
          .call(
            update => update
              .transition()
              .attr('cx', d => x(d.period) || 0)
              .attr('cy', d => y(d.amount))
          ),
        exit => exit.remove()
      )

Upvotes: 1

Views: 251

Answers (1)

Kavoos
Kavoos

Reputation: 417

OK, I found the solution myself.

First of all, I chose the second approach (the one with join). Problem was not with updating, but with selectAll. The new circles were created but not in the right place. long story short, this is the way I should select my circles (note that I use React, that's why you see svgContainer.current):

    d3
      .select(svgContext.current) // <= selecting the svg element
      .selectChild('g')           // <= selecting the g element within the svg element
      .selectAll('.time-analysis circle')
      .data(getData())
      .join(
        enter => enter
          .append('circle')
          .attr('r', 7)
          .attr('fill', '#90A4AE')
          .call(
            enter => enter
              .transition()
              .attr('cx', d => x(d.period) || 0)
              .attr('cy', d => y(d.amount))
          ),
        update => update
          .call(
            update => update
              .transition()
              .attr('cx', d => x(d.period) || 0)
              .attr('cy', d => y(d.amount))
          ),
        exit => exit.remove()
      )

Hope this will also help others :)

Upvotes: 3

Related Questions