Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

legend do not work without handles #188

Closed
kinyatoride opened this issue Jun 13, 2020 · 7 comments
Closed

legend do not work without handles #188

kinyatoride opened this issue Jun 13, 2020 · 7 comments
Labels

Comments

@kinyatoride
Copy link

Description

There seem to be issues with get_legend_handles_labels when no handles are passed to ax.legend.
It would be better if this works as sometimes making handles are cumbersome.

Steps to reproduce

import proplot as plot

fig, ax = plot.subplots()
ax.plot([0, 1, 2], label='a')
ax.plot([0, 1, 1], label='b')
ax.legend()

Expected behavior: [What you expected to happen]
legend shows up

Actual behavior: [What actually happened]

ValueError Traceback (most recent call last)
in
4 ax.plot([0, 1, 2], label='a')
5 ax.plot([0, 1, 1], label='b')
----> 6 ax.legend()

~/miniconda3/envs/basic2/lib/python3.7/site-packages/proplot/ui.py in _iterator(*args, **kwargs)
680 result = []
681 for func in objs:
--> 682 result.append(func(*args, **kwargs))
683 if len(self) == 1:
684 return result[0]

~/miniconda3/envs/basic2/lib/python3.7/site-packages/proplot/axes/base.py in legend(self, loc, width, space, *args, **kwargs)
1399
1400 # Draw legend
-> 1401 return legend_wrapper(self, *args, loc=loc, **kwargs)
1402
1403 def draw(self, renderer=None, *args, **kwargs):

~/miniconda3/envs/basic2/lib/python3.7/site-packages/proplot/axes/plot.py in legend_wrapper(self, handles, labels, ncol, ncols, center, order, loc, label, title, fontsize, fontweight, fontcolor, color, marker, lw, linewidth, dashes, linestyle, markersize, frameon, frame, **kwargs)
3137 if list_of_lists:
3138 if any(not np.iterable(_) for _ in handles):
-> 3139 raise ValueError(f'Invalid handles={handles!r}.')
3140 if not labels:
3141 labels = [None] * len(handles)

ValueError: Invalid handles=[None].

Equivalent steps in matplotlib

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.plot([0, 1, 2], label='a')
ax.plot([0, 1, 1], label='b')

ax.legend()

Screen Shot 2020-06-13 at 10 14 12

Proplot version

0.63

@lukelbd
Copy link
Collaborator

lukelbd commented Jun 14, 2020

Thanks for the report, this is fixed now. Another issue that highlights the need for more robust testing

@lukelbd lukelbd added the bug label Jun 14, 2020
@GonzaloSaez
Copy link

GonzaloSaez commented Jun 14, 2020

Hi @lukelbd ,

Is it possible to call legend on an axis of a given plot of a subplots without the handles argument? Whenever I try this I get an error:

ax[1].legend(loc='b', ncols=4, center=True)

Error:

line 3362, in legend_wrapper interval = 1 / len(pairs) # split up axes ZeroDivisionError: division by zero

It would be nice if the legend could directly access the default handles without relying on their generation when plotting...

@lukelbd
Copy link
Collaborator

lukelbd commented Jun 14, 2020

Hi @ssssoo -- thanks for the report!

