Визуализация на карте распределения голосов по Москве на выборах президента 2018

  • Tutorial

Введение


Выборы — крайне загадочный процесс, при просмотре значений результатов которого не совсем понятна общая картина. Я решил показать их на карте Москвы с делением по районам c помощью технологий InterSystems, которые обеспечивают и хранение, и анализ данных. В данном случае использовалась платформа для интеграции и разработки приложений InterSystems Ensemble, но с равным успехом можно развернуть описанное ниже решение и на мультимодельной СУБД InterSystems Caché, и на новом продукте InterSystems IRIS Data Platform.

Этапы:


Для показа карты мы выполним следующие действия:

  • сбор данных голосования, которые будут отображаться на карте;
  • приведение собранных данных к необходимому формату;
  • создание хранимых (persistent) классов и их заполнение;
  • создание OLAP-куба;
  • создание пивота (ов);
  • создание и настройка дашборда;
  • установка проектов MDX2JSON и DeepSeeWeb;
  • сбор координат полигонов;
  • создание термлистов и добавление элемента управления.

Сбор данных


Для отображения данных выборов президента нам необходима модель данных.
Создадим следующие классы:

  • map.MoscowElections2018 — класс с данными результатов выборов
  • map.MoscowRegion — справочник районов Москвы, на который будут ссылаться объекты класса map.MoscowElections2018

Начнем с создания класса map.MoscowRegion
Возьмем со страниц на википедии данные по районам и административным округам, создадим для этих данных XML-enabled класс

map.MoscowRegion
Class map.MoscowRegion Extends (%Persistent, %XML.Adaptor)
{
Index idIndex On id [ IdKey, PrimaryKey, Unique ];

/// Код
Property id As %String [ Required ];

/// Название админ. единицы
Property name As %String(MAXLEN = 250);

/// Площадь, га
Property area As %Float;

/// Население
Property population As %Integer;

/// Название вышестоящей адм. единицы
Property parentName As %String;

/// Вышестоящая адм. единица
Property parent As map.MoscowRegion;

/// Вышестоящая адм. единица
Property parentId As %Integer;

ClassMethod populateRegions() As %Status
{
	#dim sc As %Status = $$$OK
	#dim stream As %Stream.Object = ##class(%Dictionary.CompiledXData).%OpenId(..%ClassName(1) _ "||" _ "regions").Data
	#dim reader As %XML.Reader = ##class(%XML.Reader).%New()

	set sc = ..%KillExtent()
	if $$$ISERR(sc) quit sc

	set sc = reader.OpenStream(stream, "literal")
	if $$$ISERR(sc) quit sc
	
	do reader.Correlate("region", ..%ClassName(1))
	
	#dim obj As map.MoscowRegion
	while reader.Next(.obj, .sc)
	{
		if $$$ISERR(sc) quit

		if (obj.parentId) {
			set obj.parent = ..%OpenId(obj.parentId)
		}

		set sc = obj.%Save()
		if $$$ISERR(sc) quit
		
		set obj = ""
	}
	
	quit sc
}

XData regions
{
}
}


И приведем полученные данные к формату XML

XData из map.MoscowRegion
<regions>
    <region>
        <name>Центральный округ</name>
        <parentName>-</parentName>
        <area>66.18</area>
        <population>769630</population>
        <id>1001</id>
    </region>
           ...
    <region>
        <name>поселение Щербинка</name>
        <parentName>Новомосковский административный округ</parentName>
        <area>7.62</area>
        <population>47504</population>
        <id>2146</id>
        <parentId>1012</parentId>
    </region>
</regions>


За данными выборов я обратился на сайт Центральной избирательной комиссии Российской Федерации. К сожалению нормального API с возможностью получить подходящий набор данных я не нашел, поэтому пришлось брать все из сводной таблицы результатов. Там при помощи фильтров можно найти результаты выборов не только президента РФ, но и выборы депутатов и глав различных административных единиц Российской Федерации. Так как нас интересуют именно выборы президента, то находим подходящую сводную таблицу результатов выборов по Москве, выгружаем, трансформируем к подходящему формату (для данного примера был выбран формат XML, так как данный формат легко можно использовать для импорта в нашу базу данных под управлением платформы InterSystems).
В итоге имеем примерно следующий формат данных:

