14
14
import sys
15
15
import weakref
16
16
17
- import numpy as np
18
- import PIL .Image
19
-
20
17
import matplotlib as mpl
21
18
from matplotlib .backend_bases import (
22
19
_Backend , FigureCanvasBase , FigureManagerBase ,
30
27
from matplotlib .transforms import Affine2D
31
28
32
29
import wx
30
+ import wx .svg
33
31
34
32
_log = logging .getLogger (__name__ )
35
33
@@ -473,10 +471,8 @@ def __init__(self, parent, id, figure=None):
473
471
FigureCanvasBase .__init__ (self , figure )
474
472
w , h = map (math .ceil , self .figure .bbox .size )
475
473
# Set preferred window size hint - helps the sizer, if one is connected
476
- wx .Panel .__init__ (self , parent , id , size = wx .Size (w , h ))
477
- # Create the drawing bitmap
478
- self .bitmap = wx .Bitmap (w , h )
479
- _log .debug ("%s - __init__() - bitmap w:%d h:%d" , type (self ), w , h )
474
+ wx .Panel .__init__ (self , parent , id , size = parent .FromDIP (wx .Size (w , h )))
475
+ self .bitmap = None
480
476
self ._isDrawn = False
481
477
self ._rubberband_rect = None
482
478
self ._rubberband_pen_black = wx .Pen ('BLACK' , 1 , wx .PENSTYLE_SHORT_DASH )
@@ -512,6 +508,12 @@ def __init__(self, parent, id, figure=None):
512
508
self .SetBackgroundStyle (wx .BG_STYLE_PAINT ) # Reduce flicker.
513
509
self .SetBackgroundColour (wx .WHITE )
514
510
511
+ if wx .Platform == '__WXMAC__' :
512
+ # Initial scaling. Other platforms handle this automatically
513
+ dpiScale = self .GetDPIScaleFactor ()
514
+ self .SetInitialSize (self .GetSize ()* (1 / dpiScale ))
515
+ self ._set_device_pixel_ratio (dpiScale )
516
+
515
517
def Copy_to_Clipboard (self , event = None ):
516
518
"""Copy bitmap of canvas to system clipboard."""
517
519
bmp_obj = wx .BitmapDataObject ()
@@ -524,6 +526,12 @@ def Copy_to_Clipboard(self, event=None):
524
526
wx .TheClipboard .Flush ()
525
527
wx .TheClipboard .Close ()
526
528
529
+ def _update_device_pixel_ratio (self , * args , ** kwargs ):
530
+ # We need to be careful in cases with mixed resolution displays if
531
+ # device_pixel_ratio changes.
532
+ if self ._set_device_pixel_ratio (self .GetDPIScaleFactor ()):
533
+ self .draw ()
534
+
527
535
def draw_idle (self ):
528
536
# docstring inherited
529
537
_log .debug ("%s - draw_idle()" , type (self ))
@@ -631,7 +639,7 @@ def _on_size(self, event):
631
639
In this application we attempt to resize to fit the window, so it
632
640
is better to take the performance hit and redraw the whole window.
633
641
"""
634
-
642
+ self . _update_device_pixel_ratio ()
635
643
_log .debug ("%s - _on_size()" , type (self ))
636
644
sz = self .GetParent ().GetSizer ()
637
645
if sz :
@@ -655,9 +663,10 @@ def _on_size(self, event):
655
663
return # Empty figure
656
664
657
665
# Create a new, correctly sized bitmap
658
- self .bitmap = wx .Bitmap (self ._width , self ._height )
659
-
660
666
dpival = self .figure .dpi
667
+ if not wx .Platform == '__WXMSW__' :
668
+ scale = self .GetDPIScaleFactor ()
669
+ dpival /= scale
661
670
winch = self ._width / dpival
662
671
hinch = self ._height / dpival
663
672
self .figure .set_size_inches (winch , hinch , forward = False )
@@ -712,7 +721,11 @@ def _mpl_coords(self, pos=None):
712
721
else :
713
722
x , y = pos .X , pos .Y
714
723
# flip y so y=0 is bottom of canvas
715
- return x , self .figure .bbox .height - y
724
+ if not wx .Platform == '__WXMSW__' :
725
+ scale = self .GetDPIScaleFactor ()
726
+ return x * scale , self .figure .bbox .height - y * scale
727
+ else :
728
+ return x , self .figure .bbox .height - y
716
729
717
730
def _on_key_down (self , event ):
718
731
"""Capture key press."""
@@ -898,8 +911,8 @@ def __init__(self, num, fig, *, canvas_class):
898
911
# On Windows, canvas sizing must occur after toolbar addition;
899
912
# otherwise the toolbar further resizes the canvas.
900
913
w , h = map (math .ceil , fig .bbox .size )
901
- self .canvas .SetInitialSize (wx .Size (w , h ))
902
- self .canvas .SetMinSize (( 2 , 2 ))
914
+ self .canvas .SetInitialSize (self . FromDIP ( wx .Size (w , h ) ))
915
+ self .canvas .SetMinSize (self . FromDIP ( wx . Size ( 2 , 2 ) ))
903
916
self .canvas .SetFocus ()
904
917
905
918
self .Fit ()
@@ -1017,9 +1030,9 @@ def _set_frame_icon(frame):
1017
1030
class NavigationToolbar2Wx (NavigationToolbar2 , wx .ToolBar ):
1018
1031
def __init__ (self , canvas , coordinates = True , * , style = wx .TB_BOTTOM ):
1019
1032
wx .ToolBar .__init__ (self , canvas .GetParent (), - 1 , style = style )
1033
+ if wx .Platform == '__WXMAC__' :
1034
+ self .SetToolBitmapSize (self .GetToolBitmapSize ()* self .GetDPIScaleFactor ())
1020
1035
1021
- if 'wxMac' in wx .PlatformInfo :
1022
- self .SetToolBitmapSize ((24 , 24 ))
1023
1036
self .wx_ids = {}
1024
1037
for text , tooltip_text , image_file , callback in self .toolitems :
1025
1038
if text is None :
@@ -1028,7 +1041,7 @@ def __init__(self, canvas, coordinates=True, *, style=wx.TB_BOTTOM):
1028
1041
self .wx_ids [text ] = (
1029
1042
self .AddTool (
1030
1043
- 1 ,
1031
- bitmap = self ._icon (f"{ image_file } .png " ),
1044
+ bitmap = self ._icon (f"{ image_file } .svg " ),
1032
1045
bmpDisabled = wx .NullBitmap ,
1033
1046
label = text , shortHelp = tooltip_text ,
1034
1047
kind = (wx .ITEM_CHECK if text in ["Pan" , "Zoom" ]
@@ -1054,9 +1067,7 @@ def _icon(name):
1054
1067
*name*, including the extension and relative to Matplotlib's "images"
1055
1068
data directory.
1056
1069
"""
1057
- pilimg = PIL .Image .open (cbook ._get_data_path ("images" , name ))
1058
- # ensure RGBA as wx BitMap expects RGBA format
1059
- image = np .array (pilimg .convert ("RGBA" ))
1070
+ svg = cbook ._get_data_path ("images" , name ).read_bytes ()
1060
1071
try :
1061
1072
dark = wx .SystemSettings .GetAppearance ().IsDark ()
1062
1073
except AttributeError : # wxpython < 4.1
@@ -1068,11 +1079,9 @@ def _icon(name):
1068
1079
fg_lum = (.299 * fg .red + .587 * fg .green + .114 * fg .blue ) / 255
1069
1080
dark = fg_lum - bg_lum > .2
1070
1081
if dark :
1071
- fg = wx .SystemSettings .GetColour (wx .SYS_COLOUR_WINDOWTEXT )
1072
- black_mask = (image [..., :3 ] == 0 ).all (axis = - 1 )
1073
- image [black_mask , :3 ] = (fg .Red (), fg .Green (), fg .Blue ())
1074
- return wx .Bitmap .FromBufferRGBA (
1075
- image .shape [1 ], image .shape [0 ], image .tobytes ())
1082
+ svg = svg .replace (b'fill:black;' , b'fill:white;' )
1083
+ toolbarIconSize = wx .ArtProvider ().GetDIPSizeHint (wx .ART_TOOLBAR )
1084
+ return wx .BitmapBundle .FromSVG (svg , toolbarIconSize )
1076
1085
1077
1086
def _update_buttons_checked (self ):
1078
1087
if "Pan" in self .wx_ids :
@@ -1123,7 +1132,9 @@ def save_figure(self, *args):
1123
1132
1124
1133
def draw_rubberband (self , event , x0 , y0 , x1 , y1 ):
1125
1134
height = self .canvas .figure .bbox .height
1126
- self .canvas ._rubberband_rect = (x0 , height - y0 , x1 , height - y1 )
1135
+ sf = self .GetDPIScaleFactor ()
1136
+ self .canvas ._rubberband_rect = (x0 / sf , (height - y0 )/ sf ,
1137
+ x1 / sf , (height - y1 )/ sf )
1127
1138
self .canvas .Refresh ()
1128
1139
1129
1140
def remove_rubberband (self ):
0 commit comments