I'm making some scatter plots and I want to set the size of the points in the legend to a fixed, equal value.
Right now I have this:
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()
which produces this:
The sizes of the points in the legend are scaled but not the same. How can I fix the sizes of the points in the legend to an equal value without affecting the sizes in the scatter
plot?
To change the position of a legend in Matplotlib, you can use the plt. legend() function. The default location is “best” – which is where Matplotlib automatically finds a location for the legend based on where it avoids covering any data points.
To set a legend with title, we use legend() method with labels and title arguments. Then we get the legend title, by using the get_title() function. To change the font size of legend's title, we use set_fontsize() method and set it to x-large.
I had a look into the source code of matplotlib
. Bad news is that there does not seem to be any simple way of setting equal sizes of points in the legend. It is especially difficult with scatter plots (wrong: see the update below). There are essentially two alternatives:
maplotlib
codePathCollection
objects representing the dots in the image. The transform (scaling) has to take the original size into account.Neither of these is very much fun, though #1 seems to be easier. The scatter
plots are especially challenging in this respect.
However, I have a hack which does probably what you want:
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()
This gives:
Which seems to be what you wanted.
The changes:
scatter
changed into a plot
, which changes the marker scaling (hence the sqrt
) and makes it impossible to use changing marker size (if that was intended)As you can see, this utilizes hidden underscore properties (_legmarker
) and is bug-ugly. It may break down at any update in matplotlib
.
Update
Haa, I found it. A better hack:
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()
Now the _sizes
(another underscore property) does the trick. No need to touch the source, even though this is quite a hack. But now you can use everything scatter
offers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With