如何在D3.js中更改蜂群图中的点大小 [英] How to change the size of dots in beeswarm plots in D3.js

查看:68
本文介绍了如何在D3.js中更改蜂群图中的点大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在查看此示例在d3中的蜂拥情节. js和我试图弄清楚如何更改点的大小,而又不使圆圈重叠.似乎如果圆点的半径发生了变化,则在进行圆点放置位置的计算时并没有考虑到这一点.

I've been looking at this example of a beeswarm plot in d3.js and I'm trying to figure out how to change the size of the dots and without getting the circles to overlap. It seems if the radius of the dots change, it doesn't take this into account when running the calculations of where to place the dots.

推荐答案

这是很酷的可视化.

我在这里做了一些介绍: https://plnkr.co/edit/VwyXfbc94oXp6kXQ7JFx?p = preview 并对其进行了修改,使其更像您正在寻找的(我认为).真正的关键是将处理碰撞的调用更改为根据圆的半径而变化(在原始帖子中,它被硬编码为4,当r === 3时效果很好,但随着r的增加而失败).更改:

I've made a plunk of it here: https://plnkr.co/edit/VwyXfbc94oXp6kXQ7JFx?p=preview and modified it to work a bit more like you're looking for (I think). The real key is changing the call to handle collision to vary based on the radius of the circles (in the original post it's hard coded to 4, which works well when r === 3 but fails as r grows). The changes:

  • 将圆半径设为变量(script.js的第7行,var r = 3;)
  • 更改d3.forceCollide调用以使用该半径和乘数-第110行(.force("collide", d3.forceCollide(r * 1.333)))
  • 更改.enter()调用以也使用该半径(第130行:.attr("r", r))
  • Make the circle radius into a variable (line 7 of script.js, var r = 3;)
  • Change the d3.forceCollide call to use that radius and a multiplier - line 110 (.force("collide", d3.forceCollide(r * 1.333)))
  • Change the .enter() call to use that radius as well (line 130: .attr("r", r))

这对于r的合理值来说相当有效-但您需要调整高度,甚至更改整个内容以使r基于height可能甚至更好. var r = height * .01).您会注意到,现在,圆圈从图形区域的底部和顶部移出.

This works reasonably well for reasonable values of r - but you'll need to adjust the height, and it might even be nice to just change the whole thing so that r is based on height (e.g. var r = height * .01). You'll notice that as is now, the circles go off the bottom and top of the graph area.

也可能对此帖子感兴趣:

This post might be of interest as well: Conflict between d3.forceCollide() and d3.forceX/Y() with high strength() value

以下是script.js的全部内容:

var w = 1000, h = 280;

var padding = [0, 40, 34, 40];
var r = 5;

var xScale = d3.scaleLinear()
    .range([ padding[3], w - padding[1] ]);

var xAxis = d3.axisBottom(xScale)
    .ticks(10, ".0s")
    .tickSizeOuter(0);

var colors = d3.scaleOrdinal()
    .domain(["asia", "africa", "northAmerica", "europe", "southAmerica", "oceania"])
    .range(['#e41a1c','#377eb8','#4daf4a','#984ea3','#ff7f00','#ffff33']);

d3.select("#africaColor").style("color", colors("africa"));
d3.select("#namericaColor").style("color", colors("northAmerica"));
d3.select("#samericaColor").style("color", colors("southAmerica"));
d3.select("#asiaColor").style("color", colors("asia"));
d3.select("#europeColor").style("color", colors("europe"));
d3.select("#oceaniaColor").style("color", colors("oceania"));

var formatNumber = d3.format(",");

var tt = d3.select("#svganchor").append("div")  
    .attr("class", "tooltip")               
    .style("opacity", 0);

var svg = d3.select("#svganchor")
    .append("svg")
    .attr("width", w)
    .attr("height", h);

var xline = svg.append("line")
    .attr("stroke", "gray")
    .attr("stroke-dasharray", "1,2");

var chartState = {};

chartState.variable = "totalEmission";
chartState.scale = "scaleLinear";
chartState.legend = "Total emissions, in kilotonnes";