Данные выборов в формате XML
<regions>
    <region>
        <regionName>район Богородское</regionName>
        <regionId>2013</regionId>
        <votersIncludedInVotersList>65519</votersIncludedInVotersList>
        <ballotsReceivedByPrecinctElectionCommission>58800</ballotsReceivedByPrecinctElectionCommission>
        <ballotsIssuedToVotersWhoVotedEarly>0</ballotsIssuedToVotersWhoVotedEarly>
        <ballotsIssuedInPollingStationOnElectionDay>38056</ballotsIssuedInPollingStationOnElectionDay>
        <ballotsIssuedOutsidePollingStationOnElectionDay>1326</ballotsIssuedOutsidePollingStationOnElectionDay>
        <canceledBallots>19418</canceledBallots>
        <ballotsInMobileBallotBoxes>1326</ballotsInMobileBallotBoxes>
        <ballotsInStationaryBallotBoxes>38003</ballotsInStationaryBallotBoxes>
        <invalidBallots>538</invalidBallots>
        <validBallots>38791</validBallots>
        <lostBallots>0</lostBallots>
        <ballotsNotRecorded>0</ballotsNotRecorded>
        <Baburin>356</Baburin>
        <Grudinin>4738</Grudinin>
        <Zhirinovsky>2060</Zhirinovsky>
        <Putin>27833</Putin>
        <Sobchak>1602</Sobchak>
        <Suraykin>300</Suraykin>
        <Titov>668</Titov>
        <Yavlinsky>1234</Yavlinsky>
    </region>
    ...
    <region>
    <regionName>поселение Сосенское</regionName>
    <regionId>2142</regionId>
    <votersIncludedInVotersList>103818</votersIncludedInVotersList>
    <ballotsReceivedByPrecinctElectionCommission>86145</ballotsReceivedByPrecinctElectionCommission>
    <ballotsIssuedToVotersWhoVotedEarly>0</ballotsIssuedToVotersWhoVotedEarly>
    <ballotsIssuedInPollingStationOnElectionDay>63192</ballotsIssuedInPollingStationOnElectionDay>
    <ballotsIssuedOutsidePollingStationOnElectionDay>1123</ballotsIssuedOutsidePollingStationOnElectionDay>
    <canceledBallots>21829</canceledBallots>
    <ballotsInMobileBallotBoxes>1123</ballotsInMobileBallotBoxes>
    <ballotsInStationaryBallotBoxes>63139</ballotsInStationaryBallotBoxes>
    <invalidBallots>796</invalidBallots>
    <validBallots>63466</validBallots>
    <lostBallots>1</lostBallots>
    <ballotsNotRecorded>0</ballotsNotRecorded>
    <Baburin>439</Baburin>
    <Grudinin>8723</Grudinin>
    <Zhirinovsky>3110</Zhirinovsky>
    <Putin>47192</Putin>
    <Sobchak>1860</Sobchak>
    <Suraykin>345</Suraykin>
    <Titov>734</Titov>
    <Yavlinsky>1063</Yavlinsky>
</region>
</regions>


Создал для данных XML-enabled класс map.MoscowElections2018 на платформе InterSystems:

Код класса map.MoscowElections2018
Class map.MoscowElections2018 Extends (%Persistent, %XML.Adaptor)
{

/// Ссылка на регион
Property region As map.MoscowRegion;

/// Имя региона
Property regionName As %String;

/// ID региона
Property regionId As %Integer;

/// Число избирателей, включенных в список избирателей
Property votersIncludedInVotersList As %Integer;

/// Число избирательных бюллетеней, полученных участковой избирательной комиссией
Property ballotsReceivedByPrecinctElectionCommission As %Integer;

/// Число избирательных бюллетеней, выданных избирателям, проголосовавшим досрочно
Property ballotsIssuedToVotersWhoVotedEarly As %Integer;

/// Число избирательных бюллетеней, выданных в помещении для голосования в день голосования
Property ballotsIssuedInPollingStationOnElectionDay As %Integer;

/// Число избирательных бюллетеней, выданных вне помещения для голосования в день голосования
Property ballotsIssuedOutsidePollingStationOnElectionDay As %Integer;

/// Число погашенных избирательных бюллетеней
Property canceledBallots As %Integer;

/// Число избирательных бюллетеней в переносных ящиках для голосования
Property ballotsInMobileBallotBoxes As %Integer;

/// Число бюллетеней в стационарных ящиках для голосования
Property ballotsInStationaryBallotBoxes As %Integer;

/// Число недействительных избирательных бюллетеней
Property invalidBallots As %Integer;

/// Число действительных избирательных бюллетеней
Property validBallots As %Integer;

/// Число утраченных избирательных бюллетеней
Property lostBallots As %Integer;

/// Число избирательных бюллетеней, не учтенных при получении
Property ballotsNotRecorded As %Integer;

/// Бабурин Сергей Николаевич
Property Baburin As %Integer;

/// Грудинин Павел Николаевич
Property Grudinin As %Integer;

/// Жириновский Владимир Вольфович
Property Zhirinovsky As %Integer;

/// Путин Владимир Владимирович
Property Putin As %Integer;

/// Собчак Ксения Анатольевна
Property Sobchak As %Integer;

/// Сурайкин Максим Александрович
Property Suraykin As %Integer;

/// Титов Борис Юрьевич
Property Titov As %Integer;

/// Явлинский Григорий Алексеевич
Property Yavlinsky As %Integer;

ClassMethod populateElectionsData() As %Status
{
	#dim sc As %Status = $$$OK
	#dim stream As %Stream.Object = ##class(%Dictionary.CompiledXData).%OpenId(..%ClassName(1) _ "||" _ "elections").Data
	#dim reader As %XML.Reader = ##class(%XML.Reader).%New()

	set sc = ..%KillExtent()
	if $$$ISERR(sc) quit sc

	set sc = reader.OpenStream(stream, "literal")
	if $$$ISERR(sc) quit sc
	
	do reader.Correlate("region", ..%ClassName(1))
	
	#dim obj As map.MoscowElections2018
	while reader.Next(.obj, .sc)
	{
		if $$$ISERR(sc) quit

		if (obj.regionId) {
			set obj.region = ##class(map.MoscowRegion).%OpenId(obj.regionId)
		}

		set sc = obj.%Save()
		if $$$ISERR(sc) quit
		
		set obj = ""
	}
	
	quit sc
}

XData elections
{
}
}


Создание куба


Для создания OLAP-куба мы используем веб-приложение DeepSee Architect, чтобы перейти на него откроем Портал Управления Системой → DeepSee → Выбор области → Architect.
В том случае если вы не видите вашей области в списке доступных DeepSee областей — перейдите в Портал Управления Системой → Меню → Управление веб-приложениями → /csp/область, и там в поле «Включен» поставьте галочку «DeepSee» и нажмите кнопку сохранить. После этого выбранная область должна появиться в списке доступных DeepSee областей.
Создаем новый куб.

Нажав на кнопку «Создать» попадаем на экран создания нового куба, там необходимо установить следующие параметры:

  • Имя куба — название куба используемое в запросах к нему
  • Отображаемое Имя — локализуемое название куба (перевод осуществляется стандартными механизмами InterSystems)
  • Источник Cube — использовать таблицу фактов или другой куб в качестве источника данных
  • Исходный класс — если на предыдущем шаге был выбран класс, то указываем в качестве таблицы фактов класс map.MoscowElections2018.
  • Имя класса для куба — имя класса, в котором будет храниться определение куба. Создается автоматически
  • Описание класса — произвольное описание

Вот как выглядит наш новый куб:



Определяем свойства куба.


После нажатия кнопки OK будет создан новый куб:



Слева выводятся свойства базового и связанных с ним по “снежинке” классов, которые можно использовать при построении куба.

Центральная часть экрана — это скелет куба. Его можно наполнить свойствами класса с помощью drag-n-drop из области базового класса, либо добавляя элементы вручную. Основными элементами куба являются измерения, показатели и списки.

Измерения (Dimensions)


Измерения — это элементы куба, которые группируют записи таблицы фактов. В измерения обычно относят “качественные” атрибуты базового класса, которые разбивают все записи таблицы фактов по тем или иным срезам.

Например нам бы хотелось группировать все факты по Муниципальному образованию и при углублении — по району.

