🏠 back to Observable

How do I change attributes of a single element in D3?

Notebook: Beta Distribution UI / Lao / Observable

I’ve been working on a user interface for the beta distribution. The beta distribution has two parameters, alpha and beta, that define the shape of the curve. I’ve created a handle for each curve that can be clicked and dragged to change the alpha and beta parameters.

When the user mouse overs a handle for a distribution, I would like only that alpha and beta parameters for that point to be displayed. Currently, I can only figure out how to hide or show the text for all points. Could someone help?

 // INTERACTION //////////////////////////////////////////////////////////////////
  let speed = 100
  points
    .on('mouseover', function() {
      d3.select(this)
        .transition().duration(speed).attr("r", (d) => d.r+3)        // grow point by 3 when mouse over
      text.transition().duration(speed).style("fill-opacity", 1) 
    })
    .on('mouseout', function() {
      d3.select(this)
        .transition().duration(speed).attr("r", (d) => d.r)          // shrink point do default when mouse moves away
      text.transition().duration(speed).style("fill-opacity", 1e-6) 
    })

A related question is, for each frame where a point has been dragged, all curves are recalculated for each variable. I’d like to make the program more efficient and only update the curve whose handle has been dragged.

function dragged(event, d) {
    d3.select(this)
      .attr("cx", () => {
        d.x = Math.min(w-padding-1, Math.max(padding+1, event.x)); // moves x position of circle
        return d.x;
      })
      .attr("cy", () => {
        d.y = Math.min(h-padding-1, Math.max(padding, event.y));    // moves y position of circle
        return d.y;
      })
    .moveToFront(); //brings point to front
    
    text
      .attr("x", d => d.x )                                         // moves x position of text
      .attr("y", d => d.y + textOffset)                             // moves y position of text
      .text((d) => {
        shape = map(xScaleInverse(d.x), yScaleInverse(d.y))
        return shape[0].toFixed(1) + " , " +shape[1].toFixed(1)    // updates the alpha and beta of label
      })
    
    pdf
      .datum((d,i) => graphCurve(xScaleInverse(handles[i].x), yScaleInverse(handles[i].y))) // recalcs all PDFs
      .attr("d", line)
  }

Both of theses are in the last //INTERACTION section of the first code block. I think my problem is not understanding how to effect a single element in the DOM tree. I’d love to know how to edit the nth series in a set of data.

In the application of fill-opacity can check if the text shares the same datum as the point. I’ve sent you a suggestion.

1 Like

That worked fantastically, thank you so much!!

1 Like