javascript - 动态改变 d3.js 直方图的 bin 和高度

标签 javascript jquery-ui d3.js dynamic histogram

我希望能够使用范围 slider 来动态更改 bins/bars/rectangles 的数量。下面的代码差不多了,但是有几个问题我还没有弄清楚。

  1. 当我使用范围 slider 时,它似乎跳过了一些值。
  2. 滑动到低数字后,条形/矩形的高度会超出高度。

The jsfiddle is here.

CSS:

body {
    font: 10px sans-serif;
}
.bar rect {
    fill: steelblue;
    shape-rendering: crispEdges;
}
.bar text {
    fill: #fff;
}

.axis path,
.axis line {
    fill: none;
    stroke: #000;
    shape-rendering: crispEdges;
}
#slider-range-max {
    width: 100%;
}

html:

<div id="histogram_container">
    <div id="histogram"></div>
    <div align="center">
        <p>
            <label for="bins">Number of bins:</label>
            <input type="text" id="bins" readonly style="border:0; color:#f6931f; font-weight:bold;">
        </p>
        <div id="slider-range-max"></div>
    </div>
</div>

js:

var grades_data = [],
    grades = [];

var score_max = 100,
    score_min = 0;

var age_max = 18,
    age_min = 5;

var data_generator = (function() {
    var gen = d3.random.normal(score_max / 2, 15);
    return function() {
        return Math.floor(Math.max(score_min, Math.min(gen(), score_max)));
    }
}());

for (var i = 0; i < 1001; i++) {
    var age = Math.floor(Math.random() * (age_max - age_min + 1)) + age_min;
    var grade = data_generator();

    grades_data.push({
        age,
        grade
    });
    grades.push(grade);
}

var margin = {
        top: 20,
        right: 20,
        bottom: 30,
        left: 40
    },
    width = 600 - margin.left - margin.right,
    height = 600 - margin.top - margin.bottom;

var format_count = d3.format(",.0f");

var x_gh_scale = d3.scale.linear().range([0, width])
    .domain([0, 100]),
    x_gh_axis = d3.svg.axis().scale(x_gh_scale).orient("bottom");

var data = d3.layout.histogram()
    .bins(x_gh_scale.ticks(20))
    (grades);

var y_gh_scale = d3.scale.linear().range([height, 0])
    .domain([0, d3.max(data, function(d) {
        return d.y;
    })]);

var grade_histo_svg = d3.select("#histogram").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 + ")");

var bar = grade_histo_svg.selectAll(".bar")
    .data(data)
    .enter().append("g")
    .attr("class", "bar")
    .attr("transform", function(d) {
        return "translate(" + x_gh_scale(d.x) + "," + y_gh_scale(d.y) + ")";
    });

bar.append("rect")
    .attr("x", 1)
    .attr("width", x_gh_scale(data[0].dx) - 1)
    .attr("height", function(d) {
        return height - y_gh_scale(d.y);
    });

bar.append("text")
    .attr("dy", ".75em")
    .attr("y", 6)
    .attr("x", x_gh_scale(data[0].dx) / 2)
    .attr("text-anchor", "middle")
    .text(function(d) {
        return format_count(d.y);
    });

grade_histo_svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(x_gh_axis);

$(function() {
    $("#slider-range-max").slider({
        range: "max",
        min: 1,
        max: 20,
        value: 20,
        slide: function(event, ui) {
            $("#bins").val(ui.value);

            var data = d3.layout.histogram()
                .bins(x_gh_scale.ticks(ui.value))
                (grades);

            var bar = grade_histo_svg.selectAll(".bar")
                .remove()
                .data(data)
                .enter().append("g")
                .attr("class", "bar")
                .attr("transform", function(d) {
                    return "translate(" + x_gh_scale(d.x) + "," + y_gh_scale(d.y) + ")";
                });

            bar.append("rect")
                .attr("x", 1)
                .attr("width", x_gh_scale(data[0].dx) - 1)
                .attr("height", function(d) {
                    return height - y_gh_scale(d.y);
                });

            bar.append("text")
                .attr("dy", ".75em")
                .attr("y", 6)
                .attr("x", x_gh_scale(data[0].dx) / 2)
                .attr("text-anchor", "middle")
                .text(function(d) {
                    return format_count(d.y);
                });
        }
    });
    $("#bins").val($("#slider-range-max").slider("value"));
});

最佳答案

在你的代码中加入一些奇怪的东西。

首先,

 var data = d3.layout.histogram()
   .bins(x_gh_scale.ticks(ui.value)) //<-- what is your intention here?
   (grades);

.ticks 返回刻度所在的数组。您似乎将其用作 thresholds , 但这会产生不需要的 result :

The specified count is only a hint; the scale may return more or fewer values depending on the input domain.

如果你想要 N 个 bins,只需将其命名为:

var data = d3.layout.histogram()
   .bins(ui.value)
   (grades);

其次,您需要在重新装箱后调整您的 y 比例域,以防止您的 rects 流出页面。这似乎可以解决问题:

y_gh_scale.domain([0, d3.max(data, function(d){
  return d.length
})]);

第三,你不能链接你的.remove() call在你做的方式。它返回删除的元素,你只想重新输入新鲜的:

 grade_histo_svg.selectAll(".bar")
   .remove()

 var bar = grade_histo_svg.selectAll(".bar")
  .data(data)
  .enter().append("g")
  .attr("class", "bar")
  .attr("transform", function(d) {
    return "translate(" + x_gh_scale(d.x) + "," + y_gh_scale(d.y) + ")";
  });

这是一个 updated fiddle应用此更改。

关于javascript - 动态改变 d3.js 直方图的 bin 和高度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37534399/

相关文章:

javascript - Javascript 中的弹出窗口

javascript - Asp.net 使用 jQuery 启用/禁用复选框列表

javascript - 无法使用jquery创建多个日期选择器

javascript - 使用 JavaScript 打印 HTML Object 标签的内容

c# - 如何在 C# 应用程序中集成 d3.js 图表?

javascript - jQuery 查找使用函数作为参数

javascript - 韩语音节 PHP 或 JavaScript Romanizer(或任何其他替代方案?)

jQuery UI 组合框最大宽度选项

javascript - Div 在被拖动时自动调整大小(jQuery UI)

javascript - 如何在d3js中垂直树