Изобразяването на повече от 200 000 точки с данни на уеб карта не е лесна работа. Трябва да изберете правилните инструменти и да прецизирате някои части от приложението, докато постигнете най-добрата производителност.

В тази статия:

Необходимостта от инструмент за визуализация

Трябваше да анализираме данни за пътуване с влак като заминавания, пристигания, местоположение и закъснения. Понякога данните не са 100% точни. В този случай анализаторите се нуждаят от инструменти, които да им помогнат да потвърдят точността на тези данни. Инструментите за „визуализация на данни“ се използват за потвърждаване дали данните имат смисъл и помагат на нетехническите хора да разберат по-добре анализираната информация.

Разработеният от нас инструмент е създаден с цел идентифициране на тесни места и аномалии от Deutsche Bahn — германската компания за железопътен транспорт. За да постигнем това, използвахме Open Railway Map за правилно проследяване на движението на влаковете в приложението. Също така трябваше да съхраняваме големи набори от данни (~200 Mb) и да визуализираме стотици хиляди точки от данни.

Вероятно се чудите защо просто не използвахме други приложения. Опитахме, но не успяхме да намерим инструмент с достатъчен капацитет и функции, който да отговаря на нашия случай на употреба. Трябва да спомена обаче, че kepler.gl е единственото приложение, което открихме, което отговаря на повечето от нашите изисквания. Всъщност най-новата версия на нашето приложение разчита най-вече на kepler.gl за визуализиране на данни (повече за това в бъдеща публикация).

Първо внедряване: Electron + React + Leaflet

Искахме приложението да извършва изобразяване възможно най-бързо. Изобразяването на хиляди точки от данни на картата беше от решаващо значение за продукта. Затова решихме да изберем малки, но мощни библиотеки.

Въпреки че съвременните уеб браузъри имат капацитета да съхраняват относително големи количества данни, те не са готови (нито проектирани) да съхраняват стотици мегабайти данни. Едно от изискванията беше да се обработват мегабайти данни за пътуване, така че избрахме да изградим приложението върху „Electron“ и да използваме база данни „SQLite“ за съхранение на данни.

За DOM операции решихме да използваме React поради неговата стабилна екосистема и огромната съвместимост, която има с други библиотеки. Както споменахме по-рано, имахме нужда от широко използване на Open Railway Map, което означава, че се нуждаехме от библиотека, която поддържа Open Street Maps и нейните отворени стандарти. Избрахме „Leaflet“, за да се справим с изобразяването на картата и нейните маркери, най-вече защото е малка и има повечето от необходимите функции за картографиране.

С този прост стек започнахме разработването на нашия инструмент за визуализация на данни, който ще наречем ORM-Viz за справка.

ORM-Viz архитектура

Както можете да видите на диаграмата по-горе, приложението е базирано на Electron, който предоставя JavaScript среда, необходима за изпълнение на приложението React. Едно предимство, което имаме, като следваме този подход, е, че в случай, че трябва да направим нашия инструмент за визуализация изцяло базиран на браузъра, ще трябва само да заменим (или премахнем) услугата за съхранение.

Основната причина зад използването на Electron е да се избегнат ограниченията за съхранение. Потребителите на нашето приложение работят с мегабайти и гигабайти информация, което е трудно да се направи само с помощта на браузъра. Браузърите днес са в състояние да съхраняват големи количества данни с IndexedDB API, въпреки че все още не е добре стандартизиран сред браузърите и все още е ограничен за нуждите на нашите потребители. Поради тази причина решихме да интегрираме SQLite база данни с нашето приложение Electron.

Останалата част от нашата архитектура е много ясна: използваме React за изграждане на компонентите на приложението и Leaflet за рисуване на маркери върху картата, като всеки маркер представлява запис в базата данни .

Както споменахме по-рано, ние използваме Open Railways Map, за да покажем цялата информация, свързана с железопътната система по света. Той е изграден върху „Open Street Map“ и може лесно да се интегрира с Leaflet, както е показано в следващия фрагмент.

var map = L.map('map').setView([51.505, -0.09], 13);
var openrailwaymap = new L.TileLayer(
    'http://{s}.tiles.openrailwaymap.org/standard/{z}/{x}/{y}.png',
    {
	attribution:
          '<a href="https://www.openstreetmap.org/copyright">© OpenStreetMap contributors</a>, Style: <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA 2.0</a> <a href="http://www.openrailwaymap.org/">OpenRailwayMap</a> and OpenStreetMap',
	minZoom: 2,
	maxZoom: 19,
	tileSize: 256
     }).addTo(map);

Изобразяване на 1K маркери

Тук изобразяваме хиляда маркера, всеки от които представлява местоположението на влака в някакъв момент от избраната времева рамка. Целият процес отнема средно 800 ms от момента, в който потребителят кликне върху „Приложи” до момента, в който точките са начертани на картата. За нас това се счита за бавно и тази бавност се причинява главно от извличането на данни. Като добавим към това, трябваше да правим заявка за DB всеки път, когато искахме да изобразим местоположението на влака, което бързо се превърна в пречка в нашата цел да постигнем плавни визуализации.

Избор на анимирано време

Простото проектиране на данните върху картата вече е полезно за анализаторите, които искат да проверят данните, които събират от влаковете, но смятаме, че анимациите подобряват нивото на анализ, поради тази причина внедрихме основна функция за анимиране на плъзгача за време, докато показва данни, съответстващи на избрания времеви диапазон.

Под капака използваме setInterval вътре в кука за реакция и всяка секунда той задейства заявка в DB, ​​за да избере записите, които съответстват на времевата рамка, след което състоянието на приложението се актуализира с новите маркери, което стартира повторно изобразяване на компонента Map . Получихме задоволителен резултат в анимацията, като се има предвид фактът, че все още извличаме данните от SQLite DB всеки път, когато плъзгачът се актуализира със следващия времеви диапазон.

От JavaScript към WebGL

ORM-Viz, както наричаме първото внедряване на нашия инструмент за визуализация, се представи добре с малки набори от данни, но достигнахме времена за изобразяване, отнемащи повече от една секунда, за да завърши, когато приложението трябваше да изобрази над 2000 точки. Сега се сблъскахме с друго тясно място в нашия процес на изобразяване, насищането на нишката за изобразяване. В ORM-Viz една нишка трябва да поддържа състоянието на приложението, включително хиляди екземпляри на Marker Objects и React компоненти. Идентифицирахме две възможни решения за ускоряване на времето за изобразяване. Можем или да преместим някои части от приложението към Web Worker и да намалим натоварването на потока за изобразяване, или бихме могли да превключим към WebGL за изобразяване на всички маркери. След като оценихме предимствата и недостатъците на двете опции, открихме, че преминаването към WebGL е най-доброто решение, тъй като WebGL е идеален за този вид задачи, при които имате тежки изчислителни графични операции.

След тестване на различни подходи и библиотеки открихме, че kepler.gl предлага добър интерфейс за визуализация на данни. От репозитория GitHub:

Kepler.gl е агностично, високопроизводително уеб-базирано приложение за визуално изследване на широкомащабни набори от геолокационни данни. Изграден на базата на Mapbox GL и deck.gl, kepler.gl може да визуализира милиони точки, представляващи хиляди пътувания, и да извършва пространствени агрегации в движение.

Отне една седмица, за да имаме работещ прототип, базиран на Kepler.gl, трябваше да интегрираме Open Railways Map, което изискваше значително време, прекарано в проучване, и тъй като нашите потребители не се нуждаят от всичко функциите, които идват с Kepler.gl, също трябваше да опростим потребителския интерфейс. За щастие, персонализирането на потребителския интерфейс е добре документирано в проекта, поради което беше направено бързо.

Друго предимство на използването на kepler.gl като основа на нашето приложение е, че можем да имаме набори от данни в паметта, следователно не е необходимо да правим DB заявки всеки път, когато искаме да изобразим маркерите. С Kepler.gl зареждате набор от данни от източник (файл, услуга и т.н.), запазвайки всички данни в паметта. Това подобри драстично времето за изобразяване по време на анимации.

Заключение

Разработването на уеб-базиран инструмент за визуализация изисква специално съсредоточаване върху времената и техниките за изобразяване, за да се използват максимално ресурсите. В случай, че трябва да изградите уеб базиран инструмент за визуализация на данни, горещо ви препоръчвам да използвате WebGL за изобразяване на данни и избягване на множество заявки за извличане на данни, както открихме по време на нашето пътуване.