Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Fix the error- TypeError: 'float' object is not iterable #22710

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

Merged
merged 13 commits into from
Apr 5, 2022
Merged

Fix the error- TypeError: 'float' object is not iterable #22710

merged 13 commits into from
Apr 5, 2022

Conversation

krishjainx
Copy link

PR Summary

This commit fixes the issue "TypeError: 'float' object is not iterable" that I faced while training a machine learning model.

PR Checklist

Tests and Styling

  • Has pytest style unit tests (and pytest passes).
  • Is Flake 8 compliant (install flake8-docstrings and run flake8 --docstring-convention=all).

Documentation

  • New features are documented, with examples if plot related.
  • New features have an entry in doc/users/next_whats_new/ (follow instructions in README.rst there).
  • API changes documented in doc/api/next_api_changes/ (follow instructions in README.rst there).
  • Documentation is sphinx and numpydoc compliant (the docs should build without error).

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for opening your first PR into Matplotlib!

If you have not heard from us in a while, please feel free to ping @matplotlib/developers or anyone who has commented on the PR. Most of our reviewers are volunteers and sometimes things fall through the cracks.

You can also join us on gitter for real-time discussion.

For details on testing, writing docs, and our review process, please see the developer guide

We strive to be a welcoming and open project. Please follow our Code of Conduct.

@jklymak
Copy link
Member

jklymak commented Mar 26, 2022

Thanks for your contribution! Can you please provide a reproducible piece of code that failed before, but this fixes. Thanks!

@WeatherGod
Copy link
Member

WeatherGod commented Mar 26, 2022

@jklymak https://github.com/atulapra/Emotion-detection for instance


Traceback (most recent call last):
File "emotions.py", line 98, in
plot_model_history(model_info)
File "emotions.py", line 31, in plot_model_history
axs[0].set_xticks(np.arange(1,len(model_history.history['accuracy'])+1),len(model_history.history['accuracy'])/10)

The second argument to set_xticks() is a list of labels. This shows a scalar float being passed in. The bug is in that package.

and I am looking at main right now, and axis.py at these lines don't look like this, so I am quite confused about what is going on...

@WeatherGod
Copy link
Member

Ah, I was taken to the specific commit rather than the PR's changes page, which is why I was confused. Yeah, this isn't a bug in matplotlib at all. The bug is in the other package's incorrect use of set_xticks().

@krishjainx
Copy link
Author

I see. Sorry, my misunderstanding. Wouldn't my changes however, also make it work in the case where someone uses set_xticks() incorrectly? Asking because I don't understand all the working parts of matplotlib underneath the hood

@WeatherGod
Copy link
Member

No, it actually breaks things further for correct use-cases (by not working for an iterable of strings), and it wouldn't fix anything for your use-case. The code expects an iterable, and the function documentation says that it expects an iterable, and it is getting a single float value that can't serve as a list of labels.

@WeatherGod
Copy link
Member

If there is any bug here, it is that matplotlib probably could have raise an error sooner in the stack rather than deeper down in the internals.

@krishjainx
Copy link
Author

Thank you! I would like to help with raising the error, where should I start? What file would I be working on?

@WeatherGod
Copy link
Member

So, looking at the very interesting set of indirections we have (we avoid having duplicate code for x and y axis), it appears that this function actually is near the top of the stack that one could reasonably do a check. One could also do a check up in this file's set_ticks(), but that just calls set_ticklabels() if the labels aren't None, and set_ticklabels() is public-facing anyway.

So, basically, check that it is an iterable and if not, raise a TypeError. I think we have some functions for that somewhere in a utils file...

@krishjainx
Copy link
Author

Ok, will do

@krishjainx
Copy link
Author

krishjainx commented Mar 26, 2022

@WeatherGod Wouldn't

    try:
        _ = (e for e in ticklabels)
    except TypeError:
        print(ticklabels, 'is not iterable') 

be sufficient?

@WeatherGod
Copy link
Member

So, really, the objective here is a better exception message, so we'd just capture the TypeError from the list comprehension, and raise a new TypeError like so:

raise TypeError(f"{ticklabels:=} must be an iterable") from None

The from None part is important because it tells python to discard the current exception context so it doesn't think that this is an exception caused by exception-handling.

@WeatherGod
Copy link
Member

Maybe "sequence" is a better term, since a string is an iterable, but would be an incorrect input.

@krishjainx
Copy link
Author

krishjainx commented Mar 26, 2022

        try:
            _ = (e for e in ticklabels)
        except TypeError:
            raise TypeError(f"{ticklabels:=} must be a sequence") from None

Would this work?

@krishjainx
Copy link
Author

@WeatherGod

@jklymak jklymak marked this pull request as draft March 28, 2022 07:24
@jklymak
Copy link
Member

jklymak commented Mar 28, 2022

I've moved to draft until you sort out your approach. Also a reproducible self-contained example would be appreciated. You can't expect us all to download "EmotionDetection"! In lieu of this, you should add self-contained tests. Thanks....

@krishjainx
Copy link
Author

@jklymak Got it but I was referring to the approach @WeatherGod suggested and adding that to set_ticklabels() function

@tacaswell
Copy link
Member

@Krish-sysadmin Yes, that approach looks good (but I would just wrap the current list comprehension rather than adding a new local variable for a generator).

#22710 (comment) This approach of catching errors, printing, and then carrying on is something you should almost never do in a library context. We do not know enough to know that the user wanted so we can not fix it. It is then our job to tell the users something went wrong. It is then up to the application layer to catch that exception and do something about it (because at the application layer they know things might go wrong and how to fix them or know that this was an optional thing that can be ignored or ...) or pass the exception up to their caller who might know what to do and so on and so on up the callstack. In an interactive context you then hit the shell who says "right, I'll just print out the whole traceback for the human to look at" or in a script context Python say "I'm going to print the traceback, but then exit because I have nothing else I can do".

Quoting the Zen of Python https://peps.python.org/pep-0020/#the-zen-of-python

Errors should never pass silently.
Unless explicitly silenced.

I would add that I was doing some user support last week where the user had done exactly this pattern (try: ... except Exception: print() ) and it took use 15 minutes to track down where the try/except was and then once we saw the trace back about 15 seconds to understand and fix the problem.


PS sorry, you tried to fix a bug and instead got a software design philosophy discussion ;)

@krishjainx
Copy link
Author

Thanks, Thomas. If I understand correctly, this is alright then.

        try:
            [e for e in ticklabels]
        except TypeError:
            raise TypeError(f"{ticklabels:=} must be a sequence") from None

?

@krishjainx
Copy link
Author

@tacaswell

@WeatherGod
Copy link
Member

No, we mean putting the try...except around this:

        ticklabels = [t.get_text() if hasattr(t, 'get_text') else t
                      for t in ticklabels]

Of course, this is always a risk that t.get_text() has a side-effect of causing an unrelated TypeError, but it is just a getter, so it should be fine.

@krishjainx
Copy link
Author

try:
        ticklabels = [t.get_text() if hasattr(t, 'get_text') else t
                      for t in ticklabels]
except:
        raise TypeError(f"{ticklabels:=} must be a sequence") from None

@krishjainx
Copy link
Author

@WeatherGod

@krishjainx
Copy link
Author

@WeatherGod Now Linux tests fail for some reason. I suspect macos will too

@krishjainx
Copy link
Author

Wait, now all Linux, macOS and Windows tests fail

@WeatherGod WeatherGod closed this Apr 3, 2022
@WeatherGod WeatherGod reopened this Apr 3, 2022
Copy link
Member

@WeatherGod WeatherGod left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one linting error. The other errors are happening for reasons outside our control and is getting worked on separately.

@WeatherGod
Copy link
Member

Does anybody know if the build and test problems are fixed on the main branch? Would merging main into this branch likely fix it?

@rcomer
Copy link
Member

rcomer commented Apr 4, 2022

Does anybody know if the build and test problems are fixed on the main branch? Would merging main into this branch likely fix it?

I have no authority here, but I think you need #22766?

@tacaswell tacaswell closed this Apr 4, 2022
@tacaswell tacaswell reopened this Apr 4, 2022
@tacaswell
Copy link
Member

This should be squash-merged.

Copy link
Member

@tacaswell tacaswell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With a squash merge or a rebase+squash.

@QuLogic
Copy link
Member

QuLogic commented Apr 5, 2022

For 3.7?

@krishjainx
Copy link
Author

So all the tests pass. Can this be merged?

@oscargus oscargus added the status: needs workflow approval For PRs from new contributors, from which GitHub blocks workflows by default. label Apr 5, 2022
@timhoffm timhoffm modified the milestones: v3.7.0, v3.6.0 Apr 5, 2022
@timhoffm timhoffm merged commit c9614de into matplotlib:main Apr 5, 2022
@timhoffm timhoffm removed status: needs revision status: needs tests status: needs workflow approval For PRs from new contributors, from which GitHub blocks workflows by default. labels Apr 5, 2022
@timhoffm
Copy link
Member

timhoffm commented Apr 5, 2022

Thanks @Krish-sysadmin, and congratulations on your first contribution to Matplotlib. We hope to see you back!

Can this be merged?

We aim for a concise commit history. Typically that means one or very few logically grouped commits. It's helpful if you could do this in future pull requests yourself. That was the comment in @tacaswell's approval, which prevented immedate merging. - I've now squash-merged all the commits into one. No worries if you need help with handling git to directly have only one commit in your PR even with updates. We can help you in a next PR if needed.

@krishjainx
Copy link
Author

Thanks, Tim!

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

Successfully merging this pull request may close these issues.

8 participants