Qual é a diferença entre D3 e dados?

199

Alguém pode explicar a diferença entre datum () e data () no D3.js. Vejo os dois sendo usados ​​e não sei por que você deve escolher um sobre o outro?

josephmisiti
fonte

Respostas:

164

Encontrei a resposta correta aqui do próprio Mike:

D3 - como lidar com estruturas de dados JSON?

Se você deseja vincular seus dados a um único elemento SVG, use

(...).data([data])

ou

(...).datum(data)

Se você deseja vincular seus dados a vários elementos SVG

(...).data(data).enter().append("svg")

.....

josephmisiti
fonte
Obrigado por isso! o fato de você colocar dados ([dados]) passando e matriz apenas me ajudou a perceber um bug que não consegui descobrir na semana passada! Muito obrigado ... sempre essas coisas estúpidas que estão erradas.
Adam
22
data () realiza uma junção, datum () não.
S3-4v
Lembre-se de que, se houver mais elementos da matriz de dados do que elementos SVG ao vincular dados enter(), o d3 vinculará o restante dos elementos da matriz aos elementos SVG recém-criados.
aslantorret
49

Depois de analisar um pouco isso, descobri que as respostas aqui no SO não estão completas, pois só cobrem o caso quando você invoca selection.datae selection.datumcom um dataparâmetro de entrada . Mesmo nesse cenário, os dois se comportam de maneira diferente se a seleção é um único elemento e quando contém vários elementos. Além disso, esses dois métodos também podem ser chamados sem nenhum argumento de entrada, a fim de consultar os dados / dados vinculados na seleção; nesse caso, eles novamente se comportam de maneira diferente e retornam coisas diferentes.

Editar - Publiquei uma resposta um pouco mais detalhada para esta pergunta aqui , mas a postagem abaixo captura praticamente todos os pontos-chave sobre os dois métodos e como eles diferem entre si.

Ao fornecer data como argumento de entrada

  • selection.data(data)tentará executar um data-junção entre os elementos do dataarray com a seleção resultando na criação de enter(), exit()e update()seleções que você pode posteriormente operar. O resultado final disso é que, se você passar em uma matriz data = [1,2,3], é feita uma tentativa de associar cada elemento de dados individual (ou seja, dados) à seleção. Cada elemento da seleção terá apenas um único elemento de dado datavinculado a ele.

  • selection.datum(data)ignora completamente o processo de junção de dados. Isso simplesmente atribui a totalidade dataa todos os elementos na seleção como um todo, sem dividi-los, como no caso de junções de dados. Portanto, se você deseja vincular uma matriz inteira data = [1, 2, 3]a cada elemento DOM no seu selection, selection.datum(data)conseguirá isso.

Aviso: muitas pessoas acreditam que issoselection.datum(data)é equivalente,selection.data([data])mas isso só é verdade se selection contiver um único elemento . Seselectioncontiver vários elementos DOM,selection.datum(data)vinculará a totalidadedataa todos os elementos da seleção. Por outro lado,selection.data([data])apenas liga a totalidadedata ao primeiro elemento emselection. Isso é consistente com o comportamento de junção de dados deselection.data.

Ao fornecer nenhum dataargumento de entrada

  • selection.data()pegará o dado vinculado para cada elemento na seleção e os combinará em uma matriz retornada. Assim, se seu selectioninclui 3 elementos DOM com os dados "a", "b"e "c"obrigado a cada respectivamente, selection.data()retornos ["a", "b", "c"]. É importante observar que, se selectioné um único elemento com (por exemplo) o dado "a"vinculado a ele, ele selection.data()retornará ["a"]e não "a"como alguns podem esperar.

  • selection.datum()só faz sentido para uma única seleção, pois é definida como retornando o dado vinculado ao primeiro elemento da seleção. Portanto, no exemplo acima, com a seleção que consiste em elementos DOM com dados vinculados de "a", "b"e "c", selection.datum()simplesmente retornaria "a".

Note-se que mesmo se selectiontem um único elemento, selection.datum()e selection.data()retornar valores diferentes. O primeiro retorna o dado vinculado para a seleção ( "a"no exemplo acima) enquanto o último retorna o dado vinculado dentro de uma matriz ( ["a"]no exemplo acima).

Esperamos que isso ajude a esclarecer como selection.datae selection.datum()diferir um do outro ao fornecer dados como um argumento de entrada e ao consultar o dado vinculado por não fornecer nenhum argumento de entrada.

