Может кто-нибудь объяснить, пожалуйста, разницу между datum () и data () в D3.js? Я вижу, как используются оба, и я не уверен, почему вы должны выбрать один из других?
Может кто-нибудь объяснить, пожалуйста, разницу между datum () и data () в D3.js? Я вижу, как используются оба, и я не уверен, почему вы должны выбрать один из других?
Ответы:
Я нашел правильный ответ здесь от самого Майка:
D3 - как бороться со структурами данных JSON?
Если вы хотите привязать ваши данные к одному элементу SVG, используйте
(...).data([data])
или
(...).datum(data)
Если вы хотите связать свои данные с несколькими элементами SVG
(...).data(data).enter().append("svg")
.....
enter()
, d3 свяжет остальные элементы массива с вновь созданными элементами SVG.
Посмотрев немного, я обнаружил, что ответы на SO здесь неполные, поскольку они охватывают только случай, когда вы вызываете, selection.data
и selection.datum
с входным data
параметром. Даже в этом сценарии они ведут себя по-разному, если выделение представляет собой один элемент, и если оно содержит несколько элементов. Более того, оба этих метода также могут быть вызваны без каких-либо входных аргументов для запроса связанных данных / данных в выборе, и в этом случае они снова ведут себя по-разному и возвращают разные вещи.
Изменить - я разместил чуть более подробный ответ на этот вопрос здесь , но пост ниже в значительной степени отражает все ключевые моменты, касающиеся двух методов и того, как они отличаются друг от друга.
При поставке data
как качестве входного аргумента
selection.data(data)
будет пытаться выполнить соединение данных между элементами data
массива с выбором, результатом которого будет создание enter()
, exit()
и с update()
выборками, с которыми вы впоследствии сможете работать. Конечный результат этого, если вы передаете в массивеdata = [1,2,3]
, когда делается попытка соединить каждый отдельный элемент данных (т. Е. Данные) с выбором. Каждый элемент выбора будет иметь только один элемент привязки, data
связанный с ним.
selection.datum(data)
обходит процесс присоединения данных в целом. Это просто присваивает совокупность data
всем элементам в выделении в целом, не разделяя его, как в случае объединения данных. Так что если вы хотите привязать весь массив data = [1, 2, 3]
к каждому элементу DOM в вашем selection
, то selection.datum(data)
добьетесь этого.
Предупреждение: многие люди считают, что
selection.datum(data)
это эквивалентно,selection.data([data])
но это верно только в том случае, еслиselection
содержит один элемент . Еслиselection
содержит несколько элементов DOM, тоselection.datum(data)
будет привязывать всеdata
к каждому элементу в выборе. Напротив,selection.data([data])
связывает только полностьюdata
с первым элементом вselection
. Это согласуется с поведением при присоединении данныхselection.data
.
При data
вводе без входного аргумента
selection.data()
возьмет привязанные данные для каждого элемента в выделении и объединит их в массив, который возвращается. Таким образом, если ваш selection
включает в себя 3 DOM элементов с данными "a"
, "b"
и "c"
связаны друг с соответственно, selection.data()
возвращается ["a", "b", "c"]
. Важно отметить, что если selection
это один элемент с (в качестве примера) "a"
привязанным к нему датумом , то selection.data()
он вернет["a"]
а не так, "a"
как некоторые ожидают.
selection.datum()
имеет смысл только для одного выбора, так как он определен как возвращение данных, привязанных к первому элементу выбора. Таким образом, в приведенном выше примере с выбором, состоящим из элементов DOM со связанным значением "a"
, "b"
и "c"
, selection.datum()
просто вернет"a"
.
Обратите внимание, что даже если
selection
есть один элемент,selection.datum()
иselection.data()
возвращают разные значения. Первый возвращает связанный элемент данных для выбора ("a"
в примере выше), тогда как второй возвращает связанный элемент данных в массиве (["a"]
в примере выше).
Надеемся, что это поможет прояснить, как selection.data
и чем они selection.datum()
отличаются друг от друга как при предоставлении данных в качестве входного аргумента, так и при запросе связанных данных, не предоставляя никаких входных аргументов.
PS. Лучший способ понять, как это работает, - начать с пустого HTML-документа в Chrome, открыть консоль и попробовать добавить несколько элементов в документ, а затем начать связывать данные с помощью selection.data
и selection.datum
. Иногда гораздо проще «прогнать» что-то, чем читать.
Вот несколько хороших ссылок:
Хорошее обсуждение D3 "data ()": понимание того, как D3.js связывает данные с узлами
По последнему:
# selection.data([values[, key]])
Объединяет указанный массив данных с текущим выбором. Указанные значения - это массив значений данных, например, массив чисел или объектов, или функция, которая возвращает массив значений.
...
# selection.datum([value])
Получает или задает связанные данные для каждого выбранного элемента. В отличие от метода selection.data, этот метод не вычисляет соединение (и, следовательно, не вычисляет выборки входа и выхода).
Я думаю, что объяснение, данное HamsterHuey, пока лучшее. Чтобы расширить его и наглядно представить различия, я создал образец документа, который иллюстрирует хотя бы часть различий между data
и datum
.
Приведенный ниже ответ является скорее мнением, полученным при использовании этих методов, но я рад, что меня исправят, если я ошибаюсь.
Этот пример можно запустить ниже или в этой скрипке .
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}`)
Я думаю, что datum
это проще понять, так как это не делает соединение, но, конечно, это также означает, что у него разные варианты использования.
Для меня одно большое отличие - хотя есть и большее - заключается в том, что data
это просто естественный способ делать (живые) обновления на графике d3, поскольку весь шаблон ввода / обновления / выхода делает его простым, как только вы его получите.
datum
с другой стороны, мне кажется, больше подходит для статических представлений. Например, в приведенном ниже примере я мог бы добиться того же результата, если бы зацикливался на исходном массиве и обращался к данным по индексу следующим образом:
data.map((n, i) => {
el
.append('div')
.classed('a', true)
.datum(data)
.text(d => `node-${n} => data: ${d[i]}`);
});
Попробуйте это здесь: https://jsfiddle.net/gleezer/e4m6j2d8/6/
Опять же, я думаю, что это гораздо проще понять, поскольку вы освобождаетесь от умственного бремени, возникающего из шаблона ввода / обновления / выхода, но как только вам нужно обновить или изменить выбор, вам наверняка будет лучше прибегнуть к помощи .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>