11
11
`matplotlib.backend_managers.ToolManager`
12
12
"""
13
13
14
-
15
- from matplotlib import rcParams
16
- from matplotlib ._pylab_helpers import Gcf
17
- import matplotlib .cbook as cbook
18
- from weakref import WeakKeyDictionary
19
14
import six
15
+
16
+ import functools
20
17
import time
21
18
import warnings
19
+ from weakref import WeakKeyDictionary
20
+
22
21
import numpy as np
23
22
23
+ from matplotlib import rcParams
24
+ from matplotlib ._pylab_helpers import Gcf
25
+ import matplotlib .cbook as cbook
26
+
24
27
25
28
class Cursors (object ):
26
29
"""Simple namespace for cursor reference"""
27
30
HAND , POINTER , SELECT_REGION , MOVE , WAIT = list (range (5 ))
28
31
cursors = Cursors ()
29
32
30
- # Views positions tool
31
- _views_positions = 'viewpos'
33
+
34
+ _registered_tools = {}
35
+ _tools_inheritance = {}
36
+
37
+
38
+ def register_tool (name , backend = "" , cls = None ):
39
+ """Declares that class *cls* implements tool *name* for backend *backend*.
40
+
41
+ Can be used as a class decorator.
42
+ """
43
+ if cls is None :
44
+ return functools .partial (register_tool , name , backend )
45
+ if (name , backend ) in _registered_tools :
46
+ raise KeyError ("Tool {!r} is already registered for backend {!r}"
47
+ .format (name , backend ))
48
+ _registered_tools [name , backend ] = cls
49
+ return cls
50
+
51
+
52
+ def _inherit_tools (child , parent ):
53
+ """Declares that backend *child* should default to the tools of *parent*.
54
+ """
55
+ _tools_inheritance [child ] = parent
56
+
57
+
58
+ def get_tool (name , backend ):
59
+ """Get the tool class for tool name *name* and backend *backend*.
60
+ """
61
+ try :
62
+ return _registered_tools [name , backend ]
63
+ except KeyError :
64
+ try :
65
+ return _registered_tools [name , _tools_inheritance [backend ]]
66
+ except KeyError :
67
+ return _registered_tools [name , "" ]
32
68
33
69
34
70
class ToolBase (object ):
@@ -305,6 +341,7 @@ def set_cursor(self, cursor):
305
341
raise NotImplementedError
306
342
307
343
344
+ @register_tool ("position" )
308
345
class ToolCursorPosition (ToolBase ):
309
346
"""
310
347
Send message with the current pointer position
@@ -378,6 +415,7 @@ def remove_rubberband(self):
378
415
pass
379
416
380
417
418
+ @register_tool ("quit" )
381
419
class ToolQuit (ToolBase ):
382
420
"""Tool to call the figure manager destroy method"""
383
421
@@ -388,6 +426,7 @@ def trigger(self, sender, event, data=None):
388
426
Gcf .destroy_fig (self .figure )
389
427
390
428
429
+ @register_tool ("quit_all" )
391
430
class ToolQuitAll (ToolBase ):
392
431
"""Tool to call the figure manager destroy method"""
393
432
@@ -398,6 +437,7 @@ def trigger(self, sender, event, data=None):
398
437
Gcf .destroy_all ()
399
438
400
439
440
+ @register_tool ("allnav" )
401
441
class ToolEnableAllNavigation (ToolBase ):
402
442
"""Tool to enable all axes for toolmanager interaction"""
403
443
@@ -414,6 +454,7 @@ def trigger(self, sender, event, data=None):
414
454
a .set_navigate (True )
415
455
416
456
457
+ @register_tool ("nav" )
417
458
class ToolEnableNavigation (ToolBase ):
418
459
"""Tool to enable a specific axes for toolmanager interaction"""
419
460
@@ -465,6 +506,7 @@ def _get_uniform_grid_state(ticks):
465
506
return None
466
507
467
508
509
+ @register_tool ("grid" )
468
510
class ToolGrid (_ToolGridBase ):
469
511
"""Tool to toggle the major grids of the figure"""
470
512
@@ -486,6 +528,7 @@ def _get_next_grid_states(self, ax):
486
528
y_state , "major" if y_state else "both" )
487
529
488
530
531
+ @register_tool ("grid_minor" )
489
532
class ToolMinorGrid (_ToolGridBase ):
490
533
"""Tool to toggle the major and minor grids of the figure"""
491
534
@@ -506,6 +549,7 @@ def _get_next_grid_states(self, ax):
506
549
return x_state , "both" , y_state , "both"
507
550
508
551
552
+ @register_tool ("fullscreen" )
509
553
class ToolFullScreen (ToolToggleBase ):
510
554
"""Tool to toggle full screen"""
511
555
@@ -536,16 +580,7 @@ def disable(self, event):
536
580
self .figure .canvas .draw_idle ()
537
581
538
582
539
- class ToolYScale (AxisScaleBase ):
540
- """Tool to toggle between linear and logarithmic scales on the Y axis"""
541
-
542
- description = 'Toogle Scale Y axis'
543
- default_keymap = rcParams ['keymap.yscale' ]
544
-
545
- def set_scale (self , ax , scale ):
546
- ax .set_yscale (scale )
547
-
548
-
583
+ @register_tool ("xscale" )
549
584
class ToolXScale (AxisScaleBase ):
550
585
"""Tool to toggle between linear and logarithmic scales on the X axis"""
551
586
@@ -556,6 +591,18 @@ def set_scale(self, ax, scale):
556
591
ax .set_xscale (scale )
557
592
558
593
594
+ @register_tool ("yscale" )
595
+ class ToolYScale (AxisScaleBase ):
596
+ """Tool to toggle between linear and logarithmic scales on the Y axis"""
597
+
598
+ description = 'Toogle Scale Y axis'
599
+ default_keymap = rcParams ['keymap.yscale' ]
600
+
601
+ def set_scale (self , ax , scale ):
602
+ ax .set_yscale (scale )
603
+
604
+
605
+ @register_tool ("viewpos" )
559
606
class ToolViewsPositions (ToolBase ):
560
607
"""
561
608
Auxiliary Tool to handle changes in views and positions
@@ -714,12 +761,13 @@ class ViewsPositionsBase(ToolBase):
714
761
_on_trigger = None
715
762
716
763
def trigger (self , sender , event , data = None ):
717
- self .toolmanager .get_tool (_views_positions ).add_figure (self .figure )
718
- getattr (self .toolmanager .get_tool (_views_positions ),
764
+ self .toolmanager .get_tool ("viewpos" ).add_figure (self .figure )
765
+ getattr (self .toolmanager .get_tool ("viewpos" ),
719
766
self ._on_trigger )()
720
- self .toolmanager .get_tool (_views_positions ).update_view ()
767
+ self .toolmanager .get_tool ("viewpos" ).update_view ()
721
768
722
769
770
+ @register_tool ("home" )
723
771
class ToolHome (ViewsPositionsBase ):
724
772
"""Restore the original view lim"""
725
773
@@ -729,6 +777,7 @@ class ToolHome(ViewsPositionsBase):
729
777
_on_trigger = 'home'
730
778
731
779
780
+ @register_tool ("back" )
732
781
class ToolBack (ViewsPositionsBase ):
733
782
"""Move back up the view lim stack"""
734
783
@@ -738,6 +787,7 @@ class ToolBack(ViewsPositionsBase):
738
787
_on_trigger = 'back'
739
788
740
789
790
+ @register_tool ("forward" )
741
791
class ToolForward (ViewsPositionsBase ):
742
792
"""Move forward in the view lim stack"""
743
793
@@ -747,13 +797,15 @@ class ToolForward(ViewsPositionsBase):
747
797
_on_trigger = 'forward'
748
798
749
799
800
+ @register_tool ("subplots" )
750
801
class ConfigureSubplotsBase (ToolBase ):
751
802
"""Base tool for the configuration of subplots"""
752
803
753
804
description = 'Configure subplots'
754
805
image = 'subplots'
755
806
756
807
808
+ @register_tool ("save" )
757
809
class SaveFigureBase (ToolBase ):
758
810
"""Base tool for figure saving"""
759
811
@@ -794,7 +846,7 @@ def disable(self, event):
794
846
self .figure .canvas .mpl_disconnect (self ._idScroll )
795
847
796
848
def trigger (self , sender , event , data = None ):
797
- self .toolmanager .get_tool (_views_positions ).add_figure (self .figure )
849
+ self .toolmanager .get_tool ("viewpos" ).add_figure (self .figure )
798
850
ToolToggleBase .trigger (self , sender , event , data )
799
851
800
852
def scroll_zoom (self , event ):
@@ -818,14 +870,15 @@ def scroll_zoom(self, event):
818
870
# If last scroll was done within the timing threshold, delete the
819
871
# previous view
820
872
if (time .time ()- self .lastscroll ) < self .scrollthresh :
821
- self .toolmanager .get_tool (_views_positions ).back ()
873
+ self .toolmanager .get_tool ("viewpos" ).back ()
822
874
823
875
self .figure .canvas .draw_idle () # force re-draw
824
876
825
877
self .lastscroll = time .time ()
826
- self .toolmanager .get_tool (_views_positions ).push_current ()
878
+ self .toolmanager .get_tool ("viewpos" ).push_current ()
827
879
828
880
881
+ @register_tool ("zoom" )
829
882
class ToolZoom (ZoomPanBase ):
830
883
"""Zoom to rectangle"""
831
884
@@ -843,7 +896,7 @@ def _cancel_action(self):
843
896
for zoom_id in self ._ids_zoom :
844
897
self .figure .canvas .mpl_disconnect (zoom_id )
845
898
self .toolmanager .trigger_tool ('rubberband' , self )
846
- self .toolmanager .get_tool (_views_positions ).refresh_locators ()
899
+ self .toolmanager .get_tool ("viewpos" ).refresh_locators ()
847
900
self ._xypress = None
848
901
self ._button_pressed = None
849
902
self ._ids_zoom = []
@@ -948,10 +1001,11 @@ def _release(self, event):
948
1001
self ._zoom_mode , twinx , twiny )
949
1002
950
1003
self ._zoom_mode = None
951
- self .toolmanager .get_tool (_views_positions ).push_current ()
1004
+ self .toolmanager .get_tool ("viewpos" ).push_current ()
952
1005
self ._cancel_action ()
953
1006
954
1007
1008
+ @register_tool ("pan" )
955
1009
class ToolPan (ZoomPanBase ):
956
1010
"""Pan axes with left mouse, zoom with right"""
957
1011
@@ -970,7 +1024,7 @@ def _cancel_action(self):
970
1024
self ._xypress = []
971
1025
self .figure .canvas .mpl_disconnect (self ._idDrag )
972
1026
self .toolmanager .messagelock .release (self )
973
- self .toolmanager .get_tool (_views_positions ).refresh_locators ()
1027
+ self .toolmanager .get_tool ("viewpos" ).refresh_locators ()
974
1028
975
1029
def _press (self , event ):
976
1030
if event .button == 1 :
@@ -1007,7 +1061,7 @@ def _release(self, event):
1007
1061
self ._cancel_action ()
1008
1062
return
1009
1063
1010
- self .toolmanager .get_tool (_views_positions ).push_current ()
1064
+ self .toolmanager .get_tool ("viewpos" ).push_current ()
1011
1065
self ._cancel_action ()
1012
1066
1013
1067
def _mouse_move (self , event ):
@@ -1018,24 +1072,11 @@ def _mouse_move(self, event):
1018
1072
self .toolmanager .canvas .draw_idle ()
1019
1073
1020
1074
1021
- default_tools = {'home' : ToolHome , 'back' : ToolBack , 'forward' : ToolForward ,
1022
- 'zoom' : ToolZoom , 'pan' : ToolPan ,
1023
- 'subplots' : 'ToolConfigureSubplots' ,
1024
- 'save' : 'ToolSaveFigure' ,
1025
- 'grid' : ToolGrid ,
1026
- 'grid_minor' : ToolMinorGrid ,
1027
- 'fullscreen' : ToolFullScreen ,
1028
- 'quit' : ToolQuit ,
1029
- 'quit_all' : ToolQuitAll ,
1030
- 'allnav' : ToolEnableAllNavigation ,
1031
- 'nav' : ToolEnableNavigation ,
1032
- 'xscale' : ToolXScale ,
1033
- 'yscale' : ToolYScale ,
1034
- 'position' : ToolCursorPosition ,
1035
- _views_positions : ToolViewsPositions ,
1036
- 'cursor' : 'ToolSetCursor' ,
1037
- 'rubberband' : 'ToolRubberband' ,
1038
- }
1075
+ default_tools = [
1076
+ 'home' , 'back' , 'forward' , 'zoom' , 'pan' , 'subplots' , 'save' ,
1077
+ 'grid' , 'grid_minor' , 'fullscreen' , 'quit' , 'quit_all' , 'allnav' , 'nav' ,
1078
+ 'xscale' , 'yscale' , 'position' , 'viewpos' , 'cursor' , 'rubberband' ,
1079
+ ]
1039
1080
"""Default tools"""
1040
1081
1041
1082
default_toolbar_tools = [['navigation' , ['home' , 'back' , 'forward' ]],
@@ -1052,13 +1093,12 @@ def add_tools_to_manager(toolmanager, tools=default_tools):
1052
1093
----------
1053
1094
toolmanager: ToolManager
1054
1095
`backend_managers.ToolManager` object that will get the tools added
1055
- tools : {str: class_like}, optional
1056
- The tools to add in a {name: tool} dict, see `add_tool` for more
1057
- info.
1096
+ tools : List[str], optional
1097
+ The tools to add.
1058
1098
"""
1059
1099
1060
- for name , tool in six . iteritems ( tools ) :
1061
- toolmanager .add_tool (name , tool )
1100
+ for tool_name in tools :
1101
+ toolmanager .add_tool (tool_name )
1062
1102
1063
1103
1064
1104
def add_tools_to_container (container , tools = default_toolbar_tools ):
0 commit comments