d3.csv("co2bee.csv", function(error, data) {
    if (error) throw error;

    var dataSet = data;

    xScale.domain(d3.extent(data, function(d) { return +d.totalEmission; }));

    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + (h - padding[2]) + ")")
        .call(xAxis);

    var legend = svg.append("text")
        .attr("text-anchor", "middle")
        .attr("x", w / 2)
        .attr("y", h - 4)
        .attr("font-family", "PT Sans")
        .attr("font-size", 12)
        .attr("fill", "darkslategray")
        .attr("fill-opacity", 1)
        .attr("class", "legend");

    redraw(chartState.variable);

    d3.selectAll(".button1").on("click", function(){
        var thisClicked = this.value;
        chartState.variable = thisClicked;
        if (thisClicked == "totalEmission"){
            chartState.legend = "Total emissions, in kilotonnes";
        }
        if (thisClicked == "emissionPerCap"){
            chartState.legend = "Per Capita emissions, in metric tons";
        }
        redraw(chartState.variable);
    });

    d3.selectAll(".button2").on("click", function(){
        var thisClicked = this.value;
        chartState.scale = thisClicked;
        redraw(chartState.variable);
    });

    d3.selectAll("input").on("change", filter);

    function redraw(variable){

        if (chartState.scale == "scaleLinear"){ xScale = d3.scaleLinear().range([ padding[3], w - padding[1] ]);}

        if (chartState.scale == "scaleLog"){ xScale = d3.scaleLog().range([ padding[3], w - padding[1] ]);}

        xScale.domain(d3.extent(dataSet, function(d) { return +d[variable]; }));

        var xAxis = d3.axisBottom(xScale)
            .ticks(10, ".0s")
            .tickSizeOuter(0);

        d3.transition(svg).select(".x.axis").transition().duration(1000)
            .call(xAxis);

        var simulation = d3.forceSimulation(dataSet)
            .force("x", d3.forceX(function(d) { return xScale(+d[variable]); }).strength(2))
            .force("y", d3.forceY((h / 2)-padding[2]/2))
            .force("collide", d3.forceCollide(r * 1.333))
            .stop();

        for (var i = 0; i < dataSet.length; ++i) simulation.tick();

        var countriesCircles = svg.selectAll(".countries")
            .data(dataSet, function(d) { return d.countryCode});

        countriesCircles.exit()
            .transition()
            .duration(1000)
            .attr("cx", 0)
            .attr("cy", (h / 2)-padding[2]/2)
            .remove();

        countriesCircles.enter()
            .append("circle")
            .attr("class", "countries")
            .attr("cx", 0)
            .attr("cy", (h / 2)-padding[2]/2)
            .attr("r", r)
            .attr("fill", function(d){ return colors(d.continent)})
            .merge(countriesCircles)
            .transition()
            .duration(2000)
            .attr("cx", function(d) { console.log(d); return d.x; })
            .attr("cy", function(d) { return d.y; });

        legend.text(chartState.legend);

        d3.selectAll(".countries").on("mousemove", function(d) {
            tt.html("Country: <strong>" + d.countryName + "</strong><br>"
            + chartState.legend.slice(0, chartState.legend.indexOf(",")) + ": <strong>" + formatNumber(d[variable]) + "</strong>" + chartState.legend.slice(chartState.legend.lastIndexOf(" ")))
                .style('top', d3.event.pageY - 12 + 'px')
                .style('left', d3.event.pageX + 25 + 'px')
                .style("opacity", 0.9);

                xline.attr("x1", d3.select(this).attr("cx"))
                    .attr("y1", d3.select(this).attr("cy"))
                    .attr("y2", (h - padding[2]))
                    .attr("x2",  d3.select(this).attr("cx"))
                    .attr("opacity", 1);

        }).on("mouseout", function(d) {
            tt.style("opacity", 0);
            xline.attr("opacity", 0);
        });

        d3.selectAll(".x.axis, .legend").on("mousemove", function(){
            tt.html("This axis uses SI prefixes:<br>m: 10<sup>-3</sup><br>k: 10<sup>3</sup><br>M: 10<sup>6</sup>")
                .style('top', d3.event.pageY - 12 + 'px')
                .style('left', d3.event.pageX + 25 + 'px')
                .style("opacity", 0.9);
        }).on("mouseout", function(d) {
            tt.style("opacity", 0);
        });

    //end of redraw
    }

    function filter(){

        function getCheckedBoxes(chkboxName) {
          var checkboxes = document.getElementsByName(chkboxName);
          var checkboxesChecked = [];
          for (var i=0; i<checkboxes.length; i++) {
             if (checkboxes[i].checked) {
                checkboxesChecked.push(checkboxes[i].defaultValue);
             }
          }
          return checkboxesChecked.length > 0 ? checkboxesChecked : null;
        }

        var checkedBoxes = getCheckedBoxes("continent");

        var newData = [];

        if (checkedBoxes == null){ 
            dataSet = newData; 
            redraw(); 
            return;
        };

        for (var i = 0; i < checkedBoxes.length; i++){
            var newArray = data.filter(function(d){
                return d.continent == checkedBoxes[i];
            });
            Array.prototype.push.apply(newData, newArray);
        }

        dataSet = newData;

        redraw(chartState.variable);

    //end of filter
    }

//end of d3.csv
});

这篇关于如何在D3.js中更改蜂群图中的点大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