¿Alguien puede explicar la diferencia entre datum () y data () en D3.js? Veo que ambos se usan y no estoy seguro de por qué debería elegir uno sobre el otro.
¿Alguien puede explicar la diferencia entre datum () y data () en D3.js? Veo que ambos se usan y no estoy seguro de por qué debería elegir uno sobre el otro.
Respuestas:
Encontré la respuesta correcta aquí del propio Mike:
D3: ¿cómo lidiar con las estructuras de datos JSON?
Si desea vincular sus datos a un solo elemento SVG, use
(...).data([data])
o
(...).datum(data)
Si desea vincular sus datos a múltiples elementos SVG
(...).data(data).enter().append("svg")
.....
enter()
, d3 vinculará el resto de elementos de matriz con elementos SVG recién creados.
Después de analizar esto un poco, descubrí que las respuestas aquí en SO no están completas, ya que solo cubren el caso cuando se invoca selection.data
y selection.datum
con un data
parámetro de entrada . Incluso en ese escenario, los dos se comportan de manera diferente si la selección es un elemento único en comparación con cuando contiene múltiples elementos. Además, ambos métodos también pueden invocarse sin ningún argumento de entrada para consultar los datos / datos vinculados en la selección, en cuyo caso una vez más se comportan de manera diferente y devuelven cosas diferentes.
Editar: publiqué una respuesta un poco más detallada a esta pregunta aquí , pero la publicación a continuación captura prácticamente todos los puntos clave con respecto a los dos métodos y cómo se diferencian entre sí.
Al suministrar data
como argumento de entrada
selection.data(data)
intentará realizar una unión de datos entre los elementos de la data
matriz con la selección resultante en la creación de enter()
, exit()
y las update()
selecciones en las que puede operar posteriormente. El resultado final de esto es que si pasa una matriz data = [1,2,3]
, se intenta unir cada elemento de datos individual (es decir, dato) con la selección. Cada elemento de la selección solo tendrá un único elemento de referencia data
vinculado.
selection.datum(data)
evita el proceso de unión de datos por completo. Esto simplemente asigna la totalidad de data
todos los elementos en la selección como un todo sin dividirlo como en el caso de las uniones de datos. Entonces, si desea vincular una matriz completa data = [1, 2, 3]
a cada elemento DOM en su selection
, entonces selection.datum(data)
lo logrará.
Advertencia: Muchas personas creen que
selection.datum(data)
es equivalente a,selection.data([data])
pero esto solo es cierto siselection
contiene un solo elemento . Siselection
contiene varios elementos DOM,selection.datum(data)
se unirádata
a todos los elementos de la selección. Por el contrario,selection.data([data])
solo une la totalidad deldata
primer elemento enselection
. Esto es coherente con el comportamiento de unión de datos deselection.data
.
Cuando no se proporciona data
argumento de entrada
selection.data()
tomará el dato enlazado para cada elemento en la selección y los combinará en una matriz que se devuelve. Por lo tanto, si selection
incluye 3 elementos DOM con los datos "a"
, "b"
y está "c"
vinculado a cada uno respectivamente, selection.data()
regresa ["a", "b", "c"]
. Es importante tener en cuenta que si selection
es un elemento único con (a modo de ejemplo) el dato "a"
unido a él, entonces selection.data()
volverá ["a"]
y no "a"
como algunos podrían esperar.
selection.datum()
solo tiene sentido para una sola selección, ya que se define como devolver el dato vinculado al primer elemento de la selección. Entonces, en el ejemplo anterior, la selección consiste en elementos DOM con datos vinculados de "a"
, "b"
y "c"
, selection.datum()
simplemente regresaría "a"
.
Tenga en cuenta que incluso si
selection
tiene un solo elemento,selection.datum()
yselection.data()
devuelve valores diferentes. El primero devuelve el dato enlazado para la selección ("a"
en el ejemplo anterior) mientras que el segundo devuelve el dato enlazado dentro de una matriz (["a"]
en el ejemplo anterior).
Esperemos que esto ayude a aclarar cómo selection.data
y selection.datum()
diferir entre sí tanto al proporcionar datos como argumento de entrada como al consultar el dato enlazado al no proporcionar ningún argumento de entrada.
PD: la mejor manera de entender cómo funciona esto es comenzar con un documento HTML en blanco en Chrome y abrir la consola e intentar agregar algunos elementos al documento y luego comenzar a vincular datos usando selection.data
y selection.datum
. A veces, es mucho más fácil "asimilar" algo haciendo que leyendo.
Aquí hay algunos buenos enlaces:
Buena discusión sobre D3 "data ()": comprender cómo D3.js une datos a nodos
Por lo último:
# selection.data([values[, key]])
Une la matriz de datos especificada con la selección actual. Los valores especificados son una matriz de valores de datos, como una matriz de números u objetos, o una función que devuelve una matriz de valores.
...
# selection.datum([value])
Obtiene o establece los datos enlazados para cada elemento seleccionado. A diferencia del método selection.data, este método no calcula una unión (y, por lo tanto, no calcula las selecciones de entrada y salida).
Creo que la explicación dada por HamsterHuey es la mejor hasta ahora. Para ampliarlo y dar una representación visual de las diferencias, creé un documento de muestra que ilustra al menos parte de las diferencias entre data
y datum
.
La respuesta a continuación es más una opinión derivada del uso de estos métodos, pero estoy feliz de que me corrijan si me equivoco.
Este ejemplo se puede ejecutar a continuación o en este 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}`)
Creo que datum
es más fácil de entender, ya que no se une, pero, por supuesto, esto también significa que tiene diferentes casos de uso.
Para mí, una gran diferencia, aunque hay más, es el hecho de que data
es la forma natural de hacer actualizaciones (en vivo) en un gráfico d3, ya que todo el patrón de entrada / actualización / salida lo hace simple, una vez que lo obtiene.
datum
Por otro lado, me parece más adecuado para las representaciones estáticas. En el ejemplo a continuación, por ejemplo, podría lograr el mismo resultado de mi bucle en la matriz original y acceder a los datos por índice de la siguiente manera:
data.map((n, i) => {
el
.append('div')
.classed('a', true)
.datum(data)
.text(d => `node-${n} => data: ${d[i]}`);
});
Pruébelo aquí: https://jsfiddle.net/gleezer/e4m6j2d8/6/
Nuevamente, creo que esto es mucho más fácil de entender ya que te mantienes libre de la carga mental que proviene del patrón de entrada / actualización / salida, pero tan pronto como necesites actualizar o cambiar la selección, seguramente será mejor que recurras a ella .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>