d3.js - 使用不同颜色的 dc.js 显示原始(有条件)拉丝未拉丝交叉过滤器条

标签 d3.js dc.js crossfilter

假设我们有以下 crossfilter/dc.js 应用程序:

Original

虽然这很好,但用户在刷牙时会失去对人群的“引用”。我希望图表 xyza 在其他情况下保留“基础”条形图表被刷了。也许采用不同的颜色,如下所示:

Desired Results

我相信这可能需要更新 dc.renderAll() 函数,但我什至不确定如何开始。


以下是使用作为要点托管的 .csv 数据重现此应用程序的所有代码。

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Data Exploration Tool MVP</title>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"/>
    <link rel="stylesheet" href="http://unpkg.com/dc@3/dc.css"/>
    <style>
      #data-count {
        margin-top: 0;
        text-align: left;
        float: none;
      }
      table {
        table-layout: fixed;
      }
      td {
        width: 1%;
      }
    </style>
</head>
<body>

<div class="container-fluid" style="margin: 10px;">

  <div class="row">
    <h2>Data Exploration Tool</h2>
    <div class="col-md-3 well well-sm">
      <div class="dc-data-count" id="data-count">
          <span class="filter-count"></span>
           selected out of
          <span class="total-count"></span>
           points |
          <a href="javascript:dc.filterAll(); dc.renderAll();">Reset All</a><br>
      </div>
    </div>
  </div>


  <div class="row">
    <div class="col-md-12">

      <!-- First row of charts -->
      <div class="row">
        <div class="col-md-3">
          <div id="chart-11" style="width:100%;">
            <div id="chart-11-title"></div>
            <div class="reset" style="visibility: hidden;">range: <span class="filter"></span>
              <a href="javascript:chart_11.filterAll();dc.redrawAll();">reset</a>
            </div>
          </div>
        </div>
        <div class="col-md-3">
          <div id="chart-12" style="width:100%;">
            <div id="chart-12-title"></div>
            <div class="reset" style="visibility: hidden;">selected: <span class="filter"></span>
              <a href="javascript:chart_12.filterAll();dc.redrawAll();">reset</a>
            </div>
          </div>
        </div>
        <div class="col-md-3">
          <div id="chart-13" style="width:100%;">
              <div id="chart-13-title"></div>
            <div class="reset" style="visibility: hidden;">selected: <span class="filter"></span>
              <a href="javascript:chart_13.filterAll();dc.redrawAll();">reset</a>
            </div>
          </div>
        </div>
        <div class="col-md-3">
            <div id="chart-14" style="width:100%;">
                <div id="chart-14-title"></div>
              <div class="reset" style="visibility: hidden;">selected: <span class="filter"></span>
                <a href="javascript:chart_14.filterAll();dc.redrawAll();">reset</a>
              </div>
            </div>
          </div>
      </div>

      <!-- Second row of chart -->
      <div class="row">
        <div class="col-md-3">
          <div id="chart-21" style="width:100%;">
            <div id="chart-21-title"></div>
            <div class="reset" style="visibility: hidden;">selected: <span class="filter"></span>
              <a href="javascript:chart_21.filterAll();dc.redrawAll();">reset</a>
            </div>
          </div>
        </div>
        <div class="col-md-3">
          <div id="chart-22" style="width:100%;">
            <div id="chart-22-title"></div>
            <div class="reset" style="visibility: hidden;">range: <span class="filter"></span>
              <a href="javascript:chart_22.filterAll();dc.redrawAll();">reset</a>
            </div>
          </div>
        </div>
        <div class="col-md-3">
          <div id="chart-23"style="width:100%;">
            <div id="chart-23-title"></div>
            <div class="reset" style="visibility: hidden;">selected: <span class="filter"></span>
              <a href="javascript:chart_23.filterAll();dc.redrawAll();">reset</a>
            </div>
          </div>
        </div>
        <div class="col-md-3">
            <div id="chart-24"style="width:100%;">
              <div id="chart-24-title"></div>
              <div class="reset" style="visibility: hidden;">selected: <span class="filter"></span>
                <a href="javascript:chart_24.filterAll();dc.redrawAll();">reset</a>
              </div>
            </div>
          </div>
      </div>
    </div>
  </div>

</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.9.1/d3.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.js"></script>
<script src="http://unpkg.com/dc@3/dc.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"></script>

<script type="text/javascript">

'use strict';

dc.config.defaultColors(d3.schemeSet1);

var 
    chart_11   = dc.barChart("#chart-11"),
    chart_12   = dc.barChart("#chart-12"),
    chart_13   = dc.barChart("#chart-13"),
    chart_21   = dc.barChart("#chart-21"),
    chart_22   = dc.barChart("#chart-22"),
    chart_23   = dc.barChart("#chart-23"),
    data_count = dc.dataCount(".dc-data-count");