Для разбиения фактов по территориальной принадлежности прекрасно подойдет свойство Territory. Так как у нас иерархия начинается с муниципального образования, то на первом уровне должно быть измерение родителя региона, то есть — мы нажимаем на стрелочку у свойства region в левом списке, в раскрывшемся списке также раскрываем свойство parent и перетягиваем name на область измерений — в результате Архитектор добавит в куб измерение name с одной иерархией H1 и одним уровнем name. для удобства переименуем измерение из name в Territory и первый уровень в Region.

Измерения помимо группировки позволяют строить иерархии вложенности фактов от общего к частному. Для этого добавим уровень Subregion перетаскиванием имени региона на иерархию H1 добавим свойства население и имя в оба измерения и также пока магическое свойство coordsKey со значением имени измерения — данное свойство будет использовано для поиска координат соответствующего данному муниципальному образованию/району полигона для подсвечивания на карте. Укажем отображаемые названия в подписях к измерению и уровню.



Показатели (Measures)


Показатели или метрики это такие элементы куба, куда относят какие-либо «количественные» данные, которые необходимо посчитать для «качественных» измерений куба (Dimensions).

Например в таблице фактов такими показателями могут быть свойства:

  • population (Население),
  • validBallots (Число действительных избирательных бюллетеней),
  • votersIncludedInVotersList (Число избирателей),
  • отдельные показатели по каждому из восьми кондидатов
  • Baburin (Бабурин СН),
  • Grudinin (Грудинин ПН),
  • Putin (Путин ВВ),
  • Sobchak (Собчак КА),
  • Suraykin (Сурайкин МА),
  • Titov (Титов БЮ),
  • Yavlinsky (Явлинский ГА),
  • Zhirinovsky (Жириновский ВВ).

Перетянем каждое свойство на область показателей и создадим числовой показатель типа Integer функцией SUM, которая будет считать общее количество голосов в текущем срезе. Также для каждого показателя укажем отображаемое имя.



Компиляция куба


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

Скомпилируем класс куба (Кнопка «Компилировать»). Если ошибок компиляции нет, значит куб создан правильно и можно наполнить его данными.

Для этого нужно нажать «Построить куб» — в результате DeepSee загрузит данные из таблицы фактов в хранилище данных куба.

Для работы с данными куба нам пригодится другое веб-приложение — DeepSee Analyzer.

Построение сводной таблицы (Pivot)


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

В рабочем окне Аналайзера слева мы видим элементы созданного куба: показатели и измерения. Комбинируя их мы строим запросы к кубу на языке MDX — аналоге языка SQL для многомерных OLAP кубов.

Чтобы создать сводную таблицу перетянем в поле колонок измерения Бабурин СН, Грудинин ПН, Путин ВВ, Собчак КА, Сурайкин МА, Титов БЮ, Явлинский ГА, Жириновский ВВ. Показателем выберем «Административный округ». В результате получим таблицу количества по административному округу с возможностью углубления (DrillDown — переход по иерархии измерения от общего к частному) в районы.



В Аналайзере двойной щелчок по заголовку измерения приводит переходу к следующему по иерархии измерению (DrillDown). В данном случае двойной клик по административному округу приведет к переходу к районам этого административного округа. В итоге можно посмотреть сколько было отдано голосов в разрезе по районам.

Также для подсвечивания определенных АО/районов нам необходим показатель, по которому будет высчитываться цвет данного полигона — данное значение будет браться из колонки со спец. именем ColorHSLValue (ссылка на инструкцию по настройке виджетов использующих карты приведен в конце статьи) — чем выше значение чем ближе цвет будет к красному и к зеленому в обратном случае. Для выведения названия полигона при наведении на него курсора используется спец. имя колонки TooltipValue. Для текста в всплывающем окне, которое появляется при нажатии на определенный полигон используйте имя измерения PopupValue, есть возможность использовать html для разметки значения.

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

Список специальных полей для карт


ColorHSLValue:
Тип элемента: Показатель
Имя элемента: ColorHSLValue
Тип: Число
Описание: Определяет цвет полигона от зелёного к красному в зависимости от значения.
Выражение:

[Measures].[attandance]/[Measures].[votersIncludedInVotersList]

