2025, Nov 16 12:01

Увеличиваем маркер scatter и шрифт легенды в Matplotlib

Разберемся, почему маркер scatter в легенде Matplotlib остается маленьким, и как увеличить его: через markerscale при legend() или set_sizes у PathCollection.

При подготовке фигур Matplotlib к экспорту увеличить кегль текста в легенде несложно, но значок scatter в легенде часто остается крошечным. Обычные правки, затрагивающие только шрифт, не меняют сам маркер, из‑за чего аккуратно выверенная фигура выглядит несогласованной. Ниже показано, как корректно масштабировать и текст легенды, и маркер scatter.

Воспроизводим проблему

Задумка — укрупнить текст легенды, но точка рядом с подписью остается маленькой:

import matplotlib.pyplot as plt

def grow_legend(ax_obj, text_size=25):
    for t in ax_obj.get_legend().get_texts():
        t.set_fontsize(text_size)

fig, axe = plt.subplots()
axe.scatter([1, 2, 3], [2, 3, 1], label="auto")
axe.legend()
grow_legend(axe)

Кегль действительно увеличивается, но размер маркера в легенде не меняется.

Что на самом деле происходит

Символ, который попадает в легенду для scatter-графика, — это PathCollection, а не Line2D или Patch. Поэтому get_patches и get_lines для этой легенды возвращают пустые последовательности. Видимый маркер — не линия и не патч; это handle коллекции scatter. Чтобы масштабировать этот символ, либо задайте markerscale при создании легенды, либо измените sizes у коллекции после создания легенды.

Два практических способа решения

Самый прямой подход — управлять символом при создании легенды через markerscale. Он масштабирует маркер легенды относительно размера маркера на графике и логично сочетается с fontsize:

import matplotlib.pyplot as plt

fig, axis = plt.subplots()
axis.scatter([1, 2, 3], [2, 3, 1], label='auto')

# Масштабируем и текст, и точку легенды
axis.legend(fontsize=25, markerscale=3)

Если удобнее воспользоваться вспомогательной функцией для уже существующей легенды, можно изменить и текст, и размеры handle scatter. Главное — получить handles легенды и вызвать set_sizes, передав площадь в пунктах²:

import matplotlib.pyplot as plt

def resize_legend(axi, txt_size=25, dot_area=200):
    leg = axi.get_legend()
    for item in leg.get_texts():
        item.set_fontsize(txt_size)
    # Учтите различия в названиях атрибутов между версиями Matplotlib
    handles = getattr(leg, "legendHandles", getattr(leg, "legend_handles", []))
    for h in handles:
        h.set_sizes([dot_area])

fig, axis = plt.subplots()
axis.scatter([1, 2, 3], [2, 3, 1], label='auto')
axis.legend()
resize_legend(axis)

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

Почему это важно

Легенды — часть визуальной иерархии фигуры. Когда шрифт становится крупнее, а символы остаются мелкими, баланс нарушается, и просматривать такую легенду сложнее. Совместное масштабирование маркеров и подписей сохраняет целостность рисунка и повышает читаемость в отчетах и публикациях.

Рекомендации

Используйте markerscale, если при создании легенды вы заранее знаете целевой размер. Если нужно доработать уже построенные графики или требуется явный контроль площади маркера в пунктах², получите handles легенды и вызовите set_sizes у PathCollection. В средах с разными версиями Matplotlib обращайтесь к handles «защитно», как показано выше, чтобы избежать ошибок атрибутов.

Согласованность текста и маркеров в легенде — небольшая доработка с большим эффектом для ясности и качества подачи.