@@ -1055,21 +1055,24 @@ def make_image(self, renderer, magnification=1.0, unsampled=False):
10551055 B [:, :, 0 :3 ] = A
10561056 B [:, :, 3 ] = 255
10571057 A = B
1058- l , b , r , t = self .axes .bbox .extents
1059- width = int (((round (r ) + 0.5 ) - (round (l ) - 0.5 )) * magnification )
1060- height = int (((round (t ) + 0.5 ) - (round (b ) - 0.5 )) * magnification )
1058+ magnified_extents = (self .axes .bbox .extents * magnification + 0.5 ).astype (int )
1059+ l , b , r , t = magnified_extents / magnification
1060+ width = int ((r - l ) * magnification )
1061+ height = int ((t - b ) * magnification )
10611062
10621063 invertedTransform = self .axes .transData .inverted ()
1063- x_pix = invertedTransform .transform (
1064- [(x , b ) for x in np .linspace (l , r , width )])[:, 0 ]
1065- y_pix = invertedTransform .transform (
1066- [(l , y ) for y in np .linspace (b , t , height )])[:, 1 ]
1064+ x_pix_edges = invertedTransform .transform (
1065+ [(x , b ) for x in np .linspace (l , r , width + 1 )])[:, 0 ]
1066+ y_pix_edges = invertedTransform .transform (
1067+ [(l , y ) for y in np .linspace (b , t , height + 1 )])[:, 1 ]
1068+ x_pix_centers = (x_pix_edges [:- 1 ] + x_pix_edges [1 :]) / 2
1069+ y_pix_centers = (y_pix_edges [:- 1 ] + y_pix_edges [1 :]) / 2
10671070
10681071 if self ._interpolation == "nearest" :
10691072 x_mid = (self ._Ax [:- 1 ] + self ._Ax [1 :]) / 2
10701073 y_mid = (self ._Ay [:- 1 ] + self ._Ay [1 :]) / 2
1071- x_int = x_mid .searchsorted (x_pix )
1072- y_int = y_mid .searchsorted (y_pix )
1074+ x_int = x_mid .searchsorted (x_pix_centers )
1075+ y_int = y_mid .searchsorted (y_pix_centers )
10731076 # The following is equal to `A[y_int[:, None], x_int[None, :]]`,
10741077 # but many times faster. Both casting to uint32 (to have an
10751078 # effectively 1D array) and manual index flattening matter.
@@ -1080,16 +1083,16 @@ def make_image(self, renderer, magnification=1.0, unsampled=False):
10801083 else : # self._interpolation == "bilinear"
10811084 # Use np.interp to compute x_int/x_float has similar speed.
10821085 x_int = np .clip (
1083- self ._Ax .searchsorted (x_pix ) - 1 , 0 , len (self ._Ax ) - 2 )
1086+ self ._Ax .searchsorted (x_pix_centers ) - 1 , 0 , len (self ._Ax ) - 2 )
10841087 y_int = np .clip (
1085- self ._Ay .searchsorted (y_pix ) - 1 , 0 , len (self ._Ay ) - 2 )
1088+ self ._Ay .searchsorted (y_pix_centers ) - 1 , 0 , len (self ._Ay ) - 2 )
10861089 idx_int = np .add .outer (y_int * A .shape [1 ], x_int )
10871090 x_frac = np .clip (
1088- np .divide (x_pix - self ._Ax [x_int ], np .diff (self ._Ax )[x_int ],
1091+ np .divide (x_pix_centers - self ._Ax [x_int ], np .diff (self ._Ax )[x_int ],
10891092 dtype = np .float32 ), # Downcasting helps with speed.
10901093 0 , 1 )
10911094 y_frac = np .clip (
1092- np .divide (y_pix - self ._Ay [y_int ], np .diff (self ._Ay )[y_int ],
1095+ np .divide (y_pix_centers - self ._Ay [y_int ], np .diff (self ._Ay )[y_int ],
10931096 dtype = np .float32 ),
10941097 0 , 1 )
10951098 f00 = np .outer (1 - y_frac , 1 - x_frac )
@@ -1242,22 +1245,24 @@ def make_image(self, renderer, magnification=1.0, unsampled=False):
12421245 if (padded_A [0 , 0 ] != bg ).all ():
12431246 padded_A [[0 , - 1 ], :] = padded_A [:, [0 , - 1 ]] = bg
12441247
1245- l , b , r , t = self . axes . bbox . extents
1246- width = ( round ( r ) + 0.5 ) - ( round ( l ) - 0.5 )
1247- height = ( round ( t ) + 0.5 ) - ( round ( b ) - 0.5 )
1248- width = round ( width * magnification )
1249- height = round ( height * magnification )
1248+ # Round to the nearest output pixels after magnification
1249+ l , b , r , t = ( self . axes . bbox . extents * magnification + 0.5 ). astype ( int )
1250+ width = r - l
1251+ height = t - b
1252+
12501253 vl = self .axes .viewLim
12511254
1252- x_pix = np .linspace (vl .x0 , vl .x1 , width )
1253- y_pix = np .linspace (vl .y0 , vl .y1 , height )
1254- x_int = self ._Ax .searchsorted (x_pix )
1255- y_int = self ._Ay .searchsorted (y_pix )
1255+ x_pix_edges = np .linspace (vl .x0 , vl .x1 , width + 1 )
1256+ y_pix_edges = np .linspace (vl .y0 , vl .y1 , height + 1 )
1257+ x_pix_centers = (x_pix_edges [:- 1 ] + x_pix_edges [1 :]) / 2
1258+ y_pix_centers = (y_pix_edges [:- 1 ] + y_pix_edges [1 :]) / 2
1259+ x_int = self ._Ax .searchsorted (x_pix_centers )
1260+ y_int = self ._Ay .searchsorted (y_pix_centers )
12561261 im = ( # See comment in NonUniformImage.make_image re: performance.
12571262 padded_A .view (np .uint32 ).ravel ()[
12581263 np .add .outer (y_int * padded_A .shape [1 ], x_int )]
12591264 .view (np .uint8 ).reshape ((height , width , 4 )))
1260- return im , l , b , IdentityTransform ()
1265+ return im , l / magnification , b / magnification , IdentityTransform ()
12611266
12621267 def _check_unsampled_image (self ):
12631268 return False
0 commit comments