является количество явившихся на выборы результатом отношения количества проголосовавших в данном АО/районе, таким образом чем выше данная пропорция — тем ближе цвет к красному.

PopupValue:
Тип элемента: Измерение
Имя измерения: custom
Имя элемента: PopupValue
Тип: Строка
Описание: Определяет цвет полигона от зелёного к красному в зависимости от значения.
Выражение:

"<b>" + [Territory].[H1].[Region].CurrentMember.Properties("name") + "</b><br/>Население: " + [Measures].[Population] + " чел.<br/>Число избирателей: " + [Measures].[votersIncludedInVotersList] + "чел."

будет выведено имя данного АО/региона, население, количество проголосовавших избирателей

TooltipValue:
Тип элемента: Измерение
Имя измерения: custom
Имя элемента: TooltipValue
Тип: Строка
Описание: Определяет сообщение появляющееся при наведении на полигон.
Выражение:

[Territory].[H1].[Region].CurrentMember.Properties("name")

И после добавления данных колонок пивот выглядит следующим образом:



Сохраним данный пивот как MoscowElections/mainPivot2018.

Также создадим еще один пивот с информацией по всем избираемым кандидатам для выведения в виде пай-чара.

Перенесем показатели всех кандидатов в колонку «Показатели» и выберите в параметрах показателей — «Разместить показатели на» — «строки»



Сохраним получившийся пивот как MoscowElections/countPivot2018 и перейдем к созданию индикаторной панели

Построение панели индикаторов (Dashboard)


Портал Пользователя — это веб-приложение для создания и использования дашбордов (панелей индикаторов). Дашборды содержат виджеты: таблицы, графики и карты на основе сводных таблиц, созданных аналитиками в Аналайзере.

Для перехода к Порталу Пользователя DeepSee откроем Портал Управления Системой → DeepSee → Выбор области → Портал Пользователя.



Создадим новый дашборд нажав на стрелку справа → добавить → Добавить индикаторную панель.



Создадим три виджета.

Для создания — нажмем на стрелку справа → Виджеты → "+" → выберем тип виджета в левом списке → источник данных и имя виджета:

Виджет с картой:

Тип виджета — Карта → Карта
Источник данных — MoscowElections/mainPivot2018
Имя виджета — moscowElectionsMap

Табличный виджет с данными с карты:

Тип виджета — Сводные таблицы и диаграммы → Таблица
Ссылка на — moscowElectionsMap
Имя виджета — tableWidget

Пай-чарт виджет с данными кандитатов:

Тип виджета — Сводные таблицы и диаграммы → Круговая диаграмма
Источник данных — MoscowElections/countPivot2018

Для второго и третьего виджетов необходимо создать элементы управления. Для табличного виджета — элемент управления, с помощью которого мы определим какие из поступающих колоном мы будем отображать (Напомню, что в пивоте мы определили спец. колонки которые нужны для карты, но которые не стоит отображать в табличном виджете). Для третьего — фильтр по АО/районам, значение которого будет устанавливаться автоматически при нажатии на любой АО/район. Сделать это можно следующим образом — нажмем на стрелку справа → Виджеты → tableWidget → Элементы управления → "+"

Расположение — Виджет
Цель — tableWidget
Действие — Установить спец. столбца
Тип — hidden

После подтверждения создания элемента управления — определим показываемые столбцы — необходимый формат — MDX

{[Measures].[Baburin],[Measures].[Grudinin],[Measures].[Zhirinovsky],[Measures].[Putin],[Measures].[Sobchak],[Measures].[Suraykin],[Measures].[Titov],[Measures].[Yavlinsky]}



Элемент управления для пай-чар виджета мы создадим в виджете-карте.

Расположение — Щелчок мыши
Цель — Виджет3
Действие — Применить фильтр

После этого сохраним дашборд.

Установка MDX2JSON и DeepSeeWeb


Для визуализации созданного дашборда можно использовать следующие OpenSource решения:

  • MDX2JSON — REST API предоставляет информацию о кубах, пивотах, дашбордах и многих других элементах DeepSee, в частности — результатах исполнения MDX запросов, что позволяет встраивать пользовательский интерфейс аналитического решения на DeepSee в любое современное Web или мобильное приложение.
  • DeepSeeWeb — AngularJS приложение, предоставляющее альтернативную реализацию портала пользователя DeepSee. Может быть легко кастомизирован. Использует MDX2JSON в качестве бэкэнда.

