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

标签 javascript d3.js scatter-plot

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

enter image description here

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

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

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

 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)

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

enter image description here

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

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

最佳答案

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

在保留 this_case 的第一个定义的同时,尝试重命名传递到函数作用域的变量,如下所示,我刚刚将其更改为 d:

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

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

关于javascript - 根据条件改变D3散点图上多个点的半径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59490983/

相关文章:

javascript - 检查用户是否使用 FB.ui 在共享对话框中发布(或取消)共享到 Facebook

javascript - 我们可以在 asp.net 页面中使用 $(document).ready() 吗?

javascript - 过渡不起作用 d3

r - R 中的基本 2D 颜色平滑

python - 在字典中绘制嵌套列表 - python

javascript - 鼠标点击不起作用,鼠标移动可以

javascript - 响应图像和不同的图片分辨率

javascript - 使用 d3 将圆弧内的文本居中

html - 如何使用 d3.js 创建定义列表?

javascript - d3.缺失数据。仅绘制每组中的初始值