Новый Qlik Sense APIs позволяет легко создавать расширения, которые увеличивают библиотеку стандартных визуализаций. Одна из самых распространенных библиотек – мощная подборка javascript-библиотек d3.js. Именно поэтому хочу сегодня рассказать о том, как создать расширение визуализации с помощью d3. Буду писать очень подробно, чтобы даже новичок легко смог воссоздать то, о чем я расскажу.

НА ЗАМЕТКУ! Само название d3 расшифровывается как Data-Driven Documents, то есть ключевой основой этой библиотеки является созданий мощнейший визуализаций данных. D3 – комбинация трех компонентов, а именно CSS, JS и SVG, поэтому графика у нас будет векторного формата, что очень важно для ее качественного отображения. Прочие подробности можно узнать на официальном сайте библиотеки http://d3js.org/ .

После прочтения я вам обещаю, что всего за 10 минут, вы сможете создать собственное расширение. Тяжело в ученье, легко в бою! В бой, друзья! 

Расширение QlikSense: 4 шага к созданию

1) Пишем небольшую d3-визуализацию.

2) Получаем тестовые данные для работы и загрузки в Qlik Sense.

3) Запускаем новое расширение и делаем нужные настройки параметров.

4) Вставляем код d3 в расширение и изменяем источник данных из расширения.

НА ЗАМЕТКУ!  Я предполагаю, что вам известны основы скриптинга Qlik Sense и JavaScript, поэтому не буду вас учить этому здесь. НО, все-таки, весь код буду сопровождать легкими объяснениями – чтобы вы могли просто копипастить, вникая в суть дела, но так, чтобы не утонули :)).

Источник:

В итоге получим вот такую визуализацию:

Диаграмма Qlik Sense

Итак, дорогие мои! Стартуем!

d3 в деле

Наш график создан по двум метрикам и цвет определяется на основе измерения. Qlik Sense имеет встроенную визуализацию с одним измерением, но при этом по умолчанию нет второго измерения, которое позволяет сгруппировать точки по цветам. Как раз в этом нам поможет библиотека решений d3.

Когда вы откроете источник данных, вы увидите два файла: html-файл с графиком и .tsv-файл, который содержит данные. Мы же будем использовать куски кода из html-файла и Qlik Sense, вместо tsv-файла.

Когда будем готовы использовать d3, вернемся к этому шагу. Сейчас идем дальше.

Получаем тестовые данные и загружаем в Qlik Sense

Нам нужные данные с двумя метриками и двумя измерениями для создания диаграммы. Две метрики будут отвечать за оси X и Y. Одно измерение будет использоваться, чтобы нарисовать каждую точку, второе – для назначения цвета. Использую данные из отчета о развитии человечества за 2014 г. Human Development Report 2014. Заголовки таблицы содержат следующие данные:

Development Group Country Obesity % Life Expectancy at age 60

Мои две метрики – процент ожирения и ожидаемая длительность жизни в возрасте 60 лет. Измерением будет каждая страна. В качестве цвета выбираем группу развития страны.

Также я удалил те строки, в которых были пропущены данные.

Сохраните ваши данные в ту директорию, откуда вы сможете загрузить данные.

Создаем новое приложение в Qlik Sense

Первое, что нам нужно сделать – создать новое приложение Qlik Sense.

Откройте Qlik Sense. Вы увидите хаб. Выбирайте “Создать новое приложение” в верхнем правом углу.

Qlik Sense Desktop

Дайте своему приложение название и затем нажмите на него, чтобы открыть.

Измените скрипт загрузки и загрузите ваши данные

Мы создали и открыли приложение, которое сейчас у нас пустое. Сейчас нам нужно загрузить наши данные. Данные могут быть загружены через редактор загрузки данных.

Нажмите на иконку компаса в верхнем левом углу и выберите «Редактор загрузки данных», у вас откроется окно.

Scatter Extension

Слева, вы увидите панель, которая управляет загрузкой скрипта в разных вкладках. Основная вкладка – конфигурация переменных. Нам не нужно изменять их. Нажмите на “+”, чтобы создать новую вкладку. Задайте название вкладке.

Пустая вкладка скриптинга будет теперь видна справа.

Чтобы сгенерировать наш скрипт загрузки, нам нужно установить соединение с директорией, откуда будем загружать данные В правой части области скриптинга нажимаем «Создать соединение».  Выбираем директорию, где сохранен CSV-файл (назначаем имя и жмем сохранить).

