Экскурсия по внедрению модулей визуализации с динамическими наборами данных
Общим удалить существующие масштабируемые векторные графики (SVG) элемент, позвонив d3.select ('# Chart'). Удалить () Перед рендерингом нового диаграммы.
Тем не менее, могут быть сценарии, когда вам нужно создавать динамические визуализации из источников, таких как внешние API. Эта статья покажет вам, как это сделать, используя d3.js.
D3.js обрабатывает динамические данные, приняв общий шаблон обновления. Это обычно описывается как соединение данных, а затем операции на выборах ввода, обновления и выхода. Освоение этих методов выбора позволит вам производить бесшовные переходы между состояниями, позволяя вам рассказывать значимые истории с данными.
Начиная
Требования
Мы будем строить график, который иллюстрирует движение нескольких обменных средств (ETF) в течение второй половины 2018 года. График состоит из следующих инструментов:
- Закрывающая диаграмма цен
- Объем торговли гистограмма
- 50-дневный простой скользящий средний
- Bollinging Bands (20-дневный простой скользящий средний, со стандартным набором отклонения в 2.0)
- Открытый низкий близкий ( OHLC ) Диаграмма
- Подсвечники
Эти инструменты обычно используются в техническом анализе акций, товаров и других ценных бумаг. Например, трейдеры могут использовать полосы Боллинджера и подсвечниками, чтобы получить узоры, которые представляют собой сигналы покупки или продажи.
Вот как будет выглядеть график:
В этой статье призвана оснащена фундаментальным теориям присоединения данных и шаблон выхода в Enter-Update, чтобы вы могли легко визуализировать динамические наборы данных. Кроме того, мы будем покрывать выбор , который введен в выпуске D3.js V5.8.0.
Общее обновление
Гист общего узора обновления является выбор элементов модели объекта документа (DOM), а затем связывание данных к этим элементам. Эти элементы затем создаются, обновляются или удалены, чтобы представлять необходимые данные.
Присоединение к новым данным.
Данные соединяются – это отображение n Количество элементов в наборе данных с n Количество узлов выбранного объекта документа (DOM), указывая требуемое действие на DOM в качестве изменения данных.
Мы используем Данные () Способ для отображения каждой точки данных в соответствующий элемент в выборе DOM. Кроме того, это хорошая практика для поддержания Постоянство объекта Указав ключ в качестве уникального идентификатора в каждой точке данных. Давайте посмотрим на следующий пример, который является первым шагом к рендерингу баров объема торговли:
const bars = d3
.select('#volume-series')
.selectAll(.'vol')
.data(this.currentData, d => d['date']);Вышеуказанная линия кода выбирает все элементы с классом Воль с последующим сопоставлением this.currentData Массив с выбором элементов DOM с использованием Данные () метод.
Второй дополнительный аргумент Данные () принимает точку данных в качестве ввода и возвращает Дата Свойство в качестве выбранного ключа для каждой точки данных.
Выбор ввода/обновления
.enter () Возвращает выбор ввода, который представляет элементы, которые необходимо добавлять, когда соединенный массив длиннее выбора. Это сопровождается звонком .append. () , который создает или обновляет элементы на DOM. Мы можем реализовать это следующим образом:
bars
.enter()
.append('rect')
.attr('class', 'vol')
.merge(bars)
.transition()
.duration(750)
.attr('x', d => this.xScale(d['date']))
.attr('y', d => yVolumeScale(d['volume']))
.attr('fill', (d, i) => {
if (i === 0) {
return '#03a678';
} else {
// green bar if price is rising during that period, and red when price is falling
return this.currentData[i - 1].close > d.close
? '#c0392b'
: '#03a678';
}
})
.attr('width', 1)
.attr('height', d => this.height - yVolumeScale(d['volume']));.merge () Обновляет обновление и вводить выбор, прежде чем применять последующие сетевые сети для создания анимации между переходами и обновлять их связанные атрибуты. Вышеуказанный блок кода позволяет выполнять следующие действия на выбранных элементах DOM:
- Выбор обновления, который состоит из точек данных, представленных
Элементы на графике будут обновляться свои атрибуты соответствующим образом. - Создание
Элементы с классомВоль, с приведенными выше атрибутами, определенными в каждом элементе, поскольку выбор ввода состоит из точек данных, которые не представлены на графике.
Выход выбора
Удалите элементы из нашего набора набора данных, следуя простым шагам ниже: BARS.EXIT (). Удалить ();
.exit () Возвращает выбор выхода, который указывает точки данных, которые необходимо удалить. .remove () Метод впоследствии удаляет выделение от DOM.
Вот как строки ряда томов будут реагировать на изменения данных:
Обратите внимание на то, как DOM и соответствующие атрибуты каждого Элемент обновляется, как выбираем другой набор данных:
Selection.join (как V5.8.0)
Введение Выбор. Джойин В V5.8.0 D3.js упростил весь процесс соединения данных. Отдельные функции теперь передаются для обработки Enter , Обновление , и выход, который, в свою очередь, возвращает объединенный ввод и выборы обновления.
selection.join(
enter => // enter.. ,
update => // update.. ,
exit => // exit..
)
// allows chained operations on the returned selectionsВ случае стержней объемных рядов приложение Выбор. Джойин приведет к следующим изменениям в нашем коде:
//select, followed by updating data join
const bars = d3
.select('#volume-series')
.selectAll('.vol')
.data(this.currentData, d => d['date']);
bars.join(
enter =>
enter
.append('rect')
.attr('class', 'vol')
.attr('x', d => this.xScale(d['date']))
.attr('y', d => yVolumeScale(d['volume']))
.attr('fill', (d, i) => {
if (i === 0) {
return '#03a678';
} else {
return this.currentData[i - 1].close > d.close
? '#c0392b'
: '#03a678';
}
})
.attr('width', 1)
.attr('height', d => this.height - yVolumeScale(d['volume'])),
update =>
update
.transition()
.duration(750)
.attr('x', d => this.xScale(d['date']))
.attr('y', d => yVolumeScale(d['volume']))
.attr('fill', (d, i) => {
if (i === 0) {
return '#03a678';
} else {
return this.currentData[i - 1].close > d.close
? '#c0392b'
: '#03a678';
}
})
.attr('width', 1)
.attr('height', d => this.height - yVolumeScale(d['volume']))
);Также обратите внимание, что мы внесли некоторые изменения в анимацию баров. Вместо того, чтобы пройти Переход () Метод с объединенным выбором ввода и обновления, он теперь используется в выделении обновления, такие, как переходы будут применяться только при изменении набора данных.
Возвращенные выборы ввода и обновления затем объединяются и возвращаются Выбор. Джойин Отказ
Боллингер группы
Точно так же мы можем подать заявку Выбор. Джойин на рендеринге полосы Боллинджера. Перед отображением полос мы обязаны рассчитать следующие свойства каждой точки данных:
- 20-дневный простой скользящий средний.
- Верхние и нижние полосы, которые имеют стандартное отклонение 2,0 выше и ниже 20-дневного простого скользящего среднего, соответственно.
Это формула для расчета стандартного отклонения:
Теперь мы переведем вышеуказанную формулу в код JavaScript:
calculateBollingerBands(data, numberOfPricePoints) {
let sumSquaredDifference = 0;
return data.map((row, index, total) => {
const start = Math.max(0, index - numberOfPricePoints);
const end = index;
// divide the sum with subset.length to obtain moving average
const subset = total.slice(start, end + 1);
const sum = subset.reduce((a, b) => {
return a + b['close'];
}, 0);
const sumSquaredDifference = subset.reduce((a, b) => {
const average = sum / subset.length;
const dfferenceFromMean = b['close'] - average;
const squaredDifferenceFromMean = Math.pow(dfferenceFromMean, 2);
return a + squaredDifferenceFromMean;
}, 0);
const variance = sumSquaredDifference / subset.length;
return {
date: row['date'],
average: sum / subset.length,
standardDeviation: Math.sqrt(variance),
upperBand: sum / subset.length + Math.sqrt(variance) * 2,
lowerBand: sum / subset.length - Math.sqrt(variance) * 2
};
});
}
.
.
// calculates simple moving average, and standard deviation over 20 days
this.bollingerBandsData = this.calculateBollingerBands(validData, 19);Быстрое объяснение расчета стандартного отклонения и значения полосы Боллинжера на вышеупомянутой блоке кода следующая:
Для каждой итерации,
- Рассчитайте среднее значение тесной цены.
- Найдите разницу между средним значением и тесной ценой для этой точки данных.
- Квадрат результат каждой разницы.
- Найдите сумму в квадратных различиях.
- Рассчитайте среднее значение в квадратных различиях, чтобы получить дисперсию
- Получите квадратный корень дисперсии, чтобы получить стандартное отклонение для каждой точки данных.
- Умножьте стандартное отклонение на 2. Рассчитайте значения верхних и нижних полос, добавляя или вычитая среднее значение с умноженным значением.
С определенным точками данных, мы можем использовать Выбор. Джойин Для рендеринга Bollinger Bands:
// code not shown: rendering of upper and lower bands
.
.
// bollinger bands area chart
const area = d3
.area()
.x(d => this.xScale(d['date']))
.y0(d => this.yScale(d['upperBand']))
.y1(d => this.yScale(d['lowerBand']));
const areaSelect = d3
.select('#chart')
.select('svg')
.select('g')
.selectAll('.band-area')
.data([this.bollingerBandsData]);
areaSelect.join(
enter =>
enter
.append('path')
.style('fill', 'darkgrey')
.style('opacity', 0.2)
.style('pointer-events', 'none')
.attr('class', 'band-area')
.attr('clip-path', 'url(#clip)')
.attr('d', area),
update =>
update
.transition()
.duration(750)
.attr('d', area)
);Это отображает диаграмму площади, которая обозначает область, заполненную полосами Боллинджера. В функции обновления мы можем использовать selection.transition () Метод для обеспечения анимированных переходов на выделение обновления.
Подсвечники
Диаграмма подсвечников отображает высокие, низкие, открытые и закрытые цены на акции на определенный период. Каждый подсвечник представляет точку данных. Зеленый представляет, когда запас закрывается выше, в то время как красный представляет, когда запас закрывается при более низком уровне.
В отличие от полос Боллинджера, нет необходимости в дополнительных расчетах, поскольку цены доступны в существующем наборе данных.
const bodyWidth = 5;
const candlesticksLine = d3
.line()
.x(d => d['x'])
.y(d => d['y']);
const candlesticksSelection = d3
.select('#chart')
.select('g')
.selectAll('.candlesticks')
.data(this.currentData, d => d['volume']);
candlesticksSelection.join(enter => {
const candlesticksEnter = enter
.append('g')
.attr('class', 'candlesticks')
.append('g')
.attr('class', 'bars')
.classed('up-day', d => d['close'] > d['open'])
.classed('down-day', d => d['close'] <= d['open']);
В функции ввода каждый подсвечник отображается на основе его отдельных свойств.
Прежде всего, каждый элемент Candlestick Group присваивается класс Up-Day Если тесная цена выше, чем открытая цена, а День за день Если цена тесной цены ниже или равна открытой цене.
candlesticksEnter
.append('path')
.classed('high-low', true)
.attr('d', d => {
return candlesticksLine([
{ x: this.xScale(d['date']), y: this.yScale(d['high']) },
{ x: this.xScale(d['date']), y: this.yScale(d['low']) }
]);
});Далее мы добавляем путь Элемент, который представляет собой самую высокую и самую низкую цену в тот день, к вышеуказанному выбору.
candlesticksEnter
.append('rect')
.attr('x', d => this.xScale(d.date) - bodyWidth / 2)
.attr('y', d => {
return d['close'] > d['open']
? this.yScale(d.close)
: this.yScale(d.open);
})
.attr('width', bodyWidth)
.attr('height', d => {
return d['close'] > d['open']
? this.yScale(d.open) - this.yScale(d.close)
: this.yScale(d.close) - this.yScale(d.open);
});
});Сопровождается добавлением Reble элемент к выбору. Высота каждого Reble Элемент непосредственно пропорционален своему дневному диапазону, полученный, вычитая открытую цену с тесной ценой.
На наших стилях мы определим следующие свойства CSS для наших классов, что делает подсвечники красные или зеленые:
.bars.up-day path {
stroke: #03a678;
}
.bars.down-day path {
stroke: #c0392b;
}
.bars.up-day rect {
fill: #03a678;
}
.bars.down-day rect {
fill: #c0392b;
}Это приводит к рендерингу группов Боллинджера и подсвечников:
Новый синтаксис оказался проще и интуитивно понятен, чем явно вызов selection.enter , selection.append , Selection.merge и Selection.remove. .
Обратите внимание, что для тех, кто развивается с V5.8.0 и дальше D3.JS, это было Рекомендуется Mike Bostock, что эти пользователи начинают использовать Выбор. Джойин Из-за вышеуказанных преимуществ.
Заключение
Потенциал D3.js безграничен, а приведенные выше иллюстрации – это просто вершина айсберга. Многие довольные пользователи создали визуализацию, которые являются значительно более сложными и сложными, чем одно шоу выше. Это Список бесплатные apis Может заинтересовать вас, если вы хотите отправиться в свои собственные проекты визуализации данных.
Не стесняйтесь проверить Исходный код и Полная демонстрация этого проекта.
Большое спасибо за прочтение этой статьи. Если у вас есть какие-либо вопросы или предложения, не стесняйтесь оставлять их в комментариях ниже!
Новый до d3.js? Вы можете обратиться к этому Статья На основах внедрения общих компонентов диаграммы.
Особая благодарность Дебби Леону для рассмотрения этой статьи.
Дополнительные ссылки:
Оригинал: “https://www.freecodecamp.org/news/how-to-work-with-d3-jss-general-update-pattern-8adce8d55418/”