2025, Dec 10 09:01
Подписи в Scattermapbox не отображаются: рабочее решение
Как показать подписи в Plotly Scattermapbox: используйте слой mode="text" без textposition. Код-пример и советы по размещению над столбиками.
Наносить столбики в конкретных точках на карте — удобный способ имитировать 3D‑диаграмму в 2D. На практике часто требуется поставить числовые подписи над каждым столбиком, чтобы значения читались без наведения курсора. Если вы пробовали сделать это в Plotly с Scattermapbox и подписи загадочно отказываются появляться, читайте дальше.
Описание проблемы
Нужно нарисовать короткие вертикальные столбики по заданным координатам на подложке карты и разместить числовые подписи чуть выше вершины каждого столбика. Сами столбики отображаются как надо, но подписи на карте не видны.
Воспроизводимый пример
Фрагмент ниже настраивает подложку Mapbox, рисует вертикальные столбики как линейные трейсы и пытается добавить подписи значений вторым трейсом в точке вершины столбика.
import plotly.graph_objects as go
canvas = go.Figure()
canvas.add_trace(go.Choroplethmapbox(
geojson=hsa_df.geometry.__geo_interface__,
locations=hsa_df.index,
z=[0] * len(hsa_df),
colorscale=[[0, "white"], [1, "white"]],
showscale=False,
marker_opacity=0.2,
marker_line_width=1,
marker_line_color="black",
hoverinfo="skip",
name="HSA Zones"
))
offset_step = 0.05
level_color = {"Major": "red", "Moderate": "orange", "Minor": "green"}
height_ratio = 0.05
stroke_px = 10
legend_seen = {"Major": False, "Moderate": False, "Minor": False}
for _, rec in hsa_df.iterrows():
xlon = rec["lon"]
ylat = rec["lat"]
for i, level in enumerate(["Major", "Moderate", "Minor"]):
shift = (i - 1) * offset_step
pct = rec[level]
bar_h = pct * height_ratio
canvas.add_trace(go.Scattermapbox(
mode="lines",
lon=[xlon + shift, xlon + shift],
lat=[ylat, ylat + bar_h],
line=dict(width=stroke_px, color=level_color[level]),
hoverinfo="text",
text=f"{rec['RegionName']}
{level}: {pct:.2f}%",
showlegend=not legend_seen[level],
name=level
))
legend_seen[level] = True
canvas.add_trace(go.Scattermapbox(
mode="markers+text",
lon=[xlon + shift],
lat=[ylat + bar_h + 0.015],
text=[f"{pct:.1f}%"],
textposition="center",
textfont=dict(size=12, color=level_color[level], family="Arial"),
marker=dict(size=1, color=level_color[level]),
showlegend=False,
hoverinfo="skip"
))
canvas.update_layout(
title="New York State HSA Zones with Risk Bar Charts",
mapbox_style="carto-positron",
mapbox_zoom=5.5,
mapbox_center={"lat": hsa_df["lat"].mean(), "lon": hsa_df["lon"].mean()},
height=800,
margin=dict(l=0, r=0, b=0, t=50),
legend=dict(
title="Risk Level",
orientation="v",
yanchor="top",
y=0.95,
xanchor="right",
x=1.02,
bgcolor="rgba(255,255,255,0.8)",
bordercolor="black",
borderwidth=1,
itemsizing="trace"
),
showlegend=True
)
canvas.show()
Что именно идёт не так
Передача параметра textposition="center" в трейс go.Scattermapbox приводит к тому, что Plotly пропускает отрисовку текста, хотя в документации указано, что параметр поддерживается. Столбики отображаются, потому что это отдельный трейс с линиями, но слой с подписями так и не появляется. И при этом нет необходимости ставить невидимый маркер, чтобы якорить текст.
Решение
Используйте чисто текстовый слой и полностью уберите textposition. В таком режиме подписи стабильно рисуются в тех lon/lat, которые вы задаёте.
canvas.add_trace(go.Scattermapbox(
mode="text",
lon=[xlon + shift],
lat=[ylat + bar_h + 0.10],
text=[f"{pct:.1f}%"],
textfont=dict(size=12, color="black"),
showlegend=False,
hoverinfo="skip",
))
Это изменение сохраняет прежнюю логику размещения подписей. Оно лишь переводит слой с markers+text и textposition в специализированный текстовый режим, который рендерится предсказуемо.
Почему это важно
В составных геовизуализациях стабильная отрисовка текста — ключ к читаемости и к обмену статичными изображениями, где нет интерактивности. Если подписи молча не появляются, пользователи теряют возможность мгновенно понять карту. Держите слой подписей минимальным и явным — так меньше сюрпризов и проще поддержка.
Выводы
Если подписи в Scattermapbox не показываются, уберите textposition="center" и используйте mode="text" для слоя с подписями. Располагайте их по lon/lat, настраивайте внешний вид через textfont и держите слой подписей независимым от маркеров. Этот небольшой шаг помогает числовым аннотациям надёжно рендериться поверх тайлов Mapbox.