2026, Jan 02 21:02
Как сделать легенду в GeoPandas: прокси-artist в Matplotlib
Почему легенда в GeoPandas остается пустой и как исправить в Matplotlib: используем proxy artist (Patch) вместо Axes, приводим минимальный пример и рабочий код.
Получить работающую легенду в графике GeoPandas бывает неожиданно сложно. Рисунок отображается, но легенда остаётся пустой или появляется предупреждение. Причина проста: в legend надо передавать рисуемый artist, а не объект Axes, который возвращает GeoPandas.
Минимальный пример, воспроизводящий проблему
import geopandas as gpd
from shapely.geometry import box, Polygon, LineString
import matplotlib.pyplot as plt
fig_map, ax_map = plt.subplots()
bounds = [9.454, 80.4, 12, 80.88]
rect = box(*bounds)
geo_frame = gpd.GeoDataFrame(geometry=[rect])
drawn = geo_frame.plot(
ax=ax_map,
edgecolor='red',
facecolor='none',
linewidth=2,
label="user bbox query"
)
# Это не сработает: "drawn" — это Axes, а не объект для легенды
ax_map.legend(handles=[drawn])
plt.xlabel('Longitude')
plt.ylabel('Latitude')
plt.show()
Matplotlib объясняет, почему это не срабатывает:
Легенда не поддерживает handles для экземпляров Axes. Вместо этого можно использовать прокси-объект (proxy artist).
Почему так происходит
GeoPandas использует Matplotlib под капотом. Вызов GeoDataFrame.plot возвращает Axes. Легенды же строятся из artists — патчей, линий или коллекций, то есть объектов, которые реально рисуются на графике. Передача Axes в legend не поддерживается и приводит к пустой легенде. Решение — дать легенде прокси‑artist с теми же стилями, что и у нарисованного объекта.
Рабочий подход с прокси‑объектом
Создайте Patch с теми же стилями, что у вашего полигона, и передайте его в legend. Размещение легенды вне области осей помогает избежать перекрытия карты и делает подпись читаемой.
import geopandas as gpd
from shapely.geometry import box
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
fig_map, ax_map = plt.subplots()
bounds = [9.454, 80.4, 12, 80.88]
rect = box(*bounds)
geo_frame = gpd.GeoDataFrame(geometry=[rect])
geo_frame.plot(
ax=ax_map,
edgecolor='red',
facecolor='none',
linewidth=2
)
legend_item = mpatches.Patch(
facecolor='none',
edgecolor='red',
linewidth=2,
label='user bbox query'
)
ax_map.legend(handles=[legend_item], bbox_to_anchor=(1.05, 1), loc='upper left')
plt.xlabel('Longitude')
plt.ylabel('Latitude')
plt.tight_layout()
plt.show()
Почему это стоит запомнить
Легенды в Matplotlib зависят от передаваемых handle-объектов. Если handle не является рисуемым artist, легенда не покажет ожидаемый результат. В рабочих процессах с GeoPandas это встречается часто, потому что удобный API для построения графиков возвращает Axes, тогда как легенде нужен artist. Использование прокси‑объекта вроде Patch сохраняет точность легенды и читаемость карты. Размещение легенды за пределами области построения с помощью bbox_to_anchor помогает, когда содержимое карты плотно заполняет оси.
Вывод
Если легенда в GeoPandas пустая или не отображается, не передавайте Axes в legend. Дайте легенде прокси‑artist, повторяющий стиль вашей геометрии, и расположите её там, где есть место. Шаблон прост: отрисуйте данные, создайте соответствующий Patch (или другой artist), передайте его в legend и доверьте tight_layout расстановку отступов.