Number of points in legend

Hi all,

By default, 'legend' uses two points two represent a line. This looks
a bit weird when you have only markers (no line), e.g.,

import matplotlib.pyplot as plt
plt.plot([1,2,3], [4,5,6], 'x', label='first line')
plt.legend()
plt.show()

Notice how there are two crosses in the legend. Having only one, as in

import matplotlib.pyplot as plt
plt.plot([1,2,3], [4,5,6], 'x', label='first line')
plt.legend(numpoints=1)
plt.show()

would look better.

Unfortunately, I can't always use numpoints=1, because then the legend
for a normal line isn't drawn properly:

import matplotlib.pyplot as plt
plt.plot([1,2,3], [4,5,6], 'x-', label='first line')
plt.legend(numpoints=1)
plt.show()

What would be ideal (for me personally), is to have, for numpoints=1:

linestyle 'x' ---> legend ' x '
linestyle '-x' ---> legend '---x---'

Has this been considered before? If not, I'll write a patch.

Regards
Stéfan

I think this is just something that has been overlooked. The legend
code is quite old, so don't be surprised if it looks a little crusty
in there, as it was one of the early features, and it has been updated
piecemeal with new features. A patch would be great.

JDH

···

On Thu, Jun 12, 2008 at 7:56 AM, Stéfan van der Walt <stefan@...337...> wrote:

linestyle 'x' ---> legend ' x '
linestyle '-x' ---> legend '---x---'

Has this been considered before? If not, I'll write a patch.

Hi John

2008/6/12 John Hunter <jdh2358@...149...>:

matplotlib_legend.patch (1.86 KB)

···

On Thu, Jun 12, 2008 at 7:56 AM, Stéfan van der Walt <stefan@...337...> wrote:

linestyle 'x' ---> legend ' x '
linestyle '-x' ---> legend '---x---'

Has this been considered before? If not, I'll write a patch.

I think this is just something that has been overlooked. The legend
code is quite old, so don't be surprised if it looks a little crusty
in there, as it was one of the early features, and it has been updated
piecemeal with new features. A patch would be great.

The idea I had was to plot two lines on top of each other: one for the
line-style, and one for the bullets. Unfortunately, I can't get the
lines to co-incide. Could you look at the attached toy-patch and tell
me where I am going wrong? Note how the X is somewhat below the line.

Thanks
Stéfan

Hi all,

Sorry to bump the thread, but has anyone had a chance to take a look?

I've re-attached the patch.

Regards
Stéfan

2008/6/17 Stéfan van der Walt <stefan@...337...>:

matplotlib_legend.patch (1.86 KB)

···

Hi John

2008/6/12 John Hunter <jdh2358@...149...>:

On Thu, Jun 12, 2008 at 7:56 AM, Stéfan van der Walt <stefan@...337...> wrote:

linestyle 'x' ---> legend ' x '
linestyle '-x' ---> legend '---x---'

Has this been considered before? If not, I'll write a patch.

I think this is just something that has been overlooked. The legend
code is quite old, so don't be surprised if it looks a little crusty
in there, as it was one of the early features, and it has been updated
piecemeal with new features. A patch would be great.

The idea I had was to plot two lines on top of each other: one for the
line-style, and one for the bullets. Unfortunately, I can't get the
lines to co-incide. Could you look at the attached toy-patch and tell
me where I am going wrong? Note how the X is somewhat below the line.

Thanks
Stéfan

Thanks for the reminder and sorry for the delay getting back. The
problem in the patch was that the "self.texts" variable and
"self.legendHandles" variables are assumed to be equal length lists.
When you added an extra marker line but not an extra label, the layout
got out of whack, but this was masked in "_update_positions" by a
silent zip failure. I replaced that call with our cbook.safezip
function, which will at least fail noisily if the input lists are
unequal (note to all mpl devels, use safezip rather than zip).

The solution was not to modify the legendHandles return list "ret" at
all, since tracking that through all the hairy legend code proved
untenable. Instead, I made the code a little hairier by tacking on
your marker proxy as an attribute of the legend line::

                legline_marker = Line2D(xdata_marker, ydata[:len(xdata_marker)])
                legline_marker.update_from(handle)
                legline_marker.set_linestyle('None')
                self._set_artist_props(legline_marker)
                # we don't want to add this to the return list because
                # the texts and handles are assumed to be in one to ne
                # correpondence.
                legline._legmarker = legline_marker

and then accessing the "_legmarker" attr in _update_positions and
draw. Note you can use the marker 'None' rather than setting the
markersize to 0; we use the string 'None' for the marker and linestyle
since None means "do the rc default" in many contexts.

Committed to svn r5654 -- here is the test script::

  import numpy as np
  import matplotlib.pyplot as plt
  plt.plot(np.random.rand(10), 'x-', label='first line')
  plt.plot(np.random.rand(10), 'o-.', label='second line')
  plt.legend(numpoints=1)
  plt.show()

At some point we need to do a clean room impl of the legend code as it
is suffering from feature creep and the internals are getting uglier.

JDH

···

On Tue, Jun 24, 2008 at 1:57 AM, Stéfan van der Walt <stefan@...337...> wrote:

Hi all,

Sorry to bump the thread, but has anyone had a chance to take a look?

I've re-attached the patch.

2008/6/24 John Hunter <jdh2358@...149...>:

Committed to svn r5654 -- here is the test script::

import numpy as np
import matplotlib.pyplot as plt
plt.plot(np.random.rand(10), 'x-', label='first line')
plt.plot(np.random.rand(10), 'o-.', label='second line')
plt.legend(numpoints=1)
plt.show()

Thank you very much, that looks great!

Regards
Stéfan