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

Locators raise unclear exceptions on MappingView input #7527

Closed
godaygo opened this issue Nov 28, 2016 · 7 comments

Comments

Projects
None yet
4 participants
@godaygo
Copy link

commented Nov 28, 2016

When dict_values are passed to plt.xticks(dict_values), Matplotlib raises non obvious exception and corresponding traceback:

In[ ]:  plt.xticks(dict_values)

         TypeError                                 Traceback (most recent call last)
         <ipython-input-9-14733a10526c> in <module>()
         ----> 1 plt.xticks(dct.values())

         ...

         TypeError: len() of unsized object

Is it expected to fail? And if so, why such a strange error? Because len(dict_values) is ok.

Matplotlib 1.5.3
Python 3.5.2
Windows

p.s.: I'm new to Python and its community. Is it the right place to post such questions?

@story645

This comment has been minimized.

Copy link
Member

commented Nov 28, 2016

You need to cast dict_values to a list because in py3 dict_values are a mapping view object rather than a list. I think dict_values are also nondeterministic and so probably shouldnt be used.

@godaygo

This comment has been minimized.

Copy link
Author

commented Nov 28, 2016

@story645 Sorry, I can`t catch your idea. If I cast dict_values the order will also be unpredictable. I agree that it is not good idea to use them (In my case, for positions the order really doesn't matter).

But the exception looks very strange (because len(dict_values) is ok). As I see there're two possibilities to raise something meaningful or to cast them implicitly.

@story645

This comment has been minimized.

Copy link
Member

commented Nov 28, 2016

list(dict_values) will work, but now I'd really like to know what you're trying to do.

Support for dict_values as input into the plotting routines is baked into 2.0, as is direct support for textual data. I think that negates adding support for using dict_values directly in labels (though this may not be hard to do) as that's a thing people shouldn't ever be doing. But hmm, I would agree that maybe the message could be clearer.

Also, mappingviews don't have a fixed size as they're kind of just pointers to the dictionary and so get updated when the dict does , whereas the old dict.views() returned list copies of the current state of the keys https://docs.python.org/3/library/stdtypes.html#dict-views

@tacaswell

This comment has been minimized.

Copy link
Member

commented Nov 29, 2016

@godaya can your provide a runnable example that demonstrates the problem and include the full traceback?

@godaygo

This comment has been minimized.

Copy link
Author

commented Nov 29, 2016

@story645 , Nothing serious, I was trying to execute examples from a book:)

@tacaswell , I believe that Exceptions are my best friends, and here the message that does not tell anything. Also there is some inconsistency, because in some places its OK and not in another one.

Code:

import numpy as np
import matplotlib.pyplot as plt

dct = {'A':10, 'B':40, 'C':70, 'D':90}

plt.bar(np.arange(len(dct)), dct.values())        #here dict_values is ok!!!
plt.xticks(np.arange(len(dct))+0.4, dct.keys())   #here dict_keys is ok!!!

plt.yticks(dct.values())     #but here it is ERROR!!!

plt.show()

Traceback:

TypeError                                 Traceback (most recent call last)
<ipython-input-15-6d0248e07c61> in <module>()
      8 
      9 
---> 10 plt.yticks(dct.values()) #but here it is ERROR
     11 plt.show()

c:\python35\lib\site-packages\matplotlib\pyplot.py in yticks(*args, **kwargs)
   1718     elif len(args)==1:
   1719         locs = ax.set_yticks(args[0])
-> 1720         labels = ax.get_yticklabels()
   1721     elif len(args)==2:
   1722         locs = ax.set_yticks(args[0])

c:\python35\lib\site-packages\matplotlib\axes\_base.py in get_yticklabels(self, minor, which)
   3148         return cbook.silent_list('Text yticklabel',
   3149                                  self.yaxis.get_ticklabels(minor=minor,
-> 3150                                                            which=which))
   3151 
   3152     @docstring.dedent_interpd

c:\python35\lib\site-packages\matplotlib\axis.py in get_ticklabels(self, minor, which)
   1207         if minor:
   1208             return self.get_minorticklabels()
-> 1209         return self.get_majorticklabels()
   1210 
   1211     def get_majorticklines(self):

c:\python35\lib\site-packages\matplotlib\axis.py in get_majorticklabels(self)
   1161     def get_majorticklabels(self):
   1162         'Return a list of Text instances for the major ticklabels'
-> 1163         ticks = self.get_major_ticks()
   1164         labels1 = [tick.label1 for tick in ticks if tick.label1On]
   1165         labels2 = [tick.label2 for tick in ticks if tick.label2On]

c:\python35\lib\site-packages\matplotlib\axis.py in get_major_ticks(self, numticks)
   1290         'get the tick instances; grow as necessary'
   1291         if numticks is None:
-> 1292             numticks = len(self.get_major_locator()())
   1293         if len(self.majorTicks) < numticks:
   1294             # update the new tick label properties from the old

TypeError: len() of unsized object
@story645

This comment has been minimized.

Copy link
Member

commented Nov 29, 2016

plt.xticks(np.arange(len(dct))+0.4, dct.keys())   #here dict_keys is ok!!!
plt.yticks(dct.values())     #but here it is ERROR!!!

The argument order for both is plt.xticks(locs, labels) and plt.yticks(locs, labels). Different code handles where the ticks are located and how to label it, and the support/lack thereof is due to how the code is structured.

The code to create labels (the thing that works) creates list by iterating over the input and appending, and so anything that supports iteration (including dict_views) works.

The code for creating ticks is the rabbit hole that error message spits out. This also fails:

plt.xticks(dct.values(), dct.keys())

@story645 story645 changed the title Ticks and dict_values fails with unobvious exception Tick Locators Fail on MappingView Objects with Unclear Error Message Nov 29, 2016

@story645 story645 changed the title Tick Locators Fail on MappingView Objects with Unclear Error Message Tick locators raise unclear exceptions on mappingview input Nov 29, 2016

@story645 story645 changed the title Tick locators raise unclear exceptions on mappingview input Tick locators raise unclear exceptions on MappingView input Nov 29, 2016

@story645 story645 changed the title Tick locators raise unclear exceptions on MappingView input Locators raise unclear exceptions on MappingView input Nov 29, 2016

@anntzer

This comment has been minimized.

Copy link
Contributor

commented Oct 16, 2017

Closing because I would consider that ultimately all python(3) users will need to learn that dict views are, well, not lists, and I don't think it particularly makes sense to try catching all kinds of unsupported input to rephrase the error message.
We could support dict views as tick values but I would prefer not (the benefits are dubious at best, IMO).

@anntzer anntzer closed this Oct 16, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.