-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Multitouch touchscreen support #8041
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
Conversation
just realized I have some misses on the pep8 compliance--will fix and amend my commit. |
- support for touch-to-drag and pinch-to-zoom in NavigationToolbar2 - pass touchscreen events from Qt4 and Qt5 backends - add option in matplotlibrc to pass touches as mouse events if desired
908f70b
to
b168863
Compare
fixed the pep8 issues and it should be good to go! (I think the appveyor tests failed due to some issue on their side... it seems there was a problem at runtime?) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, I don't have a touch screen, so I can't really say whether this does or does not work. It looks sane, anyway.
|
||
""" | ||
x = None # x position - pixels from left of canvas | ||
y = None # y position - pixels from right of canvas |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right -> bottom
""" | ||
x = None # x position - pixels from left of canvas | ||
y = None # y position - pixels from right of canvas | ||
inaxes = None # the Axes instance if mouse us over axes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
us -> is (but there's no mouse in this event, is there?)
|
||
def __init__(self, name, canvas, x, y, ID, guiEvent=None): | ||
""" | ||
x, y in figure coords, 0,0 = bottom, left |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bottom, left -> left, bottom
'touch_update_event', | ||
'touch_end_event') | ||
|
||
In addition to the :class:`Event` and :class:`LocationEvent` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't derive from LocationEvent
?
|
||
touches : None, or list | ||
A list of the touches (possibly several), which will be of class Touch. | ||
They are passed to the class as a list of triples of the form (ID,x,y), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How they are passed to the class has nothing to do with how the attribute is accessed. This would be something to go in docs for __init__
, maybe.
elif twiny and not twinx: | ||
a._set_view((xlims[0], xlims[1], ymin, ymax)) | ||
elif not twinx and not twiny: | ||
a._set_view(list(xlims)+list(ylims)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is lims.T.flatten()
.
orig_IDs = {t.ID for t in self._touches} | ||
e_IDs = {t.ID for t in event.touches} | ||
if (len(event.touches) != len(self._touches) or | ||
not orig_IDs == e_IDs): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
orig_IDs != e_IDs
@@ -66,6 +66,12 @@ backend : $TEMPLATE_BACKEND | |||
# you if backend_fallback is True | |||
#backend_fallback: True | |||
|
|||
# if you are using Qt4 or Qt5 backend and have a touchscreen or touchpad, | |||
# you can interact with the plot using touch gestures (pinch to zoom, | |||
# touch and drag). if this option is set to false, touch events will |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Capitalize 'If' on both sentences.
if event.type() in TOUCH_EVENTS: | ||
etype = TOUCH_EVENTS[event.type()] | ||
|
||
touches = [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These above two lines can go after the quick-return below.
orig_IDs = {t.ID for t in self._touches} | ||
e_IDs = {t.ID for t in event.touches} | ||
if (len(event.touches) != len(self._touches) or | ||
not orig_IDs == e_IDs): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not orig_IDs == eIDs
-> orig_IDs != eIDs
Thanks for the comments! Re: testing, yes, I thought it might be an obstacle that people don't have an easy way to test it. a couple ideas, if it isn't too much of a hassle to set up:
Will go through your comments when I have a chance. Oh, and it shouldn't be too hard to write some unit tests at least for the general stuff in cheers |
As a heads-up, over at hyperspy/hyperspy-demos#44, we've just realised that using Binder (or public jupyter servers) we can now access jupyter notebooks on our phones. This provides another avenue for testing and especially using multitouch! I'd love to see this implemented and expanded on! |
@GregDMeyer were you planning to come back to this? The rebase has gotten large, but maybe its straight forward. Is there a reason you didn't follow up because this was apparently significant work. In general this would probably be good to get in. I would bet 50/50 that macs will have touchscreens in the next few months. And some PCs have touch. |
Unfortunately what happened was that I started grad school and lost track of most of my side projects ;) But I certainly think this would still be a valuable feature, and I'm happy to take another look in the next couple weeks to fix the pull request. I do have a feeling that fixing it up probably won't be that much work. (Also, I have a lot more experience with Python now, so I will definitely want to clean a few things up from my original code). |
My laptop is multi-touch & I'd be happy for the feature/to test it. |
@story645 is it OK to assign you to keep an eye on this? If not, please feel free to unassigned yourself! |
I can test touch screen support as well. |
Closing as abandoned. Thanks for the PR, and sorry it didn't get in. If you do come back to this, please feel free to request this be re-opened, or open a fresh PR! |
These changes add support for intuitive touchscreen interaction with Matplotlib, specifically touch-drag to pan and two-finger pinch to zoom.
When dragging, the plot is panned so that the same point in data coords stays under one's finger. When zooming, the plot is zoomed and panned simultaneously such that the same two points in data coords stay under the two touch points (except in cases such as holding down the 'x' key, locking motion to the x axis). These behaviors are meant to mimic what one would imagine physically sliding and/or stretching something.
Touch support is similarly added for the Axes3D class, such that a drag rotates the axes, and two-finger pinch scales the plot (zooms).
I only set up the Qt4 and Qt5 backends to send touch events to the figures, mostly because I don't know enough about gtk, javascript, etc to do it for the other backends. But it shouldn't be that hard for people who know those things, because
NavigationToolbar2
does the heavy lifting. All you have to do is send it the touches' coordinates and a unique ID for each touch.Summary of changes:
NavigationToolbar2
inbackend_bases.py
has new functions for handling touches, implementing touch-drag to pan and two-finger pinch to zoom.Touch
andTouchEvent
to store touch event data.FigureCanvasBase
has new functions to trigger the callbacks for touch events.matplotlibrc.template
and the other rc files are set up for the flagbackends.touch
, which defines whether to accept touch input. If it is false, Qt turns touches into regular mouse events.FigureCanvasBase
functionsI tested on Python 2.7 and 3.5, with PyQt4 and PySide (both on python 2.7) and PyQt5 (python 2.7 and 3.5), on a Dell XPS 13 running Ubuntu 16.04.
I mentioned that I was working on this in #7789.