Установка MDX2JSON


Для установки MDX2JSON надо:

  1. Загрузить Installer.xml и импортировать его в любую область с помощью Studio, Портала Управления Системой или Do $System.OBJ.Load(file).
  2. Выполнить в терминале (пользователем с ролью %ALL): Do ##class(MDX2JSON.Installer).setup()

Для проверки установки надо открыть в браузере страницу http://server:port/MDX2JSON/Test?Debug. Возможно потребуется ввести логин и пароль (в зависимости от настроек безопасности сервера). Должна открыться страница с информацией о сервере. В случае получения ошибки, можно почитать на Readme и Wiki.

Установка DeepSeeWeb


Для установки DeepSeeWeb надо:

  1. Загрузить установщик и импортировать его в любую область с помощью Studio, Портала Управления Системой или Do $System.OBJ.Load(file).
  2. Выполнить в терминале (пользователем с ролью %ALL): Do ##class(DSW.Installer).setup()

Для проверки установки надо открыть в браузере страницу http://server:port/dsw/index.html. Должна открыться страница авторизации. В области SAMPLES представлено множество уже готовых дашбордов и все они автоматически отображаются в DeepSeeWeb.

Сбор координат полигонов


Для отображения собранных данных на карте нам необходим набор координат полигонов административных округов и районов Москвы. Взять их можно например на сайте gis-lab. Далее так как эти данные будут использоваться DeepSeeWeb нам нужно их привести к формату, который сможет обработать DSW:

Укороченный код moscowElectionsMap.js
function loadCoordinates(polygonCoordsArray)
	{
	polygonCoordsArray['Троицкий административный округ'] =
	 '36.8031,55.44083,0 ... 37.37279,55.80868,0'
	...
	polygonCoordsArray['район Некрасовка'] =
	 '37.90613,55.70626,0 ... 37.37296,55.80745,0'
	}


Сохраним полученный js файл в папку web приложения нашей области и вуаля.



Создание списка терминов


Также мы можем добавить возможность определения критерия окраски карты. если у нас сейчас окрашивается по отношения всего проголосовавших к населению АО/района, мы можем сделать окраску по отношению голосов за кандидата к населению. Сделать это можно следующим образом — мы создадим список терминов — список пар ключ-значение, при выборе ключа — значение будет подставляться в MDX выражение запроса. MDX выражение нашего пивота следующее:

SELECT NON EMPTY {[Measures].[Putin],[Measures].[Zhirinovsky],[Measures].[Baburin],[Measures].[Grudinin],[Measures].[Sobchak],[Measures].[Suraykin],[Measures].[Titov],[Measures].[Yavlinsky],[MEASURES].[COLORRGBVALUE],[CUSTOM].[TooltipValue],[CUSTOM].[PopupValue]} ON 0,NON EMPTY [Territory].[H1].[Region].Members ON 1 FROM [ELECTIONS2018CUBE]

Заменяться будет часть которая окружена фигурными скобками.

Создать список терминов можно в Диспетчере списка терминов — откройте портал пользователя → Инструменты → Диспетчер списка терминов

Для Путина будет следующая строка

Ключ: 2. Путин
Значение:

{[Measures].[Putin]\,%LABEL([Measures].[Putin]/[Measures].[votersIncludedInVotersList]\,"ColorRGBValue")\,[CUSTOM].[TooltipValue]\,%LABEL("<b>" + [Territory].[H1].[Region].CurrentMember.Properties("name") + "</b><br/>Население: " + [Measures].[Population] + " чел.<br/>Число избирателей: " + [Measures].[votersIncludedInVotersList] + " чел.<br/>За Путина проголосовало: " + [Measures].[Putin] + "чел."\,"PopupValue")}

Сохраним данный список терминов как MoscowElections2018.

Далее создадим элемент управления на странице настройки дашборда для пивота с картой:

Расположение — Щелчок мышки
Действие — Выбрать спец. строки
Нажимаем «OK»

