Создание связанного размера легенды разметки matplotlib

Я ищу способ включения легенды (matplotlib), описывающей размер точек в диаграмме рассеяния, поскольку это может быть связано с другой переменной, как в этом базовом примере:

import numpy as np
import matplotlib.pyplot as plt

N = 50
x = np.random.rand(N)
y = np.random.rand(N)
a2 = 400*np.random.rand(N)

plt.scatter(x, y, s=a2, alpha=0.5)
plt.show()

(вдохновленный: http://matplotlib.org/examples/shapes_and_collections/scatter_demo.html)

поэтому в легенде было бы идеально мало пятен, соответствующих размерам 0-400 (переменная a2), в соответствии с дескриптором s в scatter.

Ответ 1

В приведенном ниже решении используется pandas для группировки размеров вместе в множество бункеров (с groupby). Он отображает каждую группу и присваивает ей метку и размер для маркеров. Я использовал рецепт binning из этого вопроса.

Примечание это немного отличается от вашей заявленной проблемы, поскольку размеры маркера бинны, это означает, что два элемента в a2, скажем, 36 и 38, будут иметь тот же размер, что и в пределах тот же биннинг. Вы всегда можете увеличить количество ящиков, чтобы сделать его более тонким, как вам подходит.

Используя этот метод, вы можете изменять другие параметры для каждого бункера, такие как форма или цвет маркера.

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

N = 50
M = 5 # Number of bins

x = np.random.rand(N)
y = np.random.rand(N)
a2 = 400*np.random.rand(N)

# Create the DataFrame from your randomised data and bin it using groupby.
df = pd.DataFrame(data=dict(x=x, y=y, a2=a2))
bins = np.linspace(df.a2.min(), df.a2.max(), M)
grouped = df.groupby(np.digitize(df.a2, bins))

# Create some sizes and some labels.
sizes = [50*(i+1.) for i in range(M)]
labels = ['Tiny', 'Small', 'Medium', 'Large', 'Huge']

for i, (name, group) in enumerate(grouped):
    plt.scatter(group.x, group.y, s=sizes[i], alpha=0.5, label=labels[i])

plt.legend()
plt.show()

Plot

Ответ 2

Это также сработает, и я думаю, это немного проще:

msizes = np.array([3, 4, 5, 6, 7, 8])

l1, = plt.plot([],[], 'or', markersize=msizes[0])
l2, = plt.plot([],[], 'or', markersize=msizes[1])
l3, = plt.plot([],[], 'or', markersize=msizes[2])
l4, = plt.plot([],[], 'or', markersize=msizes[3])

labels = ['M3', 'M4', 'M5', 'M6']

leg = plt.legend([l1, l2, l3, l4], labels, ncol=1, frameon=True, fontsize=12,
handlelength=2, loc = 8, borderpad = 1.8,
handletextpad=1, title='My Title', scatterpoints = 1)

Взято из: Означает размерные легенды в графиках matplotlib и baseemap

Ответ 3

Мне почти нравится ответ mjp, но он не работает, потому что аргумент plt.plot 'markersize' не означает то же, что аргумент plt.scatter '. Ваши размеры будут неправильными с использованием plt.plot.

Вместо этого используйте:

    marker1 = plt.scatter([],[], s=a2.min())
    marker2 = plt.scatter([],[], s=a2.max())
    legend_markers = [marker1, marker2]

    labels = [
        str(round(a2.min(),2)),
        str(round(a2.max(),2))
        ]

    fig.legend(handles=legend_markers, labels=labels, loc='upper_right',
        scatterpoints=1)

Ответ 4

Основываясь на ответах mjp и jpobst, если у вас более двух отдельных размеров, вы можете сделать цикл и включить метки в вызов plt.scatter():

msizes = [3, 4, 5, 6, 7]
markers = []
for size in msizes:
    markers.append(plt.scatter([],[], s=size, label=size)

plt.legend(handles=markers)

Обратите внимание, что вы можете отформатировать метку, используя стандартное форматирование строки, например label = ('M%d' %size) для меток в ответе mjp.

Ответ 5

Я нашел это здесь, это так просто и лаконично. Надеюсь, это поможет

import matplotlib.pyplot as plt
import numpy as np

import plotly.plotly as py
import plotly.tools as tls

fig = plt.figure()
ax = fig.add_subplot(111)

x = [0,2,4,6,8,10]
y = [0]*len(x)
s = [100,  400, 490, 600, 240, 160] # Specifies marker size

ax.scatter(x,y,s=s)
ax.set_title('Plot with Different Marker size, matplotlib and plotly')

plotly_fig = tls.mpl_to_plotly( fig )
plotly_fig['layout']['showlegend'] = True
plotly_url = py.plot(plotly_fig, filename='mpl-marker-size')

Ответ 6

Используйте .legend_elements("sizes"):

import numpy as np
import matplotlib.pyplot as plt

N = 50
x = np.random.rand(N)
y = np.random.rand(N)
a2 = 400*np.random.rand(N)

sc = plt.scatter(x, y, s=a2, alpha=0.5)
plt.legend(*sc.legend_elements("sizes", num=6))
plt.show()

enter image description here