d3.js - 如何在 D3.js 中更改蜂群图中点的大小

标签 d3.js visualization

我一直在看this example d3.js 中的蜂群图,我正在尝试弄清楚如何更改点的大小而不让圆圈重叠。似乎如果点的半径发生变化,则在运行计算点的放置位置时不会考虑到这一点。

最佳答案

这是一个很酷的可视化。

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

  • 将圆半径做成变量(script.js第7行,var r = 3;)
  • 更改 d3.forceCollide 调用以使用该半径和乘数 - 第 110 行 (.force("collide", d3.forceCollide(r * 1.333)) )
  • 更改 .enter() 调用以也使用该半径(第 130 行:.attr("r", r))

这对于 r 的合理值来说工作得相当好 - 但你需要调整高度,甚至可能只是改变整个事情,这样 r 基于 height(例如 var r = height * .01)。您会注意到,与现在一样,圆圈超出了图形区域的底部和顶部。

这篇文章可能也很有趣: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 - 如何在 D3.js 中更改蜂群图中点的大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42631671/

相关文章:

javascript - 在 d3 节点上调用 if…then 函数

firefox - nvd3 图表在 Firefox 中无法正确加载

javascript - 在 d3.js 中绘制不同颜色的公寓和城镇

database-design - 用于流程图和数据库表连接可视化的开源或免费软件?

python - python中节点图的ASCII可视化

可视化 100k 顶点和 1M 边的 Python 工具?

javascript - 我怎样才能用d3把一个圆圈放在前面?

javascript - d3 退出转换 : how to flatten path and then remove

javascript - 测试 JavaScript 图表

c++ - 从数据中创建/放置圆圈/网格的简单数据可视化