I would like to add a "red filled square" symbol beside the "red filled circle" symbol under legend. How do I achieve this? I prefer to stick with pyplot rather than pylab.
Below is the code I've been using:
fig = plt.figure()
ax1 = fig.add_axes([0.1,0.29,0.86,0.68])
plt.ylabel('Radial Velocity (km s$^{-1}$)')
plt.plot(time_model, rv_model_primary, 'k-', label = 'Primary')
plt.plot(time_model_sec, rv_model_secondary, 'k--', label = 'Secondary')
plt.plot(time_obs, rv_obs_primary, 'bo', label='XYZ')
plt.plot(time_obs_apg, rv_obs_primary_apg, 'ro', label='This Work')
plt.plot(time_obs_apg_sec, rv_obs_secondary_apg, 'rs')
plt.plot((0.0, 1.0),(0.0,0.0), 'k-.')
plt.legend(loc='upper left', numpoints=1)
Here's what I tried:
p1=plt.plot(time_model, rv_model_primary, 'k-')
p2=plt.plot(time_model_sec, rv_model_secondary, 'k--')
p3=plt.plot(time_obs, rv_obs_primary, 'bo')
p4=plt.plot(time_obs_apg, rv_obs_primary_apg, 'ro')
p5=plt.plot(time_obs_apg_sec, rv_obs_secondary_apg, 'rs')
plt.legend([p1,p2,p3,(p4,p5)],["Primary", "Secondary", "XYZ", "This Work"])
After making changes to the code using tcaswell's suggestions I get the following. The looks good but I would like to have just one symbol for blue while keeping the two for red. Currently there are two.
The final solution by adding numpoints=1 to the general legend() worked. Here's how I wanted it. Thanks tcaswell!
Legend Markers can be displayed within the legend to help end-users visually identify different chart elements such as the series, constant lines and strips indicated by the legend. The content of each legend marker depends upon the type of the corresponding chart element.
In the matplotlib library, there's a function called legend() which is used to Place a legend on the axes. The attribute Loc in legend() is used to specify the location of the legend. Default value of loc is loc=”best” (upper left).
Suspect you need to do:
p1, = plt.plot(time_model, rv_model_primary, 'k-')
p2, = plt.plot(time_model_sec, rv_model_secondary, 'k--')
p3, = plt.plot(time_obs, rv_obs_primary, 'bo')
p4, = plt.plot(time_obs_apg, rv_obs_primary_apg, 'ro')
p5, = plt.plot(time_obs_apg_sec, rv_obs_secondary_apg, 'rs')
plot
returns a list of Line2D
objects (the extra ,
unpacks it) and I think that the expected types in are getting mucked up. This fixes your exceptions issue, but does not actually solve your problem.
A some what hacky way to solve this is:
plt.legend([p1,p2,p3,(p5,p4)],["Primary", "Secondary", "XYZ", "This Work"],
handler_map={p4:HandlerLine2D(numpoints=2), p5:HandlerLine2D(numpoints=1)})
which gives you three points, two of one and one of the other.
from matplotlib.legend_handler import HandlerLine2D
class HandlerXoffset(HandlerLine2D):
def __init__(self, marker_pad=0.3, numpoints=1, x_offset=0, **kw):
HandlerLine2D.__init__(self, marker_pad=marker_pad, numpoints=numpoints, **kw)
self._xoffset = x_offset
def get_xdata(self, legend, xdescent, ydescent, width, height, fontsize):
numpoints = self.get_numpoints(legend)
if numpoints > 1:
# we put some pad here to compensate the size of the
# marker
xdata = np.linspace(-xdescent + self._marker_pad * fontsize,
width - self._marker_pad * fontsize,
numpoints) - self._xoffset
xdata_marker = xdata
elif numpoints == 1:
xdata = np.linspace(-xdescent, width, 2) - self._xoffset
xdata_marker = [0.5 * width - 0.5 * xdescent - self._xoffset]
print xdata, self._xoffset
print xdata_marker
return xdata, xdata_marker
time_model = time_model_sec = time_obs = time_obs_apg = time_obs_apg_sec = range(5)
rv_model_primary = np.random.rand(5)
rv_model_secondary = np.random.rand(5)
rv_obs_primary = np.random.rand(5)
rv_obs_primary_apg = np.random.rand(5)
rv_obs_secondary_apg = np.random.rand(5)
p1,=plt.plot(time_model, rv_model_primary, 'k-')
p2,=plt.plot(time_model_sec, rv_model_secondary, 'k--')
p3,=plt.plot(time_obs, rv_obs_primary, 'bo')
p4,=plt.plot(time_obs_apg, rv_obs_primary_apg, 'ro')
p5,=plt.plot(time_obs_apg_sec, rv_obs_secondary_apg, 'rs')
plt.legend([p1,p2,p3,(p5,p4)],
["Primary", "Secondary", "XYZ", "This Work"],
handler_map={p4:HandlerXoffset(x_offset=10),
p5:HandlerXoffset(x_offset=-10)})
gist
You will probably have to play with x_offset
a bit to make it look right, and there is probably a better way to automatically figure out what it's value should be, but this should be enough to get you started.
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