Scatter Extension

Создав соединение с директорией, мы можем использовать это соединение для загрузки данных из директории. Справа появится наше соединение в виде иконки. Нажимая на эту иконку, мы увидим меню, из которого можем загружать файлы из директории. Нажмите на сохраненный файл в директории, нажимайте выбрать.

Загрузчик поможет нам сконфигурировать нашу загрузку. Нам будет доступен предпросмотр и можем настроить параметры. У нас есть источник данных, разделенный запятыми и ярлыки первой строки источника, которые мы будем использовать как наши имена столбцов. Измените настройки загрузки, как показано ниже:

Загрузка данных Qlik Sense

Нажмите кнопку «Вставить скрипт», чтобы импортировать сгенерированный скрипт загрузки в ваш редактор скрипта. Получится как-то так:

Scatter Extension

Теперь мы можем загрузить данные в наше приложение, нажав кнопку «Загрузка данных» в верхнем правом углу.

Запуск нового расширения и настройка его параметров

Теперь у нас готовые данные к тестированию, и мы можем настроить фреймворк для нашего расширения. Вместо написания кода, используем готовое решение  Qlik Sense и изменим код под наши цели.

Заходим в директорию расширения. Директория по умолчанию находится по следующему пути My Documents\Qlik\Sense\Extensions. Дублируем расширение “SimpleTable”.

Запускаем расширение

Дублируем расширение “SimpleTable” и называем его “TwoDimScatter”. Затем открываем директорию. Вы увидите следующие файлы:

  • com-qliktech-simpletable.js – файл Javascript , который подгружает данные в Qlik Sense и создает пользовательскую визуализацию.
  • com-qliktech-simpletable.qext – файл настроек, который состоит из таких атрибутов как название расширения.
  • simpletable.css – файл стиля, где мы можем определить стиль визуализации (шрифты и цвета).
  • wbfolder.wbl – просто оставим как есть и не трогаем.

Обновите все имена файлов, кроме wbfolder.wbl на “twodimscatter”. Например, “com-qliktech-simpletable.js” станет “twodimscatter.js”.

Также нам необходимо добавить в эту директорию d3.min.js, который позволяет нам использовать библиотеку D3. Последняя версия связана с разделом Resources. В итоге получится такая структура файлов:

Qlik Sense источники 

Конфигурация файла Расширение

Открываем файл “twodimscatter.qext” в редакторе текста. У меня такие настройки:

1

2

3

4

5

6

7

8

9{

«name» : «Two Dimensional Scatter»,

«description» : «A scatter plot that uses two dimensions»,

«icon» : «table»,

«type» : «visualization»,

«version»: «1.0»,

«preview» : «table»,

«author»: «Speros»

}

Сохраняем и закрываем.

Готовим CSS

Открываем файл “twodimscatter.css” в редакторе текста. CSS состоит из правил стиля для элементов нашей визуализации. Теперь давайте оптимизируем наш файл и оставим только то, что нам нужно.

Первая строка имеет запись для “.qv-object-com-qliktech-simpletable div.qv-object-content-container”. “div.qv-object-content-container” – див-блок, которые содержит наше расширение. Первый класс из списка — “.qv-object-com-qliktech-simpletable”, описывает наш класс. Делаем так, чтобы CSS применялся только для вновь созданных объектов в расширении. Оставляем все как есть, кроме двух правок:

1) меняем название класса с “.qv-object-com-qliktech-simpletable” на “.qv-object-twodimscatter”.

2) удаляем строчку “overflow: auto;”

Весь остальной CSS удаляем. В итоге, файл CSS должен получиться таким:

1

2.qv-object-twodimscatter div.qv-object-content-container {

}

Настраиваем файл JS

Открывает Javascript-файл в текстовом редакторе. Файл определяет поведение объекта. Настраиваем конфигурацию и функции расширения, для начала.

Характеристики

В самой первой строчки написан определитель define(), который назначает порядок загрузки, а затем запускает функцию после загрузки. Define() — часть AMD API и доступна нам из нашего расширения, потому что Qlik Sense использует RequireJS.

Изменяем файл: jQuery, css и наш файл d3.min.js.

Меняем

[«jquery», «text!./simpletable.css»]

