d3.geom.contour - 无限循环如果max(轮廓级)> max(data) [英] d3.geom.contour - endless loop if max(contour levels) > max(data)

查看:211
本文介绍了d3.geom.contour - 无限循环如果max(轮廓级)> max(data)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当使用域运行 http://bl.ocks.org/mbostock/4241134 时, / p>

When running http://bl.ocks.org/mbostock/4241134 with domain

  [95, 115, 135, 155, 175, 196]

而不是

  [95, 115, 135, 155, 175, 195]

,轮廓算法进入无限循环。当轮廓线的最大值(上面的195和196)大于轮廓线的数据的最大值时,会发生这种情况。

as in the example, the contouring algorithms goes into an endless loop. This happens when the maximum value of the contour levels (195 and 196 above) is larger than the maximum value of the data being contoured.

您可以通过使用只有一个轮廓级别:

You can reproduce the behaviour by using just one contour level as well:

  [ 195 ] -> ok
  [ 196 ] -> endless loop

至少不会崩溃的一个明显的解决方法是将数据集中的一个值设置为大值(大于最大轮廓级别)。但这很丑陋...

An obvious workaround for at least not crashing is to set one value in the dataset to a large value (larger than the maximum contour level) manually. But that's kind of ugly ...

推荐答案

正如@LarsKotthoff所说,没有意识到绘图区域的范围该函数的标准版本。然而,这是一个非常小的模块,并轻松下载,修改和与您的代码集成。下面是一个例子。

As @LarsKotthoff mentioned, there is no awareness of the extent of the plot area within the standard version of this function. It is however, a very small module and easily downloaded, modified and integrated with your code. Here is an example of one way to do it...

function Contour (xScale, yScale) {

    function contour(grid, _, _, start) {
        var s = start || _contourStart(grid); // starting point
        if (!s) return;
        var c = [],    // contour polygon
            x = s[0],  // current x position
            y = s[1],  // current y position
            dx = 0,    // next x direction
            dy = 0,    // next y direction
            pdx = NaN, // previous x direction
            pdy = NaN, // previous y direction
            i = 0;

        do {
            // determine marching squares index
            i = 0;
            if (grid(x-1, y-1)) i += 1;
            if (grid(x,   y-1)) i += 2;
            if (grid(x-1, y  )) i += 4;
            if (grid(x,   y  )) i += 8;

            // determine next direction
            // disambiguate
            if (i === 6) {
                dx = pdy === -1 ? -1 : 1;
                dy = 0;
            } else if (i === 9) {
                dx = 0;
                dy = pdx === 1 ? -1 : 1;
            } else {
                // unambiguous cases
                dx = _contourDx[i];
                dy = _contourDy[i];
            }
            // update contour polygon
            if (dx != pdx && dy != pdy) {
                c.push([x, y]);
                pdx = dx;
                pdy = dy;
            }
            x += dx;
            y += dy;
        } while (s[0] != x || s[1] != y);

        return c;
    };

// lookup tables for marching directions
    var _contourDx = [1, 0, 1, 1,-1, 0,-1, 1,0, 0,0,0,-1, 0,-1,NaN],
        _contourDy = [0,-1, 0, 0, 0,-1, 0, 0,1,-1,1,1, 0,-1, 0,NaN];

    var xDomain = xScale.domain(), xMin = xDomain[0], xMax = xDomain[1],
        yDomain = yScale.domain(), yMin = yDomain[0], yMax = yDomain[1];

    function _contourStart(grid) {
        var x = 0, y = 0;
        // search for a starting point; begin at origin
        // and proceed along outward-expanding diagonals
        while (!(x == xMax && y > yMax)) {
            var px;
            if (grid(x,y)) {
                return [x,y];
            }
            //if the left or top limit is reached
            if ((px = x) <= xMin || y >= yMax) {
                //start a new scan line
                //reflect the x ordinate in y=x in range coordinates and saturate
                x = Math.min(x + y + 1, xMax);
                //if x is not saturated, reset to the minimum y value in range coordinates
                //  use basic similar triangles to calculate the new starting point
                //  return to the start of the current line, then add 1
                y = x === xMax ? y === yMax ? yMax - xMax + px + 1 : y - xMax + 1 : yMin;
            } else {
                x = x - 1;
                y = y + 1;
            }
        }
    }

    return contour;
};

此版本在搜索轮廓启动时稍微更有效如果不能找到轮廓并且像原始版本一样,它将返回 null ,将只返回给定值的一个轮廓它需要被多次调用,具有不同的起点,以忠实地渲染非单调表面)。

它不会像原始版本一样扩展d3对象,但它的用法是惯用的。例如...

This version is slightly more efficient in searching for the contour starts (it uses it's new-found knowledge of the plot extent to limit it's search to that) and it returns null if it fails to find the contour and like the original version, will only return one contour for a given value (it needs to be called multiple times, with different starting points, to faithfully render non-monotonic surfaces).
It doesn't augment the d3 object like the original version but its usage is idiomatic. For example...

  var x = d3.scale.linear()
    .range([0, width]);
  var y = d3.scale.linear()
    .range([height, 0]);

  var contour = Contour(x, y),
    line = d3.svg.line()
      .interpolate("basis")
      .x(function(d){return x(d[0])})
      .y(function(d){return y(d[1])}),
    contours = svg.selectAll(".isoline")
      .data(bands.map(isoline));
  contours.enter().append("path");
  contours.datum(contour)
    .attr("class", "isoline")
    .attr("d", function (d) {
      return line(d);
    })
    .attr("fill", function (d, i) {
      return color(bands[i]);
    })
    .style("stroke", isoLines.value());
  contours.exit().remove();

这篇关于d3.geom.contour - 无限循环如果max(轮廓级)> max(data)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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