Вопрос или проблема
Я хочу нарисовать контур, выделяющий форму на хоровой карте, построенной из GeoJSON с использованием Plotly (в моем случае через Dash).
У меня есть dataframe “df”, похожий на этот:
state (строка) value (число с плавающей точкой)
STATE_1 50.0
STATE_2 30.5
STATE_3 66.2
У меня также есть GeoJSON, загруженный как объект с этой структурой:
{
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'id': 1,
'properties': {
'id': 'STATE_1',
},
'geometry': {'type': 'Polygon', 'coordinates': [...]},
},
...
]
}
Я нарисовал свою базовую карту вот так:
fig = px.choropleth(
df,
geojson=my_geojson,
color="value",
locations="state",
featureidkey='properties.id',
projection='Mercator',
)
fig.update_geos(
fitbounds="locations",
visible=False,
)
fig.update_layout(
coloraxis=dict(
colorbar=dict(
title="",
orientation='h',
x=0.5,
y=0.1,
xanchor="center",
yanchor="top",
),
colorscale=[[0, '#04cc9a'], [1, '#5259ad']],
),
margin={"r": 0, "t": 0, "l": 0, "b": 0},
dragmode=False,
)
Я пытался добавить другой след безуспешно, чтобы показать контур одного из штатов. Я пробовал как с использованием plotly express, так и объектов графиков plotly без результата.
Как мне это сделать?
Стратегия, которая в конце концов сработала для меня, была следующей:
- Создать основную фигуру, как показано в вопросе
- Создать вспомогательную фигуру с помощью plotly express. Это было необходимо для того, чтобы задать новому следу его маркер и цвет заливки. В противном случае он был бы заменен конфигурацией основной фигуры.
- Добавить след из вспомогательной фигуры в основную
Это будет что-то вроде этого:
# Создать основную фигуру, как показано в вопросе
fig = ...
# Отфильтровать данные и geojson, чтобы создать новый след
df_aux = df[df['state'] == 'STATE_1']
my_filtered_geojson = {...} # Отфильтровывать так, чтобы он содержал только один Feature, соответствующий STATE_1
# Заменить значение на фиктивное, чтобы мы могли залить форму прозрачным цветом
df_aux ['value'] = 1
# Создать вспомогательную фигуру
fig_aux = go.Figure(go.Choropleth(
geojson=my_filtered_geojson,
featureidkey='properties.id',
locationmode="geojson-id",
locations=df_aux['state'],
z=df_aux['value'], # Фиктивное значение, которое мы только что установили выше
zmax=1,
zmin=0,
colorscale=[[0, 'rgba(0,0,0,0)'], [1, 'rgba(0,0,0,0)']], # Цвета с альфа-каналом, оба полностью прозрачные
showscale=False,
marker=dict(
line=dict(
color="red",
width=4,
)
),
hoverinfo='skip', # Скрыть информацию при наведении, чтобы получить информацию основной фигуры
))
# Добавить новый след в основную фигуру
fig_principal.add_trace(fig_aux.data[0])
После некоторого стилирования вы должны получить что-то подобное. В моем случае я показываю оригинальные цвета хоровой карты, и поверх этого выделяю один из штатов на карте фиолетовым цветом. Также вы должны получить информацию при наведении на оригинальную карту:
Ответ или решение
Чтобы добавить контур к фигуре на хоровой карте (Choropleth-karte) с помощью Plotly и GeoJSON, вам потребуется осуществить несколько шагов, как показано в вашем вопросе. Ниже представлена пошаговая инструкция, основываясь на ваших исходных данных и форматах.
Шаг 1: Создание основной карты
Сначала создайте основную карту, используя ваш DataFrame и GeoJSON. Используйте библиотеку Plotly Express для упрощения этого процесса:
import plotly.express as px
fig = px.choropleth(
df,
geojson=my_geojson,
color="value",
locations="state",
featureidkey='properties.id',
projection='Mercator',
)
fig.update_geos(
fitbounds="locations",
visible=False,
)
fig.update_layout(
coloraxis=dict(
colorbar=dict(
title="",
orientation='h',
x=0.5,
y=0.1,
xanchor="center",
yanchor="top",
),
colorscale=[[0, '#04cc9a'], [1, '#5259ad']],
),
margin={"r": 0, "t": 0, "l": 0, "b": 0},
dragmode=False,
)
Шаг 2: Создание вспомогательной карты для контура
Для добавления контура вам нужно создать вспомогательную карту. Эта карта будет использовать ту же структуру GeoJSON, но только для выделяемого региона, в данном случае STATE_1
. Вот как это можно сделать:
- Отфильтруйте DataFrame и GeoJSON так, чтобы они содержали только нужный вами объект.
- Задайте непрозрачные цвета для контура.
# Фильтрация DataFrame для вашего конкретного состояния
df_aux = df[df['state'] == 'STATE_1']
# Отфильтруйте GeoJSON
my_filtered_geojson = {
'type': 'FeatureCollection',
'features': [feature for feature in my_geojson['features'] if feature['properties']['id'] == 'STATE_1']
}
# Установите фиктивное значение для корректного отображения
df_aux['value'] = 1
# Создайте вспомогательную фигуру
import plotly.graph_objects as go
fig_aux = go.Figure(go.Choropleth(
geojson=my_filtered_geojson,
featureidkey='properties.id',
locationmode="geojson-id",
locations=df_aux['state'],
z=df_aux['value'], # Используйте фиктивное значение
zmax=1,
zmin=0,
colorscale=[[0, 'rgba(0,0,0,0)'], [1, 'rgba(0,0,0,0)']], # Полностью прозрачные цвета
showscale=False,
marker=dict(
line=dict(
color="red", # Цвет контура
width=4, # Ширина контура
)
),
hoverinfo='skip', # Скрыть информацию о наведение
))
Шаг 3: Добавление контура в основную фигуру
После создания вспомогательной карты, добавьте её в основную фигуру:
# Добавьте новый след в основную фигуру
fig.add_trace(fig_aux.data[0])
Шаг 4: Тестирование и визуализация
После выполнения всех шагов вы сможете увидеть хоровую карту с добавленным контуром, который выделяет определённое состояние. Убедитесь, что всё отображается правильно, и что информация о наведении мыши работает на оригинальной карте.
Итоговая визуализация
Теперь вы сможете визуализировать хоровую карту, выделяя штаты, и сохранить информацию о платформе Dash. Ваша конечная версия карты будет выглядеть так, как вы планировали, совмещая оригинальные цвета хоровой карты с контуром выбранного объекта.
Эта инструкция является достаточно универсальной и может быть адаптирована под разные нужды. Настройка и стилизация карты могут зависеть от ваших предпочтений и бренда, однако приведённый выше пример должен служить хорошей основой для реализации данного функционала.
Спасибо за подробное решение! Хотел бы предложить альтернативный подход, который может упростить ваш код и избежать создания дополнительной фигуры.
Вместо создания вспомогательной фигуры и добавления её следа, можно добавить контур напрямую в основную фигуру, используя объект
go.Scattergeo
. Это позволит выделить нужный штат без изменения исходных данных или создания фиктивных значений.Вот пример того, как это можно реализовать:
import plotly.express as px
import plotly.graph_objects as go
# Создаем основную фигуру
fig = px.choropleth(
df,
geojson=my_geojson,
color="value",
locations="state",
featureidkey='properties.id',
projection='mercator',
)
# Ищем координаты полигона для STATE_1
for feature in my_geojson['features']:
if feature['properties']['id'] == 'STATE_1':
geometry = feature['geometry']
break
# Проверяем тип геометрии и извлекаем координаты
if geometry['type'] == 'Polygon':
coordinates = geometry['coordinates']
elif geometry['type'] == 'MultiPolygon':
# Если это MultiPolygon, объединяем все координаты
coordinates = [coord for polygon in geometry['coordinates'] for coord in polygon]
# Преобразуем координаты в списки долгот и широт
lons = []
lats = []
for polygon in coordinates:
lon_vals = [point[0] for point in polygon]
lat_vals = [point[1] for point in polygon]
# Добавляем None для разделения полигонов
lons += lon_vals + [None]
lats += lat_vals + [None]
# Добавляем контур в основную фигуру
fig.add_trace(go.Scattergeo(
lon = lons,
lat = lats,
mode = 'lines',
line = dict(color='red', width=4),
showlegend=False,
hoverinfo='skip',
))
# Обновляем параметры географии
fig.update_geos(fitbounds="locations", visible=False)
# Обновляем макет фигуры
fig.update_layout(
margin={"r":0,"t":0,"l":0,"b":0},
dragmode=False
)
# Отображаем фигуру
fig.show()
Данный метод позволяет напрямую добавить контур нужного штата, избегая создания дополнительных фигур и модификации данных. Это делает код более простым и читаемым.
Кроме того, если вам нужно выделить несколько штатов, вы можете добавить их координаты в списки
lons
иlats
аналогичным образом.Надеюсь, этот подход будет вам полезен!