Параллельные координаты с всплывающей подсказкой - PullRequest
0 голосов
/ 13 ноября 2018

Я использовал эти две библиотеки (они одинаковые, но последняя использует d3 v5 и имеет несколько добавленных реализаций: https://github.com/syntagmatic/parallel-coordinates и https://github.com/BigFatDog/parcoords-es/blob/master/demo/nutrients.html) для parcoords, но в последние 3 дня Я не нашел способ показать всплывающую подсказку, когда поверх кривых. Я хочу, чтобы имя объекта отображалось при наведении мыши, но я не знаю, как получить доступ к линиям. Я пытался вызвать svg или canvas (я думаю, что линии нарисованы там), чтобы дать им .on и создать маленькую метку при наведении курсора мыши на доступ к данным, переданным parcoord, но это было не так просто, как я только что описал. Вот пример того, как выглядит мой код (он из демонстрации библиотеки, но мой код выглядит немного более тяжелым):

<!doctype html>
<title>Linking to Data Table</title>
<link rel="stylesheet" type="text/css" href="./parcoords.css">
<link rel="stylesheet" type="text/css" href="style.css">
<style>
    body, html { margin: 0; padding: 0; width: 100%; height: 100%; }
    /* parcoords */
    #nutrients { height: 600px; width: 98%; }
    #nutrients text { font-size: 10px; }
</style>
<script src="lib/d3.v5.min.js"></script>
<script src="./parcoords.standalone.js"></script>
<script src="lib/underscore.js"></script>
<div id="nutrients" class="parcoords"></div>
<script id="brushing">
    var parcoords = ParCoords()("#nutrients");
    d3.csv('data/nutrients.csv').then(function(data) {
        var colorList = ['#3b73b9', '#aa71aa', '#ee3224', '#00aeef', '#f8981d',
            '#80bb42', '#aacdef', '#cacec2', '#aaa6ce', '#df9e9d', '#6ab2e7',
            '#ffdd00', '#9ac2b9', '#a7a9ac', '#bbbb42', '#e6a6ce'];
        var groups = _(data).chain()
            .pluck('group')
            .uniq();
        var colorScale = d3.scaleOrdinal().domain(groups).range(colorList);
        var color = function(d) { return colorScale(d.group); };
        parcoords
            .data(data)
            .color(color)
            .hideAxis(['name'])
            .margin({ top: 24, left: 60, bottom: 12, right: 0 })
            .mode("queue")
            .alpha(0.7)
            .render()
            .brushMode("1D-axes");  // enable brushing
    });
</script>

В этом примере имя будет, например, сыр, появиться, когда мышь находится над соответствующей строкой. Я хочу этого, потому что у меня много строк, и если бы я использовал ось для этого, имена перекрывали друг друга, и пользователь не мог бы их видеть (если у вас есть другая идея, как это сделать)

Я был бы очень благодарен, если бы кто-то мог избавить меня от этого страдания. Спасибо!

edit, я думаю, что здесь созданы строки, ctx является контекстом 2d холста:

  var singlePath = function singlePath(config, position, d, ctx) {
    Object.keys(config.dimensions).map(function (p) {
      return [position(p), d[p] === undefined ? getNullPosition(config) : config.dimensions[p].yscale(d[p])];
    }).sort(function (a, b) {
      return a[0] - b[0];
    }).forEach(function (p, i) {
      i === 0 ? ctx.moveTo(p[0], p[1]) : ctx.lineTo(p[0], p[1]);
    });
  };

  // draw single polyline
  var colorPath = function colorPath(config, position, d, ctx) {
    ctx.beginPath();
    if (config.bundleDimension !== null && config.bundlingStrength > 0 || config.smoothness > 0) {
      singleCurve(config, position, d, ctx);
    } else {
      singlePath(config, position, d, ctx);
    }
    ctx.stroke();
  };

1 Ответ

0 голосов
/ 18 ноября 2018

Для всех с такой же проблемой есть ссылка: http://bl.ocks.org/mostaphaRoudsari/b4e090bb50146d88aec4, которая очень помогает в этой области.

Если вы используете ту же библиотеку, что и я, с d3.js v5 (последняяссылка на библиотеку в моем вопросе) просто добавьте это в библиотеку параллельных координат (или автономную):

function compute_centroids(config, position) {
        return function (row) {
            var centroids = [];
            var p = Object.keys(config.dimensions);
            var cols = p.length;
            var a = 0.5; // center between axes
            for (var i = 0; i < cols; ++i) {
                // centroids on 'real' axes
                var x = position(p[i]);
                var y = config.dimensions[p[i]].yscale(row[p[i]]);
                centroids.push(([x, y]));

                // centroids on 'virtual' axes
                if (i < cols - 1) {
                    var cx = x + a * (position(p[i + 1]) - x);
                    var cy = y + a * (config.dimensions[p[i + 1]].yscale(row[p[i + 1]]) - y);
                    if (config.bundleDimension !== null) {
                        var leftCentroid = config.clusterCentroids.get(config.dimensions[config.bundleDimension].yscale(row[config.bundleDimension])).get(p[i]);
                        var rightCentroid = config.clusterCentroids.get(config.dimensions[config.bundleDimension].yscale(row[config.bundleDimension])).get(p[i + 1]);
                        var centroid = 0.5 * (leftCentroid + rightCentroid);
                        cy = centroid + (1 - config.bundlingStrength) * (cy - centroid);
                    }
                    centroids.push(([cx, cy]));
                }
            }

        return centroids;}
};

И в конце, где конструктор добавить эту строку:

pc.compute_centroids = compute_centroids(config,position);

Тогда вы легко сможете использовать функции, показанные в этой ссылке bl.ock, если у вас возникнут какие-либо проблемы, вы также можете задать

...