ПИТОН. НАУКА ДАННЫХ. ГЕОВИЗУАЛИЗАЦИЯ
Битва при Хороплетах — Часть 3 — Фолиум
Использование пакета Folium для создания потрясающих хороплетов
В последних двух статьях этой серии мы смогли создать хороплеты из пакетов Geopandas и Altair. Давайте продолжим наше обучение, но на этот раз воспользуемся пакетом folium.
ПАКЕТ ФОЛИУМ
В этой статье мы представили пакет folium, а также преимущества и недостатки пакета.
Как мы увидим позже, folium предоставляет множество инструментов настройки, которые помогут сделать нашу карту более интерактивной и профессионально выглядящей. Это происходит, конечно, с дополнительными затратами на несколько дополнительных строк кода.
Без дальнейших церемоний, давайте начнем.
КОДИРОВАНИЕ
Часть кодирования аналогична предыдущим двум статьям, но в этой нам не нужно объединять набор данных (за исключением случаев, когда мы хотим создать собственную цветовую карту, как мы увидим позже).
ПОДГОТОВКА
import pandas as pd import numpy as np import geopandas as gpd import folium
ЗАГРУЗКА И ПРЕДВАРИТЕЛЬНАЯ ОБРАБОТКА ДАННЫХ
df = pd.read_csv('data/gdp_per_capita.csv', skiprows=4) df = df.loc[:,['Country Name','Country Code', '2020']] #Choose only 2020 df = df.fillna(0) #New step df.head()
ЗАГРУЗИТЬ ШЕЙПФАЙЛ
gdf = gpd.read_file('shapefiles/world-administrative-boundaries/world-administrative-boundaries.shp') gdf.head()
ПЛАНИРОВАНИЕ
НАЧАТЬ КАРТУ
#Folium mymap = folium.Map(location=[19.0649070739746, 73.1308670043945], zoom_start=2,tiles=None) #ADDING TILES AS A SEPARATE LAYER ALLOWS FOR MORE CONTROL AND MORE SUTOMIZATION folium.TileLayer('CartoDB positron',name="Light Map",control=False).add_to(mymap) #Calling the map mymap
СОЗДАНИЕ ХОРОПЛЕТА ДЛЯ ДОБАВЛЕНИЯ В КАЧЕСТВЕ СЛОЯ
choropleth = folium.Choropleth( geo_data=gdf, #the dataset merged with the geometry and the data we need to plot on, data=df, key_on='feature.properties.name', columns=['Country Name', '2020'], #the first one is the 'index' which needs to be connected with the 'key_on' property of the geo_data name = 'GDP per capita (Constant USD 2015 )', fill_color='YlGn', fill_opacity=0.7, line_opacity=0.5, ).add_to(mymap) mymap
Давайте обсудим параметры кода:
geo_data
— набор данных шейп-файлаdata
— содержит значения, которые являются основой для цветов картограммы.key_on
— это относится к столбцу, найденному в шейп-файле (или параметруgeo_data
), который будет использоваться для объединения значений со значением параметраdata
. Причина, по которой мы пропустили часть данных слияния, заключается в следующем: folium выполнит слияние, используя этот параметр..add_to
— чтобы добавить слой картограммы на нашу инициализированную карту.
Одна потенциальная слабость листа Choropleth заключается в том, что он имеет ограниченную цветовую палитру. Пока мы использовали желто-зеленый, но есть способ настроить его позже.
НАСТРОЙКИ
Давайте настроим нашу хороплет, выполнив две вещи:
- Добавить всплывающую подсказку для интерактивности
- Создайте собственную палитру — красно-желто-зеленую.
ДОБАВИТЬ ПОДСКАЗКУ
Чтобы добавить настраиваемую всплывающую подсказку, нам нужно вызвать класс GeoJsonTooltip
фолиума. Это дает нам возможность взаимодействовать и просматривать наши данные, что особенно удобно, когда мы делаем некоторые отчеты.
# Display Region Label choropleth.geojson.add_child( folium.features.GeoJsonTooltip(['name'], labels=True) ) mymap
СОЗДАТЬ ПОЛЬЗОВАТЕЛЬСКУЮ КАРТУ ЦВЕТОВ
Чтобы попытаться воспроизвести цветовую схему первой серии, необходимо создать пользовательскую карту цветов. Как упоминалось ранее, цветовая палитра, доступная в folium, ограничена, и для создания индивидуальной палитры нам нужно добавить больше строк кода.
В нашей оригинальной статье мы использовали цветовую карту «Красный-Желто-Зеленый». Чтобы использовать это здесь, нам нужно сделать несколько вещей:
1. Создать пользовательскую палитру с помощью библиотеки branca
. Цветовая карта, доступная в Folium, ограничена, и если мы хотим создать собственную, нам нужно использовать библиотеку branca
.
2. Объединить данные с геоданными. Теперь это стало необходимо, потому что для добавления слоя, где цвет зависит от значения, должны присутствовать данные геометрии.
3. Добавьте отдельный слой с настраиваемой картой цветов. .
import branca import branca.colormap as cm #First determine your maximum and minimum values - this becomes the basis for the steps in the map vmax = df['2020'].max() vmin = df['2020'].min() colormap = cm.LinearColormap(colors=['red', 'yellow','green'], vmin=vmin, vmax=vmax)
ОБЪЕДИНИТЕ ДАННЫЕ
merged = gdf.merge(df, left_on='name', right_on='Country Name' ) merged.head()
ДОБАВИТЬ КАК ОТДЕЛЬНЫЙ СЛОЙ
# First create a function that would call on these values style_function = lambda x: {"weight":0.5, 'color':'black', 'fillColor':colormap(x['properties']['2020']), 'fillOpacity':0.75} #Add the colormap as a legend colormap.add_to(mymap) #Save it as an object so you can add it folium.features.GeoJson( merged.fillna(0), style_function=style_function, ).add_to(mymap) mymap
Теперь она напоминает оригинальную карту Альтаира, которую мы создали. Ура!
Чтобы сделать цвет более равномерным, то есть игнорировать выбросы, как мы сделали, используя метод квантилей, нам нужно добавить больше кодов.
КОЛИЧЕСТВЕННЫЙ ПОДХОД — РЕПЛИКАЦИЯ УЧАСТКОВ ИЗ ПРЕДЫДУЩИХ СТАТЕЙ
Чтобы полностью воспроизвести карты, которые мы создали в первых двух статьях, нам нужно убедиться, что значения разделены на несколько шагов (игнорируя выбросы, для которых было сделано предостережение в последней части статьи).
Обратите внимание, однако, что по мере того, как вы постоянно добавляете слои на карту, она загромождается, поэтому может быть проще просто начать новую. Но если вы планируете создать настраиваемую карту цветов, может быть проще не содержать часть картограммы в чистоте следующим образом:
# My Map #Folium mymap = folium.Map(location=[19.0649070739746, 73.1308670043945], zoom_start=2,tiles=None) #ADDING TILES AS A SEPARATE LAYER ALLOWS FOR MORE CONTROL AND MORE SUTOMIZATION folium.TileLayer('CartoDB positron',name="Light Map",control=False).add_to(mymap) choropleth = folium.Choropleth( geo_data=gdf, name = 'GDP per capita (Constant USD 2015 )', ).add_to(mymap) mymap
В приведенном ниже коде показаны предлагаемые нами шаги:
- Мы используем индекс (который вручную диктует точки разделения цветов. Для этого сначала требуется, чтобы мы знали максимальное и минимальное значения ряда.
- Мы линеаризовали палитру, чтобы значения могли попадать в ячейки в индексе.
- Как видите, мы дважды повторили шестнадцатеричный код
#c7f6b6
. Это не случайно. Похоже, у Folium возникают проблемы с вырезанием последнего цвета в списке, поэтому добавление большего количества цветов обеспечивает более линейный переход перед последним зеленым цветом. Конечно, этот цвет должен быть градиентом последнего, чтобы шестнадцатеричный код был светло-зеленым. - Мы вырезали указатель вручную, и в исходном было использовано всего пять разрезов. Однако для этой карты кажется, что 7 лучше (Напомним, что при индексации диапазона чисел последнее значение все равно игнорируется в Python).
#First determine your maximum and minimum values - this becomes the basis for the steps in the map vmax = df['2020'].max() vmin = df['2020'].min() colormap = cm.LinearColormap(colors=['red','yellow' , '#c7f6b6' ,'#c7f6b6','green'], vmin=vmin, vmax=vmax) # We add this in extra step to emulate the coloring scheme of the prveious articles n_steps = 7 # Quantiles list_of_values = df['2020'].sort_values() #Remove all 0's as the geopandas version did not count 0 on the count of merging list_of_values = [i for i in list_of_values if i != 0] length = len(list_of_values) index = [list_of_values[int((length/n_steps)*i)] for i in range(n_steps)] print(index) colormap = colormap.to_step(index=index)
Последние штрихи:
Обратите внимание, что в этом случае всплывающую подсказку нужно было добавить как часть последнего слоя, чтобы ее можно было использовать, поэтому мы включили ее в последний использованный слой.
# First create a function that would call on these values style_function = lambda x: {"weight":0.5, 'color':'black', 'fillColor':colormap(x['properties']['2020']), 'fillOpacity':0.75} #Add the colormap as a legend colormap.add_to(mymap) #Save it as an object so you can add it folium.features.GeoJson( merged, style_function=style_function, tooltip=folium.features.GeoJsonTooltip(['name'], labels=True) ).add_to(mymap) mymap
Вуаля! Мы смогли точно воспроизвести карту, которая была у нас в первых двух статьях, хотя и не без труда.
ЗАКЛЮЧИТЕЛЬНЫЕ ЗАМЕЧАНИЯ
Как мы видели на примере фолиума, возможность настройки достигается за счет удобства. Чтобы воссоздать всю карту из первых двух статей, которые мы создали, нам потребовалось добавить дополнительный код.
Эта стоимость может быть оправдана для тех, кто намеревается развернуть карту, так как выходные данные фолиума можно сохранить в формате HTML. Кроме того, другие функции, такие как возможность добавления настраиваемой всплывающей подсказки, создание визуального радиуса вокруг определенных областей и многие другие, делают folium хорошим пакетом для картограмм.
Полный код на моей странице Github.