This was an unfortunate bug that occured when using the "side" locations instead of an inner location like 'upper left'. I copied your comment into a dedicated thread (#189), it's now fixed in the master branch.

@kinyatoride
Copy link
Author

Hi @lukelbd

This issue still appears when loc is passed.

ax.legend(loc='b')

Error:

No handles with labels found to put in legend.
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-58dceaf93eec> in <module>
      4 ax.plot([0, 1, 2], label='a')
      5 ax.plot([0, 1, 1], label='b')
----> 6 ax.legend(loc='b')

~/miniconda3/envs/basic/lib/python3.8/site-packages/proplot/ui.py in _iterator(*args, **kwargs)
    680                 result = []
    681                 for func in objs:
--> 682                     result.append(func(*args, **kwargs))
    683                 if len(self) == 1:
    684                     return result[0]

~/miniconda3/envs/basic/lib/python3.8/site-packages/proplot/axes/base.py in legend(self, loc, width, space, *args, **kwargs)
   1369         if loc in ('left', 'right', 'top', 'bottom'):
   1370             ax = self.panel_axes(loc, width=width, space=space, filled=True)
-> 1371             return ax.legend(*args, loc='fill', **kwargs)
   1372 
   1373         # Fill

~/miniconda3/envs/basic/lib/python3.8/site-packages/proplot/axes/base.py in legend(self, loc, width, space, *args, **kwargs)
   1399 
   1400         # Draw legend
-> 1401         return legend_wrapper(self, *args, loc=loc, **kwargs)
   1402 
   1403     def draw(self, renderer=None, *args, **kwargs):

~/miniconda3/envs/basic/lib/python3.8/site-packages/proplot/axes/plot.py in legend_wrapper(self, handles, labels, ncol, ncols, center, order, loc, label, title, fontsize, fontweight, fontcolor, color, marker, lw, linewidth, dashes, linestyle, markersize, frameon, frame, **kwargs)
   3329 
   3330         # Draw legend
-> 3331         leg = mlegend.Legend(self, *zip(*pairs), ncol=ncol, loc=loc, **kwargs)
   3332         legs = [leg]
   3333 

TypeError: __init__() missing 2 required positional arguments: 'handles' and 'labels'

@lukelbd
Copy link
Collaborator

lukelbd commented Jun 28, 2020

@kinyatoride It should be fixed on master; do you have the "development" version? Can be installed with pip install git+https://github.com/lukelbd/proplot

@kinyatoride
Copy link
Author

@lukelbd

This issue appears again in the development version (0.8.0.post5).

Error:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/tmp/ipykernel_92559/3733033338.py in <module>
      5 ax.plot([0, 1, 1], label='b')
      6 #ax.legend(loc='b')
----> 7 ax.legend()

~/miniconda3/envs/basicf5/lib/python3.9/site-packages/proplot/figure.py in _grid_command(self, *args, **kwargs)
   2004         objs = []
   2005         for ax in self:
-> 2006             obj = getattr(ax, name)(*args, **kwargs)
   2007             if obj is not None:
   2008                 objs.append(obj)

~/miniconda3/envs/basicf5/lib/python3.9/site-packages/proplot/axes/base.py in legend(self, handles, labels, loc, location, queue, **kwargs)
   2765             self._add_guide('legend', obj, loc, **kwargs)
   2766         else:
-> 2767             leg = self._draw_legend(handles, labels, loc=loc, **kwargs)
   2768             return leg
   2769 

~/miniconda3/envs/basicf5/lib/python3.9/site-packages/proplot/axes/base.py in _draw_legend(self, handles, labels, loc, width, pad, space, frame, frameon, ncol, ncols, alphabetize, center, order, label, title, fontsize, fontweight, fontcolor, titlefontsize, titlefontweight, titlefontcolor, **kwargs)
   2638             else:  # figure panel i.e. figure-wide legend
   2639                 axs = list(self.figure._iter_axes(hidden=False, children=True))
-> 2640         pairs = self._parse_handles_labels(
   2641             axs, handles, labels,
   2642             ncol=ncol, order=order, center=center, alphabetize=alphabetize,

~/miniconda3/envs/basicf5/lib/python3.9/site-packages/proplot/axes/base.py in _parse_handles_labels(self, axs, handles, labels, ncol, order, center, alphabetize)
   2339         axs = axs or ()
   2340         handles, labels = _to_list(handles), _to_list(labels)
-> 2341         list_of_lists = any(isinstance(h, (list, np.ndarray)) and len(h) > 1 for h in handles)  # noqa: E501
   2342         if list_of_lists and ncol is not None:
   2343             warnings._warn_proplot(

TypeError: 'NoneType' object is not iterable

@lukelbd
Copy link
Collaborator

lukelbd commented Aug 19, 2021

Thanks, this was another quick fix (fdd53a6). The refactors in v0.8 had been hanging over my head for 2 years -- now that they're finally done the next step is obviously to add many many more automated tests (goal for the end of 2021).

import proplot as plot
fig, ax = plot.subplots()
ax.plot([0, 1, 2], label='a')
ax.plot([0, 1, 1], label='b')
ax.legend()

test1

import proplot as plot
fig, ax = plot.subplots()
ax.plot([0, 1, 2])
ax.plot([0, 1, 1])
ax.legend(labels=['a', 'b'])

test2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants