Skip to content

Switching to log scale when there is no positive data crashes the Qt5 backend, causes inconsistent internal state in others #6852

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

Closed
anntzer opened this issue Jul 28, 2016 · 4 comments
Milestone

Comments

@anntzer
Copy link
Contributor

anntzer commented Jul 28, 2016

mpl 1.5.1/2.0b3/master, Qt5Agg backend, Python 3.5.2, Arch Linux

plt.plot([-1, -2]); plt.show()

and press l while the mouse is over the axes.

Qt5 aborts Python due to the exception propagating out of the slot:

/usr/lib/python3.5/site-packages/matplotlib/axes/_base.py:2270: RuntimeWarning: invalid value encountered in double_scalars
  delta = (x1t - x0t) * margin
Traceback (most recent call last):
  File "/usr/lib/python3.5/site-packages/matplotlib/backends/backend_qt5.py", line 314, in keyPressEvent
    FigureCanvasBase.key_press_event(self, key, guiEvent=event)
  File "/usr/lib/python3.5/site-packages/matplotlib/backend_bases.py", line 1842, in key_press_event
    self.callbacks.process(s, event)
  File "/usr/lib/python3.5/site-packages/matplotlib/cbook.py", line 550, in process
    proxy(*args, **kwargs)
  File "/usr/lib/python3.5/site-packages/matplotlib/cbook.py", line 417, in __call__
    return mtd(*args, **kwargs)
  File "/usr/lib/python3.5/site-packages/matplotlib/backend_bases.py", line 2639, in key_press
    key_press_handler(event, self.canvas, self.canvas.toolbar)
  File "/usr/lib/python3.5/site-packages/matplotlib/backend_bases.py", line 2546, in key_press_handler
    ax.set_yscale('log')
  File "/usr/lib/python3.5/site-packages/matplotlib/axes/_base.py", line 3146, in set_yscale
    self.autoscale_view(scalex=False)
  File "/usr/lib/python3.5/site-packages/matplotlib/axes/_base.py", line 2288, in autoscale_view
    margins['bottom'], margins['top'], self.set_ybound)
  File "/usr/lib/python3.5/site-packages/matplotlib/axes/_base.py", line 2278, in handle_single_axis
    x0, x1 = locator.view_limits(x0, x1)
  File "/usr/lib/python3.5/site-packages/matplotlib/ticker.py", line 1803, in view_limits
    "Data has no positive values, and therefore can not be "
ValueError: Data has no positive values, and therefore can not be log-scaled.
Fatal Python error: Aborted

Not sure what the best approach is but I think we should certainly try to avoid a fatal crash...

While it may be tempting to just wrap key_press_handler in a try... except or disable the abort()ing behavior of PyQt5 by installing a custom excepthook (see http://pyqt.sourceforge.net/Docs/PyQt5/incompatibilities.html section for PyQt5.5), this would hide the fact that the canvas is left in an inconsistent state as the axes internally believe to have switched to log-scale. This can be seen e.g. by using the Qt4Agg backend (where the exception is printed but the program not abort()ed), by typing l and then trying to zoom in (again with the mouse): the canvas becomes completely empty in that case.

@LindyBalboa
Copy link
Contributor

LindyBalboa commented Jul 29, 2016

Would it perhaps make sense to change the default to symlog? I know it is only suppose to be used for exceptional sign changes to standard math (I use it all the time for transistor curves), but I think it would lead to a more intuitive behavior.

Edit: Shouldn't this be handled by nonposy nonposx in mpl.axes.Axes.set_yscale?

@LindyBalboa
Copy link
Contributor

I posted here last night, but maybe forgot to submit?

I played around with it and it seems nonposy is only successfully handled via masking and clipping if there is at least one positive value. The existing structures don't seem too well suited to handle this situation. The way it is, I would guess the smallest effective change would be to add a all(i<0 for i in y) somewhere inside `set_x/yscale' or the appropriate method called from it.

I personally would still recommend changing the default behavior of l and k to symlog. Although it isn't mathematically correct, it has more real world applications and is more intuitive from a graphical sense.

@anntzer
Copy link
Contributor Author

anntzer commented Aug 26, 2016

Actually my comment about wrapping in a try... except was incorrect: that can work, one simply has to restore the original scale in case of a failure. See #6983.

@tacaswell
Copy link
Member

Closed by #6983

please re-open if I am confused.

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

No branches or pull requests

4 participants