Two unique marker symbols for one legend

2024/10/15 8:24:09

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"])

enter image description here

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.

enter image description here

The final solution by adding numpoints=1 to the general legend() worked. Here's how I wanted it. Thanks tcaswell!

enter image description here

Answer

solve exception issue

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.

hacky solution

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.

cleaner solution

from matplotlib.legend_handler import HandlerLine2Dclass 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_offsetdef 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# markerxdata = np.linspace(-xdescent + self._marker_pad * fontsize,width - self._marker_pad * fontsize,numpoints) - self._xoffsetxdata_marker = xdataelif numpoints == 1:xdata = np.linspace(-xdescent, width, 2) - self._xoffsetxdata_marker = [0.5 * width - 0.5 * xdescent - self._xoffset]print xdata, self._xoffsetprint xdata_markerreturn xdata, xdata_markertime_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.

enter image description here

https://en.xdnf.cn/q/69307.html

Related Q&A

What is Rubys equivalent to Pythons multiprocessing module?

To get real concurrency in Ruby or Python, I need to create new processes. Python makes this pretty straightforward using the multiprocessing module, which abstracts away all the fork / wait goodness a…

Using grep in python

There is a file (query.txt) which has some keywords/phrases which are to be matched with other files using grep. The last three lines of the following code are working perfectly but when the same comma…

shuffling a list with restrictions in Python

I have a problem with randomizing a list with restrictions in Python (3). I have seen a few other questions relating to this, but none of them really seem to solve my problem. Im a beginner, so any hel…

Django: Is it reasonable to use objects as dictionary keys?

Is it reasonable to use objects as keys to a dictionary in django? I have done so and it works. But I am wondering if this is best practice, or if it is going to make difficulties I dont foresee righ…

How do I now (since June 2022) send an email via Gmail using a Python script?

I had a Python script which did this. I had to enable something in the Gmail account. For maybe 3 years the script then ran like this: import smtplib, ssl ... subject = some subject message body = &quo…

Fast relational database for simple use with Python [closed]

Closed. This question is seeking recommendations for books, tools, software libraries, and more. It does not meet Stack Overflow guidelines. It is not currently accepting answers.We don’t allow questi…

Event handling with Jython Swing

Im making a GUI by using Swing from Jython. Event handling seems to be particularly elegant from Jython, just setJButton("Push me", actionPerformed = nameOfFunctionToCall)However, trying same…

How Does Deque Work in Python

I am having trouble understanding how the deque works in the snippet of code below, while trying to recreate a queue and a stack in Python.Stack Example - Understoodstack = ["a", "b"…

When to use generator functions and when to use loops in Python

I am coming from a Matlab background and I am finding it difficult to get around the concept of generators in Python. Can someone please answer me the following:The difference between a generator funct…

Airflow - Disable heartbeat logs

My logs are getting completely flooded with useless messages for every heartbeat. [2019-11-27 21:32:47,890] {{logging_mixin.py:112}} INFO - [2019-11-27 21:32:47,889] {local_task_job.py:124} WARNING - T…