d3.csv("https://gist.githubusercontent.com/JasonAizkalns/32ece5c815f9ac5d540c41dc0825bbab/raw/362050300ddcb99f195044c00d9f26b0d7d489ca/data.csv").then(function(data) {

var var_names = ["x", "y", "z", "a", "b", "c"];

$("#chart-11-title").append(["<h5>", var_names[0], "<br>Subtitle</h5>"].join(""));
$("#chart-12-title").append(["<h5>", var_names[1], "<br>Subtitle</h5>"].join(""));
$("#chart-13-title").append(["<h5>", var_names[2], "<br>Subtitle</h5>"].join(""));
$("#chart-21-title").append(["<h5>", var_names[3], "<br>Subtitle</h5>"].join(""));
$("#chart-22-title").append(["<h5>", var_names[4], "<br>Subtitle</h5>"].join(""));
$("#chart-23-title").append(["<h5>", var_names[5], "<br>Subtitle</h5>"].join(""));

var c11_bin = 10,
    c12_bin = 10,
    c13_bin = 500,
    c21_bin = 100,
    c22_bin = 20,
    c23_bin = 1000;


var ndx = crossfilter(data),

    chart_11_dim = ndx.dimension(function(d) { return +d[var_names[0]]; }),
    chart_12_dim = ndx.dimension(function(d) { return +d[var_names[1]]; }),
    chart_13_dim = ndx.dimension(function(d) { return +d[var_names[2]]; }),
    chart_21_dim = ndx.dimension(function(d) { return +d[var_names[3]]; }),
    chart_22_dim = ndx.dimension(function(d) { return +d[var_names[4]]; }),
    chart_23_dim = ndx.dimension(function(d) { return +d[var_names[5]]; }),

    chart_11_grp = chart_11_dim.group(function(d) { return Math.floor(d / c11_bin) * c11_bin }).reduceCount(),
    chart_12_grp = chart_12_dim.group(function(d) { return Math.floor(d / c12_bin) * c12_bin }).reduceCount(),
    chart_13_grp = chart_13_dim.group(function(d) { return Math.floor(d / c13_bin) * c13_bin }).reduceCount(),
    chart_21_grp = chart_21_dim.group(function(d) { return Math.floor(d / c21_bin) * c21_bin }).reduceCount(),
    chart_22_grp = chart_22_dim.group(function(d) { return Math.floor(d / c22_bin) * c22_bin }).reduceCount(),
    chart_23_grp = chart_23_dim.group(function(d) { return Math.floor(d / c23_bin) * c23_bin }).reduceCount();

var all = ndx.groupAll();

data_count.dimension(ndx)
  .group(all);

var chart_11_min = +chart_11_dim.bottom(1)[0][var_names[0]],
    chart_11_max = +chart_11_dim.top(1)[0][var_names[0]],
    chart_12_min = +chart_12_dim.bottom(1)[0][var_names[1]],
    chart_12_max = +chart_12_dim.top(1)[0][var_names[1]],
    chart_13_min = +chart_13_dim.bottom(1)[0][var_names[2]],
    chart_13_max = +chart_13_dim.top(1)[0][var_names[2]],
    chart_21_min = +chart_21_dim.bottom(1)[0][var_names[3]],
    chart_21_max = +chart_21_dim.top(1)[0][var_names[3]],
    chart_22_min = +chart_22_dim.bottom(1)[0][var_names[4]],
    chart_22_max = +chart_22_dim.top(1)[0][var_names[4]],
    chart_23_min = +chart_23_dim.bottom(1)[0][var_names[5]],
    chart_23_max = +chart_23_dim.top(1)[0][var_names[5]];

var breathing_room = 0.05;

chart_11
  .dimension(chart_11_dim)
  .group(chart_11_grp)
  .round(dc.round.floor)
  .alwaysUseRounding(true)
  .x(d3.scaleLinear().domain([chart_11_min - ((chart_11_max - chart_11_min) * breathing_room), chart_11_max + ((chart_11_max - chart_11_min) * breathing_room)]))
  .xUnits(function(start, end, xDomain) { return (end - start) / c11_bin; })
  .controlsUseVisibility(true);

chart_12
  .dimension(chart_12_dim)
  .group(chart_12_grp)
  .round(dc.round.floor)
  .alwaysUseRounding(true)
  .x(d3.scaleLinear().domain([chart_12_min - ((chart_12_max - chart_12_min) * breathing_room), chart_12_max + ((chart_12_max - chart_12_min) * breathing_room)]))
  .xUnits(function(start, end, xDomain) { return (end - start) / c12_bin; })
  .controlsUseVisibility(true);

chart_13
  .dimension(chart_13_dim)
  .group(chart_13_grp)
  .round(dc.round.floor)
  .alwaysUseRounding(true)
  .x(d3.scaleLinear().domain([chart_13_min - ((chart_13_max - chart_13_min) * breathing_room), chart_13_max + ((chart_13_max - chart_13_min) * breathing_room)]))
  .xUnits(function(start, end, xDomain) { return (end - start) / c13_bin; })
  .controlsUseVisibility(true);

chart_21
  .dimension(chart_21_dim)
  .group(chart_21_grp)
  .round(dc.round.floor)
  .alwaysUseRounding(true)
  .x(d3.scaleLinear().domain([chart_21_min - ((chart_21_max - chart_21_min) * breathing_room), chart_21_max + ((chart_21_max - chart_21_min) * breathing_room)]))
  .xUnits(function(start, end, xDomain) { return (end - start) / c21_bin; })
  .controlsUseVisibility(true);

chart_22
  .dimension(chart_22_dim)
  .group(chart_22_grp)
  .round(dc.round.floor)
  .alwaysUseRounding(true)
  .x(d3.scaleLinear().domain([chart_22_min - ((chart_22_max - chart_22_min) * breathing_room), chart_22_max + ((chart_22_max - chart_22_min) * breathing_room)]))
  .xUnits(function(start, end, xDomain) { return (end - start) / c22_bin; })
  .controlsUseVisibility(true);

chart_23
  .dimension(chart_23_dim)
  .group(chart_23_grp)
  .round(dc.round.floor)
  .alwaysUseRounding(true)
  .x(d3.scaleLinear().domain([chart_23_min - ((chart_23_max - chart_23_min) * breathing_room), chart_23_max + ((chart_23_max - chart_23_min) * breathing_room)]))
  .xUnits(function(start, end, xDomain) { return (end - start) / c23_bin; })
  .controlsUseVisibility(true);

dc.renderAll();

});

