score:2

Accepted answer

This is because you are re-assigning rects to rects.enter(). Initially rects contains "updated" rectangles. What you want is to get both "enter" and "update", which can be done with merge.

var scale = d3.scaleLinear().domain([1,5]).range([0,200]);
            
var svg = d3.select("body")
            .append("svg")
            .attr("width",250)
            .attr("height",250);

function render(data,color){
    // update
    var rects = svg.selectAll("rect").data(data, d => d);

    // enter 
    rects
      .enter().append("rect")
      // enter + update
      .merge(rects)
        .attr("x", scale)
        .attr("y",50)
        .attr("width",20)
        .attr("height",20)
        .attr("fill",color);
};

render([1,2,3.5],"red");
render([1,2,3,4,5],"blue");
<script src="https://d3js.org/d3.v5.min.js"></script>

Edit: By default, when you call .data(...) d3 joins by index, so 3.5 becomes 3. If you want to join by numerical value , so that 3, 4 and 5 get inserted, you can pass second parameter to .data (read more
https://github.com/d3/d3-selection#selection_data)


Related Query