În d3.js, săriți append () pentru datele null

Aduc un grafic grafic din gloanțe mici. Cu toate acestea, datele au găuri în el, care sunt reprezentate de null în matricea mea. Firește, oriunde nu există date, nu ar trebui să existe cercuri. Dar metoda d3's append() le adaugă oricum. Cum evit asta?

Iată un mockup jsFiddle care reproduce exact problema mea.

Mă interesează NU având acea serie de cercuri care se află pe axa X a graficului meu, deoarece acestea sunt toate nulls.

Codul relevant de la linkul jsfiddle:

svg.selectAll('circle').data(values).enter()
  .append('circle')// <-- I don't want to do this for null's
  .attr('fill', '#c00')
  .attr('r', 3)
  .attr('cx', xi)
  .attr('cy', yFlipped)
16

5 răspunsuri

O opțiune este reprezentarea datelor în mod diferit, astfel încât să nu depindeți de index pentru a calcula coordonatele x. De exemplu, dacă ați reprezentat fiecare origine ca obiect (de exemplu, {x: 0, y: 0.2840042} ), atunci ați putea calcula coordonatele x ca x (dx) > mai degrabă decât x (i) .

O altă opțiune ar fi să setați raza la zero când valoarea este nulă, astfel că cercurile sunt ascunse: cerc.attr ("r", funcția (d) {return d == null? 0: 3; . Sau puteți ascunde cercurile: circle.style ("display", funcția (d) {return d == null? "None": null;}) .

De asemenea, ați putea elimina elementele nula după ce le-ați adăugat: circle.filter (funcția (d) {return d == null;}) remove() . Acest lucru ar funcționa pentru crearea inițială, dar nu aș recomanda acest lucru deoarece indexul s-ar schimba dacă ați re-selectat elementele mai târziu.

28
adăugat
În afară de aceasta, în ceea ce privește abordarea cu zero raze - cu matricea mea mare dar insuficientă, am performanță mult mai bună atunci când creez și utilizez un nou filtru matricial prin developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… . Îmi dau seama că @meetamit dorește să mențină indicii originali, dar credeam că aș putea spune că pot exista implicații de performanță nedorite. Poate d3 poate adresa acest lucru prin scurtcircuitar
adăugat autor Ken Lin, sursa
Am folosit metoda circle.filter (funcția (d) {return d == null;}.) Remove() pentru problema mea și a funcționat frumos!
adăugat autor Climbs_lika_Spyder, sursa

Cea mai simplă opțiune este filtrarea nulilor din datele transmise în .data (...) , augmentând datele pentru a menține indexul:

svg.selectAll('circle')
  .data(values
    .map(function(v, idx) { return v == null? null : { idx: idx, value: v })
    .filter(function(v) { return v != null })
  )
  .enter()
    .append('circle')
    .attr('fill', '#c00')
    .attr('r', 3)
    .attr('cx', function(d) { return d.idx * 10 })//or whatever
    .attr('cy', function(d) { return d.value.y })//or whatever

Rețineți că puteți urma, de asemenea, acest tip de subelemente individuale, chiar dacă acestea nu sunt liste naturale. De exemplu, luați în considerare o situație în care doriți să adăugați condițional un al doilea cerc:

var circles = [
    { color: 'red', cx: 30, cy: 30, subCircleColor: 'blue' },
    { color: 'blue', cx: 60, cy: 60, subCircleColor: 'green' },
    { color: 'green', cx: 90, cy: 90 },
];

// Create a group which will hold the circles, since the result will
// be:
//    
//      
//      
//    
var circlesGroups = svg.selectAll("g.circles")
    .data(circles)
    .enter()
        .append("g").attr({"class": "circles"})

// Add the first circle to the group
circlesGroups
    .append("circle").attr({
        "fill": function(d) { return d.color },
        "r": 20,
        "cx": function(d) { return d.cx },
        "cy": function(d) { return d.cy },
    })

// If there is a subCircleColor, add the second circle to the group
circlesGroups.selectAll("circle.sub-circle")
    .data(function(d) {
        if (d.subCircleColor)
            return [d];
        return [];
    })
    .enter()
        .append("circle").attr({
            "class": "sub-circle",
            "fill": function(d) { return d.subCircleColor; },
            "r": 10,
            "cx": function(d) { return d.cx },
            "cy": function(d) { return d.cy },
        })

Fiddle: http://jsfiddle.net/3d6e648k/

1
adăugat

Doar filtrați-o.

values.filter(function(el){return el !== null;})
1
adăugat
Mulțumesc, dar acest lucru elimină doar acele elemente din matrice, care afectează indexul, care a trecut în funcțiile mele de setare attr (). Am nevoie ca indexul să rămână neschimbat, pentru că este ceea ce folosesc pentru a calcula pozițiile x.
adăugat autor meetamit, sursa
Aceasta a fost de fapt problema mea și m-am simțit prost, fără să mă gândesc doar la filtrarea afară. Cred că am fost atât de prins în "Cum face acest lucru?" că nu m-am gândit :)
adăugat autor freeall, sursa

Încercați acest model, care vă poate șterge sau ascunde cercurile.

// Step 1: hides all circles which are "null"
d3.selectAll(".yourItem")
.data(data)
.enter()
    .append("circle")
    .attr("visibility", function(d,i){
        if(yourFunction(d) == null) return "hidden";
})

// Step 2: optional, deletes all circles which are "hidden"
d3.selectAll("circle[visibility=hidden]").remove();
1
adăugat

Iată o modalitate dacă nu vreți să o adăugați niciodată în primul rând. Am folosit o declarație if în interiorul unui .each() și apoi d3.select (this) pentru a o adăuga la elementul curent.

var data = [9, 0, 7, 0, 5, 0, 3, 0, 1];

var svg = d3.select('#svg').append('svg').attr({'viewBox': '-10 -10 99 20'});

svg.selectAll('g').data(data).enter().append('g').each(function (d,i) {
 if(d){
  d3.select(this).append('circle').attr({r:5,cx:(i*9)});
 }else{
  d3.select(this).remove();
 }
});

Here is a bin http://jsbin.com/qojifug/edit?js,output

1
adăugat
Deși aceasta se anulează adăugând un , acesta încă adaugă un ca container - doar îl lasă gol când d care ar putea fi avantajoasă în cazul în care intenționați să adăugați și alte elemente în interiorul , nu treceți de fapt de adăugarea unui . De asemenea, .selectAll ('z') ar trebui să fie .selectAll ('g') , în caz contrar să repetați apelurile la acest cod datele ) vor adăuga de fiecare dată elemente suplimentare .
adăugat autor meetamit, sursa
Da - apelând .remove() obține rezultatul de a avea numai s, deoarece există date . De asemenea, i se păstrează în sincronizare cu poziția d în data . Dar, în funcție de contextul mai larg, ar putea exista probleme cu acest lucru. De exemplu, dacă ați apelat o funcție suplimentară (de exemplu, .attr sau .remove ) în actualizarea sau > rezultatele acestui .data() se alăture, este posibil să primiți o eroare, deoarece unele elemente vor fi deja e
adăugat autor meetamit, sursa
Fără testări, nu sunt sigur că exemplele problematice pe care le-am subliniat ar apărea de fapt așa cum este descris. Mă refer în principal la presupunerea că dacă vreodată .remove() un membru al unei selecții d3 fără a utiliza selecția ieșirea pentru aceasta, ați putea avea probleme. Deoarece am postat această întrebare (acum 5 ani, geez), am adoptat în principiu recomandarea lui mbostock (pe această pagină) de a nu se baza niciodată pe i pentru reprezentarea datelor și în loc să folosească d cât mai mult posibil.
adăugat autor meetamit, sursa
Vă mulțumim pentru recenzie. Cum de a adăuga altceva pentru a elimina g dacă nu există d? "altceva {d3.select (this) .remove ()}"
adăugat autor getsetbro, sursa
JavaScript, România - Moldova
JavaScript, România - Moldova
328 participanți

Comunitatea Română JavaScript: github.com/js-ro Pentru confort, opriți notificările. Parteneri: @node_ro, @php_ro, @python_ro, @seo_ro, @RomaniaGroup, @ai_ro, @Grupuri_IT Offtop: @holywars_ro Joburi: @js_jobs_ro Sponsored with ❤️ by ciupacabra.com