Skip to content

document event handling with twined axes #10009

Closed

Description

@darioflute

Bug report

Bug summary

In matplotlib 2.1.0 it was possible to define a SpanSelector attached to an axes object,
then define another axes system connected to the first one with twinx or twiny.
The SpanSelector was still active and returning the values on the first axes object.

With matplotlib 2.1.1 this is no more working.
The SpanSelector works only if attached to the latest axes object defined.

The same effect happens also when using draggable annotate attached to an axes object.
After defining a twin axes, the annotations are no more draggable.

Code for reproduction

As an example, I include a slight modification of the matplotlib tutorial about the usage
of span_selector:
https://matplotlib.org/examples/widgets/span_selector.html

At the end of the code I added twin axes which neutralize the span selector.
After uncommenting the last three lines, the span selector works again.
With matplotlib 2.1.0, the code was working without uncommenting the lines.

#!/usr/bin/env python
"""
The SpanSelector is a mouse widget to select a xmin/xmax range and plot the
detail view of the selected region in the lower axes
"""
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import SpanSelector

fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(211, facecolor='#FFFFCC')

x = np.arange(0.0, 5.0, 0.01)
y = np.sin(2*np.pi*x) + 0.5*np.random.randn(len(x))

ax.plot(x, y, '-')
ax.set_ylim(-2, 2)
ax.set_title('Press left mouse button and drag to test')


ax2 = fig.add_subplot(212, facecolor='#FFFFCC')
line2, = ax2.plot(x, y, '-')


def onselect(xmin, xmax):
    indmin, indmax = np.searchsorted(x, (xmin, xmax))
    indmax = min(len(x) - 1, indmax)
    print(indmin,indmax)

    thisx = x[indmin:indmax]
    thisy = y[indmin:indmax]
    line2.set_data(thisx, thisy)
    ax2.set_xlim(thisx[0], thisx[-1])
    ax2.set_ylim(thisy.min(), thisy.max())
    fig.canvas.draw()

# set useblit True on gtkagg for enhanced performance
span = SpanSelector(ax, onselect, 'horizontal', useblit=True,
                    rectprops=dict(alpha=0.5, facecolor='red'))

ax1 = ax.twinx()
ax1.get_yaxis().set_tick_params(labelright='on',right='on', direction='in')
ax1.set_ylim([0,1])

# Uncomment here to work with matplotlib 2.1.1 (possible bug)
#span = SpanSelector(ax1, onselect, 'horizontal', useblit=True,
#                    rectprops=dict(alpha=0.5, facecolor='red'))


plt.show()

Actual outcome

The span selector does not work.

# If applicable, paste the console output here
#
#

Expected outcome

I expected that the spanselector would work.

This was working with matplotlib 2.1.0

Matplotlib version

  • Operating system: mac os-x
  • Matplotlib version: 2.1.1
  • Matplotlib backend (print(matplotlib.get_backend())):
  • Python version: 3.6.1
  • Jupyter version (if applicable):
  • Other libraries:

conda

default

Activity

  1. efiring commented on Dec 14, 2017

    @efiring
    Member

    The problem here is that only one Axes gets the events, and it is hard to figure out which one that will be. I didn't realize it had changed between 2.1 and 2.1.1, though--that's really bad! I tried to address an aspect of this in #2986; there, @tacaswell pointed out that the real solution would be to let all Axes receive all events, but I don't think any of us ever followed through on that.

  2. jklymak commented on Dec 14, 2017

    @jklymak
    Member

    Confirmed: This worked in 2.1.0, but doesn't work now. Checked qt5Agg and maxosx backends, so must be somewhere generic.

  3. jklymak commented on Dec 14, 2017

    @jklymak
    Member

    This is almost certainly #9389

    I'm not sure the behaviour is incorrect per-se here, unless the docs somewhere specify what order events are to be received in. ax1 was drawn last so it gets the events. I'll let @anntzer chime in but it seems if you want to garauntee ax gets the events, either draw it last, or set its zorder larger than ax1.

    As @efiring says, maybe it'd make sense to let both axes get the events, but that seems ripe for confusion as well..

  4. anntzer commented on Dec 14, 2017

    @anntzer
    Contributor

    As long as only one axes can receive the event, I strongly believe it is the topmost one that should get them.

  5. jklymak commented on Dec 14, 2017

    @jklymak
    Member

    I guess one could argue that twinx should put the twinned axes with a lower z-order than the original axes.

  6. darioflute commented on Dec 14, 2017

    @darioflute
    Author

    Thanks @jklymak,

    a simple solution as you suggest, is to add the lines:

    ax.set_zorder(ax1.get_zorder()+1)
    ax.patch.set_visible(False)

    This solution works for matplotlib 2.1.0 and 2.1.1.

  7. thriveth commented on Feb 22, 2018

    @thriveth

    Confirmed, this also broke my code after the latest update.

    I do not understand the underlying workings of matplotlib event handling, but it seems quite counterintuitive that when you assign a SpanSelector to a given axes object, it's another axes object that actually receives the event. My immediate expectation would be that the axes I assigned to the widget is also the one that is listening to it.

  8. added this to the milestone on Feb 23, 2018
  9. 6 remaining items

  10. modified the milestones: v3.0, v3.1 on Aug 11, 2018
  11. modified the milestones: v3.1.0, v3.2.0 on Feb 27, 2019
  12. tacaswell commented on Mar 10, 2020

    @tacaswell
    Member

    @thriveth Sorry, this got lost in my mentions. I would like to apologize (2 years on). I am sure I did not intend to be rude or mock you, it was meant to be self-deprecating humor on how every change to a library the size / complexity of Matplotlib, even ones that seem like they are obviously bug-fixes are going to break someone (despite our best attempts). I'll try to refrain from making that joke in the future.

  13. thriveth commented on Mar 10, 2020

    @thriveth

    @tacaswell No problem, frankly I'd long forgotten this issue.
    Thanks for all your work on Matplotlib!

  14. github-actions commented on Apr 28, 2023

    @github-actions

    This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!

  15. QuLogic commented on Apr 28, 2023

    @QuLogic
    Member

    The above linked PR should fix this, no need to close as inactive.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions