January 24

Стилизация данных в Overpass Turbo

Введение

Карты — это язык, на котором говорит география. Но даже самые точные данные теряют силу, если их нельзя «увидеть». Представьте: вы нашли в OpenStreetMap все нужные объекты — дороги, парки, кафе — но на карте они сливаются в одно серое пятно. Как выделить главное? Как сделать так, чтобы карта «заговорила»?

Ответ — MapCSS. Оно помогает нам отображать данные как мы того хотим. Мы можем менять цвета, иконки, прозрачность, режим отображения, вывод информации как хотим. Всё это помогает в расследовании и изучении местности.

Начало

Что такое MapCSS?

MapCSS — это язык стилей для карт. Если вы знакомы с CSS, который используется для оформления веб-страниц, то MapCSS покажется вам очень похожим. Но вместо того чтобы стилизовать HTML-элементы, MapCSS работает с географическими данными.

Основные возможности MapCSS:

  1. Цвета и прозрачность
    Задавайте цвета для линий, заливки полигонов и текста.
  2. Иконки и изображения
    Добавляйте иконки для точек (например, кафе, парков, магазинов).
  3. Текстовые подписи
    Отображайте теги (например, name, population) прямо на карте.
  4. Условные стили
    Меняйте внешний вид объектов в зависимости от их тегов (например, дороги разного типа могут быть разного цвета).

Начинаем стилизовать данные.

Цвета.

А как использовать MapCSS в Overpass Turbo?

Для этого используется специальный блок {{style: ... }}, который добавляется в ваш запрос.

Давайте начнем с простого. Найдём кафе в центре Москвы.

nwr["amenity"="cafe"]({{bbox}});
out center;

Пока у нас результаты отображаются в виде жёлтых точек.

Давайте поменяем цвет.

В конце кода добавляем это:

{{style: 

// а тут будут мы будем стилизовать наши данные

}}
  1. Внутри нам нужно будет указать, что мы хотим стилизовать. Мы укажем node, потому что у нас результат - это точки.
  2. Далее ставим квадратные скобки и в них пишем какие именно точки мы хотим стилизовать, в нашем случае amenity=cafe (можно указать просто amenity, если у нас только cafe и других amenity не имеется)
  3. Ставим фигурные скобки и в них уже стилизуем нашу точку.

Получаем следующее:

{{style: 
node[amenity=cafe]{}
}}

Давайте поменяем цвет!

Внутри фигурных скобок пишем следующий код:

{{style:
node[amenity=cafe]{
	color: black;
  	fill-color: black; 	
}
}}

color: меняем цвет обводки.

fill-color: меняем цвет заливки.

Цвет мы можем указывать как в hex коде (например #000000), так и просто написать название цвета на английском. Я покрасил все кафешки в чёрный.

Получаем результат:


Давайте покажу еще вариации.

Если у вас на карте изображены не только кафешки, а еще и другие объекты, допустим зоопарки. То окрасить зоопарки другим цветом можно аналогичным способом, просто добавьте зоопарк в {{style:}} и стилизуйте как хотите. Получается у вас кафешки будут одного стиля, а зоопарки другого. И так вы будете их отличать. Например я хочу, чтобы кафешки были красными, а зоопарки зелеными.

Код:

(
nwr["amenity"="cafe"]({{bbox}});
nwr["tourism"="zoo"]({{bbox}});
);

out geom;

{{style: 
node[amenity=cafe]{
	color: white;
  	fill-color: red;
  	fill-opacity: 1;
}

area[tourism=zoo]{
	color: white;
  	fill-color: green;
  	fill-opacity: 0.7;
}

}}

Про area и fill-opacity мы еще поговорим в этой статье. Вот, что у нас получилось:

Непрозрачность

А как поменять прозрачность точки? Я хочу супер чёрную точку!

Это можно сделать с помощью тега fill-opacity, чтобы сделать супер черную непрозрачную точку, непрозрачность выставим на 1.

Вот, что мы получаем:

Я так делать конечно не рекомендую, потому что если много точек, то все начнет сливаться, нужно хотя бы изменить цвет контура (тег color). Давайте добавим белый цвет контура. Кстати у цвета контура тоже есть непрозрачность, для этого есть тег color-opacity, его тоже выставляем на 1.

И вот что мы получаем:

Ну это намного лучше! Теперь ничего не сливается и всё хорошо.

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

color-opacity: непрозрачность контура.

fill-opacity: непрозрачность заливки.

Непрозрачность можно делать не только для точек, а еще и для иконок, на них мы сейчас и посмотрим.

Иконки

А я не хочу, чтобы кафешки отображались просто черными точками. Я хочу добавить свою иконку, чтобы она была красивая и офигенная. Я могу такое сделать?

Да, можешь. Для этого есть такие теги:

icon-image: выбираем любую иконку для наших точек. В ключе для этого тега мы указываем URL картинки.

icon-width: размер иконки. Выбирайте какой хотите.

Я добавлю для наших кафешек вот такую иконку:

Пишем тег icon-image и указываем ссылку на изображение. А размер иконки, я пожалуй, выберу 25.

У меня получаются такие стили:

{{style: 
node[amenity=cafe]{
  	  icon-image: url('https://img4.teletype.in/files/3e/45/3e45687a-502c-4f23-a167-992702287f70.png');
      icon-width: 25;
}
}}

А вот наш результат:

Прозрачность иконок вы также можете настроить с помощью дополнительного слова opacity.

Сборник официальных иконок Overpass Turbo можете найти здесь.

Давайте повторим теги для иконок! Вот они:

icon-image: url('ссылка на картинку'); выбираем иконку.

icon-width: выбираем размер.

icon-opacity: выбираем непрозрачность иконки (если хотите)

Стилизуем вывод информации.

Я совсем не понимаю, что это за кафешки, я не вижу их названия. На каждую приходится нажимать, чтобы это посмотреть. Я хочу, чтобы названия кафешек отображались сразу! Как это сделать?

Ты можешь сделать и такое! Давай оставим наши иконки для кафешек и добавим к ним названия самого заведения.

А для этого мы используем следующий ключ:

text: что мы хотим вывести

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

text: name;

Всё! Теперь у нас отображаются еще и названия кафешек. Разве это не круто?

Вывести можно не только название, а вообще всё, что указано в характеристиках объекта (сколько этажей, часы работы, номер остановки и многое другое)

Давайте я добавлю к этой информации еще и часы работы кафешки.

Нужно как-то отобразить сразу два тега. Для этого можно использовать функцию eval(). Туда можно впихнуть любой текст и теги. Чтобы объеденять строки нужно использовать конкатенацию, в MapCSS оператором конкатенации является просто точка. Щас я вам покажу код, но вы сильно не путайтесь, щас я все объясню.

text: eval('tag("name") . '(' . tag("opening_hours") . ')'');

Если вы когда нибудь программировали на Python, то там, чтобы конкатенировать строки мы использовали знак плюс. Здесь мы используем точку, чтобы объеденять слова и значения тегов.

Здесь я соеденяю название кафешки со скобочкой, дальше конкатенирую рабочие часы и присоеденяем вторую скобочку. Чтобы ответ выглядел как-то так:

Название(время работы)

Давайте посмотрим, что у нас получилось:

Отлично! Теперь у нас указывается название кафешки и часы работы (если имеется). И так вы можете совмещать различные данные.

Можно даже сделать так, чтобы явно указать, что это название и :

text: eval(''Название: ' . tag("name") . ', Время работы: (' . tag("opening_hours") . ')'');

Получится вот так:

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

icon-width: eval("25/5");

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

Тегов к выводу информации очень много, можно настраивать шрифт и параметры вывода. Вот полный список тегов:

А нам достаточно запомнить только тег text, потому что он основной.

Стилизуем линии.

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

Сейчас я покажу как выглядят линии без стилизации. Ищем главные дороги центра в центре Москвы:

way["highway"="primary"]({{bbox}});

out geom;

Вот, что мы получаем:

Синии линии и дефолтные точки (если приблизить карту, то точки исчезают, остается только линия).

Давайте стилизуем их!

Мы можем поменять их цвет, прозрачность, ширину, паттерн отрисовки и многое другое. Ну что-же давайте поменяем цвет линии на чёрный (по классике). Добавляем в стили теги color (цвет линии), fill-color (цвет точек), opacity (непрозрачность линий):

{{style:
way[highway=primary]{
   color: black;
   fill-color: black;
   opacity: 1;
}
}}

Получаем результат:

Линии стали чёрными. Также можно отображать линии в виде штрихов. Для этого используйте тег dashes: x,x,x,x; (где x какое-то значение), можно поиграться со значениями, я поставил 8,8,4,4, также изменю ширину линии на 2 (width:2;).

Вот, что мы получаем:

Всё довольно аккуратно и понятно.

Я считаю больше вам про стилизацию линий знать и не надо, этого достаточно.

Вот основные теги для стилизации линий:

color: цвет линии.

fill-color: цвета точек (Если приближать карту, эти точки пропадают)

width: ширина линии.

dashes: x, x, x, x (где x - какое-то значение). Указываете этот тег, если хотите, чтобы линия отображалась штрихами.

Вот полная таблица тегов для линий:

Стилизуем полигоны

Полигон - это область, которым обозначают геометрию зданий, парков и других объектов, которые имеют площадь.

Давайте опять на примере кафешек поищем объекты, только на выходе пропишем

out geom;

вместо

out center;

потому что нам нужно вывести геометрию объекта.

P.S out center выводит центр всех объектов. Если это точка, то она так точкой и остается, а если это полигон, то показывается его центр как точка. (Получается на выходе мы получаем точки всех центров).

out geom показывает геометрию всех объектов. Если это точка, то она так точкой и остается, а если это полигон, он будет показываться как полигон.

Давайте найдем кафешки с геометрией:

wr["amenity"="cafe"]({{bbox}});
out geom;

wr ищет way и relation сразу, потому что полигон это замкнутая в себя линяя (way), также заведение может быть отмечено как relation. Как отмечаются заведения (почему некоторые отмечают как node, а некоторые как way и relation) я могу рассказать в полном туториале overpass turbo, поэтому поставьте лайк.

Результат:

Теперь давайте давайте добавим стили к полигону.

Окрашу кафешку красным цветом с белой обводкой, непрозрачность заливки 0.5:

{{style:
area[amenity=cafe]{
	fill-color:red;
  	fill-opacity: 0.5;
  	color: white;
}
}}

Прошу заметить, что в MapCSS для полигонов уже используется area, а не way.

Вот, что мы получаем:

Кафешек с геометрией в Москве не очень много отмечено, в основном это точки. Поэтому давайте покажу на примере зданий. Переделаем код, вот так:

wr["building"]({{bbox}});
out geom;

{{style:
area[building]{
	fill-color:red;
  	fill-opacity: 0.5;
  	color: white;
}
}}

На выходе получаем абсолютно все здания:

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

wr["building"]({{bbox}});
out geom;

{{style:
area[building]{
	fill-color:red;
  	fill-opacity: 0.5;
  	color: white;
}

area[building=apartments]{
	fill-color:blue;
  	fill-opacity: 0.5;
  	color: white;
}
}}

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

Результат:

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

Стилистика полигонов от точек ничем не отличается. Поэтому не будем заострять на них внимание.

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

Примеры использования.

1. Находим кафе, в котором был человек.

Допустим мы хотим найти кафе, в котором был человек (фото в кофе он выложил в социальной сети, определить по фото нам никак не удается). Посмотрев предыдущее выложенное фото, там он был в Cбербанке определенного района в городе Санкт-Петербург. Промежуток между постами 15 минут. Нам нужна наглядная информация обо всех кафешках в местности рядом со сбербанком, чтобы мы начали конкретный поиск.

Для этого найдём и выведем сбербанки, также выведем все кафе в этом районе, чтобы начать смотреть самые близжайшие к нему.

Код:

nwr["brand"="Сбербанк"]({{bbox}}) -> .bank;
nwr["amenity"="cafe"]({{bbox}}) -> .cafe;

.bank out geom;
.cafe out geom;

{{style: 
node[brand=Сбербанк], area[brand=Сбербанк] {
	fill-color: blue;
    color:blue;
}

node[amenity=cafe], area[amenity=cafe] {
	fill-color: red;
    color:red;  
}
}}

Кафе окрасили в красный, а сбербанки в синий.

Теперь нам наглядно видно и мы можем предположить в какое кафе пошел человек:

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

2. Наглядно показываем различие первых двух цифр в ID автобусных остановках в Южной Корее.

Кто не в курсе, то в Сеуле у автобусных остановок есть ID. Первые две цифры ID это район. Можете почитать мой райтап, если не видели. Давайте теперь найдем все автобусные остановки начинающиеся с цифр 18,19,20,21,22,23,24,25. Расскрасим их разными цветами и посмотрим на карте, что у нас получится.

Код:

nwr["highway"="bus_stop"]["ref"~"^18|^19|^20|^21|^22|^23|^24|^25"]({{bbox}});

out geom;

{{style:

node[ref=~/^18/] {
	fill-color: blue;
    color:white;
  	fill-opacity:1;
}

node[ref=~/^19/] {
	fill-color: red;
    color:white;
  	fill-opacity:1;
}

node[ref=~/^20/] {
	fill-color: green;
    color:white;
  	fill-opacity:1;
}

node[ref=~/^21/] {
	fill-color: purple;
    color:white;
  	fill-opacity:1;
}

node[ref=~/^22/] {
	fill-color: black;
    color:white;
  	fill-opacity:1;
}

node[ref=~/^23/] {
	fill-color: white;
    color:white;
  	fill-opacity:1;
}

node[ref=~/^24/] {
	fill-color: grey;
    color:white;
  	fill-opacity:1;
}

node[ref=~/^25/] {
	fill-color: orange;
    color:white;
  	fill-opacity:1;
}

}}

Уууух, код конечно не очень маленький. Но он лёгкий. В стилистике мы можем использовать regex, для этого после равно пишется ~/regex/ (вместо regex пишете свое. Знак ^ означает, что мы ищем все айдишники которые начинаются с этих цифр).

Вот, что мы получаем:

Таким образом мы наглядно увидели сколько остановок в районах 18-25.

3. Котик вместо точек.

Давайте немного расслабимся. Точки это слишком скучно, давайте поменяем точек на котика!

Окей, я не против.

В duckduckgo пишем "cat head" и указываем, что мы хотим искать transparent картинки (с прозрачным фоном).

Я выбрал такого.

А теперь я найду все ветеринарные клинки в центре Москвы и вместо точек у меня будет этот котик!

Мой код:

nwr["amenity"="veterinary"]({{bbox}});
out center;

{{style:
node[amenity=veterinary]{
  icon-image: url("https://img2.teletype.in/files/1e/05/1e05fa06-3ae8-4e94-ad04-e8014f4e2420.png");
  icon-width: 40;
}
}}

Получаем такую красоту:

4. Дурка

А теперь к нашим котикам добавим психиатрические больницы с такой иконкой:

Вот наш код с котиками и с дурками:

(
  nwr["amenity"="veterinary"]({{bbox}});
  nwr["name"~"Психиатрическая"]({{bbox}});
);

out center;

{{style:
node[amenity=veterinary]{
  icon-image: url("https://img2.teletype.in/files/1e/05/1e05fa06-3ae8-4e94-ad04-e8014f4e2420.png");
  icon-width: 40;
}

node[amenity=hospital], node[amenity=clinic]{
  icon-image: url("https://img1.teletype.in/files/06/41/0641e831-31c6-442e-b6ae-9f6b9c323cb8.png");
  icon-width: 40;

}
}}

И вот что мы получаем:

На основе этих данных, можно вычислить лучшую дурку.

Вот она. Она лучшая, потому что там наибольшая концентрация котиков, выше шанс вылечиться.

Заключение

И так мы можем стилизовать данные как хотим и сколько хотим. Менять бесконечное количество цветов, иконок, вывода информации. Всё это помогает в эффективном решении задач и проведении расследований. Я лишь показал малую часть примеров (хоть они прикольные и смешные).

Если вам было полезно, то поставьте лайк. Я старался. Можете задонатить, если хотите. Вот основные источники, которые я использовал, тут можете найти таблицу тегов и другую информацию:

Спецификация MapCSS 0.2

Документация по стилистике Overpass Turbo.

Статья может дополняться и улучшаться, по мере необходимости и желания.

В скором времени хочу написать туториал по всему Overpass Turbo, поэтому поставьте лайк :)

Спасибо!

❤️❤️❤️Угостить автора пельмешками.