使用Crossfilter和D3重绘直方图 [英] Redrawing histograms with Crossfilter and D3

查看:144
本文介绍了使用Crossfilter和D3重绘直方图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在调整示例和关于制作径向可视化的教程。以下是我认为相关的一些关键代码块:



选择新的数据源:

  d3.selectAll(#sports a)。on(click,function(d){
var newSport = d3.select(this).attr(id) ;
activate(sports,newSport);
reloadData(activeLabel(sports),activeLabel(methods));
}

d3.selectAll(#methods a)。on(click,function(d){
var newMethod = d3.select(this).attr(id) ;
activate(methods,newMethod);
reloadData(activeLabel(sports),activeLabel(methods));
}

重新载入资料:

  function reloadData(sportName,methodName){
var filebase =/ tweetolympics / data / tweet。 + sportName +。 + methodName +.all。;
var summaryList,tweetList,remaining = 2;
d3.csv(filebase +summary.csv,function(summaries){
summaries.forEach(function(d,i){
d.index = i;
d.group = parseInt(d.Group);
d.startTime = parseTime(d.Start);
d.meanTime = parseTime(d.Mean);
});
summaryList = summaries;
if(! - remaining)
plotSportData(summaryList,tweetList);
});

d3.csv(filebase +groups.csv,function(tweets){
tweets.forEach(function(d,i){
d.index =
d.group = parseInt(d.Group);
d.date = parseTime(d.Time);
});
tweetList = tweets;
if (! - remaining)
plotSportData(summaryList,tweetList);
});
}

并使用以下数据加载交叉过滤器:

  function plotSportData(summaries,tweets){

//为相关维和组创建交叉过滤器。
var tweet = crossfilter(tweets),
all = tweet.groupAll(),
date = tweet.dimension(function(d){return d3.time.day(d.date) ;}),
dates = date.group(),
hour = tweet.dimension(function(d){return d.date.getHours()+ d.date.getMinutes },
hours = hour.group(Math.floor),
cluster = tweet.dimension(function(d){return d.group;}),
clusters = cluster.group ();

var charts = [
//第一个图表跟踪每个tweet的时间。它有
//标准24小时时间范围,并使用24小时时钟。
barChart()。dimension(hour)
.group(hours)
.x(d3.scale.linear()
.domain([0,24])
.rangeRound([0,10 * 24])),
//这里添加更多图表类似...
];

//给定我们的图表数组,我们假设它们与DOM中的
// .chart元素的顺序相同,将图表绑定到DOM并渲染它们。
//我们还会监听图表的刷子事件来更新显示。
var chart = d3.selectAll(。chart)
.data(charts)
.each(function(chart){chart.on(brush,renderAll)
.on(brushend,renderAll);});

//渲染初始列表。
var list = d3.selectAll(。list)
.data([summaryList]);

//打印tweet的总数。
d3.selectAll(#total)。text(formatNumber(all.value()));

//渲染一切..
renderAll();

我的猜测是我应该开始 plotSportData 与清除旧的数据集,但我不知道什么应该看起来像什么。

解决方案

经过一夜的睡眠,解决方案来了我。



我只需要调用

  d3.selectAll(。chart (svg)。remove();在 plotSportData 开头处的

嵌套在 .chart div下的任何直方图,并删除它们。如果没有要删除的元素,它将是一个无操作。


I'm adapting the Crossfilter library to visualize some tweets i've been gathering from the Olympics. I'm attempting to essentially extend the initial example in two ways:

  1. Instead of displaying lists of flights based on the original dataset, I want to display lists of items in another dataset keyed by items currently selected by crossfilter.
  2. Switch between different data sources and reload the histograms and tables.

I've got part (1) working as planned. However, part (2) is giving me some trouble. I'm currently changing the dataset by either selecting a new "sport" to display or selecting a new summary algorithm. When switching either of these, I believe that I should first remove the filters, charts, and lists previously created and displayed and then reload the new data.

However, being somewhat new to front end visualizations, especially D3 and Crossfilter, I haven't figured out how to do this, nor am i sure how to even best phrase the question.

I have a working example of my problem here. Selecting a range on Date then switching from Archery to Fencing, then selecting reset shows a good example of what's wrong: not all of the new data is plotted.

As said, most of the code is pulled form the Crossfilter example and a Tutorial on making radial visualizations. Here's some of the key code chunks that I think are relevant:

Selecting a new data source:

d3.selectAll("#sports a").on("click", function (d) {
    var newSport = d3.select(this).attr("id");
    activate("sports", newSport);
    reloadData(activeLabel("sports"), activeLabel("methods"));
});                          

d3.selectAll("#methods a").on("click", function (d) {
    var newMethod = d3.select(this).attr("id");
    activate("methods", newMethod);
    reloadData(activeLabel("sports"), activeLabel("methods"));
}); 

Reloading the data:

function reloadData(sportName, methodName) {
    var filebase = "/tweetolympics/data/tweet." + sportName + "." + methodName + ".all.";
    var summaryList, tweetList, remaining = 2;
    d3.csv(filebase + "summary.csv", function(summaries) {
        summaries.forEach(function(d, i) {
           d.index = i;
           d.group = parseInt(d.Group);
           d.startTime = parseTime(d.Start);
           d.meanTime = parseTime(d.Mean);
        });
        summaryList = summaries;
        if (!--remaining)
            plotSportData(summaryList, tweetList);
    });

    d3.csv(filebase + "groups.csv", function(tweets) {
        tweets.forEach(function(d, i) {
            d.index = i;
            d.group = parseInt(d.Group);
            d.date = parseTime(d.Time);
        });
        tweetList = tweets;
        if (!--remaining)
            plotSportData(summaryList, tweetList);
    });
}   

And loading the cross filter using the data:

function plotSportData(summaries, tweets) {

    // Create the crossfilter for the relevant dimensions and groups.
    var tweet = crossfilter(tweets),
        all = tweet.groupAll(),
        date = tweet.dimension(function(d) { return d3.time.day(d.date); }),
        dates = date.group(),
        hour = tweet.dimension(function(d) { return d.date.getHours() + d.date.getMinutes() / 60; }),
        hours = hour.group(Math.floor),
        cluster = tweet.dimension(function(d) { return d.group; }),
        clusters = cluster.group();

     var charts = [
        // The first chart tracks the hours of each tweet.  It has the
        // standard 24 hour time range and uses a 24 hour clock.
        barChart().dimension(hour)
                  .group(hours)
                  .x(d3.scale.linear()
                             .domain([0, 24])
                             .rangeRound([0, 10 * 24])),
        // more charts added here similarly...
      ];

    // Given our array of charts, which we assume are in the same order as the
    // .chart elements in the DOM, bind the charts to the DOM and render them.
    // We also listen to the chart's brush events to update the display.
    var chart = d3.selectAll(".chart")
                  .data(charts)
                  .each(function(chart) { chart.on("brush", renderAll)
                                               .on("brushend", renderAll); });

    // Render the initial lists.
    var list = d3.selectAll(".list")
                 .data([summaryList]);

    // Print the total number of tweets.
    d3.selectAll("#total").text(formatNumber(all.value()));

    // Render everything..
    renderAll();

My guess is that I should start plotSportData with something that clears out the old dataset, but i'm not sure what that something should look like. Any suggestions or thoughts would be supremely appreciated.

解决方案

After a night's sleep, the solution came to me.

I just need to call

d3.selectAll(".chart").selectAll("svg").remove();

at the beginning of plotSportData which will grab any histograms nested under the .chart divs and remove them. And if there's no elements to remove, it'll be a no-op.

这篇关于使用Crossfilter和D3重绘直方图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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