根据条件改变D3散点图上多个点的半径

Changing radius of multiple points on D3 scatterplot based on condition

我正在使用一个函数来构建一系列 d3 散点图。基本上,每个散点图都显示了一系列“案例”,然后是每个案例的两个事件。 Y 轴是案例,X 轴是每个不同案例的两个事件。图片在这里:

每个图都基于一个 CSV,red/blue 点只是为电子表格中的每个“案例”记录绘制两个不同的日期列。

每个案例都映射到散点图上,每个案例在时间上都有两个不同的事件。目前,圆的半径会在鼠标悬停时发生变化。当其中一个悬停时,我希望能够让每个案例的两个圆圈都改变半径,以便产生“linked”效果。例如,如果您将鼠标悬停在案例 1 的蓝点或红点上,这两个圆圈都会显得更大(一种直观地 link 该案例的这两个事件的方法)。

这是我用来构建每个散点图的函数:

 function makeScatterplot(dataset, dataviz, field_1, field_2, field_3, numCases, maxAge, htmlText, xLabel, yLabel, legendItem1, legendItem2){
        
    //load csv//read the data
    d3.csv(dataset)
    .then(function(data) {

    //append svg to body of page
    var margin = {top: 60, right: 30, bottom: 50, left: 60},
    width = 580 - margin.left - margin.right,
    height = 450 - margin.top - margin.bottom;
    
    var svg = d3.select(dataviz)
    .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform",
          "translate(" + margin.left + "," + margin.top + ")");
    
    //add x axis
    var x = d3.scaleLinear()
        .domain([0,maxAge])
        .range([0, width-100])
    svg.append("g")
        .attr("transform", "translate(0," + height + ")")
        .attr("class", "axisLine")  
        .call(d3.axisBottom(x));
        
    
    //add y axis
    var y = d3.scaleLinear()
        .domain([0,numCases])
        .range([ height, 0]);
    svg.append("g")
        .attr("class", "axisLine")  
        .call(d3.axisLeft(y)); 
        
    // text label for the x axis
    svg.append("text") 
        .attr("class", "axisLabel")     
        .attr("transform",
        "translate(" + ((width-100)/2 ) + " ," + 
                       (height + margin.top + -15) + ")")
        .style("text-anchor", "middle")
        .text("Age");
                
        
    // Add the tooltip container to the vis container
    var tooltip = d3.select("#my_dataviz").append("div")
        .attr("class", "tooltip")
        .style("opacity", 0);
        
    //add dots for field 1 (red circles)
    svg.append("g")
        .selectAll("dot")
        .data(data)
        .enter()
        .append("circle")
        .attr("cx", function (d) {return x(d[field_1]);})
        .attr("cy", function (d) {return y(d.case);})
        .attr("r", 6)
        .attr("class", "events_1")
        .style("fill",  "ff4c4c")
        .style("opacity", '.7')
        .on("mouseover", function(data) {
            d3.select(this).attr("r", 10)
            d3.select('.tooltip')
            tooltip.transition()
                .duration(200)
                .style("opacity", 1);
            tooltip.html(data[field_3] + htmlText)
            
                .style("left", (d3.event.pageX + 15) + "px")
                .style("top", (d3.event.pageY - 18) + "px");
        })
        .on("mouseout", function(data) {
            d3.select(this).style("stroke", 'none')
            d3.select(this).attr("r", 6)
            tooltip.transition()
                .duration(500)
                .style("opacity", 0);
    })
    
    
    //add dots for field 2 (blue circles)
    svg.append("g")
        .selectAll("dot")
        .data(data)
        .enter()
        .append("circle")
        .attr("cy", function (d) {return y(d.case);})
        .attr("cx", function (d) {return x(d[field_2]);})
        .attr("r", 6) 
        .attr("class", "events_2")
        .style("fill",  "#6666ff")
        .style("opacity", '.8')
        .on("mouseover", function(data) {
            
                                            
            d3.select(this).attr("r", 10)
            this_case = data.case  // record the current case selected from blue circles on hover
            
            d3.selectAll(".events_1")  // change the radius of the red circle that matches the case selected from blue circles
                .attr("r", function(this_case){
                    d3.select(this)
                    this_case=data.case
                    console.log(this_case)
                    if (this_case) {
                        return 10
                    }
                    else {
                        return  6
                    }
                })  


                return this_case
                            
                
            //.data(data.filter(function(d){return d.case == d.case;}))
            d3.select('.tooltip')
            tooltip.transition()
                .duration(200)
                .style("opacity", 1);
            tooltip.html(data[field_3] + htmlText)
                .style("left", (d3.event.pageX + 15) + "px")
                .style("top", (d3.event.pageY - 18) + "px");
        })
        .on("mouseout", function(data) {
            d3.select(this).style("stroke", 'none')
            d3.select(this).attr("r", 6)
            tooltip.transition()
                .duration(500)
                .style("opacity", 0);
    })
                
    })
            
}

//Build scatterplots by calling function
makeScatterplot(dataset_suicide, dataviz_1, demo_dod, avi_suicide_date, suicide_to_DOD, 22, 70, suicide_html, xLabel, yLabel, suicide_title, dod_legend, suicide_legend, )
makeScatterplot(dataset_DOC, dataviz_1, demo_dod, doc_inc_release_dte, release_to_DOD, 20, 70, DOC_html,  xLabel, yLabel, DOC_title, dod_legend, doc_legend)
makeScatterplot(dataset_last_od, dataviz_2, demo_dod, avi_od_date, od_to_death, 41, 75, last_od_html,  xLabel, yLabel, last_od_title, dod_legend, last_od_legend)

目前,当悬停蓝色圆圈时,此代码将半径应用于所有情况:

有没有一种简单的方法可以完成我想要完成的任务?基本上,只是尝试 link 悬停这些圆圈,对于每个单独的散点图(圆圈半径只会增加散点图中选择的圆圈,在同一情况下,而不是所有散点图)。

我想我可能需要将圆圈 类 作为可变参数,以便相应地选择它们。

我明白你想用你的 if 语句做什么,但是当你将变量 this_case 定义为传递给 r 函数的对象时, d3 这是绑定到每个单独的 selected 对象的任何数据对象 - 覆盖我认为你试图为 this_case 创建上面几行的范围。

在保留 this_case 的第一个定义的同时,尝试重命名传递到函数范围的变量,就像这样,我刚刚将其更改为 d:

                .attr("r", function(d){
                    if (d.case == this_case) {
                        return 10
                    }
                    else {
                        return  6
                    }
                })  

替代方法: 如果是我,我可能会为每个案例附加一个 g 标签,并带有一个包含案例编号的 id。然后我将两个圆圈附加到这个标签,这样在鼠标悬停时我可以 select 适当的 g 标签首先用我创建的 id,然后在上面做一个 selectAll('circle') 来改变两个的圈子。只是感觉更有条理,当然,这只是我的意见!