I'm writing a GUI package on Python with Tkinter module and using matplotlib via FigureCanvasTkAgg to show some graphical data. I also want to interact with this visual representation of the data via canvas.mpl_connect method. Everything works just fine, but I do not satisfied with default arrow-like cursor: it does not allow precise clicking on my data (the actual "click point" does not match with the tip of the arrow) and also it hides from user some area near the click pint. So the question is how to change the default cursor? I tried change it through Tk config methods (like master.config(cursor="tcross")), but apparently matplotlib canvas has its own cursor configuration because this string only changes appearance of the cursor above all parts of main window except MPL canvas, above canvas the default arrow is still being shown.
-
1There's not a complete system to do so, but have a look at matplotlib.org/examples/widgets/cursor.html (Note that blit will work just fine on TkAgg, as well. If you're using blitting elsewhere in your code, you'll need to worry about synchronizing things, but that's a separate issue.)Joe Kington– Joe Kington2014-12-22 15:06:08 +00:00Commented Dec 22, 2014 at 15:06
-
Thank you! It is very interesting solution, but is there any possibility to hide/disable the mean cursor (arrow)? Now I can see both the arrow cursor and this nice MPL Cursor widget.Sergey Savchenko– Sergey Savchenko2014-12-22 15:22:49 +00:00Commented Dec 22, 2014 at 15:22
2 Answers
First off, a couple of caveats: I'm about to dive into some implementation details. I think the toolbar was recently refactored, so some of this could change with the next version of matplotlib. Furthermore, this values I've specified for the cursor only apply to the TkAgg backend. The general concept is similar for other backends, but the location of cursord and the backend-specific cursors will vary. As an example for Qt4Agg, the cursord dict is in backend_qt4 instead of backend_qt4agg, and the values are Qt cursors: e.g. QtCore.Qt.ArrowCursor.
As I mentioned in my comment, have a look at matplotlib's Cursor widget. However, the broader issue of how to customize the cursor(s) matplotlib uses is a bit hairier.
The reason that you can't directly change the cursor matplotlib uses (e.g. master.config(cursor='whatever')) is that the default toolbar overrides it (different cursors for different tools on the toolbar).
One option is to not add the toolbar. In that case, you can just call parent.config(cursor='tcross') and be done with it. However, you presumably want the toolbar to be present for easier panning/zooming/etc.
The toolbar uses a dict of present cursors for each tool: backend_tkagg.cursord. The keys for this are int codes, so it's a bit more readable to refer to them through matplotlib.backend_bases.cursors. The default tool is the cursors.POINTER.
As a quick example (For simplicity, I'm using the pyplot interface to build the canvas, figure, etc.)
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
from matplotlib.backend_bases import cursors
import matplotlib.backends.backend_tkagg as tkagg
# Change the default cursor to any valid TK cursor
# To hide it, you'd use the string "none" (or possibly "no" on windows)
tkagg.cursord[cursors.POINTER] = 'coffee_mug'
fig, ax = plt.subplots()
plt.show()
Note that you can also control the cursor for any tool (e.g. zoom, pan, etc) in the same way. Your options are cursor.HAND, cursor.POINTER, cursor.SELECT_REGION, and cursor.MOVE.
2 Comments
config(cursor='arrow') method for other widgets.For those who are looking at this question now (like me), matplotlib has since been updated and 'cursord' moved locations in matplotlib version 2.1.2. This is why the previous answer is probably giving you errors now.
To change this you have to replace the line
import matplotlib.backends.backend_tkagg as tkagg
to
import matplotlib.backends._backend_tk as tkagg instead.