</script>

</div>
</body>
</html>

最佳答案

所以,是的,dc.js 和 crossfilter 都不直接支持这个用例,并不是说人们不想要它。

Crossfilter 仅支持一个事件过滤器,并且您无法了解未应用过滤器时的总数。

编辑:现在有一个official example代码已清理以响应 the follow up code review question 。下面的讨论仍然很好地描述了该技术,但示例中的代码重复较少。

感谢您提供可重现的示例。我put your original code in a fiddle .

这有点乏味,但获得您想要的效果的一种方法是将每个图表更改为 composite两个条形图。我们将把第二个子图设置为红色并隐藏它,直到过滤掉某些内容。 (更准确地说,只要没有过滤任何内容,我们就会隐藏它。)

我们将使第一个(蓝色)子图始终显示初始值,不受任何过滤器的影响。

创建复合图表如下所示:

var chart_11   = dc.compositeChart("#chart-11"),
    chart_12   = dc.compositeChart("#chart-12"),
    chart_13   = dc.compositeChart("#chart-13"),
    chart_21   = dc.compositeChart("#chart-21"),
    chart_22   = dc.compositeChart("#chart-22"),
    chart_23   = dc.compositeChart("#chart-23");
chart_11
    .compose([
        dc.barChart(chart_11)
            .dimension(chart_11_dim)
            .group(chart_11_grp_copy)
            .controlsUseVisibility(true)
        ,
        dc.barChart(chart_11)
            .dimension(chart_11_dim)
            .group(chart_11_grp)
            .colors('red')
            .controlsUseVisibility(true)
            .brushOn(false)
    ]);

(是的,您似乎必须将 controlsUseVisibility 应用于每个子图表 - 看起来像一个错误。)

问题的核心是如何让底层的蓝色图表不发生变化。我们可以使用一个 fake group为了这。这个想法是这个对象的行为就像一个组,除了它只返回该组在页面加载时拥有的内容:

function static_copy_group(group) {
    var all = group.all().map(kv => ({key: kv.key, value: kv.value}));
    return {
            all: function() {
            return all;
        }
    }
}
var chart_11_grp_copy = static_copy_group(chart_11_grp),
    chart_12_grp_copy = static_copy_group(chart_12_grp),
    chart_13_grp_copy = static_copy_group(chart_13_grp),
    chart_21_grp_copy = static_copy_group(chart_21_grp),
    chart_22_grp_copy = static_copy_group(chart_22_grp),
    chart_23_grp_copy = static_copy_group(chart_23_grp);

是的,这是 group.all() 的深拷贝,因为 crossfilter 会更新所有内容。

最后,这是在未过滤任何内容时隐藏第二个图表的代码:

function any_filters() {
    return [chart_11, chart_12, chart_13, chart_21, chart_22, chart_23]
        .some(chart => chart.filters().length);
}

function hide_second_chart(chart) {
    chart.select('.sub._1')
        .attr('visibility', any_filters() ? 'visible' : 'hidden')
}

[chart_11, chart_12, chart_13, chart_21, chart_22, chart_23].forEach(function(chart) {
   chart.on('pretransition', hide_second_chart)
})

charts with context/reference underlay

Example fiddle .

关于d3.js - 使用不同颜色的 dc.js 显示原始(有条件)拉丝未拉丝交叉过滤器条,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55066391/

相关文章:

javascript - 使用相同的键附加值 PHP MySQL D3

javascript - Sankey 图,在 PHP 中使用查询创建多维数组

javascript - svgelement.enter() 上未发生 D3 转换

javascript - 优化一组dc.js折线图

javascript - 使用多数组通过 dc.js、d3 和 crossfilter 在散点图上绘制数据

javascript - 多个链接的 dc.js 图表的 d3-tooltips

javascript - D3 交叉过滤器分组

d3.js - 在 dc.js/Crossfilter 中添加过滤器不更新图表

javascript - 使用深度嵌套的 json 在 dc.js 中动态创建数据表

javascript - dc js - 创建多列维度