2012-08-06 9 views
15

Sto adattando la libreria Crossfilter per visualizzare alcuni tweet che ho raccolto dal Olympics. Sto tentando di estendere sostanzialmente l'esempio iniziale in due modi:Istogrammi di ridisegno con Crossfilter e D3

  1. Invece di visualizzare gli elenchi dei voli sulla base di dati originale, voglio visualizzare liste di oggetti in un altro insieme di dati digitato da elementi attualmente selezionati da crossfilter.
  2. Passa tra diverse origini dati e ricarica gli istogrammi e le tabelle.

Ho parte (1) funziona come previsto. Tuttavia, la parte (2) mi sta dando dei problemi. Attualmente sto modificando il set di dati selezionando un nuovo "sport" per visualizzare o selezionare un nuovo algoritmo di riepilogo. Quando si cambia uno di questi, credo che prima dovrei rimuovere i filtri, i grafici e gli elenchi precedentemente creati e visualizzati e quindi ricaricare i nuovi dati.

Tuttavia, essendo un po 'nuovo per le visualizzazioni front-end, in particolare D3 e Crossfilter, non ho capito come farlo, né sono sicuro di come sia meglio esprimere la domanda.

Ho un esempio funzionante del mio problema here. Selezionando un intervallo in data, passando da Archery a Fencing, la selezione di reset mostra un buon esempio di cosa non va: non tutti i nuovi dati vengono tracciati.

Screen image of Fencing data after switching sports while filtering on Date

Come detto, la maggior parte del codice è tirato forma nell'esempio Crossfilter e Tutorial on making radial visualizations. Ecco alcuni dei pezzi di codice chiave che ritengo rilevanti:

Selezione di una nuova fonte di dati:

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")); 
}); 

Ricaricare i dati:

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); 
    }); 
} 

e caricando il filtro croce utilizzando i dati:

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(); 

La mia ipotesi è che dovrei iniziare plotSportData con qualcosa che cancella il vecchio set di dati, ma non sono sicuro di come dovrebbe essere quel qualcosa. Qualsiasi suggerimento o pensiero sarebbe estremamente apprezzato.

risposta

12

Dopo una notte di sonno, la soluzione mi è venuta.

Ho solo bisogno di chiamare

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

all'inizio del plotSportData che afferrare qualsiasi istogrammi annidati sotto le .chart div e rimuoverli. E se non ci sono elementi da rimuovere, sarà un no-op.

+3

Grazie per la condivisione, non ci sono molti esempi disponibili di filtro incrociato. Buona fortuna con il vostro progetto. –