javascript - D3 放大笔刷范围

标签 javascript d3.js

我正在开发一个 web 工具,它可以用给定的数据创建一个散点图。因为我对任何可视化都不熟悉(也不是 JavaScript 专家),所以我决定使用 D3。

按照教程、观察示例并尝试一些东西,我得到了一个与画笔选择相关的散点图(尚未执行任何操作)。 现在因为目标是绘制基因,很多基因在 x 和 y 坐标方面会非常接近。所以我想实现一些东西 like this , 但在 x 和 y 方向上。基本上放大拉丝部分。

到目前为止,我无法创建这种行为,此时我的坐标轴确实发生了变化,但不再显示值,也没有发生任何缩放。你可以在my toy subdomain上看到它.我不确定哪里出了问题,所以感谢您的帮助。

toy 域上使用的 javascript:

// General variables

var svg, width, height;
var padding = 30;

var dataset = [
              [ 5,     20 ],
              [ 480,   90 ],
              [ 250,   50 ],
              [ 100,   33 ],
              [ 330,   95 ],
              [ 410,   12 ],
              [ 475,   44 ],
              [ 25,    67 ],
              [ 85,    21 ],
              [ 220,   88 ]
          ];

function drawGraph(){
    scatterplot_area_size = $("#scatterplot").width();
    width = scatterplot_area_size;
    height = scatterplot_area_size * 0.75;

    console.log(width);

    // Retrieve the interval of the x and y data
    var maxX = d3.max(dataset, function(d) {
        return d[0];  //References first value in each sub-array
    });

    var minX = d3.min(dataset, function(d) {
        return d[0];  //References first value in each sub-array
    });

    var maxY = d3.max(dataset, function(d) {
        return d[1];  //References second value in each sub-array
    });

    var minY = d3.min(dataset, function(d) {
        return d[1];  //References second value in each sub-array
    });

    // Create a (square) scatterplot area in the div with id scatterplot
    // which spans the entire div in width
    svg = d3.select("#scatterplot")
            .append("svg")
            .attr("width", width)
            .attr("height", height);

    // plot all points
    var points = svg.append("g")
        .attr("class", "point")
        .selectAll("point")
        .data(dataset)
        .enter()
        .append("circle");


    console.log(minX + " " + minY);

    // Create x and y scales
    var x = d3.scale.linear()
                     .domain([minX, maxX])
                     .range([padding, (width-padding)]);

    var y = d3.scale.linear()
                     .domain([minY, maxY])
                     .range([(height-padding), padding]); // Reverse the scale to let high values show at the top and low values at the bottom

    // Set the x and y positions as well as the radius (hard coded 5)
    points.attr("cx", function(d) {
        return x(d[0]);
    })
   .attr("cy", function(d) {
        return y(d[1]);
    })
    .attr("r", 5);

    // Create the x and y axes
    var xAxis = d3.svg.axis()
                  .scale(x)
                  .ticks(10)
                  .orient("bottom");

    var yAxis = d3.svg.axis()
                  .scale(y)
                  .ticks(10)
                  .orient("left");

    // Add the axes to the scatterplot
    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + (height-padding) + ")")
        .call(xAxis);

    svg.append("g")
        .attr("class", "y axis")
        .attr("transform", "translate(" + padding + ",0)")
        .call(yAxis);

    // Allow for brushing (selection of points)
    var brush = d3.svg.brush()
        .x(x)
        .y(y)
        .on("brush", brushmove)
        .on("brushend", brushend);

    svg.append("g")
        .attr("class", "brush")
        .call(brush)
        .selectAll('rect')
        .attr('height', height);

    function brushmove() {
      var extent = brush.extent();
      points.classed("selected", function(d) {
        return extent[0][0] <= d[0] && d[0] <= extent[1][0]
                && extent[0][1] <= d[1] && d[1] <= extent[1][1];
      });
    }

    function brushend() {
        x.domain(brush.extent());
        y.domain(brush.extent());

        transition_data();
        reset_axis();

        points.classed("selected", false);
        d3.select(".brush").call(brush.clear());
    }

    function transition_data() {
        console.log("transistion data called");
        d3.selectAll("point")
        .transition()
        .duration(500)
        .attr("cx", function(d) { console.log(d[0]); return x(d[0]); })
        .attr("cy", function(d) { return y(d[1]); });
    }

    function reset_axis() {
        svg.transition().duration(500)
        .select(".x.axis")
        .call(xAxis);

        svg.transition().duration(500)
        .select(".y.axis")
        .call(yAxis);
    }
}

// Wait until the document is loaded, then draw the graph.
$( document ).ready(function() {
    drawGraph();
});

// If the window is resized, redraw graph to make it fit again.
$( window ).resize(function() {
    if(typeof svg != 'undefined'){
        $("#scatterplot").empty();
    } 
    drawGraph();
});

最佳答案

您的代码中有两个错误:

  1. 在您的函数 brushend() 中,您在两种情况下都使用 brush.extent() 的返回值来设置比例域。但是请注意,画笔返回的范围是一个二维数组,如 [[xMin,yMin],[xMax,yMax]]。您必须使用

    var extent = brush.extent();
    x.domain([extent[0][0],extent[1][0]]);  // x.domain([xMin,xMax])
    y.domain([extent[0][1],extent[1][1]]);  // y.domain([yMin,yMax])
    

    这些调整将使您的轴正确缩放,同时点仍然固定。

  2. 您正在使用 d3.selectAll("point") 插入和操作您的数据点,这将它们称为 svg:point 类型。但是,没有这种类型的 svg 元素。尽管您对 d3.selectAll("point") 的调用仍然有效,但它始终会产生空选择,因为没有可供选择的元素。出于这个原因,您在设置 svg 时第一次调用该函数确实有效,因为它会将所有数据绑定(bind)到输入选择,从而提供所需的结果。为了正确起见,您应该将其更正为

    // plot all points
    var points = svg.append("g")
        .attr("class", "point")
        // .selectAll("point")
        .selectAll("circle")    // <-- This will work
        .data(dataset)
        .enter()
        .append("circle");
    

    在设置比例域后尝试更新您的点时,错误代码将不起作用,因为在这种情况下,空选择是没有意义的,并且对任何元素都没有影响。由于在上面引用的语句中,您已经在 var points 中存储了对您的选择的引用,因此无需再次选择它们。您可以按如下方式重写您的更新:

    function transition_data() {
        // d3.selectAll("point")   // Instead of this...
        points                     // <-- ...use the reference to your selection
            .transition()
            .duration(500)
            .attr("cx", function(d) { return x(d[0]); })
            .attr("cy", function(d) { return y(d[1]); });
    }
    

我整理了一个工作 JSFiddle演示解决方案。

关于javascript - D3 放大笔刷范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30005145/

相关文章:

javascript - Backbone Event 触发不同 View 之间的协调

javascript - setInterval 和事件循环

javascript - 如何缩小文本标签并为 D3 气泡图中的悬停信息窗口添加属性?

javascript - d3js - 将父元素添加到选择中

d3.js - 强制蜂群图 - 添加节点链接

javascript - 如何在涉及搜索事件的选择事件后重新打开菜单?

javascript - Plotly 悬停文本不显示

javascript - 拖动一个矩形并附加到相应的组

javascript - 我应该如何在 d3js 中使用嵌套数据

javascript - 将 if 语句与创建映射变量结合使用 (Javascript)