Ключевой задачей при визуализации данных является их сопоставление с визуальными элементами. Чтобы упростить процесс сопоставления D3 предоставляет специальные конструкции, которые называются scale. Однако роль scale только сопоставлением не ограничивается, они также могут служить в качестве строительных кирпичиков более сложных конструкций в d3.
Что же представляет scale? scale можно представить в качестве математической функции, которая преобразует некоторое значение из одного интервала, который называется domain, в значение, принадлежащее другому интервалу, который называется range.
Рассмотрим простейший пример. Так, у нас есть курс валют. Например, курс рубля по отношению к доллару на некотором временном промежутке изменялся и представляет следующие значения: 64, 62, 63, 59, 60, 57. То есть мы можем прикинуть примерный диапазон разброса значений - от 50 до 70 рублей за доллар. Диапазон от 50 до 70 и будет выполнять роль интервала domain.
Допустим, нам надо представить изменение курса валюты на графике, например, по оси Х. Но чтобы все выглядело более менее нам надо масштабировать интервал [50, 70] на некоторый отрезок оси X, например, на отрезок от 0 до 50. Для этого и надо использовать функцию scale.
С помощью d3 мы можем сделать подобное сопоставление следующим образом:
var data =[64, 62, 63, 59, 60, 57]; var linear = d3.scale.linear() .domain([50, 70]) .range([1, 50]); for(var i=0; i<data.length; i++) console.log(linear(data[i]));
Функция d3.scale.linear()
будет автоматически сопоставлять значения из одного интервала со значениями из другого. В итоге консоль выведет
следующие числа:
35.3 30.4 32.85 23.05 25.5 18.15
Эти числа и будут представлять координаты по оси Х.
В качестве scale здесь использовалась линейная функция d3.scale.linear()
. Но кроме нее мы можем использовать еще ряд других.
Так, функция d3.scale.pow() возвращает определенную степень числа:
var data =[1, 2, 3, 4, 5]; var pow = d3.scale.pow().exponent(2); for(var i=0; i<data.length; i++) data[i]=pow(data[i]); console.log(data);
Результатом программы будет следующий вывод:
[ 1, 4, 9, 16, 25 ]
То есть так как в метод .exponent(2)
передается двойка, то каждое число из массива возводится во вторую степень, а сама формула будет выглядеть так: f(n) = n^2. В данном случае нам необязательно использовать
интервалы domain и range. Однако можно и использовать интервалы, в этом случае формула будет также меняться:
var data =[1, 2, 3, 4, 5]; var pow = d3.scale.pow().exponent(2).domain([1, 10]) .rangeRound([1, 10]); for(var i=0; i<data.length; i++) data[i]=pow(data[i]); console.log(data);
Вместо метода range здесь применяется метод rangeRound(), который имеет то же самое предназначение, но кроме того позволяет округлять получаемые значения.
Теперь вывод будет другим:
1, 1, 2, 2, 3
А формула будет выглядеть так: f(n) = a*n^2 + b, 1 <= f(n) <= 10.
Также можно использовать логарифмическую интерполяцию с помощью функции d3.scale.log(). По умолчанию используется логарифм по основанию 10:
var data =[1, 10, 100, 1000]; var log = d3.scale.log(); for(var i=0; i<data.length; i++) data[i]=log(data[i]); console.log(data);
Вывод:
0, 1, 2, 2.9999999999999996
Чтобы сделать числа более ровными, мы можем применять округление с помощью функции d3.round: data[i]=d3.round(log(data[i]))
Еще одна функция d3.time.scale() позволяет сопоставлять линейные интервалы с временными отрезками, то может быть полезно, например, если мы решим вывести по одной оси даты:
var start = new Date(2015, 0, 1), //1 января 2015 end = new Date(2015, 2, 1), // 1 марта 2015 range = [0, 300]; // интервал значений по оси Х var data = [ // интервал дат new Date(2015, 0, 10), new Date(2015, 0, 20), new Date(2015, 0, 31), new Date(2015, 1, 8), new Date(2015, 1, 16) ]; var time = d3.time.scale().domain([start, end]).rangeRound(range); for(var i=0; i<data.length; i++) data[i]=time(data[i]); console.log(data);
Здесь некоторый набор дат из массива data интерполируется на отрезок от 0 до 300. В итоге мы получим следующий вывод:
46, 97, 153, 193, 234