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?
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?
Respostas:
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")
.....
enter()
, o d3 vinculará o restante dos elementos da matriz aos elementos SVG recém-criados.
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.data
e selection.datum
com um data
parâ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 data
array 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 data
vinculado a ele.
selection.datum(data)
ignora completamente o processo de junção de dados. Isso simplesmente atribui a totalidade data
a 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 isso
selection.datum(data)
é equivalente,selection.data([data])
mas isso só é verdade seselection
contiver um único elemento . Seselection
contiver vários elementos DOM,selection.datum(data)
vinculará a totalidadedata
a 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 data
argumento de entrada
selection.data()
pegará o dado vinculado para cada elemento na seleção e os combinará em uma matriz retornada. Assim, se seu selection
inclui 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
selection
tem um único elemento,selection.datum()
eselection.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.data
e 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.data
e selection.datum
. Às vezes, é muito mais fácil "grok" algo fazendo do que lendo.
Aqui estão alguns bons links:
Boa discussão sobre o D3 "data ()": Entendendo como o D3.js vincula dados a nós
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).
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 data
e 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.
datum
por 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>