PS - A melhor maneira de entender como isso funciona é começar com um documento HTML em branco no Chrome, abrir o console e tentar adicionar alguns elementos ao documento e começar a vincular dados usando selection.datae selection.datum. Às vezes, é muito mais fácil "grok" algo fazendo do que lendo.

HamsterHuey
fonte
O HamsterHuey já mostrou isso, mas pode ser um lembrete útil para lembrar que "datum" é singular e "data" é plural. Portanto, .datum se aplica às informações associadas a um único elemento.
Visio Guy
42

Aqui estão alguns bons links:

Por este último:

# selection.data([values[, key]])

Une a matriz de dados especificada à seleção atual. Os valores especificados são uma matriz de valores de dados, como uma matriz de números ou objetos, ou uma função que retorna uma matriz de valores.

...

# selection.datum([value])

Obtém ou define os dados associados a cada elemento selecionado. Diferentemente do método selection.data, esse método não calcula uma junção (e, portanto, não computa as seleções de entrada e saída).

paulsm4
fonte
11
dado essas definições - eu ainda estou confuso por que você iria precisar / querer usar datum ()
josephmisiti
Mais um exemplo que pode ajudar a tornar as coisas mais claras: ngokevin.com/blog/d3 . NOTAS: 1) A definição de Kevin: "O dado é o dado vinculado ao elemento". 2) Observe como nos exemplos de Kevin "incorporamos" o conjunto de dados com "data ()" ... mas "usamos" um subconjunto referenciando um "datum ()".
paulsm4
5

Eu acho que a explicação dada por HamsterHuey é a melhor até agora. Para expandir e fornecer uma representação visual das diferenças, criei um documento de exemplo que ilustra pelo menos parte das diferenças entre datae datum.

A resposta abaixo é mais uma opinião derivada do uso desses métodos, mas fico feliz em ser corrigido se estiver errado.

Este exemplo pode ser executado abaixo ou neste Fiddle .

const data = [1,2,3,4,5];
const el = d3.select('#root');

 el
  .append('div')
  .classed('a', true)
  .datum(data)
  .text(d => `node => data: ${d}`);

const join= el
.selectAll('div.b')
.data(data);

join
.enter()
.append('div')
.classed('b', true)
.text((d, i) => `node-${i + 1} => data: ${d}`)

Eu acho que datumé mais simples de entender, uma vez que não faz uma junção, mas é claro que isso também significa que ele tem diferentes casos de uso.

Para mim, uma grande diferença - embora exista mais - é o fato de que dataé apenas a maneira natural de fazer atualizações (ao vivo) em um gráfico d3, pois todo o padrão de entrada / atualização / saída simplifica quando você o obtém.

datumpor outro lado, parece-me mais adequado para representações estáticas. No exemplo abaixo, por exemplo, eu poderia obter o mesmo resultado, fazendo um loop na matriz original e acessando os dados pelo índice da seguinte forma:

data.map((n, i) => {
 el
  .append('div')
  .classed('a', true)
  .datum(data)
  .text(d => `node-${n} => data: ${d[i]}`);
});

Experimente aqui: https://jsfiddle.net/gleezer/e4m6j2d8/6/

Mais uma vez, acho que isso é muito mais fácil de entender, pois você se livra da carga mental proveniente do padrão de entrada / atualização / saída, mas assim que precisar atualizar ou alterar a seleção, certamente será melhor recorrer .data().

const data = [1,2,3,4,5];
const el = d3.select('#root');

 el
  .append('div')
  .classed('a', true)
  .datum(data)
  .text(d => `node => data: ${d}`);

const join= el
.selectAll('div.b')
.data(data);

join
.enter()
.append('div')
.classed('b', true)
.text((d, i) => `node-${i + 1} => data: ${d}`)
/* Ignore all the css */
html {
  font-family: arial;
}

.l {
  width: 20px;
  height: 20px;
  display: inline-block;
  vertical-align: middle;
  margin: 10px 0;
}
.l-a {
  background: #cf58e4;
}
.l-b {
  background:  #42e4e4;
}

.a {
  border-bottom: 2px solid #cf58e4;
}

.b {
  border-bottom: 2px solid #42e4e4;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.6.0/d3.min.js"></script>


<div style="margin-bottom: 20px;">
  <span class="l l-a"></span> .datum() <br />
  <span class="l l-b"></span> .data()
</div>

<div id="root"></div>

Nobita
fonte