Чи залежать результати виборів у Києві від розміщення гілок метрополітену – експеримент з бібліотекою d3.js
У стрічці новин я помітив матеріал, де результати волевиявлення співвітчизників у першому турі президентських виборів було нанесено на карту. Мені здалося, що результати голосування по Києву мають певну геопозиційну закономірність, а саме перевага одного кандидата на дільницях вздовж гілок метро. А оскільки я давно хотів розібратися з бібліотекою d3.js та не було завдань, де її можна використати, вирішив зробити статистичне дослідження (побудувати декілька графіків), щоб підтвердити чи спростувати цю закономірність.
Збір інформації
Коли почав збирати інформацію, відкриті дані з результатами голосування не були доступні на сайті ЦВК, оскільки ще тривав підрахунок голосів. Тож була ідея написати краулер для отримання результатів з публічних сторінок. Але обрав більш легкий варіант — запозив уже підготовлені дані з сайту dekoder.org. Крім результатів голосування на dekoder.org також запозичив координати виборчих дільниць. Координати розміщення станцій метро взяв з Вікіпедії, межі Києва — з nominatim.openstreetmap.org.
Підготовка даних
Вибірка з результатами голосування була обмежена Києвом. Для простоти та наочності з усіх кандидатів узяв тільки три лідери, а їхні імена замінив на Green, Red і Yellow, щоб їх оминули пошукові системи (і щоб ухилитися від написання легенди до графіків).
До результатів голосування на виборчих дільницях додав колонку «відстань до найблищої станції метро». Розрахунок відстані зробив за формулою «сферичної проекції землі на площину». Скрипт підготовки даних: /build/index.js.
Підводні камені
Збір проекту
Для збору проекту вирішив використати такі популярні технології: Babel@7.x.x + webpack@4.x.x. Узяв базовий «пустий» конфіг.
Babel також вимагає @babel/polyfill для реалізації можливостей, недоступних лише трансформацією синтаксиса. Як виявилося в подальшому, пакет @babel/polyfill не включає Fetch API через те, що вона не описана в ECMAScript — стандартах, тож я додав ще один поліфіл.
У якийсь момент розробки я зрозумів, що проект не працює в IE. Я почав більш детально дивитись на конфігурацію збірки webpack-а, а потім і babel, і наче все було вірно, тому я вирішив копати з боку зібраних файлів. Як виявилось, не траслітерувалися залежності з node_modules. Після подальшого пошуку я виявив, що проспав реліз 7 версії Babel, де був введений додатковий файл конфігурації ‘babel.config.js’ для npm пакетів.
d3js
Кількість реалізованих прикладів використання бібліотеки дозволяє взагалі не відкривати документацію, якщо ви на базовому рівні знайомі з SVG, звичайно. За час написання переглянув такі офіційні ресурси з прикладами: bl.ocks.org, github.com/d3/d3/wiki/Gallery, d3js.org. Але для побудови динамічних графіків (і не тільки) все ж варто розібратися, як працює концепція ‘enter/update/exit‘ (Data joins and selections). Ось статті, які допомогли розібратися з цим питанням: «Enter, Update, Exit», «Введение в d3.js» (російськомовна, та доволі якісна).
Проблему ресайзу графіків добре вирішено в туторіалі. Ця техніка буде працювати для будь-якого svg-зображення. Загалом було зроблено 21 коміт, ~800 строчок власного коду, js бандл на 556 кб.
Результати дослідження
scatter plot — де кожна точка має координати — результат у відсотках для обраних кандидатів на дільниці та віддаленість дільниці від станції метро. Інформація дає загальні уявлення, але хочеться більше структурувати дані.
line chart — об’єднання результатів дільниць за віддаленістю в групи із заданим кроком, крок задається слайдером. Також додав графік з кількістю голосів у об’єднаних групах. На графіку можна побачити що, присутні тенденції спадання у кандидата Red та зростання Green та Yellow (меншою мірою) залежно від віддаленості від станцій метро. Також через малу кількість віддалених дільниць у кінці графіка помітні стрибки.
line chart, stacked bar chart — цього разу крок розподілений таким чином, щоб кількість голосів в групах наближалась до рівномірного розподілу, тобто розділення на групи дільниць з однаковою кількістю голосів. Слайдер задає кількість груп. Графік більш плавний, подолана проблема малої насиченості в групах, але результати повторють попередні висновки.
Припустивши, що залежність результатів лінійна, також розрахував коефіцієнт кореляції Пірсона (величини представлені в першому графіку). Інтерпретація значень дозволяє зробити висновок, що кореляція присутня для всіх кандидатів, хоч і має низький рівень. Лише загальна близькість двох кандидатів дозволяє виявити її простим переглядом карти.
Насамкінець хочу поділитися думкою, що зазвичай візуалізація кластеризації на карті представлена колами, але чому б не використовувати діаграму Вороного?
Слайдер змінює к — параметр k-means кластеризації, re-call — повторює цикл кластеризації. Оскільки k-means не гарантує глобального екстремуму, кожного разу можливий інший результат (залежить від початкових точок, які в цьому прикладі обрані випадково). Оскільки оптимізацію не проводив через брак часу, можливі підвисання (винесення математики в веб-воркер мало б вирішити проблему).