на

[«jquery», «text!./twodimscatter.css»,»./d3.min»]

Теперь код расширения будет сначала загружать эти файлы, прежде чем делать что-то еще.

НА ЗАМЕТКУ! Qlik Sense работает с jQuery, поэтому нам не нужно сохранять локальные копии расширения.

Настройки и определения

Проработав со всеми нужными нам файлами, меняем настройки и определения нашего расширения. В них определяется объем получаемых данных, а также определяется, сколько измерений и выражений нужно для запуска расширения.

В этом файле, в самом начале вы увидите такой код:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40return {

initialProperties : {

version: 1.0,

qHyperCubeDef : {

qDimensions : [],

qMeasures : [],

qInitialDataFetch : [{

qWidth : 10,

qHeight : 50

}]

}

},

definition : {

type : «items»,

component : «accordion»,

items : {

dimensions : {

uses : «dimensions»,

min : 1

},

measures : {

uses : «measures»,

min : 0

},

sorting : {

uses : «sorting»

},

settings : {

uses : «settings»,

items : {

initFetchRows : {

ref : «qHyperCubeDef.qInitialDataFetch.0.qHeight»,

label : «Initial fetch rows»,

type : «number»,

defaultValue : 50

},

}

}

}

},

В строке 2 создается initialProperties-объект. В 10 строке, qWidth определяется, сколько столбцов будет иметь расширение. Измените ширину qWidth с “10″ на “4″, поскольку у нас всего два измерения и две меры. Атрибут qHeight определяет, сколько строк может быть загружено. Измените значение с “50″на “1000″.

НА ЗАМЕТКУ! Qlik Sense .96, 1000 – максимальное число, введенных строк.

Строка 13 определяет ограничения строк и измерений. В строке 19 и 23 написано, что минимальное число измерений равно 1, а минимальное число мер — 0. Мы же изменим четко значения на две меры и два измерения.

В 19 строке меняем минимум с “1″ на “2″. Затем добавляем запятую и добавляем новую строку и выбираем максимальное значение равное двум. Делаем то же самое для мер. Получится вот так:

1

2

3

4

5

6

7

8

9

10dimensions : {

uses : «dimensions»,

min : 2,

max: 2

},

measures : {

uses : «measures»,

min : 2,

max: 2

},

В 32 строке создаются элементы расширения. Удаляем 32 и 39 строку. Результат должен выглядеть так:

1

2

3settings : {

uses : «settings»

}

Функция рисования

Последняя из наши настроек – работа с функцией рисования. Эта функция подключается каждый раз, когда меняется визуализация. Например, фильтрация данных в Qlik Sense вызывает функцию перерисовки визуализации. Для наших целей делаем такие изменения:

1) измените функцию по двум параметрам: $ и макет

function($element,layout) {

2) очистите текущее содержание

function($element,layout) {}

3) назначьте эти два элемента, чтобы мы могли видеть их содержимое

function($element,layout) {

console.log($element);

console.log(layout);

}

Console.log() будет обрабатывать все  значения и передавать их в консоль JavaScript, которую можно просмотреть в QS и в браузере. Функция рисования визуализации должна выглядеть так:

1

2

3

4paint : function($element,layout) {

console.log($element);

console.log(layout);

}

 

Запуск расширения в  Qlik Sense и просмотр

Давайте отдохнем от кодинга расширения и посмотрим, как оно работает. Мы также можем посмотреть на объекты, которые мы внесли в консоль.

Откройте созданное вами приложение Qlik Sense и создайте новый лист из окна просмотра приложений.

Qlik Sense прямые таблицы

Дайте листу имя и откройте его. Он первоначально будет пустым. В правом верхнем углу нажмите кнопку «Изменить», чтобы войти в режим редактирования. В левой части страницы, есть панель, где вы можете выбрать диаграммы, которые будем добавлять. Перейдите к двумерной диаграмме рассеяния и перетащите ее на дэшборд.

Qlik Sense прямые таблицы

После добавления диаграммы, Qlik даст вам возможность добавлять свои измерения и меры. Добавьте «Уровень развития» в качестве первого измерения и «Страна» в качестве второго измерения. Для мер, нам нужно будет выбрать поле, чтобы определить то, что в нем будет рассчитываться.

 Выберите «Ожирение%» и «Ожидаемая продолжительность жизни в возрасте 60» для мер. Для функций могут быть использованы «Сумма» или «AVG». Поскольку эти значения записываются на страновом уровне, мы будем суммировать единичные значения. Я предлагаю использовать функцию AVG, чтобы возвращалось верное значение, если будет идти глубже в данные.

Qlik Sense прямые таблицы

После того, как размеры и меры добавлены, мы можем настроить ярлыки и метки. На правой панели, нажмите на заголовок измерения, чтобы расширить панель. Каждая мера должна быть указана.

Откроем Инструменты разработчика (можно открыть через Ctrl + Shift + щелчок правой  кнопкой мыши на странице) и выбираем «Показать инструменты разработчика».

 Выберите «Консоль» сверху, чтобы посмотреть на консоль JavaScript. Вы можете использовать консоль, чтобы исследовать эти элементы. Если открыть консоль, будет вот такое изображение:

Qlik Sense расширение

На картинке выше, видно, где хранится строка Албании. Мы видим, что макет имеет объект, называемый qHyperCube, который содержит массив с именем qDataPages, внутри которого есть массив QMatrix. Он описывает все строки данных. Каждый объект в строке представляет собой другой столбец. Мы можем использовать эту информацию, чтобы написать наш код JavaScript, который будет собирать данные для визуализации d3.

 Qlik Sense расширение

Вставляем и изменяем код D3

Открываем файл “twodimscatter.js” в текстовом редакторе.

Работаем с данными и div-блоком

Первое, что нам нужно сделать – извлечь полезную информацию из нашего расширения. Нам нужны данные, чтобы задать ширину и высоту объекта и уникальное id нашей диаграммы. Уникальный идентификатор пригодится, когда будем создавать новый элемент DOM.

Теперь, когда мы использовали консоль, чтобы выяснить, где наш источник данных находится и меры, мы можем строить нашу область данных в JavaScript с помощью следующих строк кода

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16// get qMatrix data array

var qMatrix = layout.qHyperCube.qDataPages[0].qMatrix;

// create a new array that contains the measure labels

var measureLabels = layout.qHyperCube.qMeasureInfo.map(function(d) {

return d.qFallbackTitle;

});

// Create a new array for our extension with a row for each row in the qMatrix

var data = qMatrix.map(function(d) {

// for each element in the matrix, create a new object that has a property

// for the grouping dimension, the first metric, and the second metric

return {

«Dim1»:d[0].qText,

«Metric1»:d[2].qNum,

«Metric2»:d[3].qNum

}

});

Теперь у нас есть массив данных, который называется measureLabels, содержащий текстовые значения наших меток.

Теперь давайте пропишем ширину, высоту и идентификатор объекта диаграммы. Получит так.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16// Chart object width

var width = $element.width();

// Chart object height

var height = $element.height();

// Chart object id

var id = «container_» + layout.qInfo.qId;

// Check to see if the chart element has already been created

if (document.getElementById(id)) {

// if it has been created, empty it’s contents so we can redraw it

$(«#» + id).empty();

}

else {

// if it hasn’t been created, create it with the appropiate id and size

$element.append($(‘<div />’).attr(«id», id).width(width).height(height));

}

И наконец, создаем функцию визуализации.

1 viz(data,measureLabels,width,height,id);

Вся функция работы с визуализацией получится такой:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38paint : function($element,layout) {

// get qMatrix data array

var qMatrix = layout.qHyperCube.qDataPages[0].qMatrix;

// create a new array that contains the measure labels

var measureLabels = layout.qHyperCube.qMeasureInfo.map(function(d) {

return d.qFallbackTitle;

});

// Create a new array for our extension with a row for each row in the qMatrix

var data = qMatrix.map(function(d) {

// for each element in the matrix, create a new object that has a property

// for the grouping dimension, the first metric, and the second metric

return {

«Dim1»:d[0].qText,

«Metric1»:d[2].qNum,

«Metric2»:d[3].qNum

}

});

 

// Chart object width

var width = $element.width();

// Chart object height

var height = $element.height();

// Chart object id

var id = «container_» + layout.qInfo.qId;

 

// Check to see if the chart element has already been created

if (document.getElementById(id)) {

// if it has been created, empty it’s contents so we can redraw it

$(«#» + id).empty();

}

else {

// if it hasn’t been created, create it with the appropiate id and size

$element.append($(‘<div />;’).attr(«id», id).width(width).height(height));

}

 

viz(data,measureLabels,width,height,id);

 

}

Создаем новую функцию визуализации viz в верхней части файла JS, вне выражения define(). Она должна описывать соответствующее число значений:

1

2var viz = function(data,labels,width,height,id) {

};

Копируем код D3

Запускаем d3 и копируем его в JavaScript. Часть JavaScript находится внутри html-файла, внутри тега <script> в теле страницы. Вставляем такой код в функцию визуализации. Получится так:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86var margin = {top: 20, right: 20, bottom: 30, left: 40},

width = 960 — margin.left — margin.right,

height = 500 — margin.top — margin.bottom;

 

var x = d3.scale.linear()

.range([0, width]);

 

var y = d3.scale.linear()

.range([height, 0]);

 

var color = d3.scale.category10();

 

var xAxis = d3.svg.axis()

.scale(x)

.orient(«bottom»);

 

var yAxis = d3.svg.axis()

.scale(y)

.orient(«left»);

 

var svg = d3.select(«body»).append(«svg»)

.attr(«width», width + margin.left + margin.right)

.attr(«height», height + margin.top + margin.bottom)

.append(«g»)

.attr(«transform», «translate(» + margin.left + «,» + margin.top + «)»);

 

d3.tsv(«data.tsv», function(error, data) {

data.forEach(function(d) {

d.sepalLength = +d.sepalLength;

d.sepalWidth = +d.sepalWidth;

});

 

x.domain(d3.extent(data, function(d) { return d.sepalWidth; })).nice();

y.domain(d3.extent(data, function(d) { return d.sepalLength; })).nice();

 

svg.append(«g»)

.attr(«class», «x axis»)

.attr(«transform», «translate(0,» + height + «)»)

.call(xAxis)

.append(«text»)

.attr(«class», «label»)

.attr(«x», width)

.attr(«y», -6)

.style(«text-anchor», «end»)

.text(«Sepal Width (cm)»);

 

svg.append(«g»)

.attr(«class», «y axis»)

.call(yAxis)

.append(«text»)

.attr(«class», «label»)

.attr(«transform», «rotate(-90)»)

.attr(«y», 6)

.attr(«dy», «.71em»)

.style(«text-anchor», «end»)

.text(«Sepal Length (cm)»)

 

svg.selectAll(«.dot»)

.data(data)

.enter().append(«circle»)

.attr(«class», «dot»)

.attr(«r», 3.5)

.attr(«cx», function(d) { return x(d.sepalWidth); })

.attr(«cy», function(d) { return y(d.sepalLength); })

.style(«fill», function(d) { return color(d.species); });

 

var legend = svg.selectAll(«.legend»)

.data(color.domain())

.enter().append(«g»)

.attr(«class», «legend»)

.attr(«transform», function(d, i) { return «translate(0,» + i * 20 + «)»; });

 

legend.append(«rect»)

.attr(«x», width — 18)

.attr(«width», 18)

.attr(«height», 18)

.style(«fill», color);

 

legend.append(«text»)

.attr(«x», width — 24)

.attr(«y», 9)

.attr(«dy», «.35em»)

.style(«text-anchor», «end»)

.text(function(d) { return d; });

 

});

Изменяем код D3

Вот, что нам нужно изменить для того, чтобы все шло по плану:

  1. Убираем описание загрузки в коде D Наши данные уже загружены через расширение.
  2. Изменяем размер значений.
  3. Настраиваем SVG.
  4. Меняем ссылки на данные.
  1. Удаляем загрузку данных D3

Вот, что мы видим

1

2

3

4

5d3.tsv(«data.tsv», function(error, data) {

data.forEach(function(d) {

d.sepalLength = +d.sepalLength;

d.sepalWidth = +d.sepalWidth;

});

Функция d3.tsv имеет два параметра: путь к файлу, а также функцию возврата для вычисления. Функция возврата включается как только запускается код создания визуализации, после загрузки файла “data.tsv”. Мы уберем, как это обращение, так и файл data.forEach. Результат будет таким:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78var margin = {top: 20, right: 20, bottom: 30, left: 40},

width = 960 — margin.left — margin.right,

height = 500 — margin.top — margin.bottom;

 

var x = d3.scale.linear()

.range([0, width]);

 

var y = d3.scale.linear()

.range([height, 0]);

 

var color = d3.scale.category10();

 

var xAxis = d3.svg.axis()

.scale(x)

.orient(«bottom»);

 

var yAxis = d3.svg.axis()

.scale(y)

.orient(«left»);

 

var svg = d3.select(«body»).append(«svg»)

.attr(«width», width + margin.left + margin.right)

.attr(«height», height + margin.top + margin.bottom)

.append(«g»)

.attr(«transform», «translate(» + margin.left + «,» + margin.top + «)»);

 

x.domain(d3.extent(data, function(d) { return d.sepalWidth; })).nice();

y.domain(d3.extent(data, function(d) { return d.sepalLength; })).nice();

 

svg.append(«g»)

.attr(«class», «x axis»)

.attr(«transform», «translate(0,» + height + «)»)

.call(xAxis)

.append(«text»)

.attr(«class», «label»)

.attr(«x», width)

.attr(«y», -6)

.style(«text-anchor», «end»)

.text(«Sepal Width (cm)»);

 

svg.append(«g»)

.attr(«class», «y axis»)

.call(yAxis)

.append(«text»)

.attr(«class», «label»)

.attr(«transform», «rotate(-90)»)

.attr(«y», 6)

.attr(«dy», «.71em»)

.style(«text-anchor», «end»)

.text(«Sepal Length (cm)»)

 

svg.selectAll(«.dot»)

.data(data)

.enter().append(«circle»)

.attr(«class», «dot»)

.attr(«r», 3.5)

.attr(«cx», function(d) { return x(d.sepalWidth); })

.attr(«cy», function(d) { return y(d.sepalLength); })

.style(«fill», function(d) { return color(d.species); });

 

var legend = svg.selectAll(«.legend»)

.data(color.domain())

.enter().append(«g»)

.attr(«class», «legend»)

.attr(«transform», function(d, i) { return «translate(0,» + i * 20 + «)»; });

 

legend.append(«rect»)

.attr(«x», width — 18)

.attr(«width», 18)

.attr(«height», 18)

.style(«fill», color);

 

legend.append(«text»)

.attr(«x», width — 24)

.attr(«y», 9)

.attr(«dy», «.35em»)

.style(«text-anchor», «end»)

.text(function(d) { return d; });

  1. Обновляем размер значений

Вторая и третья строка D3 кода определяет, какая ширина и высота значений будет, за минусом отступов. Выглядит так:

1

2width = width — margin.left — margin.right,

height = height — margin.top — margin.bottom;

  1. Настройка элемента svg

Вставляем новый элемент svg.

1 var svg = d3.select(«#»+id).append(«svg»)
  1. Использование корректных имен

Просмотрим код D3, увидим, что там используются изначальные названия таблиц. Например:

1

2

3

4

5

6

7

8svg.selectAll(«.dot»)

.data(data)

.enter().append(«circle»)

.attr(«class», «dot»)

.attr(«r», 3.5)

.attr(«cx», function(d) { return x(d.sepalWidth); })

.attr(«cy», function(d) { return y(d.sepalLength); })

.style(«fill», function(d) { return color(d.species); });

Все ссылки надо заменить с d.sepalWidth на d.Metric1; d.sepalLength на d.Metric2, а также с d.species на d.Dim1.

Ярлыки для осей представлены вот так:

1

2

3

4

5

6

7

8

9

10svg.append(«g»)

.attr(«class», «x axis»)

.attr(«transform», «translate(0,» + height + «)»)

.call(xAxis)

.append(«text»)

.attr(«class», «label»)

.attr(«x», width)

.attr(«y», -6)

.style(«text-anchor», «end»)

.text(«Sepal Width (cm)»);

Вместо того чтобы делать тяжелый код для осей, мы можем просто использовать переменные:

1

2

3

4

5

6

7

8

9

10svg.append(«g»)

.attr(«class», «x axis»)

.attr(«transform», «translate(0,» + height + «)»)

.call(xAxis)

.append(«text»)

.attr(«class», «label»)

.attr(«x», width)

.attr(«y», -6)

.style(«text-anchor», «end»)

.text(labels[0]);

Получит так:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82var viz = function (data,labels,width,height,id) {

 

var margin = {top: 20, right: 20, bottom: 30, left: 40},

width = width — margin.left — margin.right,

height = height — margin.top — margin.bottom;

 

var x = d3.scale.linear()

.range([0, width]);

 

var y = d3.scale.linear()

.range([height, 0]);

 

var color = d3.scale.category10();

 

var xAxis = d3.svg.axis()

.scale(x)

.orient(«bottom»);

 

var yAxis = d3.svg.axis()

.scale(y)

.orient(«left»);

 

var svg = d3.select(«#»+id).append(«svg»)

.attr(«width», width + margin.left + margin.right)

.attr(«height», height + margin.top + margin.bottom)

.append(«g»)

.attr(«transform», «translate(» + margin.left + «,» + margin.top + «)»);

 

x.domain(d3.extent(data, function(d) { return d.Metric1; })).nice();

y.domain(d3.extent(data, function(d) { return d.Metric2; })).nice();

 

svg.append(«g»)

.attr(«class», «x axis»)

.attr(«transform», «translate(0,» + height + «)»)

.call(xAxis)

.append(«text»)

.attr(«class», «label»)

.attr(«x», width)

.attr(«y», -6)

.style(«text-anchor», «end»)

.text(labels[0]);

 

svg.append(«g»)

.attr(«class», «y axis»)

.call(yAxis)

.append(«text»)

.attr(«class», «label»)

.attr(«transform», «rotate(-90)»)

.attr(«y», 6)

.attr(«dy», «.71em»)

.style(«text-anchor», «end»)

.text(labels[1])

 

svg.selectAll(«.dot»)

.data(data)

.enter().append(«circle»)

.attr(«class», «dot»)

.attr(«r», 3.5)

.attr(«cx», function(d) { return x(d.Metric1); })

.attr(«cy», function(d) { return y(d.Metric2); })

.style(«fill», function(d) { return color(d.Dim1); });

 

var legend = svg.selectAll(«.legend»)

.data(color.domain())

.enter().append(«g»)

.attr(«class», «legend»)

.attr(«transform», function(d, i) { return «translate(0,» + i * 20 + «)»; });

 

legend.append(«rect»)

.attr(«x», width — 18)

.attr(«width», 18)

.attr(«height», 18)

.style(«fill», color);

 

legend.append(«text»)

.attr(«x», width — 24)

.attr(«y», 9)

.attr(«dy», «.35em»)

.style(«text-anchor», «end»)

.text(function(d) { return d; });

 

}

Изменяем CSS

Завершающий шаг — изменение CSS. Если вы посмотрите на оригинал d3 диаграммы в HTML, у вас будет такой код:

1

2

3

4

5

6

7

8

9

10

11

12

13

14body {

font: 10px sans-serif;

}

 

.axis path,

.axis line {

fill: none;

stroke: #000;

shape-rendering: crispEdges;

}

 

.dot {

stroke: #000;

}

Мы можем изменить код и вставить его twodimscatter.css file. Что надо изменить:

  1. Изменить стиль “body”
  2. Добавить класс “.qv-object-twodimscatter” , чтобы наш CSS не влиял не на какие элементы вне диаграммы.

Изменения в twodimscatter.css выглядят так:

1

2

3

4

5

6

7

8

9

10

11

12

13

14.qv-object-twodimscatter div.qv-object-content-container {

font: 10px sans-serif;

}

 

.qv-object-twodimscatter .axis path,

.qv-object-twodimscatter .axis line {

fill: none;

stroke: #000;

shape-rendering: crispEdges;

}

 

.qv-object-twodimscatter .dot {

stroke: #000;

}

Просмотр расширения

После всех изменений все сохраняем и смотрим, как изменилось наше приложение. Открываем приложение Qlik Sense и находим лист с расширением.

НА ЗАМЕТКУ! Если лист уже открыт, то обновляем страницу кнопкой “F5″.

Теперь на графике добавилась легенда, цветная.

 Qlik Sense расширение

Напоследок

Мы можем продолжить работу с файлом JavaScript, чтобы снабдить визуализацию интерактивными компонентами и всплывающими ярлыками. Но в этот раз уже пора остановиться – позже вам напишу, если вам интересно узнать, как это сделать.

Код для нашего расширения. Файл JavaScript весь откомментирован, так что все качественно прописано, поэтому изучайте.

До новых встреч в эфире! Делитесь своим мнением в комментариях!