¿Cuál es la diferencia D3 datum vs. data?

199

¿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.

josephmisiti
fuente

Respuestas:

164

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

.....

josephmisiti
fuente
¡Gracias por esto! ¡El hecho de que haya pasado datos ([datos]) y una matriz me ayudó a darme cuenta de un error que no pude resolver durante la semana pasada! Muchas gracias ... siempre cosas tan estúpidas que están mal.
Adam
22
data () realiza una unión, datum () no.
s3-4v
Solo tenga en cuenta, en caso de que haya más elementos de matriz de datos que elementos SVG al vincular datos con enter(), d3 vinculará el resto de elementos de matriz con elementos SVG recién creados.
aslantorret
49

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.datay selection.datumcon un datapará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 datamatriz 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 datavinculado.

  • selection.datum(data)evita el proceso de unión de datos por completo. Esto simplemente asigna la totalidad de datatodos 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 queselection.datum(data)es equivalente a,selection.data([data])pero esto solo es cierto si selection contiene un solo elemento . Siselectioncontiene varios elementos DOM,selection.datum(data)se unirádataa 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 dataargumento 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 selectionincluye 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 selectiones 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 selectiontiene un solo elemento, selection.datum()y selection.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.datay 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.datay selection.datum. A veces, es mucho más fácil "asimilar" algo haciendo que leyendo.

HamsterHuey
fuente
HamsterHuey ya lo ha demostrado, pero podría ser un recordatorio útil recordar que "datum" es singular y "data" es plural. Por lo tanto, .datum se aplica a la información asociada de un solo elemento.
Visio Guy
42

Aquí hay algunos buenos enlaces:

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).

paulsm4
fuente
11
dadas esas definiciones - todavía estoy confundido por qué necesitarías / querrías usar datum ()
josephmisiti
Un ejemplo más que podría ayudar a aclarar las cosas: ngokevin.com/blog/d3 . NOTAS: 1) Definición de Kevin: "El dato son los datos vinculados al elemento". 2) Observe cómo en los ejemplos de Kevin "incorporamos" el conjunto de datos con "datos ()" ... pero "usamos" un subconjunto haciendo referencia a un "dato ()".
paulsm4
5

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 datay 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 datumes 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 dataes 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.

datumPor 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>

Nobita
fuente