我正在制作一些散点图,我想将图例中点的大小设置为固定的相等值。
现在我有这个:
import matplotlib.pyplot as plt
import numpy as np
def rand_data():
return np.random.uniform(low=0., high=1., size=(100,))
# Generate data.
x1, y1 = [rand_data() for i in range(2)]
x2, y2 = [rand_data() for i in range(2)]
plt.figure()
plt.scatter(x1, y1, marker='o', label='first', s=20., c='b')
plt.scatter(x2, y2, marker='o', label='second', s=35., c='r')
# Plot legend.
plt.legend(loc="lower left", markerscale=2., scatterpoints=1, fontsize=10)
plt.show()
产生这个:
图例中点的大小是缩放的但不相同。如何在不影响scatter
图中大小的情况下将图例中点的大小固定为相等的值?
答案 0 :(得分:42)
我查看了matplotlib
的源代码。坏消息是,似乎没有任何简单的方法可以在图例中设置相同大小的点。散点图特别困难(错误:请参阅下面的更新)。基本上有两种选择:
maplotlib
代码PathCollection
个对象中。变换(缩放)必须考虑原始大小。这些都不是很有趣,虽然#1似乎更容易。在这方面,scatter
地块尤其具有挑战性。
然而,我有一个黑客可能你想要的东西:
import matplotlib.pyplot as plt
import numpy as np
def rand_data():
return np.random.uniform(low=0., high=1., size=(100,))
# Generate data.
x1, y1 = [rand_data() for i in range(2)]
x2, y2 = [rand_data() for i in range(2)]
plt.figure()
plt.plot(x1, y1, 'o', label='first', markersize=np.sqrt(20.), c='b')
plt.plot(x2, y2, 'o', label='second', markersize=np.sqrt(35.), c='r')
# Plot legend.
lgnd = plt.legend(loc="lower left", numpoints=1, fontsize=10)
#change the marker size manually for both lines
lgnd.legendHandles[0]._legmarker.set_markersize(6)
lgnd.legendHandles[1]._legmarker.set_markersize(6)
plt.show()
这给出了:
这似乎是你想要的。
变化:
scatter
更改为plot
,这会更改标记比例(因此sqrt
),并且无法使用更改的标记大小(如果是这样)正如您所看到的,这利用了隐藏的下划线属性(_legmarker
),并且非常丑陋。它可能会在matplotlib
的任何更新中崩溃。
<强>更新强>
哈,我找到了。一个更好的黑客:import matplotlib.pyplot as plt
import numpy as np
def rand_data():
return np.random.uniform(low=0., high=1., size=(100,))
# Generate data.
x1, y1 = [rand_data() for i in range(2)]
x2, y2 = [rand_data() for i in range(2)]
plt.figure()
plt.scatter(x1, y1, marker='o', label='first', s=20., c='b')
plt.scatter(x2, y2, marker='o', label='second', s=35., c='r')
# Plot legend.
lgnd = plt.legend(loc="lower left", scatterpoints=1, fontsize=10)
lgnd.legendHandles[0]._sizes = [30]
lgnd.legendHandles[1]._sizes = [30]
plt.show()
现在_sizes
(另一个下划线属性)可以解决问题。不需要触摸源,即使这是一个非常黑客。但现在您可以使用scatter
提供的所有内容。
答案 1 :(得分:13)
与答案类似,假设您希望所有标记具有相同的大小:
lgnd = plt.legend(loc="lower left", scatterpoints=1, fontsize=10)
for handle in lgnd.legendHandles:
handle.set_sizes([6.0])
使用MatPlotlib 2.0.0
答案 2 :(得分:6)
使用@ DrV的解决方案并没有太大成功,尽管我的用例可能是独一无二的。由于点的密度,我使用最小的标记大小,即plt.plot(x, y, '.', ms=1, ...)
,并希望图例符号更大。
我遵循了matplotlib forums上的建议:
答案 3 :(得分:2)
这里只是另一种选择。这样做的好处是它将不使用任何“私有”方法,甚至可以与图例中存在的散点以外的其他对象一起使用。关键是使用已设置的更新功能将散点图PathCollection
映射到HandlerPathCollection
。
def update(handle, orig):
handle.update_from(orig)
handle.set_sizes([64])
plt.legend(handler_map={PathCollection : HandlerPathCollection(update_func=update)})
完整的代码示例:
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(42)
from matplotlib.collections import PathCollection
from matplotlib.legend_handler import HandlerPathCollection
colors = ["limegreen", "crimson", "indigo"]
markers = ["o", "s", r"$\clubsuit$"]
labels = ["ABC", "DEF", "XYZ"]
plt.plot(np.linspace(0,1,8), np.random.rand(8), label="A line")
for i,(c,m,l) in enumerate(zip(colors,markers,labels)):
plt.scatter(np.random.rand(8),np.random.rand(8),
c=c, marker=m, s=10+np.exp(i*2.9), label=l)
def update(handle, orig):
handle.update_from(orig)
handle.set_sizes([64])
plt.legend(handler_map={PathCollection : HandlerPathCollection(update_func=update)})
plt.show()
答案 4 :(得分:0)
您可以制作类似于所选标记的Line2D对象,但选择的标记大小不同,并使用它来构建图例。这很好,因为它不需要在轴上放置一个对象(可能触发调整大小事件),并且它不需要使用任何隐藏属性。唯一真正的缺点是您必须从对象和标签列表中明确构建图例,但这是一个记录良好的matplotlib功能,因此使用起来非常安全。
from matplotlib.lines import Line2D
import matplotlib.pyplot as plt
import numpy as np
def rand_data():
return np.random.uniform(low=0., high=1., size=(100,))
# Generate data.
x1, y1 = [rand_data() for i in range(2)]
x2, y2 = [rand_data() for i in range(2)]
plt.figure()
plt.scatter(x1, y1, marker='o', label='first', s=20., c='b')
plt.scatter(x2, y2, marker='o', label='second', s=35., c='r')
# Create dummy Line2D objects for legend
h1 = Line2D([0], [0], marker='o', markersize=np.sqrt(20), color='b', linestyle='None')
h2 = Line2D([0], [0], marker='o', markersize=np.sqrt(20), color='r', linestyle='None')
# Set axes limits
plt.gca().set_xlim(-0.2, 1.2)
plt.gca().set_ylim(-0.2, 1.2)
# Plot legend.
plt.legend([h1, h2], ['first', 'second'], loc="lower left", markerscale=2,
scatterpoints=1, fontsize=10)
plt.show()