Определяем имя и список спец. столбцов
Метка — Критерий окраски
Список спец. столбцов — MoscowElections2018.termlist

Готово!

Дополнительная возможность: определение URL тайл-сервера


Также хотелось бы указать, что DeepSeeWeb поддерживает возможность указания определенного пути тайл сервера, который будет использоваться при запросах тайлов (картинок) для карты вместо используемого по умолчанию — https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png.

Мы опустим настройку тайл сервера, т. к. данная информация уже не раз была описана в интернетах.

Для установки пути к желаемому тайл серверу необходимо выполнить следующие шаги:

  1. Создать json файл с настройками DeepSeeWeb или сгенерировать уже готовый, который используется DeepSeeWeb
  2. Указать узел “app.tileServer” со значением — url желаемого тайл сервера
  3. Импортировать полученный json файл с настройками

Создание json файла с настройками DeepSeeWeb


Наилучшим способом создания является правки в json файле который уже используется вашим приложением. Для его получения нажмите на в верхней части окна DeepSeeWeb — откроется окно с настройками DeepSeeWeb.



Нажмите “Export settings”. Откройте скачанный json файл и добавьте узел «tileServer» как подузел узла «app». Для данного примера будет использоваться URL OSM Wikipedia Maps — https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png. Сохраните файл с настройками. Откройте окно с DeepSeeWeb и загрузите полученный json файл в окне настроек DeepSeeWeb. Готово!

Выводы:


Мы показали пример использования мультимодельной СУБД InterSystems Caché, OLAP DeepSee, проектов DeepSeeWeb, MDX2JSON. Вы научились создавать хранимые классы, кубы, пивоты, индикаторные панели и осознали насколько прекрасны и удобны компоненты доступные как в платформе для интеграции и разработки приложений InterSystems Ensemble, так и в мультимодельной СУБД InterSystems Caché и на новом продукте InterSystems IRIS Data Platform.

Разработанные индикаторные панели были выложены на демо сервер:

Демо сервер

Ссылки:

InterSystems

78,00

Вендор: СУБД Caché, OLAP DeepSee, шина Ensemble

Поделиться публикацией
Комментарии 8
    0
    Настораживают слишком круглые цифры за Жириновского в Северном и Новомосковском округах, и за Титова в Южном округе. Мягко скажем, маловероятно без подтасовок.
      0
      Абсолютно так же вероятно, как и любые другие цифры.
        +2
        Три сразу, с тремя или больше нулями из 88 при приблизительно равномерном распределении (величины mod 1000) — вероятность 1/(1000^3)*C(3,88) ~= 1e-4 (109736/1e9). Маловероятно, все-таки.
          0

          3.000% и 3.456% равновероятны.
          Выпадение КОНКРЕТНОГО числа маловероятно, но они все одинаково вероятны.

            0
            А это как или, точнее, что считать. Выпадение всех цифр должно быть равномерным — например, 9 или 3 или 0 должны выпадать в среднем с одинаковой частотой. Глядя на одно число, конечно, выводы делать не стоит. Но обратить внимание вполне можно.
      0
      Одному мне кажется что это в ELK-стеке решилось бы за время, раза в три меньшее, чем чтение этой статьи?
        0
        Мне кажется, было бы интересно смотреть не только и не столько на распределение голосов между кандидатами (так как везде с большим отрывом победил один и тот же кандидат, и тут сюрпризы ожидать не приходится), но и на другие показатели:

        — процент и число голосовавших вне помещения (нет ли где аномалий)
        — размеры участков (интересно было бы узнать, как они распределены, где есть очень маленькие или огромные участки)
        — изменения размеров участков в сравнении с выборами 2016 года. Где и на сколько приросло/убыло население?
        — процент явки (нет ли тут интересных закономерностей? нет ли участков с близкой к 100% или к 0% явкой?)
        — число открепившихся и прикрепившихся. Увы, на сайте ЦИК опубликованы только числа по тем, кто подал заявление до 14 марта, но и эти цифры могут показать что-то интересное. Ведь возможностью проголосовать по месту жительства воспользовались миллионы граждан.
        — количество испорченных/недействительных бюллетеней. Где самые «против всех» участки.
          0
          В чем проблемы?
          Мы ждем статью ;)

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